cckb 0.1.3 → 0.1.5

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/README.md CHANGED
@@ -62,6 +62,9 @@ CCKB runs silently in the background, capturing conversations and building a str
62
62
  ```bash
63
63
  # From your project directory
64
64
  npx cckb init
65
+
66
+ # Install and analyze existing codebase
67
+ npx cckb init --discover
65
68
  ```
66
69
 
67
70
  ### Option 2: Global Install
@@ -78,6 +81,24 @@ cckb init
78
81
  pnpm dlx cckb init
79
82
  ```
80
83
 
84
+ ### Bootstrapping Existing Projects
85
+
86
+ For existing codebases, use the `discover` command to analyze and populate the vault:
87
+
88
+ ```bash
89
+ # After init, or anytime
90
+ cckb discover
91
+
92
+ # Or during install
93
+ cckb init --discover
94
+ ```
95
+
96
+ The discover command uses Claude to analyze your codebase and automatically populate the vault with:
97
+ - **Entities** — Data models, types, interfaces
98
+ - **Architecture** — Design patterns, structural decisions
99
+ - **Services** — Controllers, handlers, business logic
100
+ - **Knowledge** — Conventions, configuration, project context
101
+
81
102
  ---
82
103
 
83
104
  ## What Gets Installed
@@ -109,7 +130,8 @@ Edit `cc-knowledge-base/.cckb-config.json`:
109
130
  {
110
131
  "compaction": {
111
132
  "trigger": "session_end",
112
- "sizeThresholdKB": 50
133
+ "sizeThresholdKB": 50,
134
+ "cleanupAfterSummary": "keep"
113
135
  },
114
136
  "capture": {
115
137
  "tools": ["Write", "Edit", "MultiEdit", "Bash", "Task"],
@@ -122,6 +144,11 @@ Edit `cc-knowledge-base/.cckb-config.json`:
122
144
  "feedback": {
123
145
  "enabled": true,
124
146
  "contextDepth": 2
147
+ },
148
+ "discover": {
149
+ "maxFiles": 100,
150
+ "maxChunkSize": 50000,
151
+ "supportedLanguages": ["typescript", "javascript", "python", "go", "rust"]
125
152
  }
126
153
  }
127
154
  ```
@@ -130,12 +157,16 @@ Edit `cc-knowledge-base/.cckb-config.json`:
130
157
  |--------|-------------|
131
158
  | `compaction.trigger` | When to summarize: `session_end`, `size`, `messages`, or `manual` |
132
159
  | `compaction.sizeThresholdKB` | File size threshold for rotation |
160
+ | `compaction.cleanupAfterSummary` | After compaction: `keep`, `archive`, or `delete` original files |
133
161
  | `capture.tools` | Which tool outputs to capture |
134
162
  | `capture.maxContentLength` | Max characters per tool output |
135
163
  | `vault.autoIntegrate` | Auto-update vault after compaction |
136
164
  | `vault.maxDepth` | Maximum folder nesting depth |
137
165
  | `feedback.enabled` | Inject vault context into sessions |
138
166
  | `feedback.contextDepth` | How many INDEX levels to load |
167
+ | `discover.maxFiles` | Maximum files to analyze |
168
+ | `discover.maxChunkSize` | Characters per Claude analysis chunk |
169
+ | `discover.supportedLanguages` | Languages to analyze |
139
170
 
140
171
  ---
141
172
 
@@ -189,11 +220,14 @@ All hooks run silently in the background.
189
220
  ## Commands
190
221
 
191
222
  ```bash
192
- cckb init [path] # Install CCKB in a project
193
- cckb init --force # Reinstall, overwriting existing config
194
- cckb hook <name> # Run a hook (internal use)
195
- cckb version # Show version
196
- cckb help # Show help
223
+ cckb init [path] # Install CCKB in a project
224
+ cckb init --force # Reinstall, overwriting existing config
225
+ cckb init --discover # Install and analyze existing codebase
226
+ cckb discover [path] # Analyze codebase and populate vault
227
+ cckb discover --verbose # Show detailed progress
228
+ cckb hook <name> # Run a hook (internal use)
229
+ cckb version # Show version
230
+ cckb help # Show help
197
231
  ```
198
232
 
199
233
  ---
package/dist/bin/cckb.js CHANGED
@@ -1,19 +1,34 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ discover,
3
4
  install
4
- } from "../chunk-3KGJEBKK.js";
5
- import "../chunk-E2IJSPVB.js";
5
+ } from "../chunk-XOV27B2L.js";
6
+ import "../chunk-TB2GPCQP.js";
7
+ import "../chunk-4IQV2TQE.js";
8
+ import "../chunk-FRETJBP5.js";
6
9
 
7
10
  // src/bin/cckb.ts
8
11
  var args = process.argv.slice(2);
9
12
  var command = args[0];
10
13
  async function main() {
11
14
  switch (command) {
12
- case "init":
13
- const targetPath = args[1] || process.cwd();
15
+ case "init": {
16
+ const targetPath = args.slice(1).find((a) => !a.startsWith("-")) || process.cwd();
14
17
  const force = args.includes("--force");
18
+ const shouldDiscover = args.includes("--discover");
15
19
  await install(targetPath, { force });
20
+ if (shouldDiscover) {
21
+ console.log("\nRunning codebase discovery...\n");
22
+ await discover({ targetPath, verbose: true });
23
+ }
16
24
  break;
25
+ }
26
+ case "discover": {
27
+ const targetPath = args.slice(1).find((a) => !a.startsWith("-")) || process.cwd();
28
+ const verbose = args.includes("--verbose") || args.includes("-v");
29
+ await discover({ targetPath, verbose: verbose || true });
30
+ break;
31
+ }
17
32
  case "hook":
18
33
  const hookName = args[1];
19
34
  await runHook(hookName);
@@ -68,18 +83,25 @@ function printHelp() {
68
83
  CCKB - Claude Code Knowledge Base
69
84
 
70
85
  Usage:
71
- cckb init [path] Install CCKB into a project
72
- cckb hook <name> Run a specific hook (internal use)
73
- cckb version Show version
74
- cckb help Show this help message
86
+ cckb init [path] Install CCKB into a project
87
+ cckb init --discover Install and analyze existing codebase
88
+ cckb discover [path] Analyze codebase and populate vault
89
+ cckb hook <name> Run a specific hook (internal use)
90
+ cckb version Show version
91
+ cckb help Show this help message
75
92
 
76
93
  Options:
77
- --force Overwrite existing installation
94
+ --force Overwrite existing installation
95
+ --discover Run codebase analysis after init
96
+ --verbose, -v Show detailed progress during discovery
78
97
 
79
98
  Examples:
80
- cckb init Install in current directory
81
- cckb init ./myapp Install in ./myapp directory
82
- cckb init --force Reinstall, overwriting existing config
99
+ cckb init Install in current directory
100
+ cckb init ./myapp Install in ./myapp directory
101
+ cckb init --force Reinstall, overwriting existing config
102
+ cckb init --discover Install and run initial discovery
103
+ cckb discover Analyze current project's codebase
104
+ cckb discover ./myapp Analyze ./myapp codebase
83
105
  `);
84
106
  }
85
107
  main().catch((error) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/cckb.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { install } from \"../cli/install.js\";\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nasync function main() {\n switch (command) {\n case \"init\":\n const targetPath = args[1] || process.cwd();\n const force = args.includes(\"--force\");\n await install(targetPath, { force });\n break;\n\n case \"hook\":\n const hookName = args[1];\n await runHook(hookName);\n break;\n\n case \"version\":\n case \"-v\":\n case \"--version\":\n console.log(\"cckb v0.1.0\");\n break;\n\n case \"help\":\n case \"-h\":\n case \"--help\":\n default:\n printHelp();\n break;\n }\n}\n\nasync function runHook(hookName: string) {\n switch (hookName) {\n case \"session-start\": {\n const { handleSessionStart } = await import(\n \"../hooks/session-start.js\"\n );\n await handleSessionStart();\n break;\n }\n case \"user-prompt\": {\n const { handleUserPrompt } = await import(\"../hooks/user-prompt.js\");\n await handleUserPrompt();\n break;\n }\n case \"post-tool-use\": {\n const { handlePostToolUse } = await import(\"../hooks/post-tool-use.js\");\n await handlePostToolUse();\n break;\n }\n case \"stop\": {\n const { handleStop } = await import(\"../hooks/stop.js\");\n await handleStop();\n break;\n }\n case \"notification\": {\n const { handleNotification } = await import(\"../hooks/notification.js\");\n await handleNotification();\n break;\n }\n default:\n console.error(`Unknown hook: ${hookName}`);\n process.exit(1);\n }\n}\n\nfunction printHelp() {\n console.log(`\nCCKB - Claude Code Knowledge Base\n\nUsage:\n cckb init [path] Install CCKB into a project\n cckb hook <name> Run a specific hook (internal use)\n cckb version Show version\n cckb help Show this help message\n\nOptions:\n --force Overwrite existing installation\n\nExamples:\n cckb init Install in current directory\n cckb init ./myapp Install in ./myapp directory\n cckb init --force Reinstall, overwriting existing config\n`);\n}\n\nmain().catch((error) => {\n console.error(\"Error:\", error.message);\n process.exit(1);\n});\n"],"mappings":";;;;;;;AAIA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UAAU,KAAK,CAAC;AAEtB,eAAe,OAAO;AACpB,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,YAAM,aAAa,KAAK,CAAC,KAAK,QAAQ,IAAI;AAC1C,YAAM,QAAQ,KAAK,SAAS,SAAS;AACrC,YAAM,QAAQ,YAAY,EAAE,MAAM,CAAC;AACnC;AAAA,IAEF,KAAK;AACH,YAAM,WAAW,KAAK,CAAC;AACvB,YAAM,QAAQ,QAAQ;AACtB;AAAA,IAEF,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,cAAQ,IAAI,aAAa;AACzB;AAAA,IAEF,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AACE,gBAAU;AACV;AAAA,EACJ;AACF;AAEA,eAAe,QAAQ,UAAkB;AACvC,UAAQ,UAAU;AAAA,IAChB,KAAK,iBAAiB;AACpB,YAAM,EAAE,mBAAmB,IAAI,MAAM,OACnC,2BACF;AACA,YAAM,mBAAmB;AACzB;AAAA,IACF;AAAA,IACA,KAAK,eAAe;AAClB,YAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,yBAAyB;AACnE,YAAM,iBAAiB;AACvB;AAAA,IACF;AAAA,IACA,KAAK,iBAAiB;AACpB,YAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,2BAA2B;AACtE,YAAM,kBAAkB;AACxB;AAAA,IACF;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,EAAE,WAAW,IAAI,MAAM,OAAO,kBAAkB;AACtD,YAAM,WAAW;AACjB;AAAA,IACF;AAAA,IACA,KAAK,gBAAgB;AACnB,YAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,0BAA0B;AACtE,YAAM,mBAAmB;AACzB;AAAA,IACF;AAAA,IACA;AACE,cAAQ,MAAM,iBAAiB,QAAQ,EAAE;AACzC,cAAQ,KAAK,CAAC;AAAA,EAClB;AACF;AAEA,SAAS,YAAY;AACnB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAgBb;AACD;AAEA,KAAK,EAAE,MAAM,CAAC,UAAU;AACtB,UAAQ,MAAM,UAAU,MAAM,OAAO;AACrC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/bin/cckb.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { install } from \"../cli/install.js\";\nimport { discover } from \"../cli/discover.js\";\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nasync function main() {\n switch (command) {\n case \"init\": {\n // Find target path (first arg that's not a flag)\n const targetPath = args.slice(1).find((a) => !a.startsWith(\"-\")) || process.cwd();\n const force = args.includes(\"--force\");\n const shouldDiscover = args.includes(\"--discover\");\n\n await install(targetPath, { force });\n\n if (shouldDiscover) {\n console.log(\"\\nRunning codebase discovery...\\n\");\n await discover({ targetPath, verbose: true });\n }\n break;\n }\n\n case \"discover\": {\n const targetPath = args.slice(1).find((a) => !a.startsWith(\"-\")) || process.cwd();\n const verbose = args.includes(\"--verbose\") || args.includes(\"-v\");\n await discover({ targetPath, verbose: verbose || true });\n break;\n }\n\n case \"hook\":\n const hookName = args[1];\n await runHook(hookName);\n break;\n\n case \"version\":\n case \"-v\":\n case \"--version\":\n console.log(\"cckb v0.1.0\");\n break;\n\n case \"help\":\n case \"-h\":\n case \"--help\":\n default:\n printHelp();\n break;\n }\n}\n\nasync function runHook(hookName: string) {\n switch (hookName) {\n case \"session-start\": {\n const { handleSessionStart } = await import(\n \"../hooks/session-start.js\"\n );\n await handleSessionStart();\n break;\n }\n case \"user-prompt\": {\n const { handleUserPrompt } = await import(\"../hooks/user-prompt.js\");\n await handleUserPrompt();\n break;\n }\n case \"post-tool-use\": {\n const { handlePostToolUse } = await import(\"../hooks/post-tool-use.js\");\n await handlePostToolUse();\n break;\n }\n case \"stop\": {\n const { handleStop } = await import(\"../hooks/stop.js\");\n await handleStop();\n break;\n }\n case \"notification\": {\n const { handleNotification } = await import(\"../hooks/notification.js\");\n await handleNotification();\n break;\n }\n default:\n console.error(`Unknown hook: ${hookName}`);\n process.exit(1);\n }\n}\n\nfunction printHelp() {\n console.log(`\nCCKB - Claude Code Knowledge Base\n\nUsage:\n cckb init [path] Install CCKB into a project\n cckb init --discover Install and analyze existing codebase\n cckb discover [path] Analyze codebase and populate vault\n cckb hook <name> Run a specific hook (internal use)\n cckb version Show version\n cckb help Show this help message\n\nOptions:\n --force Overwrite existing installation\n --discover Run codebase analysis after init\n --verbose, -v Show detailed progress during discovery\n\nExamples:\n cckb init Install in current directory\n cckb init ./myapp Install in ./myapp directory\n cckb init --force Reinstall, overwriting existing config\n cckb init --discover Install and run initial discovery\n cckb discover Analyze current project's codebase\n cckb discover ./myapp Analyze ./myapp codebase\n`);\n}\n\nmain().catch((error) => {\n console.error(\"Error:\", error.message);\n process.exit(1);\n});\n"],"mappings":";;;;;;;;;;AAKA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UAAU,KAAK,CAAC;AAEtB,eAAe,OAAO;AACpB,UAAQ,SAAS;AAAA,IACf,KAAK,QAAQ;AAEX,YAAM,aAAa,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,CAAC,KAAK,QAAQ,IAAI;AAChF,YAAM,QAAQ,KAAK,SAAS,SAAS;AACrC,YAAM,iBAAiB,KAAK,SAAS,YAAY;AAEjD,YAAM,QAAQ,YAAY,EAAE,MAAM,CAAC;AAEnC,UAAI,gBAAgB;AAClB,gBAAQ,IAAI,mCAAmC;AAC/C,cAAM,SAAS,EAAE,YAAY,SAAS,KAAK,CAAC;AAAA,MAC9C;AACA;AAAA,IACF;AAAA,IAEA,KAAK,YAAY;AACf,YAAM,aAAa,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,CAAC,KAAK,QAAQ,IAAI;AAChF,YAAM,UAAU,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS,IAAI;AAChE,YAAM,SAAS,EAAE,YAAY,SAAS,WAAW,KAAK,CAAC;AACvD;AAAA,IACF;AAAA,IAEA,KAAK;AACH,YAAM,WAAW,KAAK,CAAC;AACvB,YAAM,QAAQ,QAAQ;AACtB;AAAA,IAEF,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,cAAQ,IAAI,aAAa;AACzB;AAAA,IAEF,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AACE,gBAAU;AACV;AAAA,EACJ;AACF;AAEA,eAAe,QAAQ,UAAkB;AACvC,UAAQ,UAAU;AAAA,IAChB,KAAK,iBAAiB;AACpB,YAAM,EAAE,mBAAmB,IAAI,MAAM,OACnC,2BACF;AACA,YAAM,mBAAmB;AACzB;AAAA,IACF;AAAA,IACA,KAAK,eAAe;AAClB,YAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,yBAAyB;AACnE,YAAM,iBAAiB;AACvB;AAAA,IACF;AAAA,IACA,KAAK,iBAAiB;AACpB,YAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,2BAA2B;AACtE,YAAM,kBAAkB;AACxB;AAAA,IACF;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,EAAE,WAAW,IAAI,MAAM,OAAO,kBAAkB;AACtD,YAAM,WAAW;AACjB;AAAA,IACF;AAAA,IACA,KAAK,gBAAgB;AACnB,YAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,0BAA0B;AACtE,YAAM,mBAAmB;AACzB;AAAA,IACF;AAAA,IACA;AACE,cAAQ,MAAM,iBAAiB,QAAQ,EAAE;AACzC,cAAQ,KAAK,CAAC;AAAA,EAClB;AACF;AAEA,SAAS,YAAY;AACnB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAuBb;AACD;AAEA,KAAK,EAAE,MAAM,CAAC,UAAU;AACtB,UAAQ,MAAM,UAAU,MAAM,OAAO;AACrC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  listDir,
5
5
  readTextFile,
6
6
  writeTextFile
7
- } from "./chunk-E2IJSPVB.js";
7
+ } from "./chunk-FRETJBP5.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-NOCXYKIE.js.map
149
+ //# sourceMappingURL=chunk-4IQV2TQE.js.map
@@ -0,0 +1,276 @@
1
+ import {
2
+ spawnClaudeAgent
3
+ } from "./chunk-TB2GPCQP.js";
4
+ import {
5
+ getConversationsPath,
6
+ loadConfig,
7
+ readTextFile,
8
+ writeTextFile
9
+ } from "./chunk-FRETJBP5.js";
10
+
11
+ // src/core/compaction-engine.ts
12
+ import * as path from "path";
13
+ import * as fs from "fs/promises";
14
+ import * as zlib from "zlib";
15
+ import { promisify } from "util";
16
+ var gzip2 = promisify(zlib.gzip);
17
+ var SUMMARIZATION_PROMPT = `You are a technical knowledge extractor. Analyze this conversation log and extract key information for a project knowledge base.
18
+
19
+ Extract and format the following:
20
+
21
+ ## Entities
22
+ For each domain entity (data model, type, class) created or modified:
23
+ - **Name**: Entity name
24
+ - **Location**: File path
25
+ - **Attributes**: Key fields/properties
26
+ - **Relations**: Related entities
27
+
28
+ ## Architecture
29
+ For each architectural pattern or design decision:
30
+ - **Pattern**: Name of pattern
31
+ - **Description**: Brief explanation
32
+ - **Affected Files**: Relevant file paths
33
+
34
+ ## Services
35
+ For each service or component created:
36
+ - **Name**: Service name
37
+ - **Location**: File path
38
+ - **Purpose**: Brief description
39
+ - **Methods**: Key methods/functions
40
+
41
+ ## Knowledge
42
+ For each convention, rule, or important context:
43
+ - **Topic**: What it's about
44
+ - **Details**: The actual information
45
+
46
+ Only include sections that have content. Be concise but complete.
47
+ Use file paths exactly as shown in the conversation.
48
+
49
+ CONVERSATION LOG:
50
+ `;
51
+ var CompactionEngine = class {
52
+ projectPath;
53
+ constructor(projectPath) {
54
+ this.projectPath = projectPath;
55
+ }
56
+ async compact(sessionId, conversation) {
57
+ try {
58
+ const summaryContent = await this.generateSummary(conversation);
59
+ if (!summaryContent) {
60
+ return null;
61
+ }
62
+ const summary = this.parseSummary(sessionId, summaryContent);
63
+ await this.writeSummary(sessionId, summaryContent);
64
+ await this.cleanupConversationFiles(sessionId);
65
+ return summary;
66
+ } catch (error) {
67
+ console.error("Compaction failed:", error);
68
+ return null;
69
+ }
70
+ }
71
+ async generateSummary(conversation) {
72
+ const prompt = SUMMARIZATION_PROMPT + conversation;
73
+ try {
74
+ const result = await spawnClaudeAgent(prompt);
75
+ return result;
76
+ } catch (error) {
77
+ return this.fallbackExtraction(conversation);
78
+ }
79
+ }
80
+ fallbackExtraction(conversation) {
81
+ const lines = conversation.split("\n");
82
+ const files = [];
83
+ const actions = [];
84
+ for (const line of lines) {
85
+ const fileMatch = line.match(/(?:Created|Modified|Edited).*?:\s*(.+\.(?:ts|js|tsx|jsx|md))/i);
86
+ if (fileMatch) {
87
+ files.push(fileMatch[1]);
88
+ }
89
+ if (line.includes("[TOOL:")) {
90
+ actions.push(line);
91
+ }
92
+ }
93
+ let summary = "# Session Summary\n\n";
94
+ if (files.length > 0) {
95
+ summary += "## Files Modified\n";
96
+ for (const file of [...new Set(files)]) {
97
+ summary += `- ${file}
98
+ `;
99
+ }
100
+ summary += "\n";
101
+ }
102
+ if (actions.length > 0) {
103
+ summary += "## Actions\n";
104
+ for (const action of actions.slice(0, 20)) {
105
+ summary += `- ${action}
106
+ `;
107
+ }
108
+ }
109
+ return summary;
110
+ }
111
+ parseSummary(sessionId, content) {
112
+ const summary = {
113
+ sessionId,
114
+ content,
115
+ entities: [],
116
+ architecture: [],
117
+ services: [],
118
+ knowledge: []
119
+ };
120
+ const entitiesMatch = content.match(/## Entities\n([\s\S]*?)(?=\n## |$)/);
121
+ if (entitiesMatch) {
122
+ summary.entities = this.parseEntities(entitiesMatch[1]);
123
+ }
124
+ const archMatch = content.match(/## Architecture\n([\s\S]*?)(?=\n## |$)/);
125
+ if (archMatch) {
126
+ summary.architecture = this.parseArchitecture(archMatch[1]);
127
+ }
128
+ const servicesMatch = content.match(/## Services\n([\s\S]*?)(?=\n## |$)/);
129
+ if (servicesMatch) {
130
+ summary.services = this.parseServices(servicesMatch[1]);
131
+ }
132
+ const knowledgeMatch = content.match(/## Knowledge\n([\s\S]*?)(?=\n## |$)/);
133
+ if (knowledgeMatch) {
134
+ summary.knowledge = this.parseKnowledge(knowledgeMatch[1]);
135
+ }
136
+ return summary;
137
+ }
138
+ parseEntities(section) {
139
+ const entities = [];
140
+ const blocks = section.split(/\n(?=- \*\*Name\*\*:)/);
141
+ for (const block of blocks) {
142
+ if (!block.trim()) continue;
143
+ const nameMatch = block.match(/\*\*Name\*\*:\s*(.+)/);
144
+ const locationMatch = block.match(/\*\*Location\*\*:\s*(.+)/);
145
+ const attributesMatch = block.match(/\*\*Attributes\*\*:\s*(.+)/);
146
+ const relationsMatch = block.match(/\*\*Relations\*\*:\s*(.+)/);
147
+ if (nameMatch) {
148
+ entities.push({
149
+ name: nameMatch[1].trim(),
150
+ location: locationMatch?.[1].trim(),
151
+ attributes: attributesMatch?.[1].split(",").map((a) => a.trim()) || [],
152
+ relations: relationsMatch?.[1].split(",").map((r) => r.trim()) || []
153
+ });
154
+ }
155
+ }
156
+ return entities;
157
+ }
158
+ parseArchitecture(section) {
159
+ const items = [];
160
+ const blocks = section.split(/\n(?=- \*\*Pattern\*\*:)/);
161
+ for (const block of blocks) {
162
+ if (!block.trim()) continue;
163
+ const patternMatch = block.match(/\*\*Pattern\*\*:\s*(.+)/);
164
+ const descMatch = block.match(/\*\*Description\*\*:\s*(.+)/);
165
+ const filesMatch = block.match(/\*\*Affected Files\*\*:\s*(.+)/);
166
+ if (patternMatch) {
167
+ items.push({
168
+ pattern: patternMatch[1].trim(),
169
+ description: descMatch?.[1].trim() || "",
170
+ affectedFiles: filesMatch?.[1].split(",").map((f) => f.trim()) || []
171
+ });
172
+ }
173
+ }
174
+ return items;
175
+ }
176
+ parseServices(section) {
177
+ const items = [];
178
+ const blocks = section.split(/\n(?=- \*\*Name\*\*:)/);
179
+ for (const block of blocks) {
180
+ if (!block.trim()) continue;
181
+ const nameMatch = block.match(/\*\*Name\*\*:\s*(.+)/);
182
+ const locationMatch = block.match(/\*\*Location\*\*:\s*(.+)/);
183
+ const purposeMatch = block.match(/\*\*Purpose\*\*:\s*(.+)/);
184
+ const methodsMatch = block.match(/\*\*Methods\*\*:\s*(.+)/);
185
+ if (nameMatch) {
186
+ items.push({
187
+ name: nameMatch[1].trim(),
188
+ location: locationMatch?.[1].trim(),
189
+ purpose: purposeMatch?.[1].trim() || "",
190
+ methods: methodsMatch?.[1].split(",").map((m) => m.trim()) || []
191
+ });
192
+ }
193
+ }
194
+ return items;
195
+ }
196
+ parseKnowledge(section) {
197
+ const items = [];
198
+ const blocks = section.split(/\n(?=- \*\*Topic\*\*:)/);
199
+ for (const block of blocks) {
200
+ if (!block.trim()) continue;
201
+ const topicMatch = block.match(/\*\*Topic\*\*:\s*(.+)/);
202
+ const detailsMatch = block.match(/\*\*Details\*\*:\s*(.+)/);
203
+ if (topicMatch) {
204
+ items.push({
205
+ topic: topicMatch[1].trim(),
206
+ details: detailsMatch?.[1].trim() || ""
207
+ });
208
+ }
209
+ }
210
+ return items;
211
+ }
212
+ async writeSummary(sessionId, content) {
213
+ const conversationsPath = getConversationsPath(this.projectPath);
214
+ const summaryPath = path.join(conversationsPath, sessionId, "summary.md");
215
+ const fullContent = `# Session Summary: ${sessionId}
216
+ Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
217
+
218
+ ${content}
219
+ `;
220
+ await writeTextFile(summaryPath, fullContent);
221
+ }
222
+ async cleanupConversationFiles(sessionId) {
223
+ const config = await loadConfig(this.projectPath);
224
+ const cleanupMode = config.compaction.cleanupAfterSummary;
225
+ if (cleanupMode === "keep") {
226
+ return;
227
+ }
228
+ const conversationsPath = getConversationsPath(this.projectPath);
229
+ const sessionPath = path.join(conversationsPath, sessionId);
230
+ const files = await fs.readdir(sessionPath);
231
+ const conversationFiles = files.filter(
232
+ (f) => /^\d+\.txt$/.test(f)
233
+ );
234
+ if (conversationFiles.length === 0) {
235
+ return;
236
+ }
237
+ if (cleanupMode === "archive") {
238
+ await this.archiveConversationFiles(sessionPath, conversationFiles);
239
+ } else if (cleanupMode === "delete") {
240
+ await this.deleteConversationFiles(sessionPath, conversationFiles);
241
+ }
242
+ }
243
+ async archiveConversationFiles(sessionPath, files) {
244
+ try {
245
+ const contents = [];
246
+ for (const file of files.sort()) {
247
+ const filePath = path.join(sessionPath, file);
248
+ const content = await readTextFile(filePath);
249
+ if (content) {
250
+ contents.push(`=== ${file} ===
251
+ ${content}`);
252
+ }
253
+ }
254
+ const combined = contents.join("\n\n");
255
+ const compressed = await gzip2(Buffer.from(combined, "utf-8"));
256
+ const archivePath = path.join(sessionPath, "raw.txt.gz");
257
+ await fs.writeFile(archivePath, compressed);
258
+ await this.deleteConversationFiles(sessionPath, files);
259
+ } catch (error) {
260
+ console.error("Failed to archive conversation files:", error);
261
+ }
262
+ }
263
+ async deleteConversationFiles(sessionPath, files) {
264
+ for (const file of files) {
265
+ try {
266
+ await fs.unlink(path.join(sessionPath, file));
267
+ } catch {
268
+ }
269
+ }
270
+ }
271
+ };
272
+
273
+ export {
274
+ CompactionEngine
275
+ };
276
+ //# sourceMappingURL=chunk-C6NR36YP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/compaction-engine.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"],"mappings":"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","names":["gzip"]}
@@ -85,6 +85,28 @@ var DEFAULT_CONFIG = {
85
85
  feedback: {
86
86
  enabled: true,
87
87
  contextDepth: 2
88
+ },
89
+ discover: {
90
+ maxFiles: 100,
91
+ maxChunkSize: 5e4,
92
+ excludePatterns: [
93
+ "*.min.js",
94
+ "*.bundle.js",
95
+ "*.map",
96
+ "coverage/**",
97
+ ".next/**",
98
+ "build/**",
99
+ "dist/**"
100
+ ],
101
+ priorityPatterns: [
102
+ "**/index.{ts,js,tsx,jsx}",
103
+ "**/main.{ts,js,py,go,rs}",
104
+ "**/app.{ts,js,py}",
105
+ "**/models/**",
106
+ "**/entities/**",
107
+ "**/services/**"
108
+ ],
109
+ supportedLanguages: ["typescript", "javascript", "python", "go", "rust"]
88
110
  }
89
111
  };
90
112
  async function loadConfig(projectPath) {
@@ -129,4 +151,4 @@ export {
129
151
  getVaultPath,
130
152
  getStatePath
131
153
  };
132
- //# sourceMappingURL=chunk-E2IJSPVB.js.map
154
+ //# sourceMappingURL=chunk-FRETJBP5.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 discover: {\n maxFiles: number;\n maxChunkSize: number;\n excludePatterns: string[];\n priorityPatterns: string[];\n supportedLanguages: string[];\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 discover: {\n maxFiles: 100,\n maxChunkSize: 50000,\n excludePatterns: [\n \"*.min.js\",\n \"*.bundle.js\",\n \"*.map\",\n \"coverage/**\",\n \".next/**\",\n \"build/**\",\n \"dist/**\",\n ],\n priorityPatterns: [\n \"**/index.{ts,js,tsx,jsx}\",\n \"**/main.{ts,js,py,go,rs}\",\n \"**/app.{ts,js,py}\",\n \"**/models/**\",\n \"**/entities/**\",\n \"**/services/**\",\n ],\n supportedLanguages: [\"typescript\", \"javascript\", \"python\", \"go\", \"rust\"],\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":"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","names":["fs","path"]}
@@ -13,7 +13,7 @@ import {
13
13
  readTextFile,
14
14
  writeJSON,
15
15
  writeTextFile
16
- } from "./chunk-E2IJSPVB.js";
16
+ } from "./chunk-FRETJBP5.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-XQXIDTUW.js.map
239
+ //# sourceMappingURL=chunk-HP5YVMZ6.js.map