@cleocode/core 2026.3.72 → 2026.3.73

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 (48) hide show
  1. package/dist/hooks/handlers/agent-hooks.d.ts +48 -0
  2. package/dist/hooks/handlers/agent-hooks.d.ts.map +1 -0
  3. package/dist/hooks/handlers/context-hooks.d.ts +53 -0
  4. package/dist/hooks/handlers/context-hooks.d.ts.map +1 -0
  5. package/dist/hooks/handlers/error-hooks.d.ts +4 -4
  6. package/dist/hooks/handlers/error-hooks.d.ts.map +1 -1
  7. package/dist/hooks/handlers/file-hooks.d.ts +3 -3
  8. package/dist/hooks/handlers/file-hooks.d.ts.map +1 -1
  9. package/dist/hooks/handlers/index.d.ts +8 -1
  10. package/dist/hooks/handlers/index.d.ts.map +1 -1
  11. package/dist/hooks/handlers/mcp-hooks.d.ts +29 -7
  12. package/dist/hooks/handlers/mcp-hooks.d.ts.map +1 -1
  13. package/dist/hooks/handlers/session-hooks.d.ts +5 -5
  14. package/dist/hooks/handlers/session-hooks.d.ts.map +1 -1
  15. package/dist/hooks/handlers/task-hooks.d.ts +5 -5
  16. package/dist/hooks/handlers/task-hooks.d.ts.map +1 -1
  17. package/dist/hooks/handlers/work-capture-hooks.d.ts +7 -7
  18. package/dist/hooks/handlers/work-capture-hooks.d.ts.map +1 -1
  19. package/dist/hooks/payload-schemas.d.ts +177 -11
  20. package/dist/hooks/payload-schemas.d.ts.map +1 -1
  21. package/dist/hooks/provider-hooks.d.ts +33 -7
  22. package/dist/hooks/provider-hooks.d.ts.map +1 -1
  23. package/dist/hooks/registry.d.ts +26 -6
  24. package/dist/hooks/registry.d.ts.map +1 -1
  25. package/dist/hooks/types.d.ts +132 -38
  26. package/dist/hooks/types.d.ts.map +1 -1
  27. package/dist/index.js +335 -59
  28. package/dist/index.js.map +4 -4
  29. package/dist/sessions/snapshot.d.ts.map +1 -1
  30. package/package.json +6 -6
  31. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.ts +634 -0
  32. package/src/hooks/handlers/agent-hooks.ts +148 -0
  33. package/src/hooks/handlers/context-hooks.ts +156 -0
  34. package/src/hooks/handlers/error-hooks.ts +8 -5
  35. package/src/hooks/handlers/file-hooks.ts +6 -4
  36. package/src/hooks/handlers/index.ts +12 -1
  37. package/src/hooks/handlers/mcp-hooks.ts +74 -9
  38. package/src/hooks/handlers/session-hooks.ts +7 -7
  39. package/src/hooks/handlers/task-hooks.ts +7 -7
  40. package/src/hooks/handlers/work-capture-hooks.ts +12 -12
  41. package/src/hooks/payload-schemas.ts +96 -26
  42. package/src/hooks/provider-hooks.ts +50 -9
  43. package/src/hooks/registry.ts +86 -23
  44. package/src/hooks/types.ts +175 -39
  45. package/src/sessions/index.ts +4 -4
  46. package/src/sessions/snapshot.ts +4 -2
  47. package/src/store/json.ts +2 -2
  48. package/src/task-work/index.ts +4 -4
@@ -2,21 +2,41 @@
2
2
  * Universal Hooks Core Types - Phase 2B of T5237
3
3
  *
4
4
  * This module defines the core type system for CLEO's Universal Hooks
5
- * integration with CAAMP 1.6.0. CLEO builds the hook registry and
6
- * execution system while CAAMP provides the event definitions.
5
+ * integration with CAAMP 1.9.1. CLEO builds the hook registry and
6
+ * execution system while CAAMP provides the canonical event definitions.
7
7
  *
8
8
  * @module @cleocode/cleo/hooks/types
9
9
  */
10
10
 
11
- import type { HookEvent as CAAMPHookEvent } from '@cleocode/caamp';
11
+ import type { CanonicalHookEvent } from '@cleocode/caamp';
12
+ import {
13
+ buildHookMatrix,
14
+ CANONICAL_HOOK_EVENTS,
15
+ HOOK_CATEGORIES,
16
+ supportsHook,
17
+ toCanonical,
18
+ toNative,
19
+ } from '@cleocode/caamp';
12
20
 
13
21
  // Re-export CAAMP provider query functions for hook capability discovery
14
22
  export { getCommonHookEvents, getProvidersByHookEvent } from '@cleocode/caamp';
23
+ export type { CanonicalHookEvent };
24
+ // Re-export CAAMP canonical event constants and normalizer APIs
25
+ export {
26
+ buildHookMatrix,
27
+ CANONICAL_HOOK_EVENTS,
28
+ HOOK_CATEGORIES,
29
+ supportsHook,
30
+ toCanonical,
31
+ toNative,
32
+ };
15
33
 
16
34
  /**
17
- * CAAMP-defined hook events supported by provider capability discovery.
35
+ * CAAMP canonical hook event type.
36
+ *
37
+ * This is the normalized 16-event taxonomy from CAAMP 1.9.1.
18
38
  */
19
- export type ProviderHookEvent = CAAMPHookEvent;
39
+ export type ProviderHookEvent = CanonicalHookEvent;
20
40
 
21
41
  /**
22
42
  * CLEO-local coordination events used by the autonomous runtime.
@@ -37,15 +57,15 @@ export type InternalHookEvent = (typeof INTERNAL_HOOK_EVENTS)[number];
37
57
  /**
38
58
  * Full CLEO hook event union.
39
59
  *
40
- * CAAMP defines provider-facing events; CLEO extends the registry with local
41
- * coordination events for autonomous execution.
60
+ * CAAMP defines provider-facing canonical events; CLEO extends the registry
61
+ * with local coordination events for autonomous execution.
42
62
  */
43
63
  export type HookEvent = ProviderHookEvent | InternalHookEvent;
44
64
 
45
65
  const INTERNAL_HOOK_EVENT_SET = new Set<string>(INTERNAL_HOOK_EVENTS);
46
66
 
47
67
  /**
48
- * Type guard for CAAMP/provider-discoverable hook events.
68
+ * Type guard for CAAMP/provider-discoverable canonical hook events.
49
69
  */
50
70
  export function isProviderHookEvent(event: HookEvent): event is ProviderHookEvent {
51
71
  return !INTERNAL_HOOK_EVENT_SET.has(event);
@@ -80,10 +100,10 @@ export interface HookPayload {
80
100
  }
81
101
 
82
102
  /**
83
- * Payload for onSessionStart hook
103
+ * Payload for SessionStart hook (canonical: was onSessionStart)
84
104
  * Fired when a CLEO session begins
85
105
  */
86
- export interface OnSessionStartPayload extends HookPayload {
106
+ export interface SessionStartPayload extends HookPayload {
87
107
  /** Session identifier (required for session events) */
88
108
  sessionId: string;
89
109
 
@@ -97,11 +117,14 @@ export interface OnSessionStartPayload extends HookPayload {
97
117
  agent?: string;
98
118
  }
99
119
 
120
+ /** @deprecated Use {@link SessionStartPayload} instead. Kept for backward compatibility. */
121
+ export type OnSessionStartPayload = SessionStartPayload;
122
+
100
123
  /**
101
- * Payload for onSessionEnd hook
124
+ * Payload for SessionEnd hook (canonical: was onSessionEnd)
102
125
  * Fired when a CLEO session ends
103
126
  */
104
- export interface OnSessionEndPayload extends HookPayload {
127
+ export interface SessionEndPayload extends HookPayload {
105
128
  /** Session identifier */
106
129
  sessionId: string;
107
130
 
@@ -112,11 +135,14 @@ export interface OnSessionEndPayload extends HookPayload {
112
135
  tasksCompleted: string[];
113
136
  }
114
137
 
138
+ /** @deprecated Use {@link SessionEndPayload} instead. Kept for backward compatibility. */
139
+ export type OnSessionEndPayload = SessionEndPayload;
140
+
115
141
  /**
116
- * Payload for onToolStart hook
142
+ * Payload for PreToolUse hook (canonical: was onToolStart)
117
143
  * Fired when a task/tool operation begins
118
144
  */
119
- export interface OnToolStartPayload extends HookPayload {
145
+ export interface PreToolUsePayload extends HookPayload {
120
146
  /** Task identifier */
121
147
  taskId: string;
122
148
 
@@ -125,13 +151,22 @@ export interface OnToolStartPayload extends HookPayload {
125
151
 
126
152
  /** Optional ID of the previous task if sequential */
127
153
  previousTask?: string;
154
+
155
+ /** Optional tool name being invoked */
156
+ toolName?: string;
157
+
158
+ /** Optional structured input to the tool */
159
+ toolInput?: Record<string, unknown>;
128
160
  }
129
161
 
162
+ /** @deprecated Use {@link PreToolUsePayload} instead. Kept for backward compatibility. */
163
+ export type OnToolStartPayload = PreToolUsePayload;
164
+
130
165
  /**
131
- * Payload for onToolComplete hook
166
+ * Payload for PostToolUse hook (canonical: was onToolComplete)
132
167
  * Fired when a task/tool operation completes
133
168
  */
134
- export interface OnToolCompletePayload extends HookPayload {
169
+ export interface PostToolUsePayload extends HookPayload {
135
170
  /** Task identifier */
136
171
  taskId: string;
137
172
 
@@ -140,8 +175,14 @@ export interface OnToolCompletePayload extends HookPayload {
140
175
 
141
176
  /** Final status of the completed task */
142
177
  status: 'done' | 'archived' | 'cancelled';
178
+
179
+ /** Optional structured result from the tool */
180
+ toolResult?: Record<string, unknown>;
143
181
  }
144
182
 
183
+ /** @deprecated Use {@link PostToolUsePayload} instead. Kept for backward compatibility. */
184
+ export type OnToolCompletePayload = PostToolUsePayload;
185
+
145
186
  /**
146
187
  * Handler function type for hook events
147
188
  * Handlers receive project root and typed payload
@@ -182,25 +223,35 @@ export interface HookConfig {
182
223
  }
183
224
 
184
225
  /**
185
- * Payload for onFileChange hook
186
- * Fired when a tracked file is written, created, or deleted
226
+ * Payload for Notification hook (canonical: was onFileChange)
227
+ * Fired when a tracked file is written, created, or deleted, or for
228
+ * general-purpose notifications.
187
229
  */
188
- export interface OnFileChangePayload extends HookPayload {
230
+ export interface NotificationPayload extends HookPayload {
189
231
  /** Absolute or project-relative path of the changed file */
190
- filePath: string;
232
+ filePath?: string;
191
233
 
192
- /** Kind of filesystem change */
193
- changeType: 'write' | 'create' | 'delete';
234
+ /** Kind of filesystem change (for file-change notifications) */
235
+ changeType?: 'write' | 'create' | 'delete';
194
236
 
195
237
  /** File size in bytes after the change (absent for deletes) */
196
238
  sizeBytes?: number;
239
+
240
+ /** Optional notification message for non-file notifications */
241
+ message?: string;
197
242
  }
198
243
 
244
+ /** @deprecated Use {@link NotificationPayload} instead. Kept for backward compatibility. */
245
+ export type OnFileChangePayload = NotificationPayload & {
246
+ filePath: string;
247
+ changeType: 'write' | 'create' | 'delete';
248
+ };
249
+
199
250
  /**
200
- * Payload for onError hook
251
+ * Payload for PostToolUseFailure hook (canonical: was onError)
201
252
  * Fired when an operation fails with a structured error
202
253
  */
203
- export interface OnErrorPayload extends HookPayload {
254
+ export interface PostToolUseFailurePayload extends HookPayload {
204
255
  /** Numeric exit code or string error code */
205
256
  errorCode: number | string;
206
257
 
@@ -220,11 +271,14 @@ export interface OnErrorPayload extends HookPayload {
220
271
  stack?: string;
221
272
  }
222
273
 
274
+ /** @deprecated Use {@link PostToolUseFailurePayload} instead. Kept for backward compatibility. */
275
+ export type OnErrorPayload = PostToolUseFailurePayload;
276
+
223
277
  /**
224
- * Payload for onPromptSubmit hook
278
+ * Payload for PromptSubmit hook (canonical: was onPromptSubmit)
225
279
  * Fired when an agent submits a prompt through a gateway
226
280
  */
227
- export interface OnPromptSubmitPayload extends HookPayload {
281
+ export interface PromptSubmitPayload extends HookPayload {
228
282
  /** Gateway that received the prompt (query / mutate) */
229
283
  gateway: string;
230
284
 
@@ -238,11 +292,14 @@ export interface OnPromptSubmitPayload extends HookPayload {
238
292
  source?: string;
239
293
  }
240
294
 
295
+ /** @deprecated Use {@link PromptSubmitPayload} instead. Kept for backward compatibility. */
296
+ export type OnPromptSubmitPayload = PromptSubmitPayload;
297
+
241
298
  /**
242
- * Payload for onResponseComplete hook
299
+ * Payload for ResponseComplete hook (canonical: was onResponseComplete)
243
300
  * Fired when a gateway operation finishes (success or failure)
244
301
  */
245
- export interface OnResponseCompletePayload extends HookPayload {
302
+ export interface ResponseCompletePayload extends HookPayload {
246
303
  /** Gateway that handled the operation */
247
304
  gateway: string;
248
305
 
@@ -262,6 +319,84 @@ export interface OnResponseCompletePayload extends HookPayload {
262
319
  errorCode?: string;
263
320
  }
264
321
 
322
+ /** @deprecated Use {@link ResponseCompletePayload} instead. Kept for backward compatibility. */
323
+ export type OnResponseCompletePayload = ResponseCompletePayload;
324
+
325
+ /**
326
+ * Payload for SubagentStart hook
327
+ * Fired when a subagent process is launched
328
+ */
329
+ export interface SubagentStartPayload extends HookPayload {
330
+ /** Subagent or worker identifier */
331
+ agentId: string;
332
+
333
+ /** Subagent role or archetype */
334
+ role?: string;
335
+
336
+ /** Task assigned to the subagent */
337
+ taskId?: string;
338
+ }
339
+
340
+ /**
341
+ * Payload for SubagentStop hook
342
+ * Fired when a subagent process completes
343
+ */
344
+ export interface SubagentStopPayload extends HookPayload {
345
+ /** Subagent or worker identifier */
346
+ agentId: string;
347
+
348
+ /** Completion status */
349
+ status?: 'complete' | 'partial' | 'blocked' | 'failed';
350
+
351
+ /** Task that was completed */
352
+ taskId?: string;
353
+
354
+ /** Optional summary reference */
355
+ summary?: string;
356
+ }
357
+
358
+ /**
359
+ * Payload for PreCompact hook
360
+ * Fired before context compaction begins
361
+ */
362
+ export interface PreCompactPayload extends HookPayload {
363
+ /** Estimated token count before compaction */
364
+ tokensBefore?: number;
365
+
366
+ /** Reason for compaction */
367
+ reason?: string;
368
+ }
369
+
370
+ /**
371
+ * Payload for PostCompact hook
372
+ * Fired after context compaction completes
373
+ */
374
+ export interface PostCompactPayload extends HookPayload {
375
+ /** Token count before compaction */
376
+ tokensBefore?: number;
377
+
378
+ /** Token count after compaction */
379
+ tokensAfter?: number;
380
+
381
+ /** Whether compaction succeeded */
382
+ success: boolean;
383
+ }
384
+
385
+ /**
386
+ * Payload for ConfigChange hook
387
+ * Fired when configuration is updated
388
+ */
389
+ export interface ConfigChangePayload extends HookPayload {
390
+ /** Configuration key that changed */
391
+ key: string;
392
+
393
+ /** Previous value */
394
+ previousValue?: unknown;
395
+
396
+ /** New value */
397
+ newValue?: unknown;
398
+ }
399
+
265
400
  /**
266
401
  * Payload for onWorkAvailable hook
267
402
  * Fired when the system detects ready work on a Loom/Tapestry
@@ -353,19 +488,20 @@ export interface OnPatrolPayload extends HookPayload {
353
488
  }
354
489
 
355
490
  /**
356
- * Mapping from CLEO internal lifecycle events to CAAMP hook events
357
- * This is where CLEO connects its lifecycle to CAAMP's event definitions
491
+ * Mapping from CLEO internal lifecycle events to CAAMP canonical hook event names.
492
+ *
493
+ * Updated for CAAMP 1.9.1 canonical taxonomy.
358
494
  */
359
495
  export const CLEO_TO_CAAMP_HOOK_MAP = {
360
- 'session.start': 'onSessionStart',
361
- 'session.end': 'onSessionEnd',
362
- 'task.start': 'onToolStart',
363
- 'task.complete': 'onToolComplete',
364
- 'file.change': 'onFileChange',
365
- 'system.error': 'onError',
366
- 'prompt.submit': 'onPromptSubmit',
367
- 'response.complete': 'onResponseComplete',
368
- } as const;
496
+ 'session.start': 'SessionStart',
497
+ 'session.end': 'SessionEnd',
498
+ 'task.start': 'PreToolUse',
499
+ 'task.complete': 'PostToolUse',
500
+ 'file.change': 'Notification',
501
+ 'system.error': 'PostToolUseFailure',
502
+ 'prompt.submit': 'PromptSubmit',
503
+ 'response.complete': 'ResponseComplete',
504
+ } as const satisfies Record<string, CanonicalHookEvent>;
369
505
 
370
506
  /**
371
507
  * Internal CLEO lifecycle events that drive autonomous coordination.
@@ -170,10 +170,10 @@ export async function startSession(
170
170
  });
171
171
  }
172
172
 
173
- // Dispatch onSessionStart hook (best-effort, don't await)
173
+ // Dispatch SessionStart hook (best-effort, don't await)
174
174
  const { hooks } = await import('../hooks/registry.js');
175
175
  hooks
176
- .dispatch('onSessionStart', cwd ?? process.cwd(), {
176
+ .dispatch('SessionStart', cwd ?? process.cwd(), {
177
177
  timestamp: new Date().toISOString(),
178
178
  sessionId: session.id,
179
179
  name: options.name,
@@ -233,10 +233,10 @@ export async function endSession(
233
233
 
234
234
  const duration = Math.floor((Date.now() - new Date(session.startedAt).getTime()) / 1000);
235
235
 
236
- // Dispatch onSessionEnd hook (best-effort, don't await)
236
+ // Dispatch SessionEnd hook (best-effort, don't await)
237
237
  const { hooks } = await import('../hooks/registry.js');
238
238
  hooks
239
- .dispatch('onSessionEnd', cwd ?? process.cwd(), {
239
+ .dispatch('SessionEnd', cwd ?? process.cwd(), {
240
240
  timestamp: new Date().toISOString(),
241
241
  sessionId: session.id,
242
242
  duration,
@@ -209,7 +209,9 @@ export async function serializeSession(
209
209
  status: task.status,
210
210
  priority: task.priority ?? 'medium',
211
211
  description: desc.length > maxDescLen ? desc.slice(0, maxDescLen) + '...' : desc,
212
- acceptance: Array.isArray(task.acceptance) ? task.acceptance.join('\n') : (task.acceptance ?? undefined),
212
+ acceptance: Array.isArray(task.acceptance)
213
+ ? task.acceptance.join('\n')
214
+ : (task.acceptance ?? undefined),
213
215
  };
214
216
  }
215
217
  } catch {
@@ -324,7 +326,7 @@ export async function restoreSession(
324
326
  // Dispatch hook (best-effort)
325
327
  try {
326
328
  const { hooks } = await import('../hooks/registry.js');
327
- await hooks.dispatch('onSessionStart', projectRoot, {
329
+ await hooks.dispatch('SessionStart', projectRoot, {
328
330
  timestamp: new Date().toISOString(),
329
331
  sessionId: restoredSession.id,
330
332
  name: restoredSession.name,
package/src/store/json.ts CHANGED
@@ -100,10 +100,10 @@ export async function saveJson(
100
100
  // Atomic write
101
101
  await atomicWriteJson(filePath, data, { indent: options?.indent });
102
102
 
103
- // Dispatch onFileChange hook (best-effort, fire-and-forget)
103
+ // Dispatch Notification hook (best-effort, fire-and-forget)
104
104
  import('../hooks/registry.js')
105
105
  .then(({ hooks: h }) =>
106
- h.dispatch('onFileChange', process.cwd(), {
106
+ h.dispatch('Notification', process.cwd(), {
107
107
  timestamp: new Date().toISOString(),
108
108
  filePath,
109
109
  changeType: 'write' as const,
@@ -123,10 +123,10 @@ export async function startTask(
123
123
  accessor,
124
124
  );
125
125
 
126
- // Dispatch onToolStart hook (best-effort, don't await)
126
+ // Dispatch PreToolUse hook (best-effort, don't await)
127
127
  const { hooks } = await import('../hooks/registry.js');
128
128
  hooks
129
- .dispatch('onToolStart', cwd ?? process.cwd(), {
129
+ .dispatch('PreToolUse', cwd ?? process.cwd(), {
130
130
  timestamp: new Date().toISOString(),
131
131
  taskId,
132
132
  taskTitle: task.title,
@@ -169,11 +169,11 @@ export async function stopTask(
169
169
 
170
170
  const now = new Date().toISOString();
171
171
 
172
- // Dispatch onToolComplete hook (best-effort, don't await)
172
+ // Dispatch PostToolUse hook (best-effort, don't await)
173
173
  if (taskId && task) {
174
174
  const { hooks } = await import('../hooks/registry.js');
175
175
  hooks
176
- .dispatch('onToolComplete', cwd ?? process.cwd(), {
176
+ .dispatch('PostToolUse', cwd ?? process.cwd(), {
177
177
  timestamp: now,
178
178
  taskId,
179
179
  taskTitle: task.title,