cckb 0.1.0 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cckb.js +2 -2
- package/dist/{chunk-GUB5D6EN.js → chunk-3KGJEBKK.js} +12 -2
- package/dist/chunk-3KGJEBKK.js.map +1 -0
- package/dist/{chunk-TFFLX3YY.js → chunk-E2IJSPVB.js} +3 -2
- package/dist/chunk-E2IJSPVB.js.map +1 -0
- package/dist/{chunk-Z3CJQKTH.js → chunk-GLYS4OA4.js} +58 -3
- package/dist/chunk-GLYS4OA4.js.map +1 -0
- package/dist/{chunk-XAY6TTXB.js → chunk-NOCXYKIE.js} +2 -2
- package/dist/{chunk-K4W3KOBL.js → chunk-XQXIDTUW.js} +2 -2
- package/dist/hooks/notification.js +2 -2
- package/dist/hooks/post-tool-use.js +2 -2
- package/dist/hooks/session-start.js +3 -3
- package/dist/hooks/stop.js +4 -4
- package/dist/hooks/user-prompt.js +2 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -5
- package/package.json +1 -1
- package/templates/settings.json.tmpl +21 -6
- package/templates/vault/INDEX.md +2 -0
- package/templates/vault/apps/INDEX.md +10 -0
- package/templates/vault/modules/INDEX.md +10 -0
- package/dist/chunk-GUB5D6EN.js.map +0 -1
- package/dist/chunk-TFFLX3YY.js.map +0 -1
- package/dist/chunk-Z3CJQKTH.js.map +0 -1
- /package/dist/{chunk-XAY6TTXB.js.map → chunk-NOCXYKIE.js.map} +0 -0
- /package/dist/{chunk-K4W3KOBL.js.map → chunk-XQXIDTUW.js.map} +0 -0
package/dist/bin/cckb.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
readTextFile,
|
|
7
7
|
writeJSON,
|
|
8
8
|
writeTextFile
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-E2IJSPVB.js";
|
|
10
10
|
|
|
11
11
|
// src/cli/install.ts
|
|
12
12
|
import * as fs from "fs/promises";
|
|
@@ -69,6 +69,8 @@ async function createDirectoryStructure(targetPath) {
|
|
|
69
69
|
"cc-knowledge-base/conversations",
|
|
70
70
|
"cc-knowledge-base/vault",
|
|
71
71
|
"cc-knowledge-base/vault/entities",
|
|
72
|
+
"cc-knowledge-base/vault/apps",
|
|
73
|
+
"cc-knowledge-base/vault/modules",
|
|
72
74
|
"cc-knowledge-base/.cckb-state"
|
|
73
75
|
];
|
|
74
76
|
for (const dir of directories) {
|
|
@@ -90,6 +92,14 @@ async function copyTemplateFiles(targetPath) {
|
|
|
90
92
|
{
|
|
91
93
|
src: "vault/entities/INDEX.md",
|
|
92
94
|
dest: "cc-knowledge-base/vault/entities/INDEX.md"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
src: "vault/apps/INDEX.md",
|
|
98
|
+
dest: "cc-knowledge-base/vault/apps/INDEX.md"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
src: "vault/modules/INDEX.md",
|
|
102
|
+
dest: "cc-knowledge-base/vault/modules/INDEX.md"
|
|
93
103
|
}
|
|
94
104
|
];
|
|
95
105
|
for (const file of vaultFiles) {
|
|
@@ -194,4 +204,4 @@ async function updateGitignore(targetPath) {
|
|
|
194
204
|
export {
|
|
195
205
|
install
|
|
196
206
|
};
|
|
197
|
-
//# sourceMappingURL=chunk-
|
|
207
|
+
//# sourceMappingURL=chunk-3KGJEBKK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/install.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as fsSync from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n ensureDir,\n fileExists,\n readJSON,\n writeJSON,\n readTextFile,\n writeTextFile,\n} from \"../utils/file-utils.js\";\nimport { DEFAULT_CONFIG } from \"../utils/config.js\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n// Find package root by looking for package.json\nfunction findPackageRoot(): string {\n let dir = __dirname;\n for (let i = 0; i < 5; i++) {\n const packageJson = path.join(dir, \"package.json\");\n if (fsSync.existsSync(packageJson)) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n // Fallback to relative from __dirname\n return path.resolve(__dirname, \"../..\");\n}\n\nconst PACKAGE_ROOT = findPackageRoot();\nconst TEMPLATES_DIR = path.join(PACKAGE_ROOT, \"templates\");\n\nexport interface InstallOptions {\n force?: boolean;\n}\n\nexport async function install(\n targetPath: string,\n options: InstallOptions = {}\n): Promise<void> {\n const resolvedPath = path.resolve(targetPath);\n\n console.log(`Installing CCKB to: ${resolvedPath}`);\n\n // Pre-flight checks\n await validateTargetPath(resolvedPath);\n await checkExistingInstallation(resolvedPath, options.force);\n\n // Create directory structure\n await createDirectoryStructure(resolvedPath);\n\n // Copy template files\n await copyTemplateFiles(resolvedPath);\n\n // Create config file\n await createConfigFile(resolvedPath);\n\n // Install hooks configuration\n await installHooks(resolvedPath);\n\n // Update CLAUDE.md\n await updateClaudeMd(resolvedPath);\n\n // Update .gitignore\n await updateGitignore(resolvedPath);\n\n console.log(\"\\nCCKB installed successfully!\");\n console.log(\"\\nNext steps:\");\n console.log(\" 1. Review cc-knowledge-base/vault/ structure\");\n console.log(\" 2. Check .claude/settings.json for hook configuration\");\n console.log(\" 3. Start a new Claude Code session to begin capturing knowledge\");\n}\n\nasync function validateTargetPath(targetPath: string): Promise<void> {\n const exists = await fileExists(targetPath);\n if (!exists) {\n throw new Error(`Target path does not exist: ${targetPath}`);\n }\n\n const stats = await fs.stat(targetPath);\n if (!stats.isDirectory()) {\n throw new Error(`Target path is not a directory: ${targetPath}`);\n }\n}\n\nasync function checkExistingInstallation(\n targetPath: string,\n force?: boolean\n): Promise<void> {\n const kbPath = path.join(targetPath, \"cc-knowledge-base\");\n const exists = await fileExists(kbPath);\n\n if (exists && !force) {\n throw new Error(\n \"CCKB is already installed in this project. Use --force to reinstall.\"\n );\n }\n}\n\nasync function createDirectoryStructure(targetPath: string): Promise<void> {\n const directories = [\n \"cc-knowledge-base\",\n \"cc-knowledge-base/conversations\",\n \"cc-knowledge-base/vault\",\n \"cc-knowledge-base/vault/entities\",\n \"cc-knowledge-base/vault/apps\",\n \"cc-knowledge-base/vault/modules\",\n \"cc-knowledge-base/.cckb-state\",\n ];\n\n for (const dir of directories) {\n await ensureDir(path.join(targetPath, dir));\n }\n\n console.log(\" Created directory structure\");\n}\n\nasync function copyTemplateFiles(targetPath: string): Promise<void> {\n const vaultFiles = [\n { src: \"vault/INDEX.md\", dest: \"cc-knowledge-base/vault/INDEX.md\" },\n {\n src: \"vault/architecture.md\",\n dest: \"cc-knowledge-base/vault/architecture.md\",\n },\n {\n src: \"vault/general-knowledge.md\",\n dest: \"cc-knowledge-base/vault/general-knowledge.md\",\n },\n {\n src: \"vault/entities/INDEX.md\",\n dest: \"cc-knowledge-base/vault/entities/INDEX.md\",\n },\n {\n src: \"vault/apps/INDEX.md\",\n dest: \"cc-knowledge-base/vault/apps/INDEX.md\",\n },\n {\n src: \"vault/modules/INDEX.md\",\n dest: \"cc-knowledge-base/vault/modules/INDEX.md\",\n },\n ];\n\n for (const file of vaultFiles) {\n const srcPath = path.join(TEMPLATES_DIR, file.src);\n const destPath = path.join(targetPath, file.dest);\n\n const content = await readTextFile(srcPath);\n if (content) {\n await writeTextFile(destPath, content);\n }\n }\n\n // Create .gitkeep for conversations\n await writeTextFile(\n path.join(targetPath, \"cc-knowledge-base/conversations/.gitkeep\"),\n \"\"\n );\n\n console.log(\" Copied vault template files\");\n}\n\nasync function createConfigFile(targetPath: string): Promise<void> {\n const configPath = path.join(\n targetPath,\n \"cc-knowledge-base\",\n \".cckb-config.json\"\n );\n\n await writeJSON(configPath, DEFAULT_CONFIG);\n\n console.log(\" Created configuration file\");\n}\n\nasync function installHooks(targetPath: string): Promise<void> {\n const claudeDir = path.join(targetPath, \".claude\");\n const settingsPath = path.join(claudeDir, \"settings.json\");\n\n await ensureDir(claudeDir);\n\n // Load existing settings or create new\n let settings: Record<string, unknown> =\n (await readJSON<Record<string, unknown>>(settingsPath)) || {};\n\n // Load hook template\n const templatePath = path.join(TEMPLATES_DIR, \"settings.json.tmpl\");\n const hookSettings = await readJSON<{ hooks: Record<string, unknown> }>(\n templatePath\n );\n\n if (!hookSettings) {\n throw new Error(\"Failed to load hook template\");\n }\n\n // Merge hooks (CCKB hooks take precedence for its own hook types)\n const existingHooks = (settings.hooks as Record<string, unknown[]>) || {};\n const newHooks = hookSettings.hooks as Record<string, unknown[]>;\n\n settings.hooks = mergeHooks(existingHooks, newHooks);\n\n await writeJSON(settingsPath, settings);\n\n console.log(\" Installed hook configuration\");\n}\n\nfunction mergeHooks(\n existing: Record<string, unknown[]>,\n incoming: Record<string, unknown[]>\n): Record<string, unknown[]> {\n const merged = { ...existing };\n\n for (const [hookType, hooks] of Object.entries(incoming)) {\n if (!merged[hookType]) {\n merged[hookType] = [];\n }\n\n // Add incoming hooks, avoiding duplicates based on command\n for (const hook of hooks) {\n const hookObj = hook as Record<string, unknown>;\n const command = hookObj.command as string | undefined;\n\n if (command?.includes(\"cckb\")) {\n // Remove any existing CCKB hooks for this type\n merged[hookType] = merged[hookType].filter((h) => {\n const existingCmd = (h as Record<string, unknown>).command as\n | string\n | undefined;\n return !existingCmd?.includes(\"cckb\");\n });\n }\n\n merged[hookType].push(hook);\n }\n }\n\n return merged;\n}\n\nasync function updateClaudeMd(targetPath: string): Promise<void> {\n const claudeMdPath = path.join(targetPath, \"CLAUDE.md\");\n const templatePath = path.join(TEMPLATES_DIR, \"CLAUDE.md.tmpl\");\n\n const template = await readTextFile(templatePath);\n if (!template) {\n throw new Error(\"Failed to load CLAUDE.md template\");\n }\n\n const marker = \"## Project Knowledge Base (CCKB)\";\n\n let existing = await readTextFile(claudeMdPath);\n\n if (existing) {\n // Check if CCKB section already exists\n if (existing.includes(marker)) {\n // Replace existing CCKB section\n const regex = /## Project Knowledge Base \\(CCKB\\)[\\s\\S]*?(?=\\n## |$)/;\n existing = existing.replace(regex, template.trim());\n } else {\n // Append CCKB section\n existing = existing.trimEnd() + \"\\n\\n\" + template;\n }\n await writeTextFile(claudeMdPath, existing);\n } else {\n // Create new CLAUDE.md with CCKB section\n await writeTextFile(claudeMdPath, template);\n }\n\n console.log(\" Updated CLAUDE.md with vault directives\");\n}\n\nasync function updateGitignore(targetPath: string): Promise<void> {\n const gitignorePath = path.join(targetPath, \".gitignore\");\n\n const entries = [\n \"\",\n \"# CCKB state files\",\n \"cc-knowledge-base/.cckb-state/\",\n ];\n\n let existing = (await readTextFile(gitignorePath)) || \"\";\n\n // Check if already added\n if (existing.includes(\"cc-knowledge-base/.cckb-state/\")) {\n return;\n }\n\n existing = existing.trimEnd() + \"\\n\" + entries.join(\"\\n\") + \"\\n\";\n await writeTextFile(gitignorePath, existing);\n\n console.log(\" Updated .gitignore\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -71,7 +71,8 @@ var DEFAULT_CONFIG = {
|
|
|
71
71
|
compaction: {
|
|
72
72
|
trigger: "session_end",
|
|
73
73
|
sizeThresholdKB: 50,
|
|
74
|
-
messageThreshold: 100
|
|
74
|
+
messageThreshold: 100,
|
|
75
|
+
cleanupAfterSummary: "keep"
|
|
75
76
|
},
|
|
76
77
|
capture: {
|
|
77
78
|
tools: ["Write", "Edit", "MultiEdit", "Bash", "Task"],
|
|
@@ -128,4 +129,4 @@ export {
|
|
|
128
129
|
getVaultPath,
|
|
129
130
|
getStatePath
|
|
130
131
|
};
|
|
131
|
-
//# sourceMappingURL=chunk-
|
|
132
|
+
//# sourceMappingURL=chunk-E2IJSPVB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/file-utils.ts","../src/utils/config.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\n\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.mkdir(dirPath, { recursive: true });\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readJSON<T>(filePath: string): Promise<T | null> {\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n\nexport async function writeJSON(\n filePath: string,\n data: unknown,\n pretty = true\n): Promise<void> {\n await ensureDir(path.dirname(filePath));\n const content = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);\n await fs.writeFile(filePath, content);\n}\n\nexport async function appendToFile(\n filePath: string,\n content: string\n): Promise<void> {\n await ensureDir(path.dirname(filePath));\n await fs.appendFile(filePath, content);\n}\n\nexport async function readTextFile(filePath: string): Promise<string | null> {\n try {\n return await fs.readFile(filePath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\nexport async function writeTextFile(\n filePath: string,\n content: string\n): Promise<void> {\n await ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content);\n}\n\nexport async function copyFile(src: string, dest: string): Promise<void> {\n await ensureDir(path.dirname(dest));\n await fs.copyFile(src, dest);\n}\n\nexport async function listDir(dirPath: string): Promise<string[]> {\n try {\n return await fs.readdir(dirPath);\n } catch {\n return [];\n }\n}\n\nexport async function getFileSize(filePath: string): Promise<number> {\n try {\n const stats = await fs.stat(filePath);\n return stats.size;\n } catch {\n return 0;\n }\n}\n\nexport function generateSessionId(): string {\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 8);\n return `${timestamp}-${random}`;\n}\n\nexport function getCurrentTimestamp(): string {\n return new Date().toISOString();\n}\n","import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\n\nexport interface CCKBConfig {\n compaction: {\n trigger: \"session_end\" | \"size\" | \"messages\" | \"manual\";\n sizeThresholdKB: number;\n messageThreshold: number;\n cleanupAfterSummary: \"keep\" | \"archive\" | \"delete\";\n };\n capture: {\n tools: string[];\n maxContentLength: number;\n };\n vault: {\n autoIntegrate: boolean;\n maxDepth: number;\n };\n feedback: {\n enabled: boolean;\n contextDepth: number;\n };\n}\n\nexport const DEFAULT_CONFIG: CCKBConfig = {\n compaction: {\n trigger: \"session_end\",\n sizeThresholdKB: 50,\n messageThreshold: 100,\n cleanupAfterSummary: \"keep\",\n },\n capture: {\n tools: [\"Write\", \"Edit\", \"MultiEdit\", \"Bash\", \"Task\"],\n maxContentLength: 500,\n },\n vault: {\n autoIntegrate: true,\n maxDepth: 5,\n },\n feedback: {\n enabled: true,\n contextDepth: 2,\n },\n};\n\nexport async function loadConfig(projectPath: string): Promise<CCKBConfig> {\n const configPath = path.join(\n projectPath,\n \"cc-knowledge-base\",\n \".cckb-config.json\"\n );\n\n try {\n const content = await fs.readFile(configPath, \"utf-8\");\n const userConfig = JSON.parse(content);\n return { ...DEFAULT_CONFIG, ...userConfig };\n } catch {\n return DEFAULT_CONFIG;\n }\n}\n\nexport async function saveConfig(\n projectPath: string,\n config: CCKBConfig\n): Promise<void> {\n const configPath = path.join(\n projectPath,\n \"cc-knowledge-base\",\n \".cckb-config.json\"\n );\n\n await fs.writeFile(configPath, JSON.stringify(config, null, 2));\n}\n\nexport function getKnowledgeBasePath(projectPath: string): string {\n return path.join(projectPath, \"cc-knowledge-base\");\n}\n\nexport function getConversationsPath(projectPath: string): string {\n return path.join(projectPath, \"cc-knowledge-base\", \"conversations\");\n}\n\nexport function getVaultPath(projectPath: string): string {\n return path.join(projectPath, \"cc-knowledge-base\", \"vault\");\n}\n\nexport function getStatePath(projectPath: string): string {\n return path.join(projectPath, \"cc-knowledge-base\", \".cckb-state\");\n}\n"],"mappings":";AAAA,YAAY,QAAQ;AACpB,YAAY,UAAU;AAEtB,eAAsB,UAAU,SAAgC;AAC9D,QAAS,SAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAC7C;AAEA,eAAsB,WAAW,UAAoC;AACnE,MAAI;AACF,UAAS,UAAO,QAAQ;AACxB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,SAAY,UAAqC;AACrE,MAAI;AACF,UAAM,UAAU,MAAS,YAAS,UAAU,OAAO;AACnD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,UACpB,UACA,MACA,SAAS,MACM;AACf,QAAM,UAAe,aAAQ,QAAQ,CAAC;AACtC,QAAM,UAAU,SAAS,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,KAAK,UAAU,IAAI;AAC5E,QAAS,aAAU,UAAU,OAAO;AACtC;AAEA,eAAsB,aACpB,UACA,SACe;AACf,QAAM,UAAe,aAAQ,QAAQ,CAAC;AACtC,QAAS,cAAW,UAAU,OAAO;AACvC;AAEA,eAAsB,aAAa,UAA0C;AAC3E,MAAI;AACF,WAAO,MAAS,YAAS,UAAU,OAAO;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,cACpB,UACA,SACe;AACf,QAAM,UAAe,aAAQ,QAAQ,CAAC;AACtC,QAAS,aAAU,UAAU,OAAO;AACtC;AAOA,eAAsB,QAAQ,SAAoC;AAChE,MAAI;AACF,WAAO,MAAS,WAAQ,OAAO;AAAA,EACjC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,YAAY,UAAmC;AACnE,MAAI;AACF,UAAM,QAAQ,MAAS,QAAK,QAAQ;AACpC,WAAO,MAAM;AAAA,EACf,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,oBAA4B;AAC1C,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC;AACxD,SAAO,GAAG,SAAS,IAAI,MAAM;AAC/B;AAEO,SAAS,sBAA8B;AAC5C,UAAO,oBAAI,KAAK,GAAE,YAAY;AAChC;;;ACzFA,YAAYA,SAAQ;AACpB,YAAYC,WAAU;AAuBf,IAAM,iBAA6B;AAAA,EACxC,YAAY;AAAA,IACV,SAAS;AAAA,IACT,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,EACvB;AAAA,EACA,SAAS;AAAA,IACP,OAAO,CAAC,SAAS,QAAQ,aAAa,QAAQ,MAAM;AAAA,IACpD,kBAAkB;AAAA,EACpB;AAAA,EACA,OAAO;AAAA,IACL,eAAe;AAAA,IACf,UAAU;AAAA,EACZ;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,EAChB;AACF;AAEA,eAAsB,WAAW,aAA0C;AACzE,QAAM,aAAkB;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI;AACF,UAAM,UAAU,MAAS,aAAS,YAAY,OAAO;AACrD,UAAM,aAAa,KAAK,MAAM,OAAO;AACrC,WAAO,EAAE,GAAG,gBAAgB,GAAG,WAAW;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAmBO,SAAS,qBAAqB,aAA6B;AAChE,SAAY,WAAK,aAAa,qBAAqB,eAAe;AACpE;AAEO,SAAS,aAAa,aAA6B;AACxD,SAAY,WAAK,aAAa,qBAAqB,OAAO;AAC5D;AAEO,SAAS,aAAa,aAA6B;AACxD,SAAY,WAAK,aAAa,qBAAqB,aAAa;AAClE;","names":["fs","path"]}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
IndexManager
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NOCXYKIE.js";
|
|
4
4
|
import {
|
|
5
5
|
appendToFile,
|
|
6
6
|
ensureDir,
|
|
7
7
|
fileExists,
|
|
8
8
|
getConversationsPath,
|
|
9
|
+
loadConfig,
|
|
9
10
|
readTextFile,
|
|
10
11
|
writeTextFile
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-E2IJSPVB.js";
|
|
12
13
|
|
|
13
14
|
// src/core/compaction-engine.ts
|
|
14
15
|
import * as path from "path";
|
|
16
|
+
import * as fs from "fs/promises";
|
|
17
|
+
import * as zlib from "zlib";
|
|
18
|
+
import { promisify } from "util";
|
|
15
19
|
|
|
16
20
|
// src/utils/claude-sdk.ts
|
|
17
21
|
import { spawn } from "child_process";
|
|
@@ -44,6 +48,7 @@ async function spawnClaudeAgent(prompt) {
|
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
// src/core/compaction-engine.ts
|
|
51
|
+
var gzip2 = promisify(zlib.gzip);
|
|
47
52
|
var SUMMARIZATION_PROMPT = `You are a technical knowledge extractor. Analyze this conversation log and extract key information for a project knowledge base.
|
|
48
53
|
|
|
49
54
|
Extract and format the following:
|
|
@@ -91,6 +96,7 @@ var CompactionEngine = class {
|
|
|
91
96
|
}
|
|
92
97
|
const summary = this.parseSummary(sessionId, summaryContent);
|
|
93
98
|
await this.writeSummary(sessionId, summaryContent);
|
|
99
|
+
await this.cleanupConversationFiles(sessionId);
|
|
94
100
|
return summary;
|
|
95
101
|
} catch (error) {
|
|
96
102
|
console.error("Compaction failed:", error);
|
|
@@ -248,6 +254,55 @@ ${content}
|
|
|
248
254
|
`;
|
|
249
255
|
await writeTextFile(summaryPath, fullContent);
|
|
250
256
|
}
|
|
257
|
+
async cleanupConversationFiles(sessionId) {
|
|
258
|
+
const config = await loadConfig(this.projectPath);
|
|
259
|
+
const cleanupMode = config.compaction.cleanupAfterSummary;
|
|
260
|
+
if (cleanupMode === "keep") {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const conversationsPath = getConversationsPath(this.projectPath);
|
|
264
|
+
const sessionPath = path.join(conversationsPath, sessionId);
|
|
265
|
+
const files = await fs.readdir(sessionPath);
|
|
266
|
+
const conversationFiles = files.filter(
|
|
267
|
+
(f) => /^\d+\.txt$/.test(f)
|
|
268
|
+
);
|
|
269
|
+
if (conversationFiles.length === 0) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (cleanupMode === "archive") {
|
|
273
|
+
await this.archiveConversationFiles(sessionPath, conversationFiles);
|
|
274
|
+
} else if (cleanupMode === "delete") {
|
|
275
|
+
await this.deleteConversationFiles(sessionPath, conversationFiles);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
async archiveConversationFiles(sessionPath, files) {
|
|
279
|
+
try {
|
|
280
|
+
const contents = [];
|
|
281
|
+
for (const file of files.sort()) {
|
|
282
|
+
const filePath = path.join(sessionPath, file);
|
|
283
|
+
const content = await readTextFile(filePath);
|
|
284
|
+
if (content) {
|
|
285
|
+
contents.push(`=== ${file} ===
|
|
286
|
+
${content}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const combined = contents.join("\n\n");
|
|
290
|
+
const compressed = await gzip2(Buffer.from(combined, "utf-8"));
|
|
291
|
+
const archivePath = path.join(sessionPath, "raw.txt.gz");
|
|
292
|
+
await fs.writeFile(archivePath, compressed);
|
|
293
|
+
await this.deleteConversationFiles(sessionPath, files);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
console.error("Failed to archive conversation files:", error);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
async deleteConversationFiles(sessionPath, files) {
|
|
299
|
+
for (const file of files) {
|
|
300
|
+
try {
|
|
301
|
+
await fs.unlink(path.join(sessionPath, file));
|
|
302
|
+
} catch {
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
251
306
|
};
|
|
252
307
|
|
|
253
308
|
// src/core/entity-detector.ts
|
|
@@ -544,4 +599,4 @@ export {
|
|
|
544
599
|
EntityDetector,
|
|
545
600
|
VaultIntegrator
|
|
546
601
|
};
|
|
547
|
-
//# sourceMappingURL=chunk-
|
|
602
|
+
//# sourceMappingURL=chunk-GLYS4OA4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/compaction-engine.ts","../src/utils/claude-sdk.ts","../src/core/entity-detector.ts","../src/core/vault-integrator.ts"],"sourcesContent":["import * as path from \"node:path\";\nimport * as fs from \"node:fs/promises\";\nimport * as zlib from \"node:zlib\";\nimport { promisify } from \"node:util\";\nimport { writeTextFile, readTextFile } from \"../utils/file-utils.js\";\nimport { getConversationsPath, loadConfig } from \"../utils/config.js\";\nimport { spawnClaudeAgent } from \"../utils/claude-sdk.js\";\n\nconst gzip = promisify(zlib.gzip);\n\nconst SUMMARIZATION_PROMPT = `You are a technical knowledge extractor. Analyze this conversation log and extract key information for a project knowledge base.\n\nExtract and format the following:\n\n## Entities\nFor each domain entity (data model, type, class) created or modified:\n- **Name**: Entity name\n- **Location**: File path\n- **Attributes**: Key fields/properties\n- **Relations**: Related entities\n\n## Architecture\nFor each architectural pattern or design decision:\n- **Pattern**: Name of pattern\n- **Description**: Brief explanation\n- **Affected Files**: Relevant file paths\n\n## Services\nFor each service or component created:\n- **Name**: Service name\n- **Location**: File path\n- **Purpose**: Brief description\n- **Methods**: Key methods/functions\n\n## Knowledge\nFor each convention, rule, or important context:\n- **Topic**: What it's about\n- **Details**: The actual information\n\nOnly include sections that have content. Be concise but complete.\nUse file paths exactly as shown in the conversation.\n\nCONVERSATION LOG:\n`;\n\nexport interface Summary {\n sessionId: string;\n content: string;\n entities: ExtractedEntity[];\n architecture: ArchitectureItem[];\n services: ServiceItem[];\n knowledge: KnowledgeItem[];\n}\n\nexport interface ExtractedEntity {\n name: string;\n location?: string;\n attributes: string[];\n relations: string[];\n}\n\nexport interface ArchitectureItem {\n pattern: string;\n description: string;\n affectedFiles: string[];\n}\n\nexport interface ServiceItem {\n name: string;\n location?: string;\n purpose: string;\n methods: string[];\n}\n\nexport interface KnowledgeItem {\n topic: string;\n details: string;\n}\n\nexport class CompactionEngine {\n private projectPath: string;\n\n constructor(projectPath: string) {\n this.projectPath = projectPath;\n }\n\n async compact(sessionId: string, conversation: string): Promise<Summary | null> {\n try {\n // Use Claude SDK to generate summary\n const summaryContent = await this.generateSummary(conversation);\n\n if (!summaryContent) {\n return null;\n }\n\n // Parse the summary to extract structured data\n const summary = this.parseSummary(sessionId, summaryContent);\n\n // Write summary to conversation folder\n await this.writeSummary(sessionId, summaryContent);\n\n // Cleanup original conversation files based on config\n await this.cleanupConversationFiles(sessionId);\n\n return summary;\n } catch (error) {\n console.error(\"Compaction failed:\", error);\n return null;\n }\n }\n\n private async generateSummary(conversation: string): Promise<string | null> {\n const prompt = SUMMARIZATION_PROMPT + conversation;\n\n try {\n const result = await spawnClaudeAgent(prompt);\n return result;\n } catch (error) {\n // Fallback to basic extraction if Claude SDK fails\n return this.fallbackExtraction(conversation);\n }\n }\n\n private fallbackExtraction(conversation: string): string {\n // Basic extraction without AI - just capture file paths and actions\n const lines = conversation.split(\"\\n\");\n const files: string[] = [];\n const actions: string[] = [];\n\n for (const line of lines) {\n // Extract file paths\n const fileMatch = line.match(/(?:Created|Modified|Edited).*?:\\s*(.+\\.(?:ts|js|tsx|jsx|md))/i);\n if (fileMatch) {\n files.push(fileMatch[1]);\n }\n\n // Extract tool actions\n if (line.includes(\"[TOOL:\")) {\n actions.push(line);\n }\n }\n\n let summary = \"# Session Summary\\n\\n\";\n\n if (files.length > 0) {\n summary += \"## Files Modified\\n\";\n for (const file of [...new Set(files)]) {\n summary += `- ${file}\\n`;\n }\n summary += \"\\n\";\n }\n\n if (actions.length > 0) {\n summary += \"## Actions\\n\";\n for (const action of actions.slice(0, 20)) {\n summary += `- ${action}\\n`;\n }\n }\n\n return summary;\n }\n\n private parseSummary(sessionId: string, content: string): Summary {\n const summary: Summary = {\n sessionId,\n content,\n entities: [],\n architecture: [],\n services: [],\n knowledge: [],\n };\n\n // Parse entities section\n const entitiesMatch = content.match(/## Entities\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (entitiesMatch) {\n summary.entities = this.parseEntities(entitiesMatch[1]);\n }\n\n // Parse architecture section\n const archMatch = content.match(/## Architecture\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (archMatch) {\n summary.architecture = this.parseArchitecture(archMatch[1]);\n }\n\n // Parse services section\n const servicesMatch = content.match(/## Services\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (servicesMatch) {\n summary.services = this.parseServices(servicesMatch[1]);\n }\n\n // Parse knowledge section\n const knowledgeMatch = content.match(/## Knowledge\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (knowledgeMatch) {\n summary.knowledge = this.parseKnowledge(knowledgeMatch[1]);\n }\n\n return summary;\n }\n\n private parseEntities(section: string): ExtractedEntity[] {\n const entities: ExtractedEntity[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Name\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const nameMatch = block.match(/\\*\\*Name\\*\\*:\\s*(.+)/);\n const locationMatch = block.match(/\\*\\*Location\\*\\*:\\s*(.+)/);\n const attributesMatch = block.match(/\\*\\*Attributes\\*\\*:\\s*(.+)/);\n const relationsMatch = block.match(/\\*\\*Relations\\*\\*:\\s*(.+)/);\n\n if (nameMatch) {\n entities.push({\n name: nameMatch[1].trim(),\n location: locationMatch?.[1].trim(),\n attributes: attributesMatch?.[1].split(\",\").map((a) => a.trim()) || [],\n relations: relationsMatch?.[1].split(\",\").map((r) => r.trim()) || [],\n });\n }\n }\n\n return entities;\n }\n\n private parseArchitecture(section: string): ArchitectureItem[] {\n const items: ArchitectureItem[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Pattern\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const patternMatch = block.match(/\\*\\*Pattern\\*\\*:\\s*(.+)/);\n const descMatch = block.match(/\\*\\*Description\\*\\*:\\s*(.+)/);\n const filesMatch = block.match(/\\*\\*Affected Files\\*\\*:\\s*(.+)/);\n\n if (patternMatch) {\n items.push({\n pattern: patternMatch[1].trim(),\n description: descMatch?.[1].trim() || \"\",\n affectedFiles: filesMatch?.[1].split(\",\").map((f) => f.trim()) || [],\n });\n }\n }\n\n return items;\n }\n\n private parseServices(section: string): ServiceItem[] {\n const items: ServiceItem[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Name\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const nameMatch = block.match(/\\*\\*Name\\*\\*:\\s*(.+)/);\n const locationMatch = block.match(/\\*\\*Location\\*\\*:\\s*(.+)/);\n const purposeMatch = block.match(/\\*\\*Purpose\\*\\*:\\s*(.+)/);\n const methodsMatch = block.match(/\\*\\*Methods\\*\\*:\\s*(.+)/);\n\n if (nameMatch) {\n items.push({\n name: nameMatch[1].trim(),\n location: locationMatch?.[1].trim(),\n purpose: purposeMatch?.[1].trim() || \"\",\n methods: methodsMatch?.[1].split(\",\").map((m) => m.trim()) || [],\n });\n }\n }\n\n return items;\n }\n\n private parseKnowledge(section: string): KnowledgeItem[] {\n const items: KnowledgeItem[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Topic\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const topicMatch = block.match(/\\*\\*Topic\\*\\*:\\s*(.+)/);\n const detailsMatch = block.match(/\\*\\*Details\\*\\*:\\s*(.+)/);\n\n if (topicMatch) {\n items.push({\n topic: topicMatch[1].trim(),\n details: detailsMatch?.[1].trim() || \"\",\n });\n }\n }\n\n return items;\n }\n\n private async writeSummary(sessionId: string, content: string): Promise<void> {\n const conversationsPath = getConversationsPath(this.projectPath);\n const summaryPath = path.join(conversationsPath, sessionId, \"summary.md\");\n\n const fullContent = `# Session Summary: ${sessionId}\nGenerated: ${new Date().toISOString()}\n\n${content}\n`;\n\n await writeTextFile(summaryPath, fullContent);\n }\n\n private async cleanupConversationFiles(sessionId: string): Promise<void> {\n const config = await loadConfig(this.projectPath);\n const cleanupMode = config.compaction.cleanupAfterSummary;\n\n if (cleanupMode === \"keep\") {\n return; // Nothing to do\n }\n\n const conversationsPath = getConversationsPath(this.projectPath);\n const sessionPath = path.join(conversationsPath, sessionId);\n\n // Get all conversation files (numbered .txt files)\n const files = await fs.readdir(sessionPath);\n const conversationFiles = files.filter(\n (f) => /^\\d+\\.txt$/.test(f)\n );\n\n if (conversationFiles.length === 0) {\n return;\n }\n\n if (cleanupMode === \"archive\") {\n await this.archiveConversationFiles(sessionPath, conversationFiles);\n } else if (cleanupMode === \"delete\") {\n await this.deleteConversationFiles(sessionPath, conversationFiles);\n }\n }\n\n private async archiveConversationFiles(\n sessionPath: string,\n files: string[]\n ): Promise<void> {\n try {\n // Combine all conversation files into one archive\n const contents: string[] = [];\n\n for (const file of files.sort()) {\n const filePath = path.join(sessionPath, file);\n const content = await readTextFile(filePath);\n if (content) {\n contents.push(`=== ${file} ===\\n${content}`);\n }\n }\n\n const combined = contents.join(\"\\n\\n\");\n const compressed = await gzip(Buffer.from(combined, \"utf-8\"));\n\n // Write archive\n const archivePath = path.join(sessionPath, \"raw.txt.gz\");\n await fs.writeFile(archivePath, compressed);\n\n // Delete original files\n await this.deleteConversationFiles(sessionPath, files);\n } catch (error) {\n console.error(\"Failed to archive conversation files:\", error);\n // Don't delete originals if archive fails\n }\n }\n\n private async deleteConversationFiles(\n sessionPath: string,\n files: string[]\n ): Promise<void> {\n for (const file of files) {\n try {\n await fs.unlink(path.join(sessionPath, file));\n } catch {\n // Ignore deletion errors\n }\n }\n }\n}\n","import { spawn } from \"node:child_process\";\n\n/**\n * Spawns a Claude Code subagent to process a prompt.\n * Uses the Claude Code CLI with the --print flag to get output.\n */\nexport async function spawnClaudeAgent(prompt: string): Promise<string> {\n return new Promise((resolve, reject) => {\n // Use claude CLI with --print to get output without interactive mode\n const child = spawn(\"claude\", [\"--print\", \"-p\", prompt], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 120000, // 2 minute timeout\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout?.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n child.stderr?.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve(stdout.trim());\n } else {\n reject(new Error(`Claude agent failed with code ${code}: ${stderr}`));\n }\n });\n\n child.on(\"error\", (error) => {\n reject(error);\n });\n });\n}\n\n/**\n * Checks if Claude CLI is available.\n */\nexport async function isClaudeAvailable(): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(\"claude\", [\"--version\"], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n child.on(\"close\", (code) => {\n resolve(code === 0);\n });\n\n child.on(\"error\", () => {\n resolve(false);\n });\n });\n}\n","import type { Summary, ExtractedEntity, ServiceItem } from \"./compaction-engine.js\";\n\nexport interface DetectedItem {\n type: \"entity\" | \"service\" | \"pattern\" | \"knowledge\";\n name: string;\n data: unknown;\n vaultPath: string;\n content: string;\n}\n\nexport class EntityDetector {\n /**\n * Analyzes a summary and determines what should be added to the vault.\n */\n detect(summary: Summary): DetectedItem[] {\n const items: DetectedItem[] = [];\n\n // Detect entities\n for (const entity of summary.entities) {\n items.push(this.createEntityItem(entity));\n\n // Also create service entries for entity-related services\n const relatedServices = summary.services.filter(\n (s) =>\n s.name.toLowerCase().includes(entity.name.toLowerCase()) ||\n s.location?.toLowerCase().includes(entity.name.toLowerCase())\n );\n\n for (const service of relatedServices) {\n items.push(this.createServiceItem(entity.name, service));\n }\n }\n\n // Detect standalone services\n const processedServiceNames = new Set<string>();\n for (const entity of summary.entities) {\n for (const service of summary.services) {\n if (\n service.name.toLowerCase().includes(entity.name.toLowerCase()) ||\n service.location?.toLowerCase().includes(entity.name.toLowerCase())\n ) {\n processedServiceNames.add(service.name);\n }\n }\n }\n\n for (const service of summary.services) {\n if (!processedServiceNames.has(service.name)) {\n items.push(this.createStandaloneServiceItem(service));\n }\n }\n\n // Detect architecture patterns\n for (const arch of summary.architecture) {\n items.push(this.createArchitectureItem(arch));\n }\n\n // Detect general knowledge\n for (const knowledge of summary.knowledge) {\n items.push(this.createKnowledgeItem(knowledge));\n }\n\n return items;\n }\n\n private createEntityItem(entity: ExtractedEntity): DetectedItem {\n const content = this.formatEntityContent(entity);\n\n return {\n type: \"entity\",\n name: entity.name,\n data: entity,\n vaultPath: `entities/${entity.name.toLowerCase()}`,\n content,\n };\n }\n\n private createServiceItem(\n entityName: string,\n service: ServiceItem\n ): DetectedItem {\n const content = this.formatServiceContent(service);\n const serviceName = service.name.toLowerCase().replace(entityName.toLowerCase(), \"\").trim();\n const fileName = serviceName || \"service\";\n\n return {\n type: \"service\",\n name: service.name,\n data: service,\n vaultPath: `entities/${entityName.toLowerCase()}/services/${fileName}`,\n content,\n };\n }\n\n private createStandaloneServiceItem(service: ServiceItem): DetectedItem {\n const content = this.formatServiceContent(service);\n\n return {\n type: \"service\",\n name: service.name,\n data: service,\n vaultPath: `services/${service.name.toLowerCase()}`,\n content,\n };\n }\n\n private createArchitectureItem(arch: {\n pattern: string;\n description: string;\n affectedFiles: string[];\n }): DetectedItem {\n const content = `## ${arch.pattern}\n\n${arch.description}\n\n### Affected Files\n${arch.affectedFiles.map((f) => `- ${f}`).join(\"\\n\")}\n`;\n\n return {\n type: \"pattern\",\n name: arch.pattern,\n data: arch,\n vaultPath: \"architecture\",\n content,\n };\n }\n\n private createKnowledgeItem(knowledge: {\n topic: string;\n details: string;\n }): DetectedItem {\n const content = `## ${knowledge.topic}\n\n${knowledge.details}\n`;\n\n return {\n type: \"knowledge\",\n name: knowledge.topic,\n data: knowledge,\n vaultPath: \"general-knowledge\",\n content,\n };\n }\n\n private formatEntityContent(entity: ExtractedEntity): string {\n let content = `# ${entity.name}\\n\\n`;\n\n if (entity.location) {\n content += `**Location**: ${entity.location}\\n\\n`;\n }\n\n if (entity.attributes.length > 0) {\n content += `## Attributes\\n\\n`;\n for (const attr of entity.attributes) {\n content += `- ${attr}\\n`;\n }\n content += \"\\n\";\n }\n\n if (entity.relations.length > 0) {\n content += `## Relations\\n\\n`;\n for (const rel of entity.relations) {\n content += `- ${rel}\\n`;\n }\n content += \"\\n\";\n }\n\n return content;\n }\n\n private formatServiceContent(service: ServiceItem): string {\n let content = `# ${service.name}\\n\\n`;\n\n if (service.location) {\n content += `**Location**: ${service.location}\\n\\n`;\n }\n\n if (service.purpose) {\n content += `## Purpose\\n\\n${service.purpose}\\n\\n`;\n }\n\n if (service.methods.length > 0) {\n content += `## Methods\\n\\n`;\n for (const method of service.methods) {\n content += `- ${method}\\n`;\n }\n content += \"\\n\";\n }\n\n return content;\n }\n}\n","import * as path from \"node:path\";\nimport {\n readTextFile,\n writeTextFile,\n appendToFile,\n ensureDir,\n fileExists,\n} from \"../utils/file-utils.js\";\nimport { IndexManager } from \"./index-manager.js\";\nimport { EntityDetector, type DetectedItem } from \"./entity-detector.js\";\nimport type { Summary } from \"./compaction-engine.js\";\n\nexport class VaultIntegrator {\n private vaultPath: string;\n private indexManager: IndexManager;\n private entityDetector: EntityDetector;\n\n constructor(vaultPath: string) {\n this.vaultPath = vaultPath;\n this.indexManager = new IndexManager(vaultPath);\n this.entityDetector = new EntityDetector();\n }\n\n async integrate(summary: Summary): Promise<void> {\n // Detect items from summary\n const items = this.entityDetector.detect(summary);\n\n if (items.length === 0) {\n return;\n }\n\n // Process each detected item\n for (const item of items) {\n await this.processItem(item);\n }\n\n // Update root INDEX.md with timestamp\n await this.updateRootIndex();\n }\n\n private async processItem(item: DetectedItem): Promise<void> {\n switch (item.type) {\n case \"entity\":\n await this.processEntity(item);\n break;\n case \"service\":\n await this.processService(item);\n break;\n case \"pattern\":\n await this.processPattern(item);\n break;\n case \"knowledge\":\n await this.processKnowledge(item);\n break;\n }\n }\n\n private async processEntity(item: DetectedItem): Promise<void> {\n const entityPath = await this.indexManager.ensureEntityFolder(item.name);\n const fullPath = path.join(this.vaultPath, entityPath);\n\n // Write attributes.md\n const attributesPath = path.join(fullPath, \"attributes.md\");\n await writeTextFile(attributesPath, item.content);\n\n // Update entity INDEX.md\n await this.indexManager.addEntry(entityPath, {\n name: \"attributes\",\n path: \"./attributes.md\",\n description: `Attributes of ${item.name}`,\n type: \"file\",\n });\n }\n\n private async processService(item: DetectedItem): Promise<void> {\n const pathParts = item.vaultPath.split(\"/\");\n const fileName = pathParts.pop() + \".md\";\n const folderPath = pathParts.join(\"/\");\n const fullFolderPath = path.join(this.vaultPath, folderPath);\n\n await ensureDir(fullFolderPath);\n\n // Write service file\n const filePath = path.join(fullFolderPath, fileName);\n await writeTextFile(filePath, item.content);\n\n // Ensure parent has INDEX.md\n const parentIndexPath = path.join(fullFolderPath, \"INDEX.md\");\n if (!(await fileExists(parentIndexPath))) {\n await this.indexManager.createIndex(folderPath, []);\n }\n\n // Update parent INDEX.md\n await this.indexManager.addEntry(folderPath, {\n name: item.name,\n path: `./${fileName}`,\n description: (item.data as { purpose?: string }).purpose || `${item.name} service`,\n type: \"file\",\n });\n\n // Update entity INDEX if this is an entity service\n if (folderPath.startsWith(\"entities/\") && folderPath.includes(\"/services\")) {\n const entityFolder = folderPath.split(\"/\").slice(0, 2).join(\"/\");\n await this.indexManager.addEntry(entityFolder, {\n name: \"services\",\n path: \"./services/INDEX.md\",\n description: \"Service layer documentation\",\n type: \"folder\",\n });\n }\n }\n\n private async processPattern(item: DetectedItem): Promise<void> {\n const archPath = path.join(this.vaultPath, \"architecture.md\");\n const existing = await readTextFile(archPath);\n\n if (!existing) {\n await writeTextFile(archPath, `# Architecture\\n\\n${item.content}`);\n return;\n }\n\n // Check if pattern already exists\n if (existing.includes(`## ${item.name}`)) {\n // Replace existing section\n const regex = new RegExp(`## ${item.name}[\\\\s\\\\S]*?(?=\\\\n## |$)`);\n const updated = existing.replace(regex, item.content);\n await writeTextFile(archPath, updated);\n } else {\n // Append new pattern\n await appendToFile(archPath, `\\n${item.content}`);\n }\n }\n\n private async processKnowledge(item: DetectedItem): Promise<void> {\n const knowledgePath = path.join(this.vaultPath, \"general-knowledge.md\");\n const existing = await readTextFile(knowledgePath);\n\n if (!existing) {\n await writeTextFile(knowledgePath, `# General Knowledge\\n\\n${item.content}`);\n return;\n }\n\n // Check if topic already exists\n if (existing.includes(`## ${item.name}`)) {\n // Replace existing section\n const regex = new RegExp(`## ${item.name}[\\\\s\\\\S]*?(?=\\\\n## |$)`);\n const updated = existing.replace(regex, item.content);\n await writeTextFile(knowledgePath, updated);\n } else {\n // Append new knowledge\n await appendToFile(knowledgePath, `\\n${item.content}`);\n }\n }\n\n private async updateRootIndex(): Promise<void> {\n const indexPath = path.join(this.vaultPath, \"INDEX.md\");\n const content = await readTextFile(indexPath);\n\n if (!content) {\n return;\n }\n\n // Update the \"Last Updated\" line\n const timestamp = new Date().toISOString();\n const updated = content.replace(\n /## Last Updated[\\s\\S]*$/,\n `## Last Updated\\n\\n${timestamp}`\n );\n\n await writeTextFile(indexPath, updated);\n }\n}\n"],"mappings":"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","names":["gzip","path"]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
listDir,
|
|
5
5
|
readTextFile,
|
|
6
6
|
writeTextFile
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-E2IJSPVB.js";
|
|
8
8
|
|
|
9
9
|
// src/core/index-manager.ts
|
|
10
10
|
import * as path from "path";
|
|
@@ -146,4 +146,4 @@ _Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}_
|
|
|
146
146
|
export {
|
|
147
147
|
IndexManager
|
|
148
148
|
};
|
|
149
|
-
//# sourceMappingURL=chunk-
|
|
149
|
+
//# sourceMappingURL=chunk-NOCXYKIE.js.map
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
readTextFile,
|
|
14
14
|
writeJSON,
|
|
15
15
|
writeTextFile
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-E2IJSPVB.js";
|
|
17
17
|
|
|
18
18
|
// src/core/conversation-manager.ts
|
|
19
19
|
import * as path from "path";
|
|
@@ -236,4 +236,4 @@ ${entry.content}
|
|
|
236
236
|
export {
|
|
237
237
|
ConversationManager
|
|
238
238
|
};
|
|
239
|
-
//# sourceMappingURL=chunk-
|
|
239
|
+
//# sourceMappingURL=chunk-XQXIDTUW.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
IndexManager
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-NOCXYKIE.js";
|
|
4
4
|
import {
|
|
5
5
|
fileExists,
|
|
6
6
|
getStatePath,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
loadConfig,
|
|
9
9
|
readJSON,
|
|
10
10
|
writeJSON
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-E2IJSPVB.js";
|
|
12
12
|
|
|
13
13
|
// src/hooks/notification.ts
|
|
14
14
|
import * as path from "path";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ConversationManager
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-XQXIDTUW.js";
|
|
4
4
|
import {
|
|
5
5
|
IndexManager
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-NOCXYKIE.js";
|
|
7
7
|
import {
|
|
8
8
|
getVaultPath
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-E2IJSPVB.js";
|
|
10
10
|
|
|
11
11
|
// src/hooks/session-start.ts
|
|
12
12
|
async function handleSessionStart() {
|
package/dist/hooks/stop.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CompactionEngine,
|
|
3
3
|
VaultIntegrator
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-GLYS4OA4.js";
|
|
5
5
|
import {
|
|
6
6
|
ConversationManager
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-XQXIDTUW.js";
|
|
8
|
+
import "../chunk-NOCXYKIE.js";
|
|
9
9
|
import {
|
|
10
10
|
getVaultPath,
|
|
11
11
|
loadConfig
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-E2IJSPVB.js";
|
|
13
13
|
|
|
14
14
|
// src/hooks/stop.ts
|
|
15
15
|
async function handleStop() {
|
package/dist/index.d.ts
CHANGED
|
@@ -64,6 +64,9 @@ declare class CompactionEngine {
|
|
|
64
64
|
private parseServices;
|
|
65
65
|
private parseKnowledge;
|
|
66
66
|
private writeSummary;
|
|
67
|
+
private cleanupConversationFiles;
|
|
68
|
+
private archiveConversationFiles;
|
|
69
|
+
private deleteConversationFiles;
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
declare class VaultIntegrator {
|
|
@@ -127,6 +130,7 @@ interface CCKBConfig {
|
|
|
127
130
|
trigger: "session_end" | "size" | "messages" | "manual";
|
|
128
131
|
sizeThresholdKB: number;
|
|
129
132
|
messageThreshold: number;
|
|
133
|
+
cleanupAfterSummary: "keep" | "archive" | "delete";
|
|
130
134
|
};
|
|
131
135
|
capture: {
|
|
132
136
|
tools: string[];
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
install
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3KGJEBKK.js";
|
|
4
4
|
import {
|
|
5
5
|
CompactionEngine,
|
|
6
6
|
EntityDetector,
|
|
7
7
|
VaultIntegrator
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-GLYS4OA4.js";
|
|
9
9
|
import {
|
|
10
10
|
ConversationManager
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-XQXIDTUW.js";
|
|
12
12
|
import {
|
|
13
13
|
IndexManager
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-NOCXYKIE.js";
|
|
15
|
+
import "./chunk-E2IJSPVB.js";
|
|
16
16
|
export {
|
|
17
17
|
CompactionEngine,
|
|
18
18
|
ConversationManager,
|
package/package.json
CHANGED
|
@@ -2,14 +2,24 @@
|
|
|
2
2
|
"hooks": {
|
|
3
3
|
"SessionStart": [
|
|
4
4
|
{
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"matcher": "",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "npx cckb hook session-start"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
7
12
|
}
|
|
8
13
|
],
|
|
9
14
|
"UserPromptSubmit": [
|
|
10
15
|
{
|
|
11
|
-
"
|
|
12
|
-
"
|
|
16
|
+
"matcher": "",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "npx cckb hook user-prompt"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
13
23
|
}
|
|
14
24
|
],
|
|
15
25
|
"PostToolUse": [
|
|
@@ -25,8 +35,13 @@
|
|
|
25
35
|
],
|
|
26
36
|
"Stop": [
|
|
27
37
|
{
|
|
28
|
-
"
|
|
29
|
-
"
|
|
38
|
+
"matcher": "",
|
|
39
|
+
"hooks": [
|
|
40
|
+
{
|
|
41
|
+
"type": "command",
|
|
42
|
+
"command": "npx cckb hook stop"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
30
45
|
}
|
|
31
46
|
],
|
|
32
47
|
"PreToolUse": [
|
package/templates/vault/INDEX.md
CHANGED
|
@@ -9,6 +9,8 @@ This vault contains structured knowledge about the project, automatically captur
|
|
|
9
9
|
| [architecture.md](./architecture.md) | Project patterns and architectural decisions |
|
|
10
10
|
| [general-knowledge.md](./general-knowledge.md) | Conventions, rules, and miscellaneous knowledge |
|
|
11
11
|
| [entities/](./entities/INDEX.md) | Domain entities and their documentation |
|
|
12
|
+
| [apps/](./apps/INDEX.md) | Application-level documentation |
|
|
13
|
+
| [modules/](./modules/INDEX.md) | Reusable modules and shared functionality |
|
|
12
14
|
|
|
13
15
|
## Usage
|
|
14
16
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/install.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as fsSync from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n ensureDir,\n fileExists,\n readJSON,\n writeJSON,\n readTextFile,\n writeTextFile,\n} from \"../utils/file-utils.js\";\nimport { DEFAULT_CONFIG } from \"../utils/config.js\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n// Find package root by looking for package.json\nfunction findPackageRoot(): string {\n let dir = __dirname;\n for (let i = 0; i < 5; i++) {\n const packageJson = path.join(dir, \"package.json\");\n if (fsSync.existsSync(packageJson)) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n // Fallback to relative from __dirname\n return path.resolve(__dirname, \"../..\");\n}\n\nconst PACKAGE_ROOT = findPackageRoot();\nconst TEMPLATES_DIR = path.join(PACKAGE_ROOT, \"templates\");\n\nexport interface InstallOptions {\n force?: boolean;\n}\n\nexport async function install(\n targetPath: string,\n options: InstallOptions = {}\n): Promise<void> {\n const resolvedPath = path.resolve(targetPath);\n\n console.log(`Installing CCKB to: ${resolvedPath}`);\n\n // Pre-flight checks\n await validateTargetPath(resolvedPath);\n await checkExistingInstallation(resolvedPath, options.force);\n\n // Create directory structure\n await createDirectoryStructure(resolvedPath);\n\n // Copy template files\n await copyTemplateFiles(resolvedPath);\n\n // Create config file\n await createConfigFile(resolvedPath);\n\n // Install hooks configuration\n await installHooks(resolvedPath);\n\n // Update CLAUDE.md\n await updateClaudeMd(resolvedPath);\n\n // Update .gitignore\n await updateGitignore(resolvedPath);\n\n console.log(\"\\nCCKB installed successfully!\");\n console.log(\"\\nNext steps:\");\n console.log(\" 1. Review cc-knowledge-base/vault/ structure\");\n console.log(\" 2. Check .claude/settings.json for hook configuration\");\n console.log(\" 3. Start a new Claude Code session to begin capturing knowledge\");\n}\n\nasync function validateTargetPath(targetPath: string): Promise<void> {\n const exists = await fileExists(targetPath);\n if (!exists) {\n throw new Error(`Target path does not exist: ${targetPath}`);\n }\n\n const stats = await fs.stat(targetPath);\n if (!stats.isDirectory()) {\n throw new Error(`Target path is not a directory: ${targetPath}`);\n }\n}\n\nasync function checkExistingInstallation(\n targetPath: string,\n force?: boolean\n): Promise<void> {\n const kbPath = path.join(targetPath, \"cc-knowledge-base\");\n const exists = await fileExists(kbPath);\n\n if (exists && !force) {\n throw new Error(\n \"CCKB is already installed in this project. Use --force to reinstall.\"\n );\n }\n}\n\nasync function createDirectoryStructure(targetPath: string): Promise<void> {\n const directories = [\n \"cc-knowledge-base\",\n \"cc-knowledge-base/conversations\",\n \"cc-knowledge-base/vault\",\n \"cc-knowledge-base/vault/entities\",\n \"cc-knowledge-base/.cckb-state\",\n ];\n\n for (const dir of directories) {\n await ensureDir(path.join(targetPath, dir));\n }\n\n console.log(\" Created directory structure\");\n}\n\nasync function copyTemplateFiles(targetPath: string): Promise<void> {\n const vaultFiles = [\n { src: \"vault/INDEX.md\", dest: \"cc-knowledge-base/vault/INDEX.md\" },\n {\n src: \"vault/architecture.md\",\n dest: \"cc-knowledge-base/vault/architecture.md\",\n },\n {\n src: \"vault/general-knowledge.md\",\n dest: \"cc-knowledge-base/vault/general-knowledge.md\",\n },\n {\n src: \"vault/entities/INDEX.md\",\n dest: \"cc-knowledge-base/vault/entities/INDEX.md\",\n },\n ];\n\n for (const file of vaultFiles) {\n const srcPath = path.join(TEMPLATES_DIR, file.src);\n const destPath = path.join(targetPath, file.dest);\n\n const content = await readTextFile(srcPath);\n if (content) {\n await writeTextFile(destPath, content);\n }\n }\n\n // Create .gitkeep for conversations\n await writeTextFile(\n path.join(targetPath, \"cc-knowledge-base/conversations/.gitkeep\"),\n \"\"\n );\n\n console.log(\" Copied vault template files\");\n}\n\nasync function createConfigFile(targetPath: string): Promise<void> {\n const configPath = path.join(\n targetPath,\n \"cc-knowledge-base\",\n \".cckb-config.json\"\n );\n\n await writeJSON(configPath, DEFAULT_CONFIG);\n\n console.log(\" Created configuration file\");\n}\n\nasync function installHooks(targetPath: string): Promise<void> {\n const claudeDir = path.join(targetPath, \".claude\");\n const settingsPath = path.join(claudeDir, \"settings.json\");\n\n await ensureDir(claudeDir);\n\n // Load existing settings or create new\n let settings: Record<string, unknown> =\n (await readJSON<Record<string, unknown>>(settingsPath)) || {};\n\n // Load hook template\n const templatePath = path.join(TEMPLATES_DIR, \"settings.json.tmpl\");\n const hookSettings = await readJSON<{ hooks: Record<string, unknown> }>(\n templatePath\n );\n\n if (!hookSettings) {\n throw new Error(\"Failed to load hook template\");\n }\n\n // Merge hooks (CCKB hooks take precedence for its own hook types)\n const existingHooks = (settings.hooks as Record<string, unknown[]>) || {};\n const newHooks = hookSettings.hooks as Record<string, unknown[]>;\n\n settings.hooks = mergeHooks(existingHooks, newHooks);\n\n await writeJSON(settingsPath, settings);\n\n console.log(\" Installed hook configuration\");\n}\n\nfunction mergeHooks(\n existing: Record<string, unknown[]>,\n incoming: Record<string, unknown[]>\n): Record<string, unknown[]> {\n const merged = { ...existing };\n\n for (const [hookType, hooks] of Object.entries(incoming)) {\n if (!merged[hookType]) {\n merged[hookType] = [];\n }\n\n // Add incoming hooks, avoiding duplicates based on command\n for (const hook of hooks) {\n const hookObj = hook as Record<string, unknown>;\n const command = hookObj.command as string | undefined;\n\n if (command?.includes(\"cckb\")) {\n // Remove any existing CCKB hooks for this type\n merged[hookType] = merged[hookType].filter((h) => {\n const existingCmd = (h as Record<string, unknown>).command as\n | string\n | undefined;\n return !existingCmd?.includes(\"cckb\");\n });\n }\n\n merged[hookType].push(hook);\n }\n }\n\n return merged;\n}\n\nasync function updateClaudeMd(targetPath: string): Promise<void> {\n const claudeMdPath = path.join(targetPath, \"CLAUDE.md\");\n const templatePath = path.join(TEMPLATES_DIR, \"CLAUDE.md.tmpl\");\n\n const template = await readTextFile(templatePath);\n if (!template) {\n throw new Error(\"Failed to load CLAUDE.md template\");\n }\n\n const marker = \"## Project Knowledge Base (CCKB)\";\n\n let existing = await readTextFile(claudeMdPath);\n\n if (existing) {\n // Check if CCKB section already exists\n if (existing.includes(marker)) {\n // Replace existing CCKB section\n const regex = /## Project Knowledge Base \\(CCKB\\)[\\s\\S]*?(?=\\n## |$)/;\n existing = existing.replace(regex, template.trim());\n } else {\n // Append CCKB section\n existing = existing.trimEnd() + \"\\n\\n\" + template;\n }\n await writeTextFile(claudeMdPath, existing);\n } else {\n // Create new CLAUDE.md with CCKB section\n await writeTextFile(claudeMdPath, template);\n }\n\n console.log(\" Updated CLAUDE.md with vault directives\");\n}\n\nasync function updateGitignore(targetPath: string): Promise<void> {\n const gitignorePath = path.join(targetPath, \".gitignore\");\n\n const entries = [\n \"\",\n \"# CCKB state files\",\n \"cc-knowledge-base/.cckb-state/\",\n ];\n\n let existing = (await readTextFile(gitignorePath)) || \"\";\n\n // Check if already added\n if (existing.includes(\"cc-knowledge-base/.cckb-state/\")) {\n return;\n }\n\n existing = existing.trimEnd() + \"\\n\" + entries.join(\"\\n\") + \"\\n\";\n await writeTextFile(gitignorePath, existing);\n\n console.log(\" Updated .gitignore\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/file-utils.ts","../src/utils/config.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\n\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.mkdir(dirPath, { recursive: true });\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readJSON<T>(filePath: string): Promise<T | null> {\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n\nexport async function writeJSON(\n filePath: string,\n data: unknown,\n pretty = true\n): Promise<void> {\n await ensureDir(path.dirname(filePath));\n const content = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);\n await fs.writeFile(filePath, content);\n}\n\nexport async function appendToFile(\n filePath: string,\n content: string\n): Promise<void> {\n await ensureDir(path.dirname(filePath));\n await fs.appendFile(filePath, content);\n}\n\nexport async function readTextFile(filePath: string): Promise<string | null> {\n try {\n return await fs.readFile(filePath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\nexport async function writeTextFile(\n filePath: string,\n content: string\n): Promise<void> {\n await ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content);\n}\n\nexport async function copyFile(src: string, dest: string): Promise<void> {\n await ensureDir(path.dirname(dest));\n await fs.copyFile(src, dest);\n}\n\nexport async function listDir(dirPath: string): Promise<string[]> {\n try {\n return await fs.readdir(dirPath);\n } catch {\n return [];\n }\n}\n\nexport async function getFileSize(filePath: string): Promise<number> {\n try {\n const stats = await fs.stat(filePath);\n return stats.size;\n } catch {\n return 0;\n }\n}\n\nexport function generateSessionId(): string {\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 8);\n return `${timestamp}-${random}`;\n}\n\nexport function getCurrentTimestamp(): string {\n return new Date().toISOString();\n}\n","import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\n\nexport interface CCKBConfig {\n compaction: {\n trigger: \"session_end\" | \"size\" | \"messages\" | \"manual\";\n sizeThresholdKB: number;\n messageThreshold: number;\n };\n capture: {\n tools: string[];\n maxContentLength: number;\n };\n vault: {\n autoIntegrate: boolean;\n maxDepth: number;\n };\n feedback: {\n enabled: boolean;\n contextDepth: number;\n };\n}\n\nexport const DEFAULT_CONFIG: CCKBConfig = {\n compaction: {\n trigger: \"session_end\",\n sizeThresholdKB: 50,\n messageThreshold: 100,\n },\n capture: {\n tools: [\"Write\", \"Edit\", \"MultiEdit\", \"Bash\", \"Task\"],\n maxContentLength: 500,\n },\n vault: {\n autoIntegrate: true,\n maxDepth: 5,\n },\n feedback: {\n enabled: true,\n contextDepth: 2,\n },\n};\n\nexport async function loadConfig(projectPath: string): Promise<CCKBConfig> {\n const configPath = path.join(\n projectPath,\n \"cc-knowledge-base\",\n \".cckb-config.json\"\n );\n\n try {\n const content = await fs.readFile(configPath, \"utf-8\");\n const userConfig = JSON.parse(content);\n return { ...DEFAULT_CONFIG, ...userConfig };\n } catch {\n return DEFAULT_CONFIG;\n }\n}\n\nexport async function saveConfig(\n projectPath: string,\n config: CCKBConfig\n): Promise<void> {\n const configPath = path.join(\n projectPath,\n \"cc-knowledge-base\",\n \".cckb-config.json\"\n );\n\n await fs.writeFile(configPath, JSON.stringify(config, null, 2));\n}\n\nexport function getKnowledgeBasePath(projectPath: string): string {\n return path.join(projectPath, \"cc-knowledge-base\");\n}\n\nexport function getConversationsPath(projectPath: string): string {\n return path.join(projectPath, \"cc-knowledge-base\", \"conversations\");\n}\n\nexport function getVaultPath(projectPath: string): string {\n return path.join(projectPath, \"cc-knowledge-base\", \"vault\");\n}\n\nexport function getStatePath(projectPath: string): string {\n return path.join(projectPath, \"cc-knowledge-base\", \".cckb-state\");\n}\n"],"mappings":";AAAA,YAAY,QAAQ;AACpB,YAAY,UAAU;AAEtB,eAAsB,UAAU,SAAgC;AAC9D,QAAS,SAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAC7C;AAEA,eAAsB,WAAW,UAAoC;AACnE,MAAI;AACF,UAAS,UAAO,QAAQ;AACxB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,SAAY,UAAqC;AACrE,MAAI;AACF,UAAM,UAAU,MAAS,YAAS,UAAU,OAAO;AACnD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,UACpB,UACA,MACA,SAAS,MACM;AACf,QAAM,UAAe,aAAQ,QAAQ,CAAC;AACtC,QAAM,UAAU,SAAS,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,KAAK,UAAU,IAAI;AAC5E,QAAS,aAAU,UAAU,OAAO;AACtC;AAEA,eAAsB,aACpB,UACA,SACe;AACf,QAAM,UAAe,aAAQ,QAAQ,CAAC;AACtC,QAAS,cAAW,UAAU,OAAO;AACvC;AAEA,eAAsB,aAAa,UAA0C;AAC3E,MAAI;AACF,WAAO,MAAS,YAAS,UAAU,OAAO;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,cACpB,UACA,SACe;AACf,QAAM,UAAe,aAAQ,QAAQ,CAAC;AACtC,QAAS,aAAU,UAAU,OAAO;AACtC;AAOA,eAAsB,QAAQ,SAAoC;AAChE,MAAI;AACF,WAAO,MAAS,WAAQ,OAAO;AAAA,EACjC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,YAAY,UAAmC;AACnE,MAAI;AACF,UAAM,QAAQ,MAAS,QAAK,QAAQ;AACpC,WAAO,MAAM;AAAA,EACf,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,oBAA4B;AAC1C,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC;AACxD,SAAO,GAAG,SAAS,IAAI,MAAM;AAC/B;AAEO,SAAS,sBAA8B;AAC5C,UAAO,oBAAI,KAAK,GAAE,YAAY;AAChC;;;ACzFA,YAAYA,SAAQ;AACpB,YAAYC,WAAU;AAsBf,IAAM,iBAA6B;AAAA,EACxC,YAAY;AAAA,IACV,SAAS;AAAA,IACT,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,EACpB;AAAA,EACA,SAAS;AAAA,IACP,OAAO,CAAC,SAAS,QAAQ,aAAa,QAAQ,MAAM;AAAA,IACpD,kBAAkB;AAAA,EACpB;AAAA,EACA,OAAO;AAAA,IACL,eAAe;AAAA,IACf,UAAU;AAAA,EACZ;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,EAChB;AACF;AAEA,eAAsB,WAAW,aAA0C;AACzE,QAAM,aAAkB;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI;AACF,UAAM,UAAU,MAAS,aAAS,YAAY,OAAO;AACrD,UAAM,aAAa,KAAK,MAAM,OAAO;AACrC,WAAO,EAAE,GAAG,gBAAgB,GAAG,WAAW;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAmBO,SAAS,qBAAqB,aAA6B;AAChE,SAAY,WAAK,aAAa,qBAAqB,eAAe;AACpE;AAEO,SAAS,aAAa,aAA6B;AACxD,SAAY,WAAK,aAAa,qBAAqB,OAAO;AAC5D;AAEO,SAAS,aAAa,aAA6B;AACxD,SAAY,WAAK,aAAa,qBAAqB,aAAa;AAClE;","names":["fs","path"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/compaction-engine.ts","../src/utils/claude-sdk.ts","../src/core/entity-detector.ts","../src/core/vault-integrator.ts"],"sourcesContent":["import * as path from \"node:path\";\nimport { writeTextFile } from \"../utils/file-utils.js\";\nimport { getConversationsPath } from \"../utils/config.js\";\nimport { spawnClaudeAgent } from \"../utils/claude-sdk.js\";\n\nconst SUMMARIZATION_PROMPT = `You are a technical knowledge extractor. Analyze this conversation log and extract key information for a project knowledge base.\n\nExtract and format the following:\n\n## Entities\nFor each domain entity (data model, type, class) created or modified:\n- **Name**: Entity name\n- **Location**: File path\n- **Attributes**: Key fields/properties\n- **Relations**: Related entities\n\n## Architecture\nFor each architectural pattern or design decision:\n- **Pattern**: Name of pattern\n- **Description**: Brief explanation\n- **Affected Files**: Relevant file paths\n\n## Services\nFor each service or component created:\n- **Name**: Service name\n- **Location**: File path\n- **Purpose**: Brief description\n- **Methods**: Key methods/functions\n\n## Knowledge\nFor each convention, rule, or important context:\n- **Topic**: What it's about\n- **Details**: The actual information\n\nOnly include sections that have content. Be concise but complete.\nUse file paths exactly as shown in the conversation.\n\nCONVERSATION LOG:\n`;\n\nexport interface Summary {\n sessionId: string;\n content: string;\n entities: ExtractedEntity[];\n architecture: ArchitectureItem[];\n services: ServiceItem[];\n knowledge: KnowledgeItem[];\n}\n\nexport interface ExtractedEntity {\n name: string;\n location?: string;\n attributes: string[];\n relations: string[];\n}\n\nexport interface ArchitectureItem {\n pattern: string;\n description: string;\n affectedFiles: string[];\n}\n\nexport interface ServiceItem {\n name: string;\n location?: string;\n purpose: string;\n methods: string[];\n}\n\nexport interface KnowledgeItem {\n topic: string;\n details: string;\n}\n\nexport class CompactionEngine {\n private projectPath: string;\n\n constructor(projectPath: string) {\n this.projectPath = projectPath;\n }\n\n async compact(sessionId: string, conversation: string): Promise<Summary | null> {\n try {\n // Use Claude SDK to generate summary\n const summaryContent = await this.generateSummary(conversation);\n\n if (!summaryContent) {\n return null;\n }\n\n // Parse the summary to extract structured data\n const summary = this.parseSummary(sessionId, summaryContent);\n\n // Write summary to conversation folder\n await this.writeSummary(sessionId, summaryContent);\n\n return summary;\n } catch (error) {\n console.error(\"Compaction failed:\", error);\n return null;\n }\n }\n\n private async generateSummary(conversation: string): Promise<string | null> {\n const prompt = SUMMARIZATION_PROMPT + conversation;\n\n try {\n const result = await spawnClaudeAgent(prompt);\n return result;\n } catch (error) {\n // Fallback to basic extraction if Claude SDK fails\n return this.fallbackExtraction(conversation);\n }\n }\n\n private fallbackExtraction(conversation: string): string {\n // Basic extraction without AI - just capture file paths and actions\n const lines = conversation.split(\"\\n\");\n const files: string[] = [];\n const actions: string[] = [];\n\n for (const line of lines) {\n // Extract file paths\n const fileMatch = line.match(/(?:Created|Modified|Edited).*?:\\s*(.+\\.(?:ts|js|tsx|jsx|md))/i);\n if (fileMatch) {\n files.push(fileMatch[1]);\n }\n\n // Extract tool actions\n if (line.includes(\"[TOOL:\")) {\n actions.push(line);\n }\n }\n\n let summary = \"# Session Summary\\n\\n\";\n\n if (files.length > 0) {\n summary += \"## Files Modified\\n\";\n for (const file of [...new Set(files)]) {\n summary += `- ${file}\\n`;\n }\n summary += \"\\n\";\n }\n\n if (actions.length > 0) {\n summary += \"## Actions\\n\";\n for (const action of actions.slice(0, 20)) {\n summary += `- ${action}\\n`;\n }\n }\n\n return summary;\n }\n\n private parseSummary(sessionId: string, content: string): Summary {\n const summary: Summary = {\n sessionId,\n content,\n entities: [],\n architecture: [],\n services: [],\n knowledge: [],\n };\n\n // Parse entities section\n const entitiesMatch = content.match(/## Entities\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (entitiesMatch) {\n summary.entities = this.parseEntities(entitiesMatch[1]);\n }\n\n // Parse architecture section\n const archMatch = content.match(/## Architecture\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (archMatch) {\n summary.architecture = this.parseArchitecture(archMatch[1]);\n }\n\n // Parse services section\n const servicesMatch = content.match(/## Services\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (servicesMatch) {\n summary.services = this.parseServices(servicesMatch[1]);\n }\n\n // Parse knowledge section\n const knowledgeMatch = content.match(/## Knowledge\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (knowledgeMatch) {\n summary.knowledge = this.parseKnowledge(knowledgeMatch[1]);\n }\n\n return summary;\n }\n\n private parseEntities(section: string): ExtractedEntity[] {\n const entities: ExtractedEntity[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Name\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const nameMatch = block.match(/\\*\\*Name\\*\\*:\\s*(.+)/);\n const locationMatch = block.match(/\\*\\*Location\\*\\*:\\s*(.+)/);\n const attributesMatch = block.match(/\\*\\*Attributes\\*\\*:\\s*(.+)/);\n const relationsMatch = block.match(/\\*\\*Relations\\*\\*:\\s*(.+)/);\n\n if (nameMatch) {\n entities.push({\n name: nameMatch[1].trim(),\n location: locationMatch?.[1].trim(),\n attributes: attributesMatch?.[1].split(\",\").map((a) => a.trim()) || [],\n relations: relationsMatch?.[1].split(\",\").map((r) => r.trim()) || [],\n });\n }\n }\n\n return entities;\n }\n\n private parseArchitecture(section: string): ArchitectureItem[] {\n const items: ArchitectureItem[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Pattern\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const patternMatch = block.match(/\\*\\*Pattern\\*\\*:\\s*(.+)/);\n const descMatch = block.match(/\\*\\*Description\\*\\*:\\s*(.+)/);\n const filesMatch = block.match(/\\*\\*Affected Files\\*\\*:\\s*(.+)/);\n\n if (patternMatch) {\n items.push({\n pattern: patternMatch[1].trim(),\n description: descMatch?.[1].trim() || \"\",\n affectedFiles: filesMatch?.[1].split(\",\").map((f) => f.trim()) || [],\n });\n }\n }\n\n return items;\n }\n\n private parseServices(section: string): ServiceItem[] {\n const items: ServiceItem[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Name\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const nameMatch = block.match(/\\*\\*Name\\*\\*:\\s*(.+)/);\n const locationMatch = block.match(/\\*\\*Location\\*\\*:\\s*(.+)/);\n const purposeMatch = block.match(/\\*\\*Purpose\\*\\*:\\s*(.+)/);\n const methodsMatch = block.match(/\\*\\*Methods\\*\\*:\\s*(.+)/);\n\n if (nameMatch) {\n items.push({\n name: nameMatch[1].trim(),\n location: locationMatch?.[1].trim(),\n purpose: purposeMatch?.[1].trim() || \"\",\n methods: methodsMatch?.[1].split(\",\").map((m) => m.trim()) || [],\n });\n }\n }\n\n return items;\n }\n\n private parseKnowledge(section: string): KnowledgeItem[] {\n const items: KnowledgeItem[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Topic\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const topicMatch = block.match(/\\*\\*Topic\\*\\*:\\s*(.+)/);\n const detailsMatch = block.match(/\\*\\*Details\\*\\*:\\s*(.+)/);\n\n if (topicMatch) {\n items.push({\n topic: topicMatch[1].trim(),\n details: detailsMatch?.[1].trim() || \"\",\n });\n }\n }\n\n return items;\n }\n\n private async writeSummary(sessionId: string, content: string): Promise<void> {\n const conversationsPath = getConversationsPath(this.projectPath);\n const summaryPath = path.join(conversationsPath, sessionId, \"summary.md\");\n\n const fullContent = `# Session Summary: ${sessionId}\nGenerated: ${new Date().toISOString()}\n\n${content}\n`;\n\n await writeTextFile(summaryPath, fullContent);\n }\n}\n","import { spawn } from \"node:child_process\";\n\n/**\n * Spawns a Claude Code subagent to process a prompt.\n * Uses the Claude Code CLI with the --print flag to get output.\n */\nexport async function spawnClaudeAgent(prompt: string): Promise<string> {\n return new Promise((resolve, reject) => {\n // Use claude CLI with --print to get output without interactive mode\n const child = spawn(\"claude\", [\"--print\", \"-p\", prompt], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 120000, // 2 minute timeout\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout?.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n child.stderr?.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve(stdout.trim());\n } else {\n reject(new Error(`Claude agent failed with code ${code}: ${stderr}`));\n }\n });\n\n child.on(\"error\", (error) => {\n reject(error);\n });\n });\n}\n\n/**\n * Checks if Claude CLI is available.\n */\nexport async function isClaudeAvailable(): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(\"claude\", [\"--version\"], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n child.on(\"close\", (code) => {\n resolve(code === 0);\n });\n\n child.on(\"error\", () => {\n resolve(false);\n });\n });\n}\n","import type { Summary, ExtractedEntity, ServiceItem } from \"./compaction-engine.js\";\n\nexport interface DetectedItem {\n type: \"entity\" | \"service\" | \"pattern\" | \"knowledge\";\n name: string;\n data: unknown;\n vaultPath: string;\n content: string;\n}\n\nexport class EntityDetector {\n /**\n * Analyzes a summary and determines what should be added to the vault.\n */\n detect(summary: Summary): DetectedItem[] {\n const items: DetectedItem[] = [];\n\n // Detect entities\n for (const entity of summary.entities) {\n items.push(this.createEntityItem(entity));\n\n // Also create service entries for entity-related services\n const relatedServices = summary.services.filter(\n (s) =>\n s.name.toLowerCase().includes(entity.name.toLowerCase()) ||\n s.location?.toLowerCase().includes(entity.name.toLowerCase())\n );\n\n for (const service of relatedServices) {\n items.push(this.createServiceItem(entity.name, service));\n }\n }\n\n // Detect standalone services\n const processedServiceNames = new Set<string>();\n for (const entity of summary.entities) {\n for (const service of summary.services) {\n if (\n service.name.toLowerCase().includes(entity.name.toLowerCase()) ||\n service.location?.toLowerCase().includes(entity.name.toLowerCase())\n ) {\n processedServiceNames.add(service.name);\n }\n }\n }\n\n for (const service of summary.services) {\n if (!processedServiceNames.has(service.name)) {\n items.push(this.createStandaloneServiceItem(service));\n }\n }\n\n // Detect architecture patterns\n for (const arch of summary.architecture) {\n items.push(this.createArchitectureItem(arch));\n }\n\n // Detect general knowledge\n for (const knowledge of summary.knowledge) {\n items.push(this.createKnowledgeItem(knowledge));\n }\n\n return items;\n }\n\n private createEntityItem(entity: ExtractedEntity): DetectedItem {\n const content = this.formatEntityContent(entity);\n\n return {\n type: \"entity\",\n name: entity.name,\n data: entity,\n vaultPath: `entities/${entity.name.toLowerCase()}`,\n content,\n };\n }\n\n private createServiceItem(\n entityName: string,\n service: ServiceItem\n ): DetectedItem {\n const content = this.formatServiceContent(service);\n const serviceName = service.name.toLowerCase().replace(entityName.toLowerCase(), \"\").trim();\n const fileName = serviceName || \"service\";\n\n return {\n type: \"service\",\n name: service.name,\n data: service,\n vaultPath: `entities/${entityName.toLowerCase()}/services/${fileName}`,\n content,\n };\n }\n\n private createStandaloneServiceItem(service: ServiceItem): DetectedItem {\n const content = this.formatServiceContent(service);\n\n return {\n type: \"service\",\n name: service.name,\n data: service,\n vaultPath: `services/${service.name.toLowerCase()}`,\n content,\n };\n }\n\n private createArchitectureItem(arch: {\n pattern: string;\n description: string;\n affectedFiles: string[];\n }): DetectedItem {\n const content = `## ${arch.pattern}\n\n${arch.description}\n\n### Affected Files\n${arch.affectedFiles.map((f) => `- ${f}`).join(\"\\n\")}\n`;\n\n return {\n type: \"pattern\",\n name: arch.pattern,\n data: arch,\n vaultPath: \"architecture\",\n content,\n };\n }\n\n private createKnowledgeItem(knowledge: {\n topic: string;\n details: string;\n }): DetectedItem {\n const content = `## ${knowledge.topic}\n\n${knowledge.details}\n`;\n\n return {\n type: \"knowledge\",\n name: knowledge.topic,\n data: knowledge,\n vaultPath: \"general-knowledge\",\n content,\n };\n }\n\n private formatEntityContent(entity: ExtractedEntity): string {\n let content = `# ${entity.name}\\n\\n`;\n\n if (entity.location) {\n content += `**Location**: ${entity.location}\\n\\n`;\n }\n\n if (entity.attributes.length > 0) {\n content += `## Attributes\\n\\n`;\n for (const attr of entity.attributes) {\n content += `- ${attr}\\n`;\n }\n content += \"\\n\";\n }\n\n if (entity.relations.length > 0) {\n content += `## Relations\\n\\n`;\n for (const rel of entity.relations) {\n content += `- ${rel}\\n`;\n }\n content += \"\\n\";\n }\n\n return content;\n }\n\n private formatServiceContent(service: ServiceItem): string {\n let content = `# ${service.name}\\n\\n`;\n\n if (service.location) {\n content += `**Location**: ${service.location}\\n\\n`;\n }\n\n if (service.purpose) {\n content += `## Purpose\\n\\n${service.purpose}\\n\\n`;\n }\n\n if (service.methods.length > 0) {\n content += `## Methods\\n\\n`;\n for (const method of service.methods) {\n content += `- ${method}\\n`;\n }\n content += \"\\n\";\n }\n\n return content;\n }\n}\n","import * as path from \"node:path\";\nimport {\n readTextFile,\n writeTextFile,\n appendToFile,\n ensureDir,\n fileExists,\n} from \"../utils/file-utils.js\";\nimport { IndexManager } from \"./index-manager.js\";\nimport { EntityDetector, type DetectedItem } from \"./entity-detector.js\";\nimport type { Summary } from \"./compaction-engine.js\";\n\nexport class VaultIntegrator {\n private vaultPath: string;\n private indexManager: IndexManager;\n private entityDetector: EntityDetector;\n\n constructor(vaultPath: string) {\n this.vaultPath = vaultPath;\n this.indexManager = new IndexManager(vaultPath);\n this.entityDetector = new EntityDetector();\n }\n\n async integrate(summary: Summary): Promise<void> {\n // Detect items from summary\n const items = this.entityDetector.detect(summary);\n\n if (items.length === 0) {\n return;\n }\n\n // Process each detected item\n for (const item of items) {\n await this.processItem(item);\n }\n\n // Update root INDEX.md with timestamp\n await this.updateRootIndex();\n }\n\n private async processItem(item: DetectedItem): Promise<void> {\n switch (item.type) {\n case \"entity\":\n await this.processEntity(item);\n break;\n case \"service\":\n await this.processService(item);\n break;\n case \"pattern\":\n await this.processPattern(item);\n break;\n case \"knowledge\":\n await this.processKnowledge(item);\n break;\n }\n }\n\n private async processEntity(item: DetectedItem): Promise<void> {\n const entityPath = await this.indexManager.ensureEntityFolder(item.name);\n const fullPath = path.join(this.vaultPath, entityPath);\n\n // Write attributes.md\n const attributesPath = path.join(fullPath, \"attributes.md\");\n await writeTextFile(attributesPath, item.content);\n\n // Update entity INDEX.md\n await this.indexManager.addEntry(entityPath, {\n name: \"attributes\",\n path: \"./attributes.md\",\n description: `Attributes of ${item.name}`,\n type: \"file\",\n });\n }\n\n private async processService(item: DetectedItem): Promise<void> {\n const pathParts = item.vaultPath.split(\"/\");\n const fileName = pathParts.pop() + \".md\";\n const folderPath = pathParts.join(\"/\");\n const fullFolderPath = path.join(this.vaultPath, folderPath);\n\n await ensureDir(fullFolderPath);\n\n // Write service file\n const filePath = path.join(fullFolderPath, fileName);\n await writeTextFile(filePath, item.content);\n\n // Ensure parent has INDEX.md\n const parentIndexPath = path.join(fullFolderPath, \"INDEX.md\");\n if (!(await fileExists(parentIndexPath))) {\n await this.indexManager.createIndex(folderPath, []);\n }\n\n // Update parent INDEX.md\n await this.indexManager.addEntry(folderPath, {\n name: item.name,\n path: `./${fileName}`,\n description: (item.data as { purpose?: string }).purpose || `${item.name} service`,\n type: \"file\",\n });\n\n // Update entity INDEX if this is an entity service\n if (folderPath.startsWith(\"entities/\") && folderPath.includes(\"/services\")) {\n const entityFolder = folderPath.split(\"/\").slice(0, 2).join(\"/\");\n await this.indexManager.addEntry(entityFolder, {\n name: \"services\",\n path: \"./services/INDEX.md\",\n description: \"Service layer documentation\",\n type: \"folder\",\n });\n }\n }\n\n private async processPattern(item: DetectedItem): Promise<void> {\n const archPath = path.join(this.vaultPath, \"architecture.md\");\n const existing = await readTextFile(archPath);\n\n if (!existing) {\n await writeTextFile(archPath, `# Architecture\\n\\n${item.content}`);\n return;\n }\n\n // Check if pattern already exists\n if (existing.includes(`## ${item.name}`)) {\n // Replace existing section\n const regex = new RegExp(`## ${item.name}[\\\\s\\\\S]*?(?=\\\\n## |$)`);\n const updated = existing.replace(regex, item.content);\n await writeTextFile(archPath, updated);\n } else {\n // Append new pattern\n await appendToFile(archPath, `\\n${item.content}`);\n }\n }\n\n private async processKnowledge(item: DetectedItem): Promise<void> {\n const knowledgePath = path.join(this.vaultPath, \"general-knowledge.md\");\n const existing = await readTextFile(knowledgePath);\n\n if (!existing) {\n await writeTextFile(knowledgePath, `# General Knowledge\\n\\n${item.content}`);\n return;\n }\n\n // Check if topic already exists\n if (existing.includes(`## ${item.name}`)) {\n // Replace existing section\n const regex = new RegExp(`## ${item.name}[\\\\s\\\\S]*?(?=\\\\n## |$)`);\n const updated = existing.replace(regex, item.content);\n await writeTextFile(knowledgePath, updated);\n } else {\n // Append new knowledge\n await appendToFile(knowledgePath, `\\n${item.content}`);\n }\n }\n\n private async updateRootIndex(): Promise<void> {\n const indexPath = path.join(this.vaultPath, \"INDEX.md\");\n const content = await readTextFile(indexPath);\n\n if (!content) {\n return;\n }\n\n // Update the \"Last Updated\" line\n const timestamp = new Date().toISOString();\n const updated = content.replace(\n /## Last Updated[\\s\\S]*$/,\n `## Last Updated\\n\\n${timestamp}`\n );\n\n await writeTextFile(indexPath, updated);\n }\n}\n"],"mappings":"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","names":["path"]}
|
|
File without changes
|
|
File without changes
|