@aitytech/agentkits-memory 1.0.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 +250 -0
- package/dist/cache-manager.d.ts +134 -0
- package/dist/cache-manager.d.ts.map +1 -0
- package/dist/cache-manager.js +407 -0
- package/dist/cache-manager.js.map +1 -0
- package/dist/cli/save.d.ts +20 -0
- package/dist/cli/save.d.ts.map +1 -0
- package/dist/cli/save.js +94 -0
- package/dist/cli/save.js.map +1 -0
- package/dist/cli/setup.d.ts +18 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +163 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli/viewer.d.ts +21 -0
- package/dist/cli/viewer.d.ts.map +1 -0
- package/dist/cli/viewer.js +182 -0
- package/dist/cli/viewer.js.map +1 -0
- package/dist/hnsw-index.d.ts +111 -0
- package/dist/hnsw-index.d.ts.map +1 -0
- package/dist/hnsw-index.js +781 -0
- package/dist/hnsw-index.js.map +1 -0
- package/dist/hooks/cli.d.ts +20 -0
- package/dist/hooks/cli.d.ts.map +1 -0
- package/dist/hooks/cli.js +102 -0
- package/dist/hooks/cli.js.map +1 -0
- package/dist/hooks/context.d.ts +31 -0
- package/dist/hooks/context.d.ts.map +1 -0
- package/dist/hooks/context.js +64 -0
- package/dist/hooks/context.js.map +1 -0
- package/dist/hooks/index.d.ts +16 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +20 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/observation.d.ts +30 -0
- package/dist/hooks/observation.d.ts.map +1 -0
- package/dist/hooks/observation.js +79 -0
- package/dist/hooks/observation.js.map +1 -0
- package/dist/hooks/service.d.ts +102 -0
- package/dist/hooks/service.d.ts.map +1 -0
- package/dist/hooks/service.js +454 -0
- package/dist/hooks/service.js.map +1 -0
- package/dist/hooks/session-init.d.ts +30 -0
- package/dist/hooks/session-init.d.ts.map +1 -0
- package/dist/hooks/session-init.js +54 -0
- package/dist/hooks/session-init.js.map +1 -0
- package/dist/hooks/summarize.d.ts +30 -0
- package/dist/hooks/summarize.d.ts.map +1 -0
- package/dist/hooks/summarize.js +74 -0
- package/dist/hooks/summarize.js.map +1 -0
- package/dist/hooks/types.d.ts +193 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +137 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/index.d.ts +173 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +564 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +9 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +9 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +22 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +368 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +14 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +110 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/types.d.ts +100 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +9 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/migration.d.ts +77 -0
- package/dist/migration.d.ts.map +1 -0
- package/dist/migration.js +457 -0
- package/dist/migration.js.map +1 -0
- package/dist/sqljs-backend.d.ts +128 -0
- package/dist/sqljs-backend.d.ts.map +1 -0
- package/dist/sqljs-backend.js +623 -0
- package/dist/sqljs-backend.js.map +1 -0
- package/dist/types.d.ts +481 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +73 -0
- package/dist/types.js.map +1 -0
- package/hooks.json +46 -0
- package/package.json +67 -0
- package/src/__tests__/index.test.ts +407 -0
- package/src/__tests__/sqljs-backend.test.ts +410 -0
- package/src/cache-manager.ts +515 -0
- package/src/cli/save.ts +109 -0
- package/src/cli/setup.ts +203 -0
- package/src/cli/viewer.ts +218 -0
- package/src/hnsw-index.ts +1013 -0
- package/src/hooks/__tests__/handlers.test.ts +298 -0
- package/src/hooks/__tests__/integration.test.ts +431 -0
- package/src/hooks/__tests__/service.test.ts +487 -0
- package/src/hooks/__tests__/types.test.ts +341 -0
- package/src/hooks/cli.ts +121 -0
- package/src/hooks/context.ts +77 -0
- package/src/hooks/index.ts +23 -0
- package/src/hooks/observation.ts +102 -0
- package/src/hooks/service.ts +582 -0
- package/src/hooks/session-init.ts +70 -0
- package/src/hooks/summarize.ts +89 -0
- package/src/hooks/types.ts +365 -0
- package/src/index.ts +755 -0
- package/src/mcp/__tests__/server.test.ts +181 -0
- package/src/mcp/index.ts +9 -0
- package/src/mcp/server.ts +441 -0
- package/src/mcp/tools.ts +113 -0
- package/src/mcp/types.ts +109 -0
- package/src/migration.ts +574 -0
- package/src/sql.js.d.ts +70 -0
- package/src/sqljs-backend.ts +789 -0
- package/src/types.ts +715 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summarize Hook Handler (Stop)
|
|
3
|
+
*
|
|
4
|
+
* Generates a session summary when Claude Code session ends.
|
|
5
|
+
* Uses template-based summarization (no LLM required).
|
|
6
|
+
*
|
|
7
|
+
* @module @agentkits/memory/hooks/summarize
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
NormalizedHookInput,
|
|
12
|
+
HookResult,
|
|
13
|
+
EventHandler,
|
|
14
|
+
} from './types.js';
|
|
15
|
+
import { MemoryHookService } from './service.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Summarize Hook - Stop Event
|
|
19
|
+
*
|
|
20
|
+
* Called when a Claude Code session ends.
|
|
21
|
+
* Generates a summary and marks the session as completed.
|
|
22
|
+
*/
|
|
23
|
+
export class SummarizeHook implements EventHandler {
|
|
24
|
+
private service: MemoryHookService;
|
|
25
|
+
|
|
26
|
+
constructor(service: MemoryHookService) {
|
|
27
|
+
this.service = service;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Execute the summarize hook
|
|
32
|
+
*/
|
|
33
|
+
async execute(input: NormalizedHookInput): Promise<HookResult> {
|
|
34
|
+
try {
|
|
35
|
+
// Initialize service
|
|
36
|
+
await this.service.initialize();
|
|
37
|
+
|
|
38
|
+
// Check if session exists
|
|
39
|
+
const session = this.service.getSession(input.sessionId);
|
|
40
|
+
if (!session) {
|
|
41
|
+
// No session to summarize
|
|
42
|
+
return {
|
|
43
|
+
continue: true,
|
|
44
|
+
suppressOutput: true,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Generate summary from observations
|
|
49
|
+
const summary = await this.service.generateSummary(input.sessionId);
|
|
50
|
+
|
|
51
|
+
// Complete the session with summary
|
|
52
|
+
await this.service.completeSession(input.sessionId, summary);
|
|
53
|
+
|
|
54
|
+
// Shutdown service
|
|
55
|
+
await this.service.shutdown();
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
continue: true,
|
|
59
|
+
suppressOutput: true,
|
|
60
|
+
};
|
|
61
|
+
} catch (error) {
|
|
62
|
+
// Log error but don't block session end
|
|
63
|
+
console.error('[AgentKits Memory] Summarize hook error:', error);
|
|
64
|
+
|
|
65
|
+
// Try to shutdown anyway
|
|
66
|
+
try {
|
|
67
|
+
await this.service.shutdown();
|
|
68
|
+
} catch {
|
|
69
|
+
// Ignore shutdown errors
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
continue: true,
|
|
74
|
+
suppressOutput: true,
|
|
75
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Create summarize hook handler
|
|
83
|
+
*/
|
|
84
|
+
export function createSummarizeHook(cwd: string): SummarizeHook {
|
|
85
|
+
const service = new MemoryHookService(cwd);
|
|
86
|
+
return new SummarizeHook(service);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export default SummarizeHook;
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook Types for AgentKits Memory
|
|
3
|
+
*
|
|
4
|
+
* Lightweight hook system for auto-capturing Claude Code sessions.
|
|
5
|
+
* Based on claude-mem patterns but simplified for project-scoped storage.
|
|
6
|
+
*
|
|
7
|
+
* @module @agentkits/memory/hooks/types
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ===== Claude Code Hook Input Types =====
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Raw input from Claude Code hooks (via stdin JSON)
|
|
14
|
+
*/
|
|
15
|
+
export interface ClaudeCodeHookInput {
|
|
16
|
+
/** Claude's session ID */
|
|
17
|
+
session_id?: string;
|
|
18
|
+
|
|
19
|
+
/** Current working directory */
|
|
20
|
+
cwd?: string;
|
|
21
|
+
|
|
22
|
+
/** User's prompt (UserPromptSubmit) */
|
|
23
|
+
prompt?: string;
|
|
24
|
+
|
|
25
|
+
/** Tool name (PostToolUse) */
|
|
26
|
+
tool_name?: string;
|
|
27
|
+
|
|
28
|
+
/** Tool input parameters (PostToolUse) */
|
|
29
|
+
tool_input?: unknown;
|
|
30
|
+
|
|
31
|
+
/** Tool response/output (PostToolUse) */
|
|
32
|
+
tool_result?: unknown;
|
|
33
|
+
|
|
34
|
+
/** Path to conversation transcript (Stop) */
|
|
35
|
+
transcript_path?: string;
|
|
36
|
+
|
|
37
|
+
/** Stop reason (Stop) */
|
|
38
|
+
stop_reason?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Normalized hook input for handlers
|
|
43
|
+
*/
|
|
44
|
+
export interface NormalizedHookInput {
|
|
45
|
+
/** Session ID */
|
|
46
|
+
sessionId: string;
|
|
47
|
+
|
|
48
|
+
/** Project directory */
|
|
49
|
+
cwd: string;
|
|
50
|
+
|
|
51
|
+
/** Project name (derived from cwd) */
|
|
52
|
+
project: string;
|
|
53
|
+
|
|
54
|
+
/** User's prompt */
|
|
55
|
+
prompt?: string;
|
|
56
|
+
|
|
57
|
+
/** Tool name */
|
|
58
|
+
toolName?: string;
|
|
59
|
+
|
|
60
|
+
/** Tool input */
|
|
61
|
+
toolInput?: unknown;
|
|
62
|
+
|
|
63
|
+
/** Tool response */
|
|
64
|
+
toolResponse?: unknown;
|
|
65
|
+
|
|
66
|
+
/** Transcript path */
|
|
67
|
+
transcriptPath?: string;
|
|
68
|
+
|
|
69
|
+
/** Stop reason */
|
|
70
|
+
stopReason?: string;
|
|
71
|
+
|
|
72
|
+
/** Timestamp */
|
|
73
|
+
timestamp: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ===== Hook Result Types =====
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Hook execution result
|
|
80
|
+
*/
|
|
81
|
+
export interface HookResult {
|
|
82
|
+
/** Continue processing (always true for us) */
|
|
83
|
+
continue: boolean;
|
|
84
|
+
|
|
85
|
+
/** Suppress output to Claude */
|
|
86
|
+
suppressOutput: boolean;
|
|
87
|
+
|
|
88
|
+
/** Additional context to inject (SessionStart only) */
|
|
89
|
+
additionalContext?: string;
|
|
90
|
+
|
|
91
|
+
/** Error message if failed */
|
|
92
|
+
error?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Hook-specific output for Claude Code
|
|
97
|
+
*/
|
|
98
|
+
export interface HookSpecificOutput {
|
|
99
|
+
hookEventName: string;
|
|
100
|
+
additionalContext?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Full hook response for Claude Code
|
|
105
|
+
*/
|
|
106
|
+
export interface ClaudeCodeHookResponse {
|
|
107
|
+
continue?: boolean;
|
|
108
|
+
suppressOutput?: boolean;
|
|
109
|
+
hookSpecificOutput?: HookSpecificOutput;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ===== Event Handler Types =====
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Hook event types
|
|
116
|
+
*/
|
|
117
|
+
export type HookEventType =
|
|
118
|
+
| 'context' // SessionStart - inject context
|
|
119
|
+
| 'session-init' // UserPromptSubmit - initialize session
|
|
120
|
+
| 'observation' // PostToolUse - capture tool usage
|
|
121
|
+
| 'summarize'; // Stop - generate summary
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Event handler interface
|
|
125
|
+
*/
|
|
126
|
+
export interface EventHandler {
|
|
127
|
+
/** Execute the hook handler */
|
|
128
|
+
execute(input: NormalizedHookInput): Promise<HookResult>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ===== Observation Types =====
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Captured observation from tool usage
|
|
135
|
+
*/
|
|
136
|
+
export interface Observation {
|
|
137
|
+
/** Unique ID */
|
|
138
|
+
id: string;
|
|
139
|
+
|
|
140
|
+
/** Session ID */
|
|
141
|
+
sessionId: string;
|
|
142
|
+
|
|
143
|
+
/** Project name */
|
|
144
|
+
project: string;
|
|
145
|
+
|
|
146
|
+
/** Tool name */
|
|
147
|
+
toolName: string;
|
|
148
|
+
|
|
149
|
+
/** Tool input (JSON) */
|
|
150
|
+
toolInput: string;
|
|
151
|
+
|
|
152
|
+
/** Tool response (JSON, truncated) */
|
|
153
|
+
toolResponse: string;
|
|
154
|
+
|
|
155
|
+
/** Working directory */
|
|
156
|
+
cwd: string;
|
|
157
|
+
|
|
158
|
+
/** Timestamp */
|
|
159
|
+
timestamp: number;
|
|
160
|
+
|
|
161
|
+
/** Observation type */
|
|
162
|
+
type: ObservationType;
|
|
163
|
+
|
|
164
|
+
/** Brief title (auto-generated) */
|
|
165
|
+
title?: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Observation types based on tool usage
|
|
170
|
+
*/
|
|
171
|
+
export type ObservationType =
|
|
172
|
+
| 'read' // Read, Glob, Grep
|
|
173
|
+
| 'write' // Write, Edit
|
|
174
|
+
| 'execute' // Bash, Task
|
|
175
|
+
| 'search' // WebSearch, WebFetch
|
|
176
|
+
| 'other'; // Unknown tools
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Session record for tracking
|
|
180
|
+
*/
|
|
181
|
+
export interface SessionRecord {
|
|
182
|
+
/** Database ID */
|
|
183
|
+
id: number;
|
|
184
|
+
|
|
185
|
+
/** Claude's session ID */
|
|
186
|
+
sessionId: string;
|
|
187
|
+
|
|
188
|
+
/** Project name */
|
|
189
|
+
project: string;
|
|
190
|
+
|
|
191
|
+
/** First user prompt */
|
|
192
|
+
prompt: string;
|
|
193
|
+
|
|
194
|
+
/** Session start time */
|
|
195
|
+
startedAt: number;
|
|
196
|
+
|
|
197
|
+
/** Session end time */
|
|
198
|
+
endedAt?: number;
|
|
199
|
+
|
|
200
|
+
/** Number of observations */
|
|
201
|
+
observationCount: number;
|
|
202
|
+
|
|
203
|
+
/** Auto-generated summary */
|
|
204
|
+
summary?: string;
|
|
205
|
+
|
|
206
|
+
/** Status */
|
|
207
|
+
status: 'active' | 'completed' | 'abandoned';
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ===== Context Types =====
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Context to inject on session start
|
|
214
|
+
*/
|
|
215
|
+
export interface MemoryContext {
|
|
216
|
+
/** Recent observations */
|
|
217
|
+
recentObservations: Observation[];
|
|
218
|
+
|
|
219
|
+
/** Previous sessions */
|
|
220
|
+
previousSessions: SessionRecord[];
|
|
221
|
+
|
|
222
|
+
/** Project-specific patterns */
|
|
223
|
+
patterns?: string[];
|
|
224
|
+
|
|
225
|
+
/** Recent decisions */
|
|
226
|
+
decisions?: string[];
|
|
227
|
+
|
|
228
|
+
/** Formatted markdown */
|
|
229
|
+
markdown: string;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ===== Utility Functions =====
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Generate observation ID
|
|
236
|
+
*/
|
|
237
|
+
export function generateObservationId(): string {
|
|
238
|
+
const timestamp = Date.now().toString(36);
|
|
239
|
+
const random = Math.random().toString(36).substring(2, 6);
|
|
240
|
+
return `obs_${timestamp}_${random}`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get project name from cwd
|
|
245
|
+
*/
|
|
246
|
+
export function getProjectName(cwd: string): string {
|
|
247
|
+
const parts = cwd.split(/[/\\]/);
|
|
248
|
+
return parts[parts.length - 1] || 'unknown';
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Determine observation type from tool name
|
|
253
|
+
*/
|
|
254
|
+
export function getObservationType(toolName: string): ObservationType {
|
|
255
|
+
const readTools = ['Read', 'Glob', 'Grep', 'LS'];
|
|
256
|
+
const writeTools = ['Write', 'Edit', 'NotebookEdit'];
|
|
257
|
+
const executeTools = ['Bash', 'Task', 'Skill'];
|
|
258
|
+
const searchTools = ['WebSearch', 'WebFetch'];
|
|
259
|
+
|
|
260
|
+
if (readTools.includes(toolName)) return 'read';
|
|
261
|
+
if (writeTools.includes(toolName)) return 'write';
|
|
262
|
+
if (executeTools.includes(toolName)) return 'execute';
|
|
263
|
+
if (searchTools.includes(toolName)) return 'search';
|
|
264
|
+
return 'other';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Generate observation title from tool usage
|
|
269
|
+
*/
|
|
270
|
+
export function generateObservationTitle(toolName: string, toolInput: unknown): string {
|
|
271
|
+
try {
|
|
272
|
+
const input = typeof toolInput === 'string' ? JSON.parse(toolInput) : toolInput;
|
|
273
|
+
|
|
274
|
+
switch (toolName) {
|
|
275
|
+
case 'Read':
|
|
276
|
+
return `Read ${input?.file_path || input?.path || 'file'}`;
|
|
277
|
+
case 'Write':
|
|
278
|
+
return `Write ${input?.file_path || input?.path || 'file'}`;
|
|
279
|
+
case 'Edit':
|
|
280
|
+
return `Edit ${input?.file_path || input?.path || 'file'}`;
|
|
281
|
+
case 'Bash':
|
|
282
|
+
const cmd = input?.command || '';
|
|
283
|
+
return `Run: ${cmd.substring(0, 50)}${cmd.length > 50 ? '...' : ''}`;
|
|
284
|
+
case 'Glob':
|
|
285
|
+
return `Find ${input?.pattern || 'files'}`;
|
|
286
|
+
case 'Grep':
|
|
287
|
+
return `Search "${input?.pattern || ''}"`;
|
|
288
|
+
case 'Task':
|
|
289
|
+
return `Task: ${input?.description || 'agent'}`;
|
|
290
|
+
case 'WebSearch':
|
|
291
|
+
return `Search: ${input?.query || ''}`;
|
|
292
|
+
case 'WebFetch':
|
|
293
|
+
return `Fetch: ${input?.url || ''}`;
|
|
294
|
+
default:
|
|
295
|
+
return `${toolName}`;
|
|
296
|
+
}
|
|
297
|
+
} catch {
|
|
298
|
+
return toolName;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Truncate string to max length
|
|
304
|
+
*/
|
|
305
|
+
export function truncate(str: string, maxLength: number = 1000): string {
|
|
306
|
+
if (str.length <= maxLength) return str;
|
|
307
|
+
return str.substring(0, maxLength) + '...[truncated]';
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Standard hook response (continue, no output)
|
|
312
|
+
*/
|
|
313
|
+
export const STANDARD_RESPONSE: ClaudeCodeHookResponse = {
|
|
314
|
+
continue: true,
|
|
315
|
+
suppressOutput: true,
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Format hook response for stdout
|
|
320
|
+
*/
|
|
321
|
+
export function formatResponse(result: HookResult): string {
|
|
322
|
+
if (result.additionalContext) {
|
|
323
|
+
return JSON.stringify({
|
|
324
|
+
hookSpecificOutput: {
|
|
325
|
+
hookEventName: 'SessionStart',
|
|
326
|
+
additionalContext: result.additionalContext,
|
|
327
|
+
},
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return JSON.stringify(STANDARD_RESPONSE);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Parse stdin input from Claude Code
|
|
336
|
+
*/
|
|
337
|
+
export function parseHookInput(stdin: string): NormalizedHookInput {
|
|
338
|
+
try {
|
|
339
|
+
const raw: ClaudeCodeHookInput = JSON.parse(stdin);
|
|
340
|
+
|
|
341
|
+
const cwd = raw.cwd || process.cwd();
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
sessionId: raw.session_id || `session_${Date.now()}`,
|
|
345
|
+
cwd,
|
|
346
|
+
project: getProjectName(cwd),
|
|
347
|
+
prompt: raw.prompt,
|
|
348
|
+
toolName: raw.tool_name,
|
|
349
|
+
toolInput: raw.tool_input,
|
|
350
|
+
toolResponse: raw.tool_result,
|
|
351
|
+
transcriptPath: raw.transcript_path,
|
|
352
|
+
stopReason: raw.stop_reason,
|
|
353
|
+
timestamp: Date.now(),
|
|
354
|
+
};
|
|
355
|
+
} catch {
|
|
356
|
+
// Fallback for empty or invalid input
|
|
357
|
+
const cwd = process.cwd();
|
|
358
|
+
return {
|
|
359
|
+
sessionId: `session_${Date.now()}`,
|
|
360
|
+
cwd,
|
|
361
|
+
project: getProjectName(cwd),
|
|
362
|
+
timestamp: Date.now(),
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
}
|