diff --git a/package-lock.json b/package-lock.json index fd31c37..ff560c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "astra", - "version": "2.2.216", + "version": "2.2.217", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "astra", - "version": "2.2.216", + "version": "2.2.217", "license": "MIT", "dependencies": { "@lmstudio/sdk": "^1.5.0", diff --git a/package.json b/package.json index 1ce7040..bec8ce2 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "astra", "displayName": "Astra", "description": "The personal intelligence layer for Antigravity and VS Code. A private cognitive partner for deep project context, memory, and proactive strategic decision-making.", - "version": "2.2.216", + "version": "2.2.217", "publisher": "g1nation", "license": "MIT", "icon": "assets/icon.png", diff --git a/src/extension.ts b/src/extension.ts index 5562ab3..b6d3de9 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -40,6 +40,7 @@ import { runConnectGoogleCalendarIcal, runConnectGoogleCalendarOAuth } from './e import { runInitialSetup } from './extension/initialSetup'; import { startStocksWatcher } from './features/stocks'; import { startDailyBriefingWatcher } from './features/briefing/dailyBriefing'; +import { ensureDefaultBrainConfigured } from './extension/brainBootstrap'; import { registerProviderCommands } from './extension/providerCommands'; import { registerScaffoldCommand } from './extension/scaffoldCommand'; import { registerLessonCommands } from './extension/lessonCommands'; @@ -65,6 +66,11 @@ export async function activate(context: vscode.ExtensionContext) { void vscode.window.showInformationMessage(`๐Ÿ“ก Astra v${version} activated (PID=${process.pid})`); logInfo(`Astra activating... version=${version} pid=${process.pid}`); + // ๋‘๋‡Œ ๊ธฐ๋ณธ ์œ„์น˜ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ โ€” ๋ฏธ์„ค์ •์ด๋ฉด ๋ฌธ์„œ\AstraBrain ์ƒ์„ฑยท๋“ฑ๋ก. + // ์„ฑ์žฅ ๋ฐ์ดํ„ฐ(๋ ˆ์Šจยท๊ธฐ์–ตยท์ง€์‹)๊ฐ€ ์ˆจ๊น€ ํด๋ฐฑ(~/.g1nation-brain)์œผ๋กœ ์กฐ์šฉํžˆ ๊ฐ€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€. + // ์ดํ›„ ์ฝ”๋“œ๊ฐ€ getConfig() ๋กœ ๋‘๋‡Œ ๊ฒฝ๋กœ๋ฅผ ์ฝ์œผ๋ฏ€๋กœ ์„ค์ • ๊ธฐ๋ก์ด ๋๋‚œ ๋’ค ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค. + await ensureDefaultBrainConfigured(); + // Initialize Astra Path Resolver (.astra โ†’ ConnectAI/.astra/) initAstraPathResolver(context); diff --git a/src/extension/brainBootstrap.ts b/src/extension/brainBootstrap.ts new file mode 100644 index 0000000..984c42a --- /dev/null +++ b/src/extension/brainBootstrap.ts @@ -0,0 +1,90 @@ +/** + * ๋‘๋‡Œ(Second Brain) ๊ธฐ๋ณธ ์œ„์น˜ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ โ€” ์ฒซ ์‹คํ–‰ ์˜จ๋ณด๋”ฉ. + * + * ๋ฌธ์ œ: ๋‘๋‡Œ ๋ฏธ์„ค์ • ์‹œ config ๊ฐ€ `~/.g1nation-brain`(์ˆจ๊น€ ์ ํด๋”)๋กœ ์กฐ์šฉํžˆ ํด๋ฐฑํ–ˆ๋‹ค. + * - ํด๋”๊ฐ€ ์‹ค์ œ๋กœ ์ƒ์„ฑ๋˜์ง€ ์•Š๊ณ , ์„ค์ • UI ์—๋„ ๋ณด์ด์ง€ ์•Š์œผ๋ฉฐ, ์ˆจ๊น€ ํด๋”๋ผ + * ๋น„๊ฐœ๋ฐœ์ž ์‚ฌ์šฉ์ž๋Š” ์ž์‹ ์˜ ์„ฑ์žฅ ๋ฐ์ดํ„ฐ(๋ ˆ์Šจยท๊ธฐ์–ตยท์ง€์‹)๊ฐ€ ์–ด๋”” ์Œ“์ด๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค. + * - ์ปดํ“จํ„ฐ๋งˆ๋‹ค ์œ„์น˜๊ฐ€ "๋ณด์ด์ง€ ์•Š๊ฒŒ" ๋‹ฌ๋ผ์ ธ ๋ฐฑ์—…ยท์ด์ „์ด ๋ถˆ๊ฐ€๋Šฅํ–ˆ๋‹ค. + * + * ํ•ด๊ฒฐ: ํ™œ์„ฑํ™” ์‹œ ๋‘๋‡Œ๊ฐ€ ๋ช…์‹œ ์„ค์ •๋ผ ์žˆ์ง€ ์•Š์œผ๋ฉด + * 1) `๋ฌธ์„œ\AstraBrain` ํด๋”๋ฅผ ์‹ค์ œ๋กœ ์ƒ์„ฑ (lessons/ ยท memory/ ํฌํ•จ) + * 2) README ๋กœ "์ด ํด๋”๊ฐ€ ASTRA ์˜ ๋‘๋‡Œ"์ž„์„ ์„ค๋ช… (๋ฐฑ์—… ์•ˆ๋‚ด ํฌํ•จ) + * 3) settings(global) ์˜ brainProfiles ์— ๋ช…์‹œ ๊ธฐ๋ก โ†’ ์„ค์ • UI ์—์„œ ๋ณด์ด๊ณ  ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ + * 4) ์‚ฌ์šฉ์ž์—๊ฒŒ 1ํšŒ ์•Œ๋ฆผ + * + * ๋ฐ์ดํ„ฐ ๋ณดํ˜ธ: ๊ณผ๊ฑฐ ํด๋ฐฑ(`~/.g1nation-brain`)์— ์ด๋ฏธ ๋ฐ์ดํ„ฐ๊ฐ€ ์Œ“์—ฌ ์žˆ์œผ๋ฉด + * ๊ทธ ๊ฒฝ๋กœ๋ฅผ ๊ทธ๋Œ€๋กœ ๋“ฑ๋กํ•œ๋‹ค (์ด๋™ํ•˜์ง€ ์•Š์Œ โ€” ๊ธฐ์กด ์„ฑ์žฅ ๋ฐ์ดํ„ฐ ์œ ์‹ค ๋ฐฉ์ง€). + * ์ด๋ฏธ brainProfiles ๋˜๋Š” legacy localBrainPath ๊ฐ€ ์„ค์ •๋œ ์‚ฌ์šฉ์ž๋Š” no-op. + */ +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import * as vscode from 'vscode'; +import { logError, logInfo } from '../utils'; + +const README_NAME = 'README-AstraBrain.md'; +const README_BODY = `# AstraBrain โ€” ASTRA ์˜ ๋‘๋‡Œ ํด๋” + +์ด ํด๋”๋Š” VS Code ํ™•์žฅ **Astra** ๊ฐ€ ํ•™์Šตยท์„ฑ์žฅํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. + +| ํด๋”/ํŒŒ์ผ | ๋‚ด์šฉ | +|---|---| +| \`lessons/\` | ์ž‘์—… ๊ฒฝํ—˜์—์„œ ๋งŒ๋“ค์–ด์ง„ ๊ตํ›ˆ (๊ฒฝํ—˜ ๊ธฐ์–ต) | +| \`memory/long_term.json\` | ๋Œ€ํ™”์—์„œ ์ถ”์ถœ๋œ ์žฅ๊ธฐ ๊ธฐ์–ต | +| \`memory/episodes/\` | ์ผํ™” ๊ธฐ์–ต | +| \`*.md\` ์ง€์‹ ๋ฌธ์„œ | ๋ฆฌ์„œ์น˜ยท์œ„ํ‚คํ™”๋กœ ์ถ•์ ๋œ ์ง€์‹ (๊ฒ€์ƒ‰/RAG ๋Œ€์ƒ) | +| \`.astra/\` | ํ‰๊ฐ€ ๊ณจ๋“ ์…‹ยท์„ฑ์žฅ ๋ฆฌํฌํŠธ ๋“ฑ | + +โš ๏ธ **์ด ํด๋”๋Š” ASTRA ์˜ ์ž์‚ฐ์ž…๋‹ˆ๋‹ค โ€” ๋ฐฑ์—…์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.** +์œ„์น˜ ๋ณ€๊ฒฝ: VS Code Settings โ†’ \`g1nation.brainProfiles\` ์˜ \`localBrainPath\`. +`; + +/** + * ๋‘๋‡Œ ๋ฏธ์„ค์ • ์‹œ ๊ธฐ๋ณธ ๋‘๋‡Œ๋ฅผ ์ƒ์„ฑยท๋“ฑ๋กํ•œ๋‹ค. ํ™œ์„ฑํ™” ์ดˆ๊ธฐ์— 1ํšŒ ํ˜ธ์ถœ. + * ๋ฐ˜ํ™˜: ์ƒˆ๋กœ ๋ถ€ํŠธ์ŠคํŠธ๋žฉํ–ˆ์œผ๋ฉด ๊ทธ ๊ฒฝ๋กœ, ์•„๋‹ˆ๋ฉด null(์ด๋ฏธ ์„ค์ •๋จ/์‹คํŒจ). + */ +export async function ensureDefaultBrainConfigured(): Promise { + try { + const cfg = vscode.workspace.getConfiguration('g1nation'); + const profiles = cfg.get>('brainProfiles', []) || []; + const legacy = (cfg.get('localBrainPath', '') || '').trim(); + // ๋ช…์‹œ ์„ค์ •์ด ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ์†๋Œ€์ง€ ์•Š๋Š”๋‹ค (๊ธฐ์กด ์‚ฌ์šฉ์ž ๋ฌด์˜ํ–ฅ). + if (profiles.some(p => (p?.localBrainPath || '').trim()) || legacy) return null; + + // ๊ณผ๊ฑฐ ์ˆจ๊น€ ํด๋ฐฑ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ด๋ฏธ ์žˆ์œผ๋ฉด ๊ทธ ๊ฒฝ๋กœ๋ฅผ ๊ทธ๋Œ€๋กœ ๋“ฑ๋ก (์œ ์‹ค ๋ฐฉ์ง€). + const dotBrain = path.join(os.homedir(), '.g1nation-brain'); + let target: string; + let reused = false; + if (fs.existsSync(dotBrain) && fs.readdirSync(dotBrain).length > 0) { + target = dotBrain; + reused = true; + } else { + const docs = path.join(os.homedir(), 'Documents'); + target = path.join(fs.existsSync(docs) ? docs : os.homedir(), 'AstraBrain'); + } + + fs.mkdirSync(path.join(target, 'lessons'), { recursive: true }); + fs.mkdirSync(path.join(target, 'memory'), { recursive: true }); + const readmePath = path.join(target, README_NAME); + if (!fs.existsSync(readmePath)) fs.writeFileSync(readmePath, README_BODY, 'utf8'); + + await cfg.update('brainProfiles', [{ + id: 'default-brain', + name: 'AstraBrain', + localBrainPath: target, + description: reused ? '๊ธฐ์กด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐœ๊ฒฌ๋˜์–ด ์ž๋™ ๋“ฑ๋ก๋จ' : '์ฒซ ์‹คํ–‰ ์‹œ ์ž๋™ ์ƒ์„ฑ๋œ ๋‘๋‡Œ ํด๋”', + }], vscode.ConfigurationTarget.Global); + await cfg.update('activeBrainId', 'default-brain', vscode.ConfigurationTarget.Global); + + logInfo('Brain bootstrap ์™„๋ฃŒ.', { target, reused }); + void vscode.window.showInformationMessage( + reused + ? `Astra ๋‘๋‡Œ: ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐœ๊ฒฌํ•ด ๋“ฑ๋กํ–ˆ์Šต๋‹ˆ๋‹ค โ€” ${target}` + : `Astra ๋‘๋‡Œ ํด๋”๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค โ€” ${target} (๋ ˆ์Šจยท๊ธฐ์–ตยท์ง€์‹์ด ์—ฌ๊ธฐ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ๋ฐฑ์—… ๊ถŒ์žฅ)`, + ); + return target; + } catch (e: any) { + logError('Brain bootstrap ์‹คํŒจ (๊ธฐ์กด ํด๋ฐฑ ๊ฒฝ๋กœ๋กœ ๋™์ž‘).', { error: e?.message ?? String(e) }); + return null; + } +}