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,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IndexManager
|
|
3
|
+
} from "../chunk-XAY6TTXB.js";
|
|
4
|
+
import {
|
|
5
|
+
fileExists,
|
|
6
|
+
getStatePath,
|
|
7
|
+
getVaultPath,
|
|
8
|
+
loadConfig,
|
|
9
|
+
readJSON,
|
|
10
|
+
writeJSON
|
|
11
|
+
} from "../chunk-TFFLX3YY.js";
|
|
12
|
+
|
|
13
|
+
// src/hooks/notification.ts
|
|
14
|
+
import * as path from "path";
|
|
15
|
+
async function handleNotification() {
|
|
16
|
+
try {
|
|
17
|
+
const input = await readStdin();
|
|
18
|
+
const data = input ? JSON.parse(input) : {};
|
|
19
|
+
const projectPath = data.cwd || process.cwd();
|
|
20
|
+
const config = await loadConfig(projectPath);
|
|
21
|
+
if (!config.feedback.enabled) {
|
|
22
|
+
console.log(JSON.stringify({ continue: true, suppressOutput: true }));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const context = await getRelevantContext(projectPath, data);
|
|
26
|
+
const output = {
|
|
27
|
+
continue: true,
|
|
28
|
+
suppressOutput: true
|
|
29
|
+
};
|
|
30
|
+
if (context) {
|
|
31
|
+
output.additionalContext = context;
|
|
32
|
+
}
|
|
33
|
+
console.log(JSON.stringify(output));
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.log(JSON.stringify({ continue: true, suppressOutput: true }));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function getRelevantContext(projectPath, input) {
|
|
39
|
+
const cache = await loadVaultCache(projectPath);
|
|
40
|
+
if (!cache) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const keywords = extractKeywords(input);
|
|
44
|
+
if (keywords.length === 0) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const matches = cache.entities.filter(
|
|
48
|
+
(entity) => keywords.some(
|
|
49
|
+
(keyword) => entity.toLowerCase().includes(keyword.toLowerCase()) || keyword.toLowerCase().includes(entity.toLowerCase())
|
|
50
|
+
)
|
|
51
|
+
);
|
|
52
|
+
if (matches.length === 0) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
return `[CCKB] Related vault knowledge: ${matches.join(", ")}. Check vault/entities/ for details.`;
|
|
56
|
+
}
|
|
57
|
+
function extractKeywords(input) {
|
|
58
|
+
const keywords = [];
|
|
59
|
+
if (input.tool_input) {
|
|
60
|
+
if (typeof input.tool_input.file_path === "string") {
|
|
61
|
+
const parts = input.tool_input.file_path.split("/");
|
|
62
|
+
keywords.push(...parts.filter((p) => p.length > 2));
|
|
63
|
+
}
|
|
64
|
+
if (typeof input.tool_input.content === "string") {
|
|
65
|
+
const content = input.tool_input.content.substring(0, 500);
|
|
66
|
+
const matches = content.match(/[A-Z][a-z]+(?:[A-Z][a-z]+)*/g);
|
|
67
|
+
if (matches) {
|
|
68
|
+
keywords.push(...matches);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (typeof input.tool_input.command === "string") {
|
|
72
|
+
const cmd = input.tool_input.command;
|
|
73
|
+
const pathMatches = cmd.match(/[\w./]+\.ts|[\w./]+\.js|[\w./]+\.tsx/g);
|
|
74
|
+
if (pathMatches) {
|
|
75
|
+
keywords.push(...pathMatches);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return [...new Set(keywords)];
|
|
80
|
+
}
|
|
81
|
+
async function loadVaultCache(projectPath) {
|
|
82
|
+
const statePath = getStatePath(projectPath);
|
|
83
|
+
const cachePath = path.join(statePath, "vault-cache.json");
|
|
84
|
+
if (await fileExists(cachePath)) {
|
|
85
|
+
const cache = await readJSON(cachePath);
|
|
86
|
+
if (cache) {
|
|
87
|
+
const cacheAge = Date.now() - new Date(cache.lastUpdated).getTime();
|
|
88
|
+
const maxAge = 5 * 60 * 1e3;
|
|
89
|
+
if (cacheAge < maxAge) {
|
|
90
|
+
return cache;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const vaultPath = getVaultPath(projectPath);
|
|
96
|
+
const indexManager = new IndexManager(vaultPath);
|
|
97
|
+
const overview = await indexManager.getVaultOverview();
|
|
98
|
+
const entities = await indexManager.listEntities();
|
|
99
|
+
const cache = {
|
|
100
|
+
overview: overview || "",
|
|
101
|
+
entities,
|
|
102
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
103
|
+
};
|
|
104
|
+
await writeJSON(cachePath, cache);
|
|
105
|
+
return cache;
|
|
106
|
+
} catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function readStdin() {
|
|
111
|
+
return new Promise((resolve) => {
|
|
112
|
+
let data = "";
|
|
113
|
+
if (process.stdin.isTTY) {
|
|
114
|
+
resolve("");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
process.stdin.setEncoding("utf8");
|
|
118
|
+
process.stdin.on("data", (chunk) => {
|
|
119
|
+
data += chunk;
|
|
120
|
+
});
|
|
121
|
+
process.stdin.on("end", () => {
|
|
122
|
+
resolve(data.trim());
|
|
123
|
+
});
|
|
124
|
+
setTimeout(() => {
|
|
125
|
+
resolve(data.trim());
|
|
126
|
+
}, 1e3);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
export {
|
|
130
|
+
handleNotification
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=notification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/notification.ts"],"sourcesContent":["import { IndexManager } from \"../core/index-manager.js\";\nimport { loadConfig, getVaultPath, getStatePath } from \"../utils/config.js\";\nimport { readJSON, writeJSON, fileExists } from \"../utils/file-utils.js\";\nimport * as path from \"node:path\";\n\ninterface NotificationInput {\n tool_name?: string;\n tool_input?: Record<string, unknown>;\n cwd?: string;\n}\n\ninterface VaultCache {\n overview: string;\n entities: string[];\n lastUpdated: string;\n}\n\ninterface HookOutput {\n continue: boolean;\n suppressOutput?: boolean;\n additionalContext?: string;\n}\n\nexport async function handleNotification(): Promise<void> {\n try {\n // Read input from stdin\n const input = await readStdin();\n const data: NotificationInput = input ? JSON.parse(input) : {};\n\n const projectPath = data.cwd || process.cwd();\n const config = await loadConfig(projectPath);\n\n if (!config.feedback.enabled) {\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n return;\n }\n\n // Get relevant context from vault cache\n const context = await getRelevantContext(projectPath, data);\n\n const output: HookOutput = {\n continue: true,\n suppressOutput: true,\n };\n\n if (context) {\n output.additionalContext = context;\n }\n\n console.log(JSON.stringify(output));\n } catch (error) {\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n }\n}\n\nasync function getRelevantContext(\n projectPath: string,\n input: NotificationInput\n): Promise<string | null> {\n // Load or refresh vault cache\n const cache = await loadVaultCache(projectPath);\n\n if (!cache) {\n return null;\n }\n\n // Analyze input for relevant keywords\n const keywords = extractKeywords(input);\n\n if (keywords.length === 0) {\n return null;\n }\n\n // Find matching entities\n const matches = cache.entities.filter((entity) =>\n keywords.some(\n (keyword) =>\n entity.toLowerCase().includes(keyword.toLowerCase()) ||\n keyword.toLowerCase().includes(entity.toLowerCase())\n )\n );\n\n if (matches.length === 0) {\n return null;\n }\n\n return `[CCKB] Related vault knowledge: ${matches.join(\", \")}. Check vault/entities/ for details.`;\n}\n\nfunction extractKeywords(input: NotificationInput): string[] {\n const keywords: string[] = [];\n\n if (input.tool_input) {\n // Extract from file paths\n if (typeof input.tool_input.file_path === \"string\") {\n const parts = input.tool_input.file_path.split(\"/\");\n keywords.push(...parts.filter((p) => p.length > 2));\n }\n\n // Extract from content (first 500 chars)\n if (typeof input.tool_input.content === \"string\") {\n const content = input.tool_input.content.substring(0, 500);\n // Find potential entity names (PascalCase or camelCase words)\n const matches = content.match(/[A-Z][a-z]+(?:[A-Z][a-z]+)*/g);\n if (matches) {\n keywords.push(...matches);\n }\n }\n\n // Extract from command\n if (typeof input.tool_input.command === \"string\") {\n const cmd = input.tool_input.command;\n // Extract file paths from command\n const pathMatches = cmd.match(/[\\w./]+\\.ts|[\\w./]+\\.js|[\\w./]+\\.tsx/g);\n if (pathMatches) {\n keywords.push(...pathMatches);\n }\n }\n }\n\n return [...new Set(keywords)];\n}\n\nasync function loadVaultCache(projectPath: string): Promise<VaultCache | null> {\n const statePath = getStatePath(projectPath);\n const cachePath = path.join(statePath, \"vault-cache.json\");\n\n // Check if cache exists and is fresh (5 minutes)\n if (await fileExists(cachePath)) {\n const cache = await readJSON<VaultCache>(cachePath);\n if (cache) {\n const cacheAge = Date.now() - new Date(cache.lastUpdated).getTime();\n const maxAge = 5 * 60 * 1000; // 5 minutes\n\n if (cacheAge < maxAge) {\n return cache;\n }\n }\n }\n\n // Refresh cache\n try {\n const vaultPath = getVaultPath(projectPath);\n const indexManager = new IndexManager(vaultPath);\n\n const overview = await indexManager.getVaultOverview();\n const entities = await indexManager.listEntities();\n\n const cache: VaultCache = {\n overview: overview || \"\",\n entities,\n lastUpdated: new Date().toISOString(),\n };\n\n await writeJSON(cachePath, cache);\n return cache;\n } catch {\n return null;\n }\n}\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve) => {\n let data = \"\";\n\n if (process.stdin.isTTY) {\n resolve(\"\");\n return;\n }\n\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (chunk) => {\n data += chunk;\n });\n process.stdin.on(\"end\", () => {\n resolve(data.trim());\n });\n\n setTimeout(() => {\n resolve(data.trim());\n }, 1000);\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConversationManager
|
|
3
|
+
} from "../chunk-K4W3KOBL.js";
|
|
4
|
+
import {
|
|
5
|
+
loadConfig
|
|
6
|
+
} from "../chunk-TFFLX3YY.js";
|
|
7
|
+
|
|
8
|
+
// src/hooks/post-tool-use.ts
|
|
9
|
+
async function handlePostToolUse() {
|
|
10
|
+
try {
|
|
11
|
+
const input = await readStdin();
|
|
12
|
+
const data = input ? JSON.parse(input) : {};
|
|
13
|
+
const projectPath = data.cwd || process.cwd();
|
|
14
|
+
const config = await loadConfig(projectPath);
|
|
15
|
+
const toolName = data.tool_name || "";
|
|
16
|
+
if (!config.capture.tools.includes(toolName)) {
|
|
17
|
+
console.log(JSON.stringify({ continue: true, suppressOutput: true }));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const manager = new ConversationManager(projectPath);
|
|
21
|
+
const sessionId = await manager.getActiveSessionId();
|
|
22
|
+
if (sessionId && data.tool_input) {
|
|
23
|
+
const { action, target } = formatToolAction(
|
|
24
|
+
toolName,
|
|
25
|
+
data.tool_input,
|
|
26
|
+
config.capture.maxContentLength
|
|
27
|
+
);
|
|
28
|
+
if (action) {
|
|
29
|
+
await manager.appendClaudeOutput(sessionId, toolName, action, target);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const output = {
|
|
33
|
+
continue: true,
|
|
34
|
+
suppressOutput: true
|
|
35
|
+
};
|
|
36
|
+
console.log(JSON.stringify(output));
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.log(JSON.stringify({ continue: true, suppressOutput: true }));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function formatToolAction(toolName, input, maxLength) {
|
|
42
|
+
switch (toolName) {
|
|
43
|
+
case "Write":
|
|
44
|
+
return {
|
|
45
|
+
action: `Created file: ${input.file_path}`,
|
|
46
|
+
target: input.file_path
|
|
47
|
+
};
|
|
48
|
+
case "Edit":
|
|
49
|
+
case "MultiEdit":
|
|
50
|
+
return {
|
|
51
|
+
action: `Modified file: ${input.file_path}`,
|
|
52
|
+
target: input.file_path
|
|
53
|
+
};
|
|
54
|
+
case "Bash": {
|
|
55
|
+
const cmd = input.command || "";
|
|
56
|
+
const truncated = cmd.length > maxLength ? cmd.substring(0, maxLength) + "..." : cmd;
|
|
57
|
+
return {
|
|
58
|
+
action: `Executed: ${truncated}`
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
case "Task": {
|
|
62
|
+
const prompt = input.prompt || "";
|
|
63
|
+
const truncated = prompt.length > maxLength ? prompt.substring(0, maxLength) + "..." : prompt;
|
|
64
|
+
return {
|
|
65
|
+
action: `Spawned agent: ${truncated}`
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
default:
|
|
69
|
+
return {
|
|
70
|
+
action: `Used tool: ${toolName}`
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function readStdin() {
|
|
75
|
+
return new Promise((resolve) => {
|
|
76
|
+
let data = "";
|
|
77
|
+
if (process.stdin.isTTY) {
|
|
78
|
+
resolve("");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
process.stdin.setEncoding("utf8");
|
|
82
|
+
process.stdin.on("data", (chunk) => {
|
|
83
|
+
data += chunk;
|
|
84
|
+
});
|
|
85
|
+
process.stdin.on("end", () => {
|
|
86
|
+
resolve(data.trim());
|
|
87
|
+
});
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
resolve(data.trim());
|
|
90
|
+
}, 1e3);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
handlePostToolUse
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=post-tool-use.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/post-tool-use.ts"],"sourcesContent":["import { ConversationManager } from \"../core/conversation-manager.js\";\nimport { loadConfig } from \"../utils/config.js\";\n\ninterface ToolInput {\n file_path?: string;\n command?: string;\n content?: string;\n old_string?: string;\n new_string?: string;\n prompt?: string;\n}\n\ninterface PostToolUseInput {\n tool_name?: string;\n tool_input?: ToolInput;\n tool_response?: unknown;\n cwd?: string;\n}\n\ninterface HookOutput {\n continue: boolean;\n suppressOutput?: boolean;\n}\n\nexport async function handlePostToolUse(): Promise<void> {\n try {\n // Read input from stdin\n const input = await readStdin();\n const data: PostToolUseInput = input ? JSON.parse(input) : {};\n\n const projectPath = data.cwd || process.cwd();\n const config = await loadConfig(projectPath);\n\n // Check if this tool should be captured\n const toolName = data.tool_name || \"\";\n if (!config.capture.tools.includes(toolName)) {\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n return;\n }\n\n // Get active session\n const manager = new ConversationManager(projectPath);\n const sessionId = await manager.getActiveSessionId();\n\n if (sessionId && data.tool_input) {\n // Format action based on tool type\n const { action, target } = formatToolAction(\n toolName,\n data.tool_input,\n config.capture.maxContentLength\n );\n\n if (action) {\n await manager.appendClaudeOutput(sessionId, toolName, action, target);\n }\n }\n\n // Silent output\n const output: HookOutput = {\n continue: true,\n suppressOutput: true,\n };\n\n console.log(JSON.stringify(output));\n } catch (error) {\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n }\n}\n\nfunction formatToolAction(\n toolName: string,\n input: ToolInput,\n maxLength: number\n): { action: string; target?: string } {\n switch (toolName) {\n case \"Write\":\n return {\n action: `Created file: ${input.file_path}`,\n target: input.file_path,\n };\n\n case \"Edit\":\n case \"MultiEdit\":\n return {\n action: `Modified file: ${input.file_path}`,\n target: input.file_path,\n };\n\n case \"Bash\": {\n const cmd = input.command || \"\";\n const truncated =\n cmd.length > maxLength ? cmd.substring(0, maxLength) + \"...\" : cmd;\n return {\n action: `Executed: ${truncated}`,\n };\n }\n\n case \"Task\": {\n const prompt = input.prompt || \"\";\n const truncated =\n prompt.length > maxLength\n ? prompt.substring(0, maxLength) + \"...\"\n : prompt;\n return {\n action: `Spawned agent: ${truncated}`,\n };\n }\n\n default:\n return {\n action: `Used tool: ${toolName}`,\n };\n }\n}\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve) => {\n let data = \"\";\n\n if (process.stdin.isTTY) {\n resolve(\"\");\n return;\n }\n\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (chunk) => {\n data += chunk;\n });\n process.stdin.on(\"end\", () => {\n resolve(data.trim());\n });\n\n setTimeout(() => {\n resolve(data.trim());\n }, 1000);\n });\n}\n"],"mappings":";;;;;;;;AAwBA,eAAsB,oBAAmC;AACvD,MAAI;AAEF,UAAM,QAAQ,MAAM,UAAU;AAC9B,UAAM,OAAyB,QAAQ,KAAK,MAAM,KAAK,IAAI,CAAC;AAE5D,UAAM,cAAc,KAAK,OAAO,QAAQ,IAAI;AAC5C,UAAM,SAAS,MAAM,WAAW,WAAW;AAG3C,UAAM,WAAW,KAAK,aAAa;AACnC,QAAI,CAAC,OAAO,QAAQ,MAAM,SAAS,QAAQ,GAAG;AAC5C,cAAQ,IAAI,KAAK,UAAU,EAAE,UAAU,MAAM,gBAAgB,KAAK,CAAC,CAAC;AACpE;AAAA,IACF;AAGA,UAAM,UAAU,IAAI,oBAAoB,WAAW;AACnD,UAAM,YAAY,MAAM,QAAQ,mBAAmB;AAEnD,QAAI,aAAa,KAAK,YAAY;AAEhC,YAAM,EAAE,QAAQ,OAAO,IAAI;AAAA,QACzB;AAAA,QACA,KAAK;AAAA,QACL,OAAO,QAAQ;AAAA,MACjB;AAEA,UAAI,QAAQ;AACV,cAAM,QAAQ,mBAAmB,WAAW,UAAU,QAAQ,MAAM;AAAA,MACtE;AAAA,IACF;AAGA,UAAM,SAAqB;AAAA,MACzB,UAAU;AAAA,MACV,gBAAgB;AAAA,IAClB;AAEA,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,SAAS,OAAO;AACd,YAAQ,IAAI,KAAK,UAAU,EAAE,UAAU,MAAM,gBAAgB,KAAK,CAAC,CAAC;AAAA,EACtE;AACF;AAEA,SAAS,iBACP,UACA,OACA,WACqC;AACrC,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,QACL,QAAQ,iBAAiB,MAAM,SAAS;AAAA,QACxC,QAAQ,MAAM;AAAA,MAChB;AAAA,IAEF,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,QACL,QAAQ,kBAAkB,MAAM,SAAS;AAAA,QACzC,QAAQ,MAAM;AAAA,MAChB;AAAA,IAEF,KAAK,QAAQ;AACX,YAAM,MAAM,MAAM,WAAW;AAC7B,YAAM,YACJ,IAAI,SAAS,YAAY,IAAI,UAAU,GAAG,SAAS,IAAI,QAAQ;AACjE,aAAO;AAAA,QACL,QAAQ,aAAa,SAAS;AAAA,MAChC;AAAA,IACF;AAAA,IAEA,KAAK,QAAQ;AACX,YAAM,SAAS,MAAM,UAAU;AAC/B,YAAM,YACJ,OAAO,SAAS,YACZ,OAAO,UAAU,GAAG,SAAS,IAAI,QACjC;AACN,aAAO;AAAA,QACL,QAAQ,kBAAkB,SAAS;AAAA,MACrC;AAAA,IACF;AAAA,IAEA;AACE,aAAO;AAAA,QACL,QAAQ,cAAc,QAAQ;AAAA,MAChC;AAAA,EACJ;AACF;AAEA,eAAe,YAA6B;AAC1C,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,OAAO;AAEX,QAAI,QAAQ,MAAM,OAAO;AACvB,cAAQ,EAAE;AACV;AAAA,IACF;AAEA,YAAQ,MAAM,YAAY,MAAM;AAChC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAU;AAClC,cAAQ;AAAA,IACV,CAAC;AACD,YAAQ,MAAM,GAAG,OAAO,MAAM;AAC5B,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,CAAC;AAED,eAAW,MAAM;AACf,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,GAAG,GAAI;AAAA,EACT,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConversationManager
|
|
3
|
+
} from "../chunk-K4W3KOBL.js";
|
|
4
|
+
import {
|
|
5
|
+
IndexManager
|
|
6
|
+
} from "../chunk-XAY6TTXB.js";
|
|
7
|
+
import {
|
|
8
|
+
getVaultPath
|
|
9
|
+
} from "../chunk-TFFLX3YY.js";
|
|
10
|
+
|
|
11
|
+
// src/hooks/session-start.ts
|
|
12
|
+
async function handleSessionStart() {
|
|
13
|
+
try {
|
|
14
|
+
const input = await readStdin();
|
|
15
|
+
const data = input ? JSON.parse(input) : {};
|
|
16
|
+
const projectPath = data.cwd || process.cwd();
|
|
17
|
+
const manager = new ConversationManager(projectPath);
|
|
18
|
+
const sessionId = await manager.getOrCreateSession(data.transcript_path);
|
|
19
|
+
await manager.setActiveSession(sessionId);
|
|
20
|
+
const vaultPath = getVaultPath(projectPath);
|
|
21
|
+
const indexManager = new IndexManager(vaultPath);
|
|
22
|
+
const vaultOverview = await indexManager.getVaultOverview();
|
|
23
|
+
const output = {
|
|
24
|
+
continue: true,
|
|
25
|
+
suppressOutput: true
|
|
26
|
+
};
|
|
27
|
+
if (vaultOverview) {
|
|
28
|
+
output.additionalContext = `[CCKB] Knowledge Base available. ${vaultOverview}`;
|
|
29
|
+
}
|
|
30
|
+
console.log(JSON.stringify(output));
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.log(JSON.stringify({ continue: true, suppressOutput: true }));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function readStdin() {
|
|
36
|
+
return new Promise((resolve) => {
|
|
37
|
+
let data = "";
|
|
38
|
+
if (process.stdin.isTTY) {
|
|
39
|
+
resolve("");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
process.stdin.setEncoding("utf8");
|
|
43
|
+
process.stdin.on("data", (chunk) => {
|
|
44
|
+
data += chunk;
|
|
45
|
+
});
|
|
46
|
+
process.stdin.on("end", () => {
|
|
47
|
+
resolve(data.trim());
|
|
48
|
+
});
|
|
49
|
+
setTimeout(() => {
|
|
50
|
+
resolve(data.trim());
|
|
51
|
+
}, 1e3);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
handleSessionStart
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=session-start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/session-start.ts"],"sourcesContent":["import { ConversationManager } from \"../core/conversation-manager.js\";\nimport { IndexManager } from \"../core/index-manager.js\";\nimport { getVaultPath } from \"../utils/config.js\";\n\ninterface SessionStartInput {\n session_id?: string;\n transcript_path?: string;\n cwd?: string;\n}\n\ninterface HookOutput {\n continue: boolean;\n suppressOutput?: boolean;\n additionalContext?: string;\n}\n\nexport async function handleSessionStart(): Promise<void> {\n try {\n // Read input from stdin\n const input = await readStdin();\n const data: SessionStartInput = input ? JSON.parse(input) : {};\n\n const projectPath = data.cwd || process.cwd();\n\n // Initialize conversation\n const manager = new ConversationManager(projectPath);\n const sessionId = await manager.getOrCreateSession(data.transcript_path);\n await manager.setActiveSession(sessionId);\n\n // Load vault context for injection\n const vaultPath = getVaultPath(projectPath);\n const indexManager = new IndexManager(vaultPath);\n const vaultOverview = await indexManager.getVaultOverview();\n\n // Prepare output\n const output: HookOutput = {\n continue: true,\n suppressOutput: true,\n };\n\n if (vaultOverview) {\n output.additionalContext = `[CCKB] Knowledge Base available. ${vaultOverview}`;\n }\n\n // Output to stdout for Claude Code to pick up\n console.log(JSON.stringify(output));\n } catch (error) {\n // Silent failure - don't interrupt session\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n }\n}\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve) => {\n let data = \"\";\n\n if (process.stdin.isTTY) {\n resolve(\"\");\n return;\n }\n\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (chunk) => {\n data += chunk;\n });\n process.stdin.on(\"end\", () => {\n resolve(data.trim());\n });\n\n // Timeout after 1 second\n setTimeout(() => {\n resolve(data.trim());\n }, 1000);\n });\n}\n"],"mappings":";;;;;;;;;;;AAgBA,eAAsB,qBAAoC;AACxD,MAAI;AAEF,UAAM,QAAQ,MAAM,UAAU;AAC9B,UAAM,OAA0B,QAAQ,KAAK,MAAM,KAAK,IAAI,CAAC;AAE7D,UAAM,cAAc,KAAK,OAAO,QAAQ,IAAI;AAG5C,UAAM,UAAU,IAAI,oBAAoB,WAAW;AACnD,UAAM,YAAY,MAAM,QAAQ,mBAAmB,KAAK,eAAe;AACvE,UAAM,QAAQ,iBAAiB,SAAS;AAGxC,UAAM,YAAY,aAAa,WAAW;AAC1C,UAAM,eAAe,IAAI,aAAa,SAAS;AAC/C,UAAM,gBAAgB,MAAM,aAAa,iBAAiB;AAG1D,UAAM,SAAqB;AAAA,MACzB,UAAU;AAAA,MACV,gBAAgB;AAAA,IAClB;AAEA,QAAI,eAAe;AACjB,aAAO,oBAAoB,oCAAoC,aAAa;AAAA,IAC9E;AAGA,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,SAAS,OAAO;AAEd,YAAQ,IAAI,KAAK,UAAU,EAAE,UAAU,MAAM,gBAAgB,KAAK,CAAC,CAAC;AAAA,EACtE;AACF;AAEA,eAAe,YAA6B;AAC1C,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,OAAO;AAEX,QAAI,QAAQ,MAAM,OAAO;AACvB,cAAQ,EAAE;AACV;AAAA,IACF;AAEA,YAAQ,MAAM,YAAY,MAAM;AAChC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAU;AAClC,cAAQ;AAAA,IACV,CAAC;AACD,YAAQ,MAAM,GAAG,OAAO,MAAM;AAC5B,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,CAAC;AAGD,eAAW,MAAM;AACf,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,GAAG,GAAI;AAAA,EACT,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CompactionEngine,
|
|
3
|
+
VaultIntegrator
|
|
4
|
+
} from "../chunk-Z3CJQKTH.js";
|
|
5
|
+
import {
|
|
6
|
+
ConversationManager
|
|
7
|
+
} from "../chunk-K4W3KOBL.js";
|
|
8
|
+
import "../chunk-XAY6TTXB.js";
|
|
9
|
+
import {
|
|
10
|
+
getVaultPath,
|
|
11
|
+
loadConfig
|
|
12
|
+
} from "../chunk-TFFLX3YY.js";
|
|
13
|
+
|
|
14
|
+
// src/hooks/stop.ts
|
|
15
|
+
async function handleStop() {
|
|
16
|
+
try {
|
|
17
|
+
const input = await readStdin();
|
|
18
|
+
const data = input ? JSON.parse(input) : {};
|
|
19
|
+
const projectPath = data.cwd || process.cwd();
|
|
20
|
+
const manager = new ConversationManager(projectPath);
|
|
21
|
+
const sessionId = await manager.getActiveSessionId();
|
|
22
|
+
if (!sessionId) {
|
|
23
|
+
console.log(JSON.stringify({ continue: true, suppressOutput: true }));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
runCompactionAsync(projectPath, sessionId).catch(() => {
|
|
27
|
+
});
|
|
28
|
+
const output = {
|
|
29
|
+
continue: true,
|
|
30
|
+
suppressOutput: true
|
|
31
|
+
};
|
|
32
|
+
console.log(JSON.stringify(output));
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.log(JSON.stringify({ continue: true, suppressOutput: true }));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function runCompactionAsync(projectPath, sessionId) {
|
|
38
|
+
const config = await loadConfig(projectPath);
|
|
39
|
+
if (config.compaction.trigger !== "session_end") {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const manager = new ConversationManager(projectPath);
|
|
43
|
+
const conversation = await manager.getFullConversation(sessionId);
|
|
44
|
+
if (!conversation || conversation.length < 100) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const compactionEngine = new CompactionEngine(projectPath);
|
|
48
|
+
const summary = await compactionEngine.compact(sessionId, conversation);
|
|
49
|
+
if (!summary) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (config.vault.autoIntegrate) {
|
|
53
|
+
const vaultPath = getVaultPath(projectPath);
|
|
54
|
+
const integrator = new VaultIntegrator(vaultPath);
|
|
55
|
+
await integrator.integrate(summary);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function readStdin() {
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
let data = "";
|
|
61
|
+
if (process.stdin.isTTY) {
|
|
62
|
+
resolve("");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
process.stdin.setEncoding("utf8");
|
|
66
|
+
process.stdin.on("data", (chunk) => {
|
|
67
|
+
data += chunk;
|
|
68
|
+
});
|
|
69
|
+
process.stdin.on("end", () => {
|
|
70
|
+
resolve(data.trim());
|
|
71
|
+
});
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
resolve(data.trim());
|
|
74
|
+
}, 1e3);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
handleStop
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=stop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/stop.ts"],"sourcesContent":["import { ConversationManager } from \"../core/conversation-manager.js\";\nimport { CompactionEngine } from \"../core/compaction-engine.js\";\nimport { VaultIntegrator } from \"../core/vault-integrator.js\";\nimport { loadConfig, getVaultPath } from \"../utils/config.js\";\n\ninterface StopInput {\n cwd?: string;\n}\n\ninterface HookOutput {\n continue: boolean;\n suppressOutput?: boolean;\n}\n\nexport async function handleStop(): Promise<void> {\n try {\n // Read input from stdin\n const input = await readStdin();\n const data: StopInput = input ? JSON.parse(input) : {};\n\n const projectPath = data.cwd || process.cwd();\n\n // Get active session\n const manager = new ConversationManager(projectPath);\n const sessionId = await manager.getActiveSessionId();\n\n if (!sessionId) {\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n return;\n }\n\n // Run compaction asynchronously (don't block session exit)\n runCompactionAsync(projectPath, sessionId).catch(() => {\n // Silent failure\n });\n\n const output: HookOutput = {\n continue: true,\n suppressOutput: true,\n };\n\n console.log(JSON.stringify(output));\n } catch (error) {\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n }\n}\n\nasync function runCompactionAsync(\n projectPath: string,\n sessionId: string\n): Promise<void> {\n const config = await loadConfig(projectPath);\n\n if (config.compaction.trigger !== \"session_end\") {\n return;\n }\n\n // Get conversation content\n const manager = new ConversationManager(projectPath);\n const conversation = await manager.getFullConversation(sessionId);\n\n if (!conversation || conversation.length < 100) {\n // Skip empty or very short conversations\n return;\n }\n\n // Run compaction\n const compactionEngine = new CompactionEngine(projectPath);\n const summary = await compactionEngine.compact(sessionId, conversation);\n\n if (!summary) {\n return;\n }\n\n // Integrate into vault if enabled\n if (config.vault.autoIntegrate) {\n const vaultPath = getVaultPath(projectPath);\n const integrator = new VaultIntegrator(vaultPath);\n await integrator.integrate(summary);\n }\n}\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve) => {\n let data = \"\";\n\n if (process.stdin.isTTY) {\n resolve(\"\");\n return;\n }\n\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (chunk) => {\n data += chunk;\n });\n process.stdin.on(\"end\", () => {\n resolve(data.trim());\n });\n\n setTimeout(() => {\n resolve(data.trim());\n }, 1000);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,eAAsB,aAA4B;AAChD,MAAI;AAEF,UAAM,QAAQ,MAAM,UAAU;AAC9B,UAAM,OAAkB,QAAQ,KAAK,MAAM,KAAK,IAAI,CAAC;AAErD,UAAM,cAAc,KAAK,OAAO,QAAQ,IAAI;AAG5C,UAAM,UAAU,IAAI,oBAAoB,WAAW;AACnD,UAAM,YAAY,MAAM,QAAQ,mBAAmB;AAEnD,QAAI,CAAC,WAAW;AACd,cAAQ,IAAI,KAAK,UAAU,EAAE,UAAU,MAAM,gBAAgB,KAAK,CAAC,CAAC;AACpE;AAAA,IACF;AAGA,uBAAmB,aAAa,SAAS,EAAE,MAAM,MAAM;AAAA,IAEvD,CAAC;AAED,UAAM,SAAqB;AAAA,MACzB,UAAU;AAAA,MACV,gBAAgB;AAAA,IAClB;AAEA,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,SAAS,OAAO;AACd,YAAQ,IAAI,KAAK,UAAU,EAAE,UAAU,MAAM,gBAAgB,KAAK,CAAC,CAAC;AAAA,EACtE;AACF;AAEA,eAAe,mBACb,aACA,WACe;AACf,QAAM,SAAS,MAAM,WAAW,WAAW;AAE3C,MAAI,OAAO,WAAW,YAAY,eAAe;AAC/C;AAAA,EACF;AAGA,QAAM,UAAU,IAAI,oBAAoB,WAAW;AACnD,QAAM,eAAe,MAAM,QAAQ,oBAAoB,SAAS;AAEhE,MAAI,CAAC,gBAAgB,aAAa,SAAS,KAAK;AAE9C;AAAA,EACF;AAGA,QAAM,mBAAmB,IAAI,iBAAiB,WAAW;AACzD,QAAM,UAAU,MAAM,iBAAiB,QAAQ,WAAW,YAAY;AAEtE,MAAI,CAAC,SAAS;AACZ;AAAA,EACF;AAGA,MAAI,OAAO,MAAM,eAAe;AAC9B,UAAM,YAAY,aAAa,WAAW;AAC1C,UAAM,aAAa,IAAI,gBAAgB,SAAS;AAChD,UAAM,WAAW,UAAU,OAAO;AAAA,EACpC;AACF;AAEA,eAAe,YAA6B;AAC1C,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,OAAO;AAEX,QAAI,QAAQ,MAAM,OAAO;AACvB,cAAQ,EAAE;AACV;AAAA,IACF;AAEA,YAAQ,MAAM,YAAY,MAAM;AAChC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAU;AAClC,cAAQ;AAAA,IACV,CAAC;AACD,YAAQ,MAAM,GAAG,OAAO,MAAM;AAC5B,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,CAAC;AAED,eAAW,MAAM;AACf,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,GAAG,GAAI;AAAA,EACT,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConversationManager
|
|
3
|
+
} from "../chunk-K4W3KOBL.js";
|
|
4
|
+
import "../chunk-TFFLX3YY.js";
|
|
5
|
+
|
|
6
|
+
// src/hooks/user-prompt.ts
|
|
7
|
+
async function handleUserPrompt() {
|
|
8
|
+
try {
|
|
9
|
+
const input = await readStdin();
|
|
10
|
+
const data = input ? JSON.parse(input) : {};
|
|
11
|
+
const projectPath = data.cwd || process.cwd();
|
|
12
|
+
const manager = new ConversationManager(projectPath);
|
|
13
|
+
const sessionId = await manager.getActiveSessionId();
|
|
14
|
+
if (sessionId && data.prompt) {
|
|
15
|
+
await manager.appendUserInput(sessionId, data.prompt);
|
|
16
|
+
}
|
|
17
|
+
const output = {
|
|
18
|
+
continue: true,
|
|
19
|
+
suppressOutput: true
|
|
20
|
+
};
|
|
21
|
+
console.log(JSON.stringify(output));
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.log(JSON.stringify({ continue: true, suppressOutput: true }));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function readStdin() {
|
|
27
|
+
return new Promise((resolve) => {
|
|
28
|
+
let data = "";
|
|
29
|
+
if (process.stdin.isTTY) {
|
|
30
|
+
resolve("");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
process.stdin.setEncoding("utf8");
|
|
34
|
+
process.stdin.on("data", (chunk) => {
|
|
35
|
+
data += chunk;
|
|
36
|
+
});
|
|
37
|
+
process.stdin.on("end", () => {
|
|
38
|
+
resolve(data.trim());
|
|
39
|
+
});
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
resolve(data.trim());
|
|
42
|
+
}, 1e3);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
handleUserPrompt
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=user-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/user-prompt.ts"],"sourcesContent":["import { ConversationManager } from \"../core/conversation-manager.js\";\n\ninterface UserPromptInput {\n prompt?: string;\n cwd?: string;\n}\n\ninterface HookOutput {\n continue: boolean;\n suppressOutput?: boolean;\n}\n\nexport async function handleUserPrompt(): Promise<void> {\n try {\n // Read input from stdin\n const input = await readStdin();\n const data: UserPromptInput = input ? JSON.parse(input) : {};\n\n const projectPath = data.cwd || process.cwd();\n\n // Get active session\n const manager = new ConversationManager(projectPath);\n const sessionId = await manager.getActiveSessionId();\n\n if (sessionId && data.prompt) {\n // Append user input to conversation\n await manager.appendUserInput(sessionId, data.prompt);\n }\n\n // Silent output - stealth mode\n const output: HookOutput = {\n continue: true,\n suppressOutput: true,\n };\n\n console.log(JSON.stringify(output));\n } catch (error) {\n // Silent failure\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n }\n}\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve) => {\n let data = \"\";\n\n if (process.stdin.isTTY) {\n resolve(\"\");\n return;\n }\n\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (chunk) => {\n data += chunk;\n });\n process.stdin.on(\"end\", () => {\n resolve(data.trim());\n });\n\n setTimeout(() => {\n resolve(data.trim());\n }, 1000);\n });\n}\n"],"mappings":";;;;;;AAYA,eAAsB,mBAAkC;AACtD,MAAI;AAEF,UAAM,QAAQ,MAAM,UAAU;AAC9B,UAAM,OAAwB,QAAQ,KAAK,MAAM,KAAK,IAAI,CAAC;AAE3D,UAAM,cAAc,KAAK,OAAO,QAAQ,IAAI;AAG5C,UAAM,UAAU,IAAI,oBAAoB,WAAW;AACnD,UAAM,YAAY,MAAM,QAAQ,mBAAmB;AAEnD,QAAI,aAAa,KAAK,QAAQ;AAE5B,YAAM,QAAQ,gBAAgB,WAAW,KAAK,MAAM;AAAA,IACtD;AAGA,UAAM,SAAqB;AAAA,MACzB,UAAU;AAAA,MACV,gBAAgB;AAAA,IAClB;AAEA,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,SAAS,OAAO;AAEd,YAAQ,IAAI,KAAK,UAAU,EAAE,UAAU,MAAM,gBAAgB,KAAK,CAAC,CAAC;AAAA,EACtE;AACF;AAEA,eAAe,YAA6B;AAC1C,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,OAAO;AAEX,QAAI,QAAQ,MAAM,OAAO;AACvB,cAAQ,EAAE;AACV;AAAA,IACF;AAEA,YAAQ,MAAM,YAAY,MAAM;AAChC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAU;AAClC,cAAQ;AAAA,IACV,CAAC;AACD,YAAQ,MAAM,GAAG,OAAO,MAAM;AAC5B,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,CAAC;AAED,eAAW,MAAM;AACf,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,GAAG,GAAI;AAAA,EACT,CAAC;AACH;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
interface InstallOptions {
|
|
2
|
+
force?: boolean;
|
|
3
|
+
}
|
|
4
|
+
declare function install(targetPath: string, options?: InstallOptions): Promise<void>;
|
|
5
|
+
|
|
6
|
+
declare class ConversationManager {
|
|
7
|
+
private projectPath;
|
|
8
|
+
constructor(projectPath: string);
|
|
9
|
+
createConversation(sessionId: string): Promise<string>;
|
|
10
|
+
appendUserInput(sessionId: string, prompt: string): Promise<void>;
|
|
11
|
+
appendClaudeOutput(sessionId: string, toolName: string, action: string, target?: string): Promise<void>;
|
|
12
|
+
getConversationFiles(sessionId: string): Promise<string[]>;
|
|
13
|
+
getFullConversation(sessionId: string): Promise<string>;
|
|
14
|
+
rotateConversation(sessionId: string): Promise<void>;
|
|
15
|
+
getOrCreateSession(transcriptPath?: string): Promise<string>;
|
|
16
|
+
getActiveSessionId(): Promise<string | null>;
|
|
17
|
+
setActiveSession(sessionId: string): Promise<void>;
|
|
18
|
+
private checkRotation;
|
|
19
|
+
private formatEntry;
|
|
20
|
+
private getSessionState;
|
|
21
|
+
private updateSessionState;
|
|
22
|
+
private loadSessionMap;
|
|
23
|
+
private saveSessionMap;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface Summary {
|
|
27
|
+
sessionId: string;
|
|
28
|
+
content: string;
|
|
29
|
+
entities: ExtractedEntity[];
|
|
30
|
+
architecture: ArchitectureItem[];
|
|
31
|
+
services: ServiceItem[];
|
|
32
|
+
knowledge: KnowledgeItem[];
|
|
33
|
+
}
|
|
34
|
+
interface ExtractedEntity {
|
|
35
|
+
name: string;
|
|
36
|
+
location?: string;
|
|
37
|
+
attributes: string[];
|
|
38
|
+
relations: string[];
|
|
39
|
+
}
|
|
40
|
+
interface ArchitectureItem {
|
|
41
|
+
pattern: string;
|
|
42
|
+
description: string;
|
|
43
|
+
affectedFiles: string[];
|
|
44
|
+
}
|
|
45
|
+
interface ServiceItem {
|
|
46
|
+
name: string;
|
|
47
|
+
location?: string;
|
|
48
|
+
purpose: string;
|
|
49
|
+
methods: string[];
|
|
50
|
+
}
|
|
51
|
+
interface KnowledgeItem {
|
|
52
|
+
topic: string;
|
|
53
|
+
details: string;
|
|
54
|
+
}
|
|
55
|
+
declare class CompactionEngine {
|
|
56
|
+
private projectPath;
|
|
57
|
+
constructor(projectPath: string);
|
|
58
|
+
compact(sessionId: string, conversation: string): Promise<Summary | null>;
|
|
59
|
+
private generateSummary;
|
|
60
|
+
private fallbackExtraction;
|
|
61
|
+
private parseSummary;
|
|
62
|
+
private parseEntities;
|
|
63
|
+
private parseArchitecture;
|
|
64
|
+
private parseServices;
|
|
65
|
+
private parseKnowledge;
|
|
66
|
+
private writeSummary;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
declare class VaultIntegrator {
|
|
70
|
+
private vaultPath;
|
|
71
|
+
private indexManager;
|
|
72
|
+
private entityDetector;
|
|
73
|
+
constructor(vaultPath: string);
|
|
74
|
+
integrate(summary: Summary): Promise<void>;
|
|
75
|
+
private processItem;
|
|
76
|
+
private processEntity;
|
|
77
|
+
private processService;
|
|
78
|
+
private processPattern;
|
|
79
|
+
private processKnowledge;
|
|
80
|
+
private updateRootIndex;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface DetectedItem {
|
|
84
|
+
type: "entity" | "service" | "pattern" | "knowledge";
|
|
85
|
+
name: string;
|
|
86
|
+
data: unknown;
|
|
87
|
+
vaultPath: string;
|
|
88
|
+
content: string;
|
|
89
|
+
}
|
|
90
|
+
declare class EntityDetector {
|
|
91
|
+
/**
|
|
92
|
+
* Analyzes a summary and determines what should be added to the vault.
|
|
93
|
+
*/
|
|
94
|
+
detect(summary: Summary): DetectedItem[];
|
|
95
|
+
private createEntityItem;
|
|
96
|
+
private createServiceItem;
|
|
97
|
+
private createStandaloneServiceItem;
|
|
98
|
+
private createArchitectureItem;
|
|
99
|
+
private createKnowledgeItem;
|
|
100
|
+
private formatEntityContent;
|
|
101
|
+
private formatServiceContent;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface IndexEntry {
|
|
105
|
+
name: string;
|
|
106
|
+
path: string;
|
|
107
|
+
description: string;
|
|
108
|
+
type: "file" | "folder";
|
|
109
|
+
}
|
|
110
|
+
declare class IndexManager {
|
|
111
|
+
private vaultPath;
|
|
112
|
+
constructor(vaultPath: string);
|
|
113
|
+
getVaultOverview(): Promise<string | null>;
|
|
114
|
+
listEntities(): Promise<string[]>;
|
|
115
|
+
readIndex(relativePath?: string): Promise<IndexEntry[]>;
|
|
116
|
+
updateIndex(relativePath: string, entries: IndexEntry[]): Promise<void>;
|
|
117
|
+
createIndex(relativePath: string, entries: IndexEntry[], title?: string): Promise<void>;
|
|
118
|
+
addEntry(relativePath: string, entry: IndexEntry): Promise<void>;
|
|
119
|
+
ensureEntityFolder(entityName: string): Promise<string>;
|
|
120
|
+
private parseIndex;
|
|
121
|
+
private buildTable;
|
|
122
|
+
private parseTableToOverview;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface CCKBConfig {
|
|
126
|
+
compaction: {
|
|
127
|
+
trigger: "session_end" | "size" | "messages" | "manual";
|
|
128
|
+
sizeThresholdKB: number;
|
|
129
|
+
messageThreshold: number;
|
|
130
|
+
};
|
|
131
|
+
capture: {
|
|
132
|
+
tools: string[];
|
|
133
|
+
maxContentLength: number;
|
|
134
|
+
};
|
|
135
|
+
vault: {
|
|
136
|
+
autoIntegrate: boolean;
|
|
137
|
+
maxDepth: number;
|
|
138
|
+
};
|
|
139
|
+
feedback: {
|
|
140
|
+
enabled: boolean;
|
|
141
|
+
contextDepth: number;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export { type CCKBConfig, CompactionEngine, ConversationManager, EntityDetector, IndexManager, VaultIntegrator, install };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
install
|
|
3
|
+
} from "./chunk-GUB5D6EN.js";
|
|
4
|
+
import {
|
|
5
|
+
CompactionEngine,
|
|
6
|
+
EntityDetector,
|
|
7
|
+
VaultIntegrator
|
|
8
|
+
} from "./chunk-Z3CJQKTH.js";
|
|
9
|
+
import {
|
|
10
|
+
ConversationManager
|
|
11
|
+
} from "./chunk-K4W3KOBL.js";
|
|
12
|
+
import {
|
|
13
|
+
IndexManager
|
|
14
|
+
} from "./chunk-XAY6TTXB.js";
|
|
15
|
+
import "./chunk-TFFLX3YY.js";
|
|
16
|
+
export {
|
|
17
|
+
CompactionEngine,
|
|
18
|
+
ConversationManager,
|
|
19
|
+
EntityDetector,
|
|
20
|
+
IndexManager,
|
|
21
|
+
VaultIntegrator,
|
|
22
|
+
install
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|