@scitrera/memorylayer-cc-plugin 0.1.22 → 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.
Files changed (53) hide show
  1. package/LICENSE +177 -0
  2. package/README.md +11 -4
  3. package/dist/bin/memorylayer-hook.js +27 -9
  4. package/dist/bin/memorylayer-hook.js.map +1 -1
  5. package/dist/src/hooks/client.d.ts +21 -0
  6. package/dist/src/hooks/client.d.ts.map +1 -0
  7. package/dist/src/hooks/client.js +57 -0
  8. package/dist/src/hooks/client.js.map +1 -0
  9. package/dist/src/hooks/formatters.d.ts +33 -0
  10. package/dist/src/hooks/formatters.d.ts.map +1 -0
  11. package/dist/src/hooks/formatters.js +187 -0
  12. package/dist/src/hooks/formatters.js.map +1 -0
  13. package/dist/src/hooks/handlers/post-tool.d.ts +10 -0
  14. package/dist/src/hooks/handlers/post-tool.d.ts.map +1 -0
  15. package/dist/src/hooks/handlers/post-tool.js +98 -0
  16. package/dist/src/hooks/handlers/post-tool.js.map +1 -0
  17. package/dist/src/hooks/handlers/pre-compact.d.ts +5 -0
  18. package/dist/src/hooks/handlers/pre-compact.d.ts.map +1 -0
  19. package/dist/src/hooks/handlers/pre-compact.js +117 -0
  20. package/dist/src/hooks/handlers/pre-compact.js.map +1 -0
  21. package/dist/src/hooks/handlers/pre-tool.d.ts +10 -0
  22. package/dist/src/hooks/handlers/pre-tool.d.ts.map +1 -0
  23. package/dist/src/hooks/handlers/pre-tool.js +114 -0
  24. package/dist/src/hooks/handlers/pre-tool.js.map +1 -0
  25. package/dist/src/hooks/handlers/session-start.d.ts +10 -0
  26. package/dist/src/hooks/handlers/session-start.d.ts.map +1 -0
  27. package/dist/src/hooks/handlers/session-start.js +111 -0
  28. package/dist/src/hooks/handlers/session-start.js.map +1 -0
  29. package/dist/src/hooks/handlers/stop.d.ts +14 -0
  30. package/dist/src/hooks/handlers/stop.d.ts.map +1 -0
  31. package/dist/src/hooks/handlers/stop.js +49 -0
  32. package/dist/src/hooks/handlers/stop.js.map +1 -0
  33. package/dist/src/hooks/handlers/user-prompt.d.ts +10 -0
  34. package/dist/src/hooks/handlers/user-prompt.d.ts.map +1 -0
  35. package/dist/src/hooks/handlers/user-prompt.js +128 -0
  36. package/dist/src/hooks/handlers/user-prompt.js.map +1 -0
  37. package/dist/src/hooks/index.d.ts +18 -0
  38. package/dist/src/hooks/index.d.ts.map +1 -0
  39. package/dist/src/hooks/index.js +23 -0
  40. package/dist/src/hooks/index.js.map +1 -0
  41. package/dist/src/hooks/observation.d.ts +59 -0
  42. package/dist/src/hooks/observation.d.ts.map +1 -0
  43. package/dist/src/hooks/observation.js +421 -0
  44. package/dist/src/hooks/observation.js.map +1 -0
  45. package/dist/src/hooks/state.d.ts +73 -0
  46. package/dist/src/hooks/state.d.ts.map +1 -0
  47. package/dist/src/hooks/state.js +168 -0
  48. package/dist/src/hooks/state.js.map +1 -0
  49. package/dist/src/hooks/types.d.ts +86 -0
  50. package/dist/src/hooks/types.d.ts.map +1 -0
  51. package/dist/src/hooks/types.js +14 -0
  52. package/dist/src/hooks/types.js.map +1 -0
  53. package/package.json +9 -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"}