@scitrera/memorylayer-cc-plugin 0.0.5 → 0.2.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/LICENSE +177 -0
- package/README.md +11 -4
- package/dist/bin/memorylayer-hook.js +27 -9
- package/dist/bin/memorylayer-hook.js.map +1 -1
- package/dist/src/hooks/client.d.ts +21 -0
- package/dist/src/hooks/client.d.ts.map +1 -0
- package/dist/src/hooks/client.js +57 -0
- package/dist/src/hooks/client.js.map +1 -0
- package/dist/src/hooks/formatters.d.ts +33 -0
- package/dist/src/hooks/formatters.d.ts.map +1 -0
- package/dist/src/hooks/formatters.js +187 -0
- package/dist/src/hooks/formatters.js.map +1 -0
- package/dist/src/hooks/handlers/post-tool.d.ts +10 -0
- package/dist/src/hooks/handlers/post-tool.d.ts.map +1 -0
- package/dist/src/hooks/handlers/post-tool.js +98 -0
- package/dist/src/hooks/handlers/post-tool.js.map +1 -0
- package/dist/src/hooks/handlers/pre-compact.d.ts +5 -0
- package/dist/src/hooks/handlers/pre-compact.d.ts.map +1 -0
- package/dist/src/hooks/handlers/pre-compact.js +117 -0
- package/dist/src/hooks/handlers/pre-compact.js.map +1 -0
- package/dist/src/hooks/handlers/pre-tool.d.ts +10 -0
- package/dist/src/hooks/handlers/pre-tool.d.ts.map +1 -0
- package/dist/src/hooks/handlers/pre-tool.js +114 -0
- package/dist/src/hooks/handlers/pre-tool.js.map +1 -0
- package/dist/src/hooks/handlers/session-start.d.ts +10 -0
- package/dist/src/hooks/handlers/session-start.d.ts.map +1 -0
- package/dist/src/hooks/handlers/session-start.js +111 -0
- package/dist/src/hooks/handlers/session-start.js.map +1 -0
- package/dist/src/hooks/handlers/stop.d.ts +14 -0
- package/dist/src/hooks/handlers/stop.d.ts.map +1 -0
- package/dist/src/hooks/handlers/stop.js +49 -0
- package/dist/src/hooks/handlers/stop.js.map +1 -0
- package/dist/src/hooks/handlers/user-prompt.d.ts +10 -0
- package/dist/src/hooks/handlers/user-prompt.d.ts.map +1 -0
- package/dist/src/hooks/handlers/user-prompt.js +128 -0
- package/dist/src/hooks/handlers/user-prompt.js.map +1 -0
- package/dist/src/hooks/index.d.ts +18 -0
- package/dist/src/hooks/index.d.ts.map +1 -0
- package/dist/src/hooks/index.js +23 -0
- package/dist/src/hooks/index.js.map +1 -0
- package/dist/src/hooks/observation.d.ts +59 -0
- package/dist/src/hooks/observation.d.ts.map +1 -0
- package/dist/src/hooks/observation.js +421 -0
- package/dist/src/hooks/observation.js.map +1 -0
- package/dist/src/hooks/state.d.ts +73 -0
- package/dist/src/hooks/state.d.ts.map +1 -0
- package/dist/src/hooks/state.js +168 -0
- package/dist/src/hooks/state.js.map +1 -0
- package/dist/src/hooks/types.d.ts +86 -0
- package/dist/src/hooks/types.d.ts.map +1 -0
- package/dist/src/hooks/types.js +14 -0
- package/dist/src/hooks/types.js.map +1 -0
- package/package.json +15 -5
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format API responses for injection into Claude's context.
|
|
3
|
+
*
|
|
4
|
+
* Uses the same types returned by MemoryLayerClient (the MCP adapter),
|
|
5
|
+
* so hooks and MCP tools share the same data contracts.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Format a single memory for display
|
|
9
|
+
*/
|
|
10
|
+
function formatMemory(memory, index) {
|
|
11
|
+
const lines = [];
|
|
12
|
+
const typeStr = memory.subtype
|
|
13
|
+
? `${memory.type}/${memory.subtype}`
|
|
14
|
+
: memory.type;
|
|
15
|
+
const relevanceStr = memory.relevance_score
|
|
16
|
+
? ` (relevance: ${(memory.relevance_score * 100).toFixed(0)}%)`
|
|
17
|
+
: "";
|
|
18
|
+
lines.push(`${index + 1}. [${typeStr}]${relevanceStr}`);
|
|
19
|
+
lines.push(` ${memory.content}`);
|
|
20
|
+
const tags = memory.tags ?? [];
|
|
21
|
+
if (tags.length > 0) {
|
|
22
|
+
lines.push(` Tags: ${tags.join(", ")}`);
|
|
23
|
+
}
|
|
24
|
+
return lines.join("\n");
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Format recall results for context injection
|
|
28
|
+
*/
|
|
29
|
+
export function formatRecallResult(result, query) {
|
|
30
|
+
if (result.memories.length === 0) {
|
|
31
|
+
return `No memories found matching "${query}".`;
|
|
32
|
+
}
|
|
33
|
+
const totalCount = result.total_count ?? result.memories.length;
|
|
34
|
+
const lines = [
|
|
35
|
+
`Found ${totalCount} memories for "${query}" (showing ${result.memories.length}):`,
|
|
36
|
+
"",
|
|
37
|
+
];
|
|
38
|
+
for (let i = 0; i < result.memories.length; i++) {
|
|
39
|
+
lines.push(formatMemory(result.memories[i], i));
|
|
40
|
+
if (i < result.memories.length - 1) {
|
|
41
|
+
lines.push("");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return lines.join("\n");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Format briefing for context injection.
|
|
48
|
+
* Accepts the ToolResponse from MemoryLayerClient.getBriefing().
|
|
49
|
+
*/
|
|
50
|
+
export function formatBriefing(briefing) {
|
|
51
|
+
if (!briefing) {
|
|
52
|
+
return "=== Workspace Briefing ===\n\nNo workspace data available.";
|
|
53
|
+
}
|
|
54
|
+
const totalMemories = briefing.total_memories ?? 0;
|
|
55
|
+
const activeTopics = briefing.active_topics ?? [];
|
|
56
|
+
const memoryTypes = briefing.memory_types ?? {};
|
|
57
|
+
const recentActivity = briefing.recent_activity ?? [];
|
|
58
|
+
const lines = [
|
|
59
|
+
"=== Workspace Briefing ===",
|
|
60
|
+
"",
|
|
61
|
+
`Total memories: ${totalMemories}`,
|
|
62
|
+
];
|
|
63
|
+
if (activeTopics.length > 0) {
|
|
64
|
+
lines.push(`Active topics: ${activeTopics.join(", ")}`);
|
|
65
|
+
}
|
|
66
|
+
// Memory type breakdown
|
|
67
|
+
const types = Object.entries(memoryTypes);
|
|
68
|
+
if (types.length > 0) {
|
|
69
|
+
lines.push("");
|
|
70
|
+
lines.push("Memory types:");
|
|
71
|
+
for (const [type, count] of types) {
|
|
72
|
+
lines.push(` - ${type}: ${count}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Recent activity
|
|
76
|
+
if (recentActivity.length > 0) {
|
|
77
|
+
lines.push("");
|
|
78
|
+
lines.push("Recent activity:");
|
|
79
|
+
for (const activity of recentActivity.slice(0, 3)) {
|
|
80
|
+
const date = new Date(activity.timestamp ?? new Date().toISOString()).toLocaleDateString();
|
|
81
|
+
lines.push(` - ${date}: ${activity.summary ?? ""} (${activity.memories_created ?? 0} memories)`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return lines.join("\n");
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Format directive memories specially (high importance user instructions)
|
|
88
|
+
*/
|
|
89
|
+
export function formatDirectives(memories) {
|
|
90
|
+
const directives = memories.filter(m => m.subtype === "directive" || (m.subtype === "preference" && (m.importance ?? 0) >= 0.9));
|
|
91
|
+
if (directives.length === 0) {
|
|
92
|
+
return "";
|
|
93
|
+
}
|
|
94
|
+
const lines = [
|
|
95
|
+
"=== User Directives (must follow) ===",
|
|
96
|
+
"",
|
|
97
|
+
];
|
|
98
|
+
for (const directive of directives) {
|
|
99
|
+
lines.push(`• ${directive.content}`);
|
|
100
|
+
}
|
|
101
|
+
return lines.join("\n");
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Format sandbox state for context injection (post-compaction recovery)
|
|
105
|
+
*/
|
|
106
|
+
export function formatSandboxState(inspectResult) {
|
|
107
|
+
const variableCount = inspectResult.variable_count ?? 0;
|
|
108
|
+
const variables = inspectResult.variables ?? {};
|
|
109
|
+
const lines = [
|
|
110
|
+
"=== Existing Sandbox State (server-side) ===",
|
|
111
|
+
"",
|
|
112
|
+
`The server-side sandbox has ${variableCount} variable(s) from a prior session or before context compaction.`,
|
|
113
|
+
"These variables are live and available for memory_context_exec, memory_context_query, and memory_context_rlm.",
|
|
114
|
+
"",
|
|
115
|
+
];
|
|
116
|
+
for (const [name, info] of Object.entries(variables)) {
|
|
117
|
+
lines.push(` ${name} (${info.type}): ${info.preview}`);
|
|
118
|
+
}
|
|
119
|
+
lines.push("");
|
|
120
|
+
lines.push("Use `memory_context_inspect` for detailed variable inspection.");
|
|
121
|
+
return lines.join("\n");
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Format combined SessionStart output
|
|
125
|
+
*/
|
|
126
|
+
export function formatSessionStart(briefing, directives, topicRecall, topic, sandboxState) {
|
|
127
|
+
const sections = [];
|
|
128
|
+
// Briefing first
|
|
129
|
+
if (briefing) {
|
|
130
|
+
sections.push(formatBriefing(briefing));
|
|
131
|
+
}
|
|
132
|
+
// Directives (high priority)
|
|
133
|
+
const directiveSection = formatDirectives(directives);
|
|
134
|
+
if (directiveSection) {
|
|
135
|
+
sections.push(directiveSection);
|
|
136
|
+
}
|
|
137
|
+
// Topic-specific recall
|
|
138
|
+
if (topicRecall && topicRecall.memories.length > 0 && topic) {
|
|
139
|
+
sections.push(formatRecallResult(topicRecall, topic));
|
|
140
|
+
}
|
|
141
|
+
// Existing sandbox state (post-compaction or resumed session)
|
|
142
|
+
if (sandboxState) {
|
|
143
|
+
sections.push(formatSandboxState(sandboxState));
|
|
144
|
+
}
|
|
145
|
+
// Add session guidance
|
|
146
|
+
const guidance = `=== Session Guidance ===
|
|
147
|
+
|
|
148
|
+
Recalling Memories:
|
|
149
|
+
- Before answering questions about preferences, setup, conventions, or past decisions, call \`memory_recall\` first
|
|
150
|
+
- For broad context gathering, use \`memory_recall\` with relevant keywords
|
|
151
|
+
- Directives (subtype: directive) and preferences (subtype: preference) represent explicit user instructions — prioritize these
|
|
152
|
+
|
|
153
|
+
Storing Memories:
|
|
154
|
+
- \`memory_remember\`: store to long-term memory with type, subtype, and importance
|
|
155
|
+
- \`memory_session_commit\`: checkpoint working memory mid-session (without ending it)
|
|
156
|
+
|
|
157
|
+
Importance Guide: directives/preferences → 0.9 | decisions/architecture → 0.7-0.8 | fixes/solutions → 0.7 | patterns → 0.5-0.6
|
|
158
|
+
Types: semantic (facts), procedural (how-to), episodic (events), working (current context, auto-expires)
|
|
159
|
+
Subtypes: directive, decision, fix, solution, code_pattern, error, workflow, preference, problem
|
|
160
|
+
|
|
161
|
+
Context Environment (sandbox survives compaction):
|
|
162
|
+
- Load + analyze memories server-side: \`memory_context_load\` → \`memory_context_query\` or \`memory_context_rlm\`
|
|
163
|
+
- Run computations on loaded data: \`memory_context_exec\` (Python sandbox)
|
|
164
|
+
- After compaction, call \`memory_context_inspect\` to re-orient with existing sandbox variables`;
|
|
165
|
+
sections.push(guidance);
|
|
166
|
+
if (sections.length === 1) {
|
|
167
|
+
// Only guidance, no prior context
|
|
168
|
+
return "MemoryLayer: No prior context found for this session.\n\n" + guidance;
|
|
169
|
+
}
|
|
170
|
+
return sections.join("\n\n");
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Format guidance for storing memories after tool use
|
|
174
|
+
*/
|
|
175
|
+
export function formatStorageGuidance(toolName, isSignificant) {
|
|
176
|
+
if (!isSignificant) {
|
|
177
|
+
return "";
|
|
178
|
+
}
|
|
179
|
+
const guidance = {
|
|
180
|
+
Task: "Consider storing exploration/research findings with `memory_remember` (subtype: decision/problem/entity).",
|
|
181
|
+
Bash: "If this was a significant git commit, test result, or build output, store with `memory_remember` (subtype: workflow).",
|
|
182
|
+
Edit: "If this edit completes a milestone, store with `memory_remember` (type: working, tags: [active-file]).",
|
|
183
|
+
Write: "If this file represents a significant deliverable, store with `memory_remember` (type: working, tags: [active-file]).",
|
|
184
|
+
};
|
|
185
|
+
return guidance[toolName] || "";
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=formatters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatters.js","sourceRoot":"","sources":["../../../src/hooks/formatters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostToolUse hook handler
|
|
3
|
+
* Silently captures tool observations as working memory
|
|
4
|
+
*/
|
|
5
|
+
import type { HookInput, HookOutput } from "../types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Handle PostToolUse event
|
|
8
|
+
*/
|
|
9
|
+
export declare function handlePostToolUse(input: HookInput): Promise<HookOutput>;
|
|
10
|
+
//# sourceMappingURL=post-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-tool.d.ts","sourceRoot":"","sources":["../../../../src/hooks/handlers/post-tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA0DzD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CA6C7E"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostToolUse hook handler
|
|
3
|
+
* Silently captures tool observations as working memory
|
|
4
|
+
*/
|
|
5
|
+
import { formatStorageGuidance } from "../formatters.js";
|
|
6
|
+
import { shouldSkipTool, buildObservation } from "../observation.js";
|
|
7
|
+
import { getClient } from "../client.js";
|
|
8
|
+
import { getCurrentPrompt } from "../state.js";
|
|
9
|
+
/**
|
|
10
|
+
* Store observation asynchronously (fire-and-forget)
|
|
11
|
+
*/
|
|
12
|
+
async function storeObservationAsync(obs) {
|
|
13
|
+
// getClient() syncs session ID from env/hook-state via resolveSessionId
|
|
14
|
+
const client = getClient();
|
|
15
|
+
const sessionId = client.getSessionId();
|
|
16
|
+
if (!sessionId)
|
|
17
|
+
return;
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
const timeout = setTimeout(() => controller.abort(), 3000);
|
|
20
|
+
try {
|
|
21
|
+
await client.setWorkingMemory(sessionId, `obs_${obs.contentHash}`, {
|
|
22
|
+
type: obs.type,
|
|
23
|
+
title: obs.title,
|
|
24
|
+
tool: obs.toolName,
|
|
25
|
+
files_read: obs.filesRead,
|
|
26
|
+
files_modified: obs.filesModified,
|
|
27
|
+
facts: obs.facts,
|
|
28
|
+
concepts: obs.concepts,
|
|
29
|
+
intent: obs.intent,
|
|
30
|
+
summary: obs.summary,
|
|
31
|
+
captured_at: new Date().toISOString(),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Silent failure - never block tool execution
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
clearTimeout(timeout);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Check if Bash output indicates significant action
|
|
43
|
+
*/
|
|
44
|
+
function isSignificantBashOutput(input) {
|
|
45
|
+
const command = input.tool_input?.command;
|
|
46
|
+
if (!command)
|
|
47
|
+
return false;
|
|
48
|
+
// Git commits
|
|
49
|
+
if (/git\s+commit/i.test(command))
|
|
50
|
+
return true;
|
|
51
|
+
// Build commands with errors
|
|
52
|
+
if (/npm\s+run\s+build|cargo\s+build|make\b|tsc\b/i.test(command)) {
|
|
53
|
+
const output = input.tool_output || "";
|
|
54
|
+
return /error|fail/i.test(output);
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Handle PostToolUse event
|
|
60
|
+
*/
|
|
61
|
+
export async function handlePostToolUse(input) {
|
|
62
|
+
const toolName = input.tool_name;
|
|
63
|
+
if (!toolName) {
|
|
64
|
+
return { success: true };
|
|
65
|
+
}
|
|
66
|
+
// Skip tools that shouldn't be captured
|
|
67
|
+
if (shouldSkipTool(toolName)) {
|
|
68
|
+
return { success: true };
|
|
69
|
+
}
|
|
70
|
+
// Build observation from tool usage
|
|
71
|
+
const currentPrompt = getCurrentPrompt();
|
|
72
|
+
const obs = buildObservation(input, currentPrompt);
|
|
73
|
+
// If observation is empty/no-op, skip
|
|
74
|
+
if (!obs) {
|
|
75
|
+
return { success: true };
|
|
76
|
+
}
|
|
77
|
+
// Fire-and-forget storage (do NOT await)
|
|
78
|
+
storeObservationAsync(obs).catch(() => { });
|
|
79
|
+
// Keep significant-event guidance for git commits and build errors
|
|
80
|
+
if (toolName === "Bash" && isSignificantBashOutput(input)) {
|
|
81
|
+
const command = input.tool_input?.command || "";
|
|
82
|
+
if (/git\s+commit/i.test(command)) {
|
|
83
|
+
return {
|
|
84
|
+
success: true,
|
|
85
|
+
additionalContext: formatStorageGuidance("Bash", true),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (/build|tsc|make/i.test(command)) {
|
|
89
|
+
return {
|
|
90
|
+
success: true,
|
|
91
|
+
additionalContext: "Build had errors. Consider storing the issue with `memory_remember` (subtype: error) for future reference.",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Silent capture - no context injection
|
|
96
|
+
return { success: true };
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=post-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-tool.js","sourceRoot":"","sources":["../../../../src/hooks/handlers/post-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Durable, deterministic pre-compaction capture for Claude Code transcripts. */
|
|
2
|
+
import type { HookInput, HookOutput } from "../types.js";
|
|
3
|
+
/** Capture raw transcript first, then best-effort commit and sandbox checkpoint. */
|
|
4
|
+
export declare function handlePreCompact(input: HookInput): Promise<HookOutput>;
|
|
5
|
+
//# sourceMappingURL=pre-compact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pre-compact.d.ts","sourceRoot":"","sources":["../../../../src/hooks/handlers/pre-compact.ts"],"names":[],"mappings":"AAAA,iFAAiF;AAIjF,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAmFzD,oFAAoF;AACpF,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CA+B5E"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/** Durable, deterministic pre-compaction capture for Claude Code transcripts. */
|
|
2
|
+
import { closeSync, existsSync, fstatSync, openSync, readSync } from "fs";
|
|
3
|
+
import { createHash } from "crypto";
|
|
4
|
+
import { getClient } from "../client.js";
|
|
5
|
+
import { acknowledgeCheckpointBoundary, getCheckpointBoundary } from "../state.js";
|
|
6
|
+
const CAPTURE_CHUNK_BYTES = 900_000;
|
|
7
|
+
const MAX_ATTEMPTS = 3;
|
|
8
|
+
function decodeUtf8Prefix(buffer) {
|
|
9
|
+
for (let trim = 0; trim <= Math.min(4, buffer.length); trim += 1) {
|
|
10
|
+
const candidate = trim === 0 ? buffer : buffer.subarray(0, buffer.length - trim);
|
|
11
|
+
try {
|
|
12
|
+
return {
|
|
13
|
+
content: new TextDecoder("utf-8", { fatal: true }).decode(candidate),
|
|
14
|
+
byteCount: candidate.length,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// A chunk may end within one UTF-8 code point; try the preceding boundary.
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
throw new Error("transcript contains malformed UTF-8");
|
|
22
|
+
}
|
|
23
|
+
async function retry(operation) {
|
|
24
|
+
let lastError;
|
|
25
|
+
const deadline = Date.now() + 5_000;
|
|
26
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt += 1) {
|
|
27
|
+
try {
|
|
28
|
+
return await operation();
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
lastError = error;
|
|
32
|
+
if (attempt < MAX_ATTEMPTS && Date.now() < deadline) {
|
|
33
|
+
await new Promise(resolve => setTimeout(resolve, attempt * 100));
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
throw lastError;
|
|
41
|
+
}
|
|
42
|
+
async function captureTranscript(input, sessionId) {
|
|
43
|
+
const transcriptPath = input.transcript_path;
|
|
44
|
+
if (!transcriptPath || !existsSync(transcriptPath)) {
|
|
45
|
+
console.error("[pre-compact] transcript path unavailable; continuing with commit/checkpoint side effects");
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
const client = getClient();
|
|
49
|
+
const descriptor = openSync(transcriptPath, "r");
|
|
50
|
+
let captured = 0;
|
|
51
|
+
try {
|
|
52
|
+
const size = fstatSync(descriptor).size;
|
|
53
|
+
let boundary = getCheckpointBoundary(sessionId, transcriptPath);
|
|
54
|
+
if (boundary > size)
|
|
55
|
+
boundary = 0;
|
|
56
|
+
while (boundary < size) {
|
|
57
|
+
const requested = Math.min(CAPTURE_CHUNK_BYTES, size - boundary);
|
|
58
|
+
const buffer = Buffer.allocUnsafe(requested);
|
|
59
|
+
const bytesRead = readSync(descriptor, buffer, 0, requested, boundary);
|
|
60
|
+
if (bytesRead === 0)
|
|
61
|
+
break;
|
|
62
|
+
const decoded = decodeUtf8Prefix(buffer.subarray(0, bytesRead));
|
|
63
|
+
if (decoded.byteCount === 0)
|
|
64
|
+
throw new Error("unable to find a complete UTF-8 boundary");
|
|
65
|
+
const nextBoundary = boundary + decoded.byteCount;
|
|
66
|
+
const contentHash = createHash("sha256").update(Buffer.from(decoded.content, "utf-8")).digest("hex");
|
|
67
|
+
const idempotencyKey = `claude-code:${sessionId}:${nextBoundary}:${contentHash}`;
|
|
68
|
+
await retry(() => client.createCheckpoint(sessionId, {
|
|
69
|
+
transcript_segment: decoded.content,
|
|
70
|
+
content_hash: contentHash,
|
|
71
|
+
idempotency_key: idempotencyKey,
|
|
72
|
+
source_kind: "claude_code_transcript",
|
|
73
|
+
source_boundary: nextBoundary,
|
|
74
|
+
}));
|
|
75
|
+
acknowledgeCheckpointBoundary(sessionId, transcriptPath, nextBoundary);
|
|
76
|
+
captured += decoded.byteCount;
|
|
77
|
+
boundary = nextBoundary;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
closeSync(descriptor);
|
|
82
|
+
}
|
|
83
|
+
return captured;
|
|
84
|
+
}
|
|
85
|
+
/** Capture raw transcript first, then best-effort commit and sandbox checkpoint. */
|
|
86
|
+
export async function handlePreCompact(input) {
|
|
87
|
+
const client = getClient();
|
|
88
|
+
const sessionId = client.getSessionId();
|
|
89
|
+
if (!sessionId) {
|
|
90
|
+
console.error("[pre-compact] no server session; MemoryLayer capture skipped without blocking compaction");
|
|
91
|
+
return { success: true };
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const captured = await captureTranscript(input, sessionId);
|
|
95
|
+
console.error(`[pre-compact] durably captured ${captured} new transcript bytes`);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
console.error("[pre-compact] raw capture failed; compaction will continue:", error instanceof Error ? error.message : error);
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
await retry(() => client.commitSession(sessionId, { importance_threshold: 0.3 }));
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
console.error("[pre-compact] working-memory commit failed:", error instanceof Error ? error.message : error);
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const status = await client.contextStatus();
|
|
108
|
+
if (status.exists && (status.variable_count ?? 0) > 0) {
|
|
109
|
+
await retry(() => client.contextCheckpoint());
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
console.error("[pre-compact] sandbox checkpoint failed:", error instanceof Error ? error.message : error);
|
|
114
|
+
}
|
|
115
|
+
return { success: true };
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=pre-compact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pre-compact.js","sourceRoot":"","sources":["../../../../src/hooks/handlers/pre-compact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PreToolUse hook handler
|
|
3
|
+
* Provides recall guidance before tool execution
|
|
4
|
+
*/
|
|
5
|
+
import type { HookInput, HookOutput } from "../types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Handle PreToolUse event
|
|
8
|
+
*/
|
|
9
|
+
export declare function handlePreToolUse(input: HookInput): Promise<HookOutput>;
|
|
10
|
+
//# sourceMappingURL=pre-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pre-tool.d.ts","sourceRoot":"","sources":["../../../../src/hooks/handlers/pre-tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAE,UAAU,EAAC,MAAM,aAAa,CAAC;AA0GvD;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAkB5E"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PreToolUse hook handler
|
|
3
|
+
* Provides recall guidance before tool execution
|
|
4
|
+
*/
|
|
5
|
+
import { getClient, checkHealth } from "../client.js";
|
|
6
|
+
import { formatRecallResult } from "../formatters.js";
|
|
7
|
+
import { wasQueryRecalledThisTurn, markRecallDone, getCurrentTopic } from "../state.js";
|
|
8
|
+
/**
|
|
9
|
+
* Handle PreToolUse for Task tool (subagent delegation)
|
|
10
|
+
*/
|
|
11
|
+
async function handleTaskTool(input) {
|
|
12
|
+
// Extract topic from Task prompt if available
|
|
13
|
+
const taskPrompt = input.tool_input?.prompt;
|
|
14
|
+
if (!taskPrompt) {
|
|
15
|
+
return {
|
|
16
|
+
success: true,
|
|
17
|
+
additionalContext: "RECALL-FIRST RULE: Consider using `memory_recall` before delegating to subagent. Subagents cannot access MemoryLayer.",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
// Use first 100 chars of task prompt as query
|
|
21
|
+
const query = taskPrompt.substring(0, 100);
|
|
22
|
+
// Check if this specific query was already recalled (allow different queries)
|
|
23
|
+
if (wasQueryRecalledThisTurn(query)) {
|
|
24
|
+
return {
|
|
25
|
+
success: true,
|
|
26
|
+
additionalContext: "Recall already done for this topic. Include relevant memories in subagent prompt.",
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
// Check server health
|
|
30
|
+
const healthy = await checkHealth();
|
|
31
|
+
if (!healthy) {
|
|
32
|
+
return { success: true };
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const client = getClient();
|
|
36
|
+
const result = await client.recall({ query, limit: 5 });
|
|
37
|
+
markRecallDone(query);
|
|
38
|
+
if (result.memories.length === 0) {
|
|
39
|
+
return {
|
|
40
|
+
success: true,
|
|
41
|
+
additionalContext: "No relevant memories found for this task. Proceeding with delegation.",
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const recallOutput = formatRecallResult(result, query);
|
|
45
|
+
return {
|
|
46
|
+
success: true,
|
|
47
|
+
additionalContext: `INCLUDE IN SUBAGENT PROMPT - Relevant context from memory:\n\n${recallOutput}`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return {
|
|
52
|
+
success: true,
|
|
53
|
+
additionalContext: "Memory recall failed. Consider manual recall before delegation.",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Handle PreToolUse for Edit/Write tools
|
|
59
|
+
*/
|
|
60
|
+
async function handleEditWriteTool(input) {
|
|
61
|
+
// Only provide guidance for non-trivial edits
|
|
62
|
+
const filePath = input.tool_input?.file_path;
|
|
63
|
+
if (!filePath) {
|
|
64
|
+
return { success: true };
|
|
65
|
+
}
|
|
66
|
+
// Build query from filename + user's current topic (if available)
|
|
67
|
+
const filename = filePath.split("/").pop() || filePath;
|
|
68
|
+
const topic = getCurrentTopic();
|
|
69
|
+
const query = topic ? `${filename} ${topic}` : `${filename} patterns solutions`;
|
|
70
|
+
// Skip if this specific query was already recalled
|
|
71
|
+
if (wasQueryRecalledThisTurn(query)) {
|
|
72
|
+
return { success: true };
|
|
73
|
+
}
|
|
74
|
+
// Check server health
|
|
75
|
+
const healthy = await checkHealth();
|
|
76
|
+
if (!healthy) {
|
|
77
|
+
return { success: true };
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const client = getClient();
|
|
81
|
+
const result = await client.recall({ query, limit: 3 });
|
|
82
|
+
if (result.memories.length === 0) {
|
|
83
|
+
return { success: true };
|
|
84
|
+
}
|
|
85
|
+
markRecallDone(query);
|
|
86
|
+
const recallOutput = formatRecallResult(result, filename);
|
|
87
|
+
return {
|
|
88
|
+
success: true,
|
|
89
|
+
additionalContext: `Relevant context for ${filename}:\n\n${recallOutput}`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return { success: true };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Handle PreToolUse event
|
|
98
|
+
*/
|
|
99
|
+
export async function handlePreToolUse(input) {
|
|
100
|
+
const toolName = input.tool_name;
|
|
101
|
+
if (!toolName) {
|
|
102
|
+
return { success: true };
|
|
103
|
+
}
|
|
104
|
+
switch (toolName) {
|
|
105
|
+
case "Task":
|
|
106
|
+
return handleTaskTool(input);
|
|
107
|
+
case "Edit":
|
|
108
|
+
case "Write":
|
|
109
|
+
return handleEditWriteTool(input);
|
|
110
|
+
default:
|
|
111
|
+
return { success: true };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=pre-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pre-tool.js","sourceRoot":"","sources":["../../../../src/hooks/handlers/pre-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionStart hook handler
|
|
3
|
+
* Retrieves briefing and relevant memories at session start
|
|
4
|
+
*/
|
|
5
|
+
import type { HookInput, HookOutput } from "../types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Handle SessionStart event
|
|
8
|
+
*/
|
|
9
|
+
export declare function handleSessionStart(input: HookInput): Promise<HookOutput>;
|
|
10
|
+
//# sourceMappingURL=session-start.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-start.d.ts","sourceRoot":"","sources":["../../../../src/hooks/handlers/session-start.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAC,SAAS,EAAE,UAAU,EAAC,MAAM,aAAa,CAAC;AA4CvD;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAmE9E"}
|