cckb 0.1.0
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 +247 -0
- package/dist/bin/cckb.d.ts +1 -0
- package/dist/bin/cckb.js +89 -0
- package/dist/bin/cckb.js.map +1 -0
- package/dist/chunk-GUB5D6EN.js +197 -0
- package/dist/chunk-GUB5D6EN.js.map +1 -0
- package/dist/chunk-K4W3KOBL.js +239 -0
- package/dist/chunk-K4W3KOBL.js.map +1 -0
- package/dist/chunk-TFFLX3YY.js +131 -0
- package/dist/chunk-TFFLX3YY.js.map +1 -0
- package/dist/chunk-XAY6TTXB.js +149 -0
- package/dist/chunk-XAY6TTXB.js.map +1 -0
- package/dist/chunk-Z3CJQKTH.js +547 -0
- package/dist/chunk-Z3CJQKTH.js.map +1 -0
- package/dist/hooks/notification.d.ts +3 -0
- package/dist/hooks/notification.js +132 -0
- package/dist/hooks/notification.js.map +1 -0
- package/dist/hooks/post-tool-use.d.ts +3 -0
- package/dist/hooks/post-tool-use.js +96 -0
- package/dist/hooks/post-tool-use.js.map +1 -0
- package/dist/hooks/session-start.d.ts +3 -0
- package/dist/hooks/session-start.js +57 -0
- package/dist/hooks/session-start.js.map +1 -0
- package/dist/hooks/stop.d.ts +3 -0
- package/dist/hooks/stop.js +80 -0
- package/dist/hooks/stop.js.map +1 -0
- package/dist/hooks/user-prompt.d.ts +3 -0
- package/dist/hooks/user-prompt.js +48 -0
- package/dist/hooks/user-prompt.js.map +1 -0
- package/dist/index.d.ts +145 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
- package/templates/CLAUDE.md.tmpl +29 -0
- package/templates/settings.json.tmpl +44 -0
- package/templates/vault/INDEX.md +19 -0
- package/templates/vault/architecture.md +15 -0
- package/templates/vault/entities/INDEX.md +10 -0
- package/templates/vault/general-knowledge.md +15 -0
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IndexManager
|
|
3
|
+
} from "./chunk-XAY6TTXB.js";
|
|
4
|
+
import {
|
|
5
|
+
appendToFile,
|
|
6
|
+
ensureDir,
|
|
7
|
+
fileExists,
|
|
8
|
+
getConversationsPath,
|
|
9
|
+
readTextFile,
|
|
10
|
+
writeTextFile
|
|
11
|
+
} from "./chunk-TFFLX3YY.js";
|
|
12
|
+
|
|
13
|
+
// src/core/compaction-engine.ts
|
|
14
|
+
import * as path from "path";
|
|
15
|
+
|
|
16
|
+
// src/utils/claude-sdk.ts
|
|
17
|
+
import { spawn } from "child_process";
|
|
18
|
+
async function spawnClaudeAgent(prompt) {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
const child = spawn("claude", ["--print", "-p", prompt], {
|
|
21
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
22
|
+
timeout: 12e4
|
|
23
|
+
// 2 minute timeout
|
|
24
|
+
});
|
|
25
|
+
let stdout = "";
|
|
26
|
+
let stderr = "";
|
|
27
|
+
child.stdout?.on("data", (data) => {
|
|
28
|
+
stdout += data.toString();
|
|
29
|
+
});
|
|
30
|
+
child.stderr?.on("data", (data) => {
|
|
31
|
+
stderr += data.toString();
|
|
32
|
+
});
|
|
33
|
+
child.on("close", (code) => {
|
|
34
|
+
if (code === 0) {
|
|
35
|
+
resolve(stdout.trim());
|
|
36
|
+
} else {
|
|
37
|
+
reject(new Error(`Claude agent failed with code ${code}: ${stderr}`));
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
child.on("error", (error) => {
|
|
41
|
+
reject(error);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/core/compaction-engine.ts
|
|
47
|
+
var SUMMARIZATION_PROMPT = `You are a technical knowledge extractor. Analyze this conversation log and extract key information for a project knowledge base.
|
|
48
|
+
|
|
49
|
+
Extract and format the following:
|
|
50
|
+
|
|
51
|
+
## Entities
|
|
52
|
+
For each domain entity (data model, type, class) created or modified:
|
|
53
|
+
- **Name**: Entity name
|
|
54
|
+
- **Location**: File path
|
|
55
|
+
- **Attributes**: Key fields/properties
|
|
56
|
+
- **Relations**: Related entities
|
|
57
|
+
|
|
58
|
+
## Architecture
|
|
59
|
+
For each architectural pattern or design decision:
|
|
60
|
+
- **Pattern**: Name of pattern
|
|
61
|
+
- **Description**: Brief explanation
|
|
62
|
+
- **Affected Files**: Relevant file paths
|
|
63
|
+
|
|
64
|
+
## Services
|
|
65
|
+
For each service or component created:
|
|
66
|
+
- **Name**: Service name
|
|
67
|
+
- **Location**: File path
|
|
68
|
+
- **Purpose**: Brief description
|
|
69
|
+
- **Methods**: Key methods/functions
|
|
70
|
+
|
|
71
|
+
## Knowledge
|
|
72
|
+
For each convention, rule, or important context:
|
|
73
|
+
- **Topic**: What it's about
|
|
74
|
+
- **Details**: The actual information
|
|
75
|
+
|
|
76
|
+
Only include sections that have content. Be concise but complete.
|
|
77
|
+
Use file paths exactly as shown in the conversation.
|
|
78
|
+
|
|
79
|
+
CONVERSATION LOG:
|
|
80
|
+
`;
|
|
81
|
+
var CompactionEngine = class {
|
|
82
|
+
projectPath;
|
|
83
|
+
constructor(projectPath) {
|
|
84
|
+
this.projectPath = projectPath;
|
|
85
|
+
}
|
|
86
|
+
async compact(sessionId, conversation) {
|
|
87
|
+
try {
|
|
88
|
+
const summaryContent = await this.generateSummary(conversation);
|
|
89
|
+
if (!summaryContent) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const summary = this.parseSummary(sessionId, summaryContent);
|
|
93
|
+
await this.writeSummary(sessionId, summaryContent);
|
|
94
|
+
return summary;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error("Compaction failed:", error);
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async generateSummary(conversation) {
|
|
101
|
+
const prompt = SUMMARIZATION_PROMPT + conversation;
|
|
102
|
+
try {
|
|
103
|
+
const result = await spawnClaudeAgent(prompt);
|
|
104
|
+
return result;
|
|
105
|
+
} catch (error) {
|
|
106
|
+
return this.fallbackExtraction(conversation);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
fallbackExtraction(conversation) {
|
|
110
|
+
const lines = conversation.split("\n");
|
|
111
|
+
const files = [];
|
|
112
|
+
const actions = [];
|
|
113
|
+
for (const line of lines) {
|
|
114
|
+
const fileMatch = line.match(/(?:Created|Modified|Edited).*?:\s*(.+\.(?:ts|js|tsx|jsx|md))/i);
|
|
115
|
+
if (fileMatch) {
|
|
116
|
+
files.push(fileMatch[1]);
|
|
117
|
+
}
|
|
118
|
+
if (line.includes("[TOOL:")) {
|
|
119
|
+
actions.push(line);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
let summary = "# Session Summary\n\n";
|
|
123
|
+
if (files.length > 0) {
|
|
124
|
+
summary += "## Files Modified\n";
|
|
125
|
+
for (const file of [...new Set(files)]) {
|
|
126
|
+
summary += `- ${file}
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
summary += "\n";
|
|
130
|
+
}
|
|
131
|
+
if (actions.length > 0) {
|
|
132
|
+
summary += "## Actions\n";
|
|
133
|
+
for (const action of actions.slice(0, 20)) {
|
|
134
|
+
summary += `- ${action}
|
|
135
|
+
`;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return summary;
|
|
139
|
+
}
|
|
140
|
+
parseSummary(sessionId, content) {
|
|
141
|
+
const summary = {
|
|
142
|
+
sessionId,
|
|
143
|
+
content,
|
|
144
|
+
entities: [],
|
|
145
|
+
architecture: [],
|
|
146
|
+
services: [],
|
|
147
|
+
knowledge: []
|
|
148
|
+
};
|
|
149
|
+
const entitiesMatch = content.match(/## Entities\n([\s\S]*?)(?=\n## |$)/);
|
|
150
|
+
if (entitiesMatch) {
|
|
151
|
+
summary.entities = this.parseEntities(entitiesMatch[1]);
|
|
152
|
+
}
|
|
153
|
+
const archMatch = content.match(/## Architecture\n([\s\S]*?)(?=\n## |$)/);
|
|
154
|
+
if (archMatch) {
|
|
155
|
+
summary.architecture = this.parseArchitecture(archMatch[1]);
|
|
156
|
+
}
|
|
157
|
+
const servicesMatch = content.match(/## Services\n([\s\S]*?)(?=\n## |$)/);
|
|
158
|
+
if (servicesMatch) {
|
|
159
|
+
summary.services = this.parseServices(servicesMatch[1]);
|
|
160
|
+
}
|
|
161
|
+
const knowledgeMatch = content.match(/## Knowledge\n([\s\S]*?)(?=\n## |$)/);
|
|
162
|
+
if (knowledgeMatch) {
|
|
163
|
+
summary.knowledge = this.parseKnowledge(knowledgeMatch[1]);
|
|
164
|
+
}
|
|
165
|
+
return summary;
|
|
166
|
+
}
|
|
167
|
+
parseEntities(section) {
|
|
168
|
+
const entities = [];
|
|
169
|
+
const blocks = section.split(/\n(?=- \*\*Name\*\*:)/);
|
|
170
|
+
for (const block of blocks) {
|
|
171
|
+
if (!block.trim()) continue;
|
|
172
|
+
const nameMatch = block.match(/\*\*Name\*\*:\s*(.+)/);
|
|
173
|
+
const locationMatch = block.match(/\*\*Location\*\*:\s*(.+)/);
|
|
174
|
+
const attributesMatch = block.match(/\*\*Attributes\*\*:\s*(.+)/);
|
|
175
|
+
const relationsMatch = block.match(/\*\*Relations\*\*:\s*(.+)/);
|
|
176
|
+
if (nameMatch) {
|
|
177
|
+
entities.push({
|
|
178
|
+
name: nameMatch[1].trim(),
|
|
179
|
+
location: locationMatch?.[1].trim(),
|
|
180
|
+
attributes: attributesMatch?.[1].split(",").map((a) => a.trim()) || [],
|
|
181
|
+
relations: relationsMatch?.[1].split(",").map((r) => r.trim()) || []
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return entities;
|
|
186
|
+
}
|
|
187
|
+
parseArchitecture(section) {
|
|
188
|
+
const items = [];
|
|
189
|
+
const blocks = section.split(/\n(?=- \*\*Pattern\*\*:)/);
|
|
190
|
+
for (const block of blocks) {
|
|
191
|
+
if (!block.trim()) continue;
|
|
192
|
+
const patternMatch = block.match(/\*\*Pattern\*\*:\s*(.+)/);
|
|
193
|
+
const descMatch = block.match(/\*\*Description\*\*:\s*(.+)/);
|
|
194
|
+
const filesMatch = block.match(/\*\*Affected Files\*\*:\s*(.+)/);
|
|
195
|
+
if (patternMatch) {
|
|
196
|
+
items.push({
|
|
197
|
+
pattern: patternMatch[1].trim(),
|
|
198
|
+
description: descMatch?.[1].trim() || "",
|
|
199
|
+
affectedFiles: filesMatch?.[1].split(",").map((f) => f.trim()) || []
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return items;
|
|
204
|
+
}
|
|
205
|
+
parseServices(section) {
|
|
206
|
+
const items = [];
|
|
207
|
+
const blocks = section.split(/\n(?=- \*\*Name\*\*:)/);
|
|
208
|
+
for (const block of blocks) {
|
|
209
|
+
if (!block.trim()) continue;
|
|
210
|
+
const nameMatch = block.match(/\*\*Name\*\*:\s*(.+)/);
|
|
211
|
+
const locationMatch = block.match(/\*\*Location\*\*:\s*(.+)/);
|
|
212
|
+
const purposeMatch = block.match(/\*\*Purpose\*\*:\s*(.+)/);
|
|
213
|
+
const methodsMatch = block.match(/\*\*Methods\*\*:\s*(.+)/);
|
|
214
|
+
if (nameMatch) {
|
|
215
|
+
items.push({
|
|
216
|
+
name: nameMatch[1].trim(),
|
|
217
|
+
location: locationMatch?.[1].trim(),
|
|
218
|
+
purpose: purposeMatch?.[1].trim() || "",
|
|
219
|
+
methods: methodsMatch?.[1].split(",").map((m) => m.trim()) || []
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return items;
|
|
224
|
+
}
|
|
225
|
+
parseKnowledge(section) {
|
|
226
|
+
const items = [];
|
|
227
|
+
const blocks = section.split(/\n(?=- \*\*Topic\*\*:)/);
|
|
228
|
+
for (const block of blocks) {
|
|
229
|
+
if (!block.trim()) continue;
|
|
230
|
+
const topicMatch = block.match(/\*\*Topic\*\*:\s*(.+)/);
|
|
231
|
+
const detailsMatch = block.match(/\*\*Details\*\*:\s*(.+)/);
|
|
232
|
+
if (topicMatch) {
|
|
233
|
+
items.push({
|
|
234
|
+
topic: topicMatch[1].trim(),
|
|
235
|
+
details: detailsMatch?.[1].trim() || ""
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return items;
|
|
240
|
+
}
|
|
241
|
+
async writeSummary(sessionId, content) {
|
|
242
|
+
const conversationsPath = getConversationsPath(this.projectPath);
|
|
243
|
+
const summaryPath = path.join(conversationsPath, sessionId, "summary.md");
|
|
244
|
+
const fullContent = `# Session Summary: ${sessionId}
|
|
245
|
+
Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
246
|
+
|
|
247
|
+
${content}
|
|
248
|
+
`;
|
|
249
|
+
await writeTextFile(summaryPath, fullContent);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// src/core/entity-detector.ts
|
|
254
|
+
var EntityDetector = class {
|
|
255
|
+
/**
|
|
256
|
+
* Analyzes a summary and determines what should be added to the vault.
|
|
257
|
+
*/
|
|
258
|
+
detect(summary) {
|
|
259
|
+
const items = [];
|
|
260
|
+
for (const entity of summary.entities) {
|
|
261
|
+
items.push(this.createEntityItem(entity));
|
|
262
|
+
const relatedServices = summary.services.filter(
|
|
263
|
+
(s) => s.name.toLowerCase().includes(entity.name.toLowerCase()) || s.location?.toLowerCase().includes(entity.name.toLowerCase())
|
|
264
|
+
);
|
|
265
|
+
for (const service of relatedServices) {
|
|
266
|
+
items.push(this.createServiceItem(entity.name, service));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const processedServiceNames = /* @__PURE__ */ new Set();
|
|
270
|
+
for (const entity of summary.entities) {
|
|
271
|
+
for (const service of summary.services) {
|
|
272
|
+
if (service.name.toLowerCase().includes(entity.name.toLowerCase()) || service.location?.toLowerCase().includes(entity.name.toLowerCase())) {
|
|
273
|
+
processedServiceNames.add(service.name);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
for (const service of summary.services) {
|
|
278
|
+
if (!processedServiceNames.has(service.name)) {
|
|
279
|
+
items.push(this.createStandaloneServiceItem(service));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
for (const arch of summary.architecture) {
|
|
283
|
+
items.push(this.createArchitectureItem(arch));
|
|
284
|
+
}
|
|
285
|
+
for (const knowledge of summary.knowledge) {
|
|
286
|
+
items.push(this.createKnowledgeItem(knowledge));
|
|
287
|
+
}
|
|
288
|
+
return items;
|
|
289
|
+
}
|
|
290
|
+
createEntityItem(entity) {
|
|
291
|
+
const content = this.formatEntityContent(entity);
|
|
292
|
+
return {
|
|
293
|
+
type: "entity",
|
|
294
|
+
name: entity.name,
|
|
295
|
+
data: entity,
|
|
296
|
+
vaultPath: `entities/${entity.name.toLowerCase()}`,
|
|
297
|
+
content
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
createServiceItem(entityName, service) {
|
|
301
|
+
const content = this.formatServiceContent(service);
|
|
302
|
+
const serviceName = service.name.toLowerCase().replace(entityName.toLowerCase(), "").trim();
|
|
303
|
+
const fileName = serviceName || "service";
|
|
304
|
+
return {
|
|
305
|
+
type: "service",
|
|
306
|
+
name: service.name,
|
|
307
|
+
data: service,
|
|
308
|
+
vaultPath: `entities/${entityName.toLowerCase()}/services/${fileName}`,
|
|
309
|
+
content
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
createStandaloneServiceItem(service) {
|
|
313
|
+
const content = this.formatServiceContent(service);
|
|
314
|
+
return {
|
|
315
|
+
type: "service",
|
|
316
|
+
name: service.name,
|
|
317
|
+
data: service,
|
|
318
|
+
vaultPath: `services/${service.name.toLowerCase()}`,
|
|
319
|
+
content
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
createArchitectureItem(arch) {
|
|
323
|
+
const content = `## ${arch.pattern}
|
|
324
|
+
|
|
325
|
+
${arch.description}
|
|
326
|
+
|
|
327
|
+
### Affected Files
|
|
328
|
+
${arch.affectedFiles.map((f) => `- ${f}`).join("\n")}
|
|
329
|
+
`;
|
|
330
|
+
return {
|
|
331
|
+
type: "pattern",
|
|
332
|
+
name: arch.pattern,
|
|
333
|
+
data: arch,
|
|
334
|
+
vaultPath: "architecture",
|
|
335
|
+
content
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
createKnowledgeItem(knowledge) {
|
|
339
|
+
const content = `## ${knowledge.topic}
|
|
340
|
+
|
|
341
|
+
${knowledge.details}
|
|
342
|
+
`;
|
|
343
|
+
return {
|
|
344
|
+
type: "knowledge",
|
|
345
|
+
name: knowledge.topic,
|
|
346
|
+
data: knowledge,
|
|
347
|
+
vaultPath: "general-knowledge",
|
|
348
|
+
content
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
formatEntityContent(entity) {
|
|
352
|
+
let content = `# ${entity.name}
|
|
353
|
+
|
|
354
|
+
`;
|
|
355
|
+
if (entity.location) {
|
|
356
|
+
content += `**Location**: ${entity.location}
|
|
357
|
+
|
|
358
|
+
`;
|
|
359
|
+
}
|
|
360
|
+
if (entity.attributes.length > 0) {
|
|
361
|
+
content += `## Attributes
|
|
362
|
+
|
|
363
|
+
`;
|
|
364
|
+
for (const attr of entity.attributes) {
|
|
365
|
+
content += `- ${attr}
|
|
366
|
+
`;
|
|
367
|
+
}
|
|
368
|
+
content += "\n";
|
|
369
|
+
}
|
|
370
|
+
if (entity.relations.length > 0) {
|
|
371
|
+
content += `## Relations
|
|
372
|
+
|
|
373
|
+
`;
|
|
374
|
+
for (const rel of entity.relations) {
|
|
375
|
+
content += `- ${rel}
|
|
376
|
+
`;
|
|
377
|
+
}
|
|
378
|
+
content += "\n";
|
|
379
|
+
}
|
|
380
|
+
return content;
|
|
381
|
+
}
|
|
382
|
+
formatServiceContent(service) {
|
|
383
|
+
let content = `# ${service.name}
|
|
384
|
+
|
|
385
|
+
`;
|
|
386
|
+
if (service.location) {
|
|
387
|
+
content += `**Location**: ${service.location}
|
|
388
|
+
|
|
389
|
+
`;
|
|
390
|
+
}
|
|
391
|
+
if (service.purpose) {
|
|
392
|
+
content += `## Purpose
|
|
393
|
+
|
|
394
|
+
${service.purpose}
|
|
395
|
+
|
|
396
|
+
`;
|
|
397
|
+
}
|
|
398
|
+
if (service.methods.length > 0) {
|
|
399
|
+
content += `## Methods
|
|
400
|
+
|
|
401
|
+
`;
|
|
402
|
+
for (const method of service.methods) {
|
|
403
|
+
content += `- ${method}
|
|
404
|
+
`;
|
|
405
|
+
}
|
|
406
|
+
content += "\n";
|
|
407
|
+
}
|
|
408
|
+
return content;
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
// src/core/vault-integrator.ts
|
|
413
|
+
import * as path2 from "path";
|
|
414
|
+
var VaultIntegrator = class {
|
|
415
|
+
vaultPath;
|
|
416
|
+
indexManager;
|
|
417
|
+
entityDetector;
|
|
418
|
+
constructor(vaultPath) {
|
|
419
|
+
this.vaultPath = vaultPath;
|
|
420
|
+
this.indexManager = new IndexManager(vaultPath);
|
|
421
|
+
this.entityDetector = new EntityDetector();
|
|
422
|
+
}
|
|
423
|
+
async integrate(summary) {
|
|
424
|
+
const items = this.entityDetector.detect(summary);
|
|
425
|
+
if (items.length === 0) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
for (const item of items) {
|
|
429
|
+
await this.processItem(item);
|
|
430
|
+
}
|
|
431
|
+
await this.updateRootIndex();
|
|
432
|
+
}
|
|
433
|
+
async processItem(item) {
|
|
434
|
+
switch (item.type) {
|
|
435
|
+
case "entity":
|
|
436
|
+
await this.processEntity(item);
|
|
437
|
+
break;
|
|
438
|
+
case "service":
|
|
439
|
+
await this.processService(item);
|
|
440
|
+
break;
|
|
441
|
+
case "pattern":
|
|
442
|
+
await this.processPattern(item);
|
|
443
|
+
break;
|
|
444
|
+
case "knowledge":
|
|
445
|
+
await this.processKnowledge(item);
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
async processEntity(item) {
|
|
450
|
+
const entityPath = await this.indexManager.ensureEntityFolder(item.name);
|
|
451
|
+
const fullPath = path2.join(this.vaultPath, entityPath);
|
|
452
|
+
const attributesPath = path2.join(fullPath, "attributes.md");
|
|
453
|
+
await writeTextFile(attributesPath, item.content);
|
|
454
|
+
await this.indexManager.addEntry(entityPath, {
|
|
455
|
+
name: "attributes",
|
|
456
|
+
path: "./attributes.md",
|
|
457
|
+
description: `Attributes of ${item.name}`,
|
|
458
|
+
type: "file"
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
async processService(item) {
|
|
462
|
+
const pathParts = item.vaultPath.split("/");
|
|
463
|
+
const fileName = pathParts.pop() + ".md";
|
|
464
|
+
const folderPath = pathParts.join("/");
|
|
465
|
+
const fullFolderPath = path2.join(this.vaultPath, folderPath);
|
|
466
|
+
await ensureDir(fullFolderPath);
|
|
467
|
+
const filePath = path2.join(fullFolderPath, fileName);
|
|
468
|
+
await writeTextFile(filePath, item.content);
|
|
469
|
+
const parentIndexPath = path2.join(fullFolderPath, "INDEX.md");
|
|
470
|
+
if (!await fileExists(parentIndexPath)) {
|
|
471
|
+
await this.indexManager.createIndex(folderPath, []);
|
|
472
|
+
}
|
|
473
|
+
await this.indexManager.addEntry(folderPath, {
|
|
474
|
+
name: item.name,
|
|
475
|
+
path: `./${fileName}`,
|
|
476
|
+
description: item.data.purpose || `${item.name} service`,
|
|
477
|
+
type: "file"
|
|
478
|
+
});
|
|
479
|
+
if (folderPath.startsWith("entities/") && folderPath.includes("/services")) {
|
|
480
|
+
const entityFolder = folderPath.split("/").slice(0, 2).join("/");
|
|
481
|
+
await this.indexManager.addEntry(entityFolder, {
|
|
482
|
+
name: "services",
|
|
483
|
+
path: "./services/INDEX.md",
|
|
484
|
+
description: "Service layer documentation",
|
|
485
|
+
type: "folder"
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
async processPattern(item) {
|
|
490
|
+
const archPath = path2.join(this.vaultPath, "architecture.md");
|
|
491
|
+
const existing = await readTextFile(archPath);
|
|
492
|
+
if (!existing) {
|
|
493
|
+
await writeTextFile(archPath, `# Architecture
|
|
494
|
+
|
|
495
|
+
${item.content}`);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
if (existing.includes(`## ${item.name}`)) {
|
|
499
|
+
const regex = new RegExp(`## ${item.name}[\\s\\S]*?(?=\\n## |$)`);
|
|
500
|
+
const updated = existing.replace(regex, item.content);
|
|
501
|
+
await writeTextFile(archPath, updated);
|
|
502
|
+
} else {
|
|
503
|
+
await appendToFile(archPath, `
|
|
504
|
+
${item.content}`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
async processKnowledge(item) {
|
|
508
|
+
const knowledgePath = path2.join(this.vaultPath, "general-knowledge.md");
|
|
509
|
+
const existing = await readTextFile(knowledgePath);
|
|
510
|
+
if (!existing) {
|
|
511
|
+
await writeTextFile(knowledgePath, `# General Knowledge
|
|
512
|
+
|
|
513
|
+
${item.content}`);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
if (existing.includes(`## ${item.name}`)) {
|
|
517
|
+
const regex = new RegExp(`## ${item.name}[\\s\\S]*?(?=\\n## |$)`);
|
|
518
|
+
const updated = existing.replace(regex, item.content);
|
|
519
|
+
await writeTextFile(knowledgePath, updated);
|
|
520
|
+
} else {
|
|
521
|
+
await appendToFile(knowledgePath, `
|
|
522
|
+
${item.content}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
async updateRootIndex() {
|
|
526
|
+
const indexPath = path2.join(this.vaultPath, "INDEX.md");
|
|
527
|
+
const content = await readTextFile(indexPath);
|
|
528
|
+
if (!content) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
532
|
+
const updated = content.replace(
|
|
533
|
+
/## Last Updated[\s\S]*$/,
|
|
534
|
+
`## Last Updated
|
|
535
|
+
|
|
536
|
+
${timestamp}`
|
|
537
|
+
);
|
|
538
|
+
await writeTextFile(indexPath, updated);
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
export {
|
|
543
|
+
CompactionEngine,
|
|
544
|
+
EntityDetector,
|
|
545
|
+
VaultIntegrator
|
|
546
|
+
};
|
|
547
|
+
//# sourceMappingURL=chunk-Z3CJQKTH.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 { 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"]}
|