@cleocode/adapters 2026.4.38 → 2026.4.39

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.
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAI7D;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAkB,YAAW,mBAAmB;IAC3D,kCAAkC;IAClC,QAAQ,CAAC,EAAE,iBAAiB;IAC5B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,WAAW;IAE3B,+CAA+C;IAC/C,YAAY,EAAE,mBAAmB,CA6B/B;IAEF,8DAA8D;IAC9D,KAAK,EAAE,sBAAsB,CAAC;IAC9B,wEAAwE;IACxE,KAAK,EAAE,uBAAuB,CAAC;IAC/B,+EAA+E;IAC/E,OAAO,EAAE,yBAAyB,CAAC;IACnC,mEAAmE;IACnE,KAAK,EAAE,sBAAsB,CAAC;IAC9B,+EAA+E;IAC/E,cAAc,EAAE,gCAAgC,CAAC;IACjD,wDAAwD;IACxD,SAAS,EAAE,2BAA2B,CAAC;IACvC,2EAA2E;IAC3E,QAAQ,EAAE,0BAA0B,CAAC;IAErC,oEAAoE;IACpE,OAAO,CAAC,UAAU,CAAuB;IACzC,kDAAkD;IAClD,OAAO,CAAC,WAAW,CAAS;;IAY5B;;;;;;;OAOG;IACG,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B;;;;;;;;;OASG;IACG,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAyCjD;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;CAG/B"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAI7D;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAkB,YAAW,mBAAmB;IAC3D,kCAAkC;IAClC,QAAQ,CAAC,EAAE,iBAAiB;IAC5B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,WAAW;IAE3B,+CAA+C;IAC/C,YAAY,EAAE,mBAAmB,CA6B/B;IAEF,8DAA8D;IAC9D,KAAK,EAAE,sBAAsB,CAAC;IAC9B,wEAAwE;IACxE,KAAK,EAAE,uBAAuB,CAAC;IAC/B,+EAA+E;IAC/E,OAAO,EAAE,yBAAyB,CAAC;IACnC,mEAAmE;IACnE,KAAK,EAAE,sBAAsB,CAAC;IAC9B,+EAA+E;IAC/E,cAAc,EAAE,gCAAgC,CAAC;IACjD,wDAAwD;IACxD,SAAS,EAAE,2BAA2B,CAAC;IACvC,2EAA2E;IAC3E,QAAQ,EAAE,0BAA0B,CAAC;IAErC,oEAAoE;IACpE,OAAO,CAAC,UAAU,CAAuB;IACzC,kDAAkD;IAClD,OAAO,CAAC,WAAW,CAAS;;IAY5B;;;;;;;OAOG;IACG,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASnD;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B;;;;;;;;;OASG;IACG,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAyCjD;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;CAG/B"}
@@ -55,33 +55,45 @@ export declare class ClaudeCodeHookProvider implements AdapterHookProvider {
55
55
  * @task T164
56
56
  */
57
57
  mapProviderEvent(providerEvent: string): string | null;
58
+ /** Project directory this hook provider was registered for. */
59
+ private projectDir;
58
60
  /**
59
61
  * Register native hooks for a project.
60
62
  *
61
- * For Claude Code, hooks are registered via the config system
62
- * (`~/.claude/settings.json`), managed by the install provider.
63
- * This method marks hooks as registered without performing filesystem operations.
63
+ * Writes CLEO hook entries to `~/.claude/settings.json` so that Claude Code's
64
+ * native event system calls cleo CLI commands when events fire. This bridges
65
+ * Claude Code's event loop to CLEO's internal hook dispatch.
64
66
  *
65
- * Iterating supported events is handled at install time using
66
- * `getSupportedCanonicalEvents()` to enumerate all 14 supported hooks.
67
+ * Idempotent: skips writing if CLEO hooks already exist in settings.json.
67
68
  *
68
- * @param _projectDir - Project directory (unused; Claude Code uses global config)
69
- * @task T164
69
+ * Hook entries registered:
70
+ * - `Stop` → `cleo session end --quiet` (triggers LLM extraction, reflector, consolidation)
71
+ * - `PostToolUse` (Write|Edit) → brain observation for file modifications
72
+ * - `SubagentStop` → brain observation for agent completion
73
+ *
74
+ * @param projectDir - Project directory for context-scoped hook commands
75
+ * @task T164 @task T555
70
76
  */
71
- registerNativeHooks(_projectDir: string): Promise<void>;
77
+ registerNativeHooks(projectDir: string): Promise<void>;
72
78
  /**
73
79
  * Unregister native hooks.
74
80
  *
75
- * For Claude Code, this is a no-op since hooks are managed through the config
76
- * system. Unregistration happens via the install provider's uninstall method.
81
+ * Removes CLEO hook entries from `~/.claude/settings.json` by filtering out
82
+ * entries containing the `# cleo-hook` marker.
77
83
  *
78
- * @task T164
84
+ * @task T164 @task T555
79
85
  */
80
86
  unregisterNativeHooks(): Promise<void>;
81
87
  /**
82
88
  * Check whether hooks have been registered via `registerNativeHooks`.
83
89
  */
84
90
  isRegistered(): boolean;
91
+ /**
92
+ * Get the project directory this hook provider was registered for.
93
+ *
94
+ * Returns null if hooks have not been registered yet.
95
+ */
96
+ getProjectDir(): string | null;
85
97
  /**
86
98
  * Get the native→canonical event mapping for introspection and debugging.
87
99
  *
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AA8C/D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,sBAAuB,YAAW,mBAAmB;IAChE,kEAAkE;IAClE,OAAO,CAAC,UAAU,CAAS;IAE3B;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItD;;;;;;;;;;;;OAYG;IACG,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7D;;;;;;;OAOG;IACG,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5C;;OAEG;IACH,YAAY,IAAI,OAAO;IAIvB;;;;;;;;OAQG;IACH,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAI/C;;;;;;;;;;OAUG;IACG,2BAA2B,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAStD;;;;;;;;;;OAUG;IACG,kBAAkB,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IASnD;;;;;;;;;;OAUG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAW9D;;;;;;;;;;;;OAYG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CA2DrF"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AA8C/D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,sBAAuB,YAAW,mBAAmB;IAChE,kEAAkE;IAClE,OAAO,CAAC,UAAU,CAAS;IAE3B;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItD,+DAA+D;IAC/D,OAAO,CAAC,UAAU,CAAuB;IAEzC;;;;;;;;;;;;;;;;OAgBG;IACG,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsE5D;;;;;;;OAOG;IACG,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IA2C5C;;OAEG;IACH,YAAY,IAAI,OAAO;IAIvB;;;;OAIG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;IAI9B;;;;;;;;OAQG;IACH,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAI/C;;;;;;;;;;OAUG;IACG,2BAA2B,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAStD;;;;;;;;;;OAUG;IACG,kBAAkB,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IASnD;;;;;;;;;;OAUG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAW9D;;;;;;;;;;;;OAYG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CA2DrF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleocode/adapters",
3
- "version": "2026.4.38",
3
+ "version": "2026.4.39",
4
4
  "description": "Unified provider adapters for CLEO (Claude Code, OpenCode, Cursor)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,8 +12,8 @@
12
12
  }
13
13
  },
14
14
  "dependencies": {
15
- "@cleocode/caamp": "2026.4.38",
16
- "@cleocode/contracts": "2026.4.38"
15
+ "@cleocode/caamp": "2026.4.39",
16
+ "@cleocode/contracts": "2026.4.39"
17
17
  },
18
18
  "license": "MIT",
19
19
  "engines": {
@@ -123,6 +123,10 @@ export class ClaudeCodeAdapter implements CLEOProviderAdapter {
123
123
  async initialize(projectDir: string): Promise<void> {
124
124
  this.projectDir = projectDir;
125
125
  this.initialized = true;
126
+
127
+ // Activate CLEO hook bridge for this project — connects Claude Code
128
+ // native events to CLEO's internal hook dispatch (T555).
129
+ await this.hooks.registerNativeHooks(projectDir);
126
130
  }
127
131
 
128
132
  /**
@@ -16,7 +16,9 @@
16
16
  * @epic T134
17
17
  */
18
18
 
19
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
19
20
  import { readdir, readFile } from 'node:fs/promises';
21
+ import { homedir } from 'node:os';
20
22
  import { join } from 'node:path';
21
23
  import type { AdapterHookProvider } from '@cleocode/contracts';
22
24
 
@@ -107,33 +109,145 @@ export class ClaudeCodeHookProvider implements AdapterHookProvider {
107
109
  return CLAUDE_CODE_EVENT_MAP[providerEvent] ?? null;
108
110
  }
109
111
 
112
+ /** Project directory this hook provider was registered for. */
113
+ private projectDir: string | null = null;
114
+
110
115
  /**
111
116
  * Register native hooks for a project.
112
117
  *
113
- * For Claude Code, hooks are registered via the config system
114
- * (`~/.claude/settings.json`), managed by the install provider.
115
- * This method marks hooks as registered without performing filesystem operations.
118
+ * Writes CLEO hook entries to `~/.claude/settings.json` so that Claude Code's
119
+ * native event system calls cleo CLI commands when events fire. This bridges
120
+ * Claude Code's event loop to CLEO's internal hook dispatch.
116
121
  *
117
- * Iterating supported events is handled at install time using
118
- * `getSupportedCanonicalEvents()` to enumerate all 14 supported hooks.
122
+ * Idempotent: skips writing if CLEO hooks already exist in settings.json.
119
123
  *
120
- * @param _projectDir - Project directory (unused; Claude Code uses global config)
121
- * @task T164
124
+ * Hook entries registered:
125
+ * - `Stop` → `cleo session end --quiet` (triggers LLM extraction, reflector, consolidation)
126
+ * - `PostToolUse` (Write|Edit) → brain observation for file modifications
127
+ * - `SubagentStop` → brain observation for agent completion
128
+ *
129
+ * @param projectDir - Project directory for context-scoped hook commands
130
+ * @task T164 @task T555
122
131
  */
123
- async registerNativeHooks(_projectDir: string): Promise<void> {
132
+ async registerNativeHooks(projectDir: string): Promise<void> {
133
+ this.projectDir = projectDir;
124
134
  this.registered = true;
135
+
136
+ // Write CLEO hook entries to ~/.claude/settings.json (idempotent)
137
+ try {
138
+ const home = homedir();
139
+ const settingsPath = join(home, '.claude', 'settings.json');
140
+
141
+ let settings: Record<string, unknown> = {};
142
+ if (existsSync(settingsPath)) {
143
+ try {
144
+ settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
145
+ } catch {
146
+ // Start fresh if settings.json is corrupt
147
+ }
148
+ }
149
+
150
+ const hooks = (settings.hooks ?? {}) as Record<string, unknown[]>;
151
+
152
+ // Check if CLEO hooks already registered (look for our marker comment in commands)
153
+ const alreadyRegistered = Object.values(hooks).some((entries) =>
154
+ Array.isArray(entries) &&
155
+ entries.some(
156
+ (e) =>
157
+ typeof e === 'object' &&
158
+ e !== null &&
159
+ Array.isArray((e as Record<string, unknown>).hooks) &&
160
+ ((e as Record<string, unknown>).hooks as Array<Record<string, string>>).some(
161
+ (h) => typeof h.command === 'string' && h.command.includes('# cleo-hook'),
162
+ ),
163
+ ),
164
+ );
165
+
166
+ if (alreadyRegistered) {
167
+ return; // Already wired — idempotent
168
+ }
169
+
170
+ // Register Stop hook → triggers cleo session end (LLM extraction, reflector, consolidation)
171
+ if (!hooks.Stop) hooks.Stop = [];
172
+ (hooks.Stop as unknown[]).push({
173
+ matcher: '',
174
+ hooks: [
175
+ {
176
+ type: 'command',
177
+ command: `cleo session end --quiet # cleo-hook`,
178
+ },
179
+ ],
180
+ });
181
+
182
+ // Register PostToolUse hook → brain observation for file writes
183
+ if (!hooks.PostToolUse) hooks.PostToolUse = [];
184
+ (hooks.PostToolUse as unknown[]).push({
185
+ matcher: 'Write|Edit',
186
+ hooks: [
187
+ {
188
+ type: 'command',
189
+ command: `cleo observe "File modified via $TOOL_NAME" --title "tool-use" --quiet # cleo-hook`,
190
+ },
191
+ ],
192
+ });
193
+
194
+ settings.hooks = hooks;
195
+ mkdirSync(join(home, '.claude'), { recursive: true });
196
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
197
+ } catch {
198
+ // Settings write failure is non-fatal — hooks can be registered manually
199
+ }
125
200
  }
126
201
 
127
202
  /**
128
203
  * Unregister native hooks.
129
204
  *
130
- * For Claude Code, this is a no-op since hooks are managed through the config
131
- * system. Unregistration happens via the install provider's uninstall method.
205
+ * Removes CLEO hook entries from `~/.claude/settings.json` by filtering out
206
+ * entries containing the `# cleo-hook` marker.
132
207
  *
133
- * @task T164
208
+ * @task T164 @task T555
134
209
  */
135
210
  async unregisterNativeHooks(): Promise<void> {
136
211
  this.registered = false;
212
+ this.projectDir = null;
213
+
214
+ try {
215
+ const home = homedir();
216
+ const settingsPath = join(home, '.claude', 'settings.json');
217
+ if (!existsSync(settingsPath)) return;
218
+
219
+ const settings = JSON.parse(readFileSync(settingsPath, 'utf-8')) as Record<string, unknown>;
220
+ const hooks = settings.hooks as Record<string, unknown[]> | undefined;
221
+ if (!hooks) return;
222
+
223
+ // Filter out entries with the cleo-hook marker
224
+ let changed = false;
225
+ for (const [event, entries] of Object.entries(hooks)) {
226
+ if (!Array.isArray(entries)) continue;
227
+ const filtered = entries.filter(
228
+ (e) =>
229
+ !(
230
+ typeof e === 'object' &&
231
+ e !== null &&
232
+ Array.isArray((e as Record<string, unknown>).hooks) &&
233
+ ((e as Record<string, unknown>).hooks as Array<Record<string, string>>).some(
234
+ (h) => typeof h.command === 'string' && h.command.includes('# cleo-hook'),
235
+ )
236
+ ),
237
+ );
238
+ if (filtered.length !== entries.length) {
239
+ hooks[event] = filtered;
240
+ changed = true;
241
+ }
242
+ }
243
+
244
+ if (changed) {
245
+ settings.hooks = hooks;
246
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
247
+ }
248
+ } catch {
249
+ // Cleanup failure is non-fatal
250
+ }
137
251
  }
138
252
 
139
253
  /**
@@ -143,6 +257,15 @@ export class ClaudeCodeHookProvider implements AdapterHookProvider {
143
257
  return this.registered;
144
258
  }
145
259
 
260
+ /**
261
+ * Get the project directory this hook provider was registered for.
262
+ *
263
+ * Returns null if hooks have not been registered yet.
264
+ */
265
+ getProjectDir(): string | null {
266
+ return this.projectDir;
267
+ }
268
+
146
269
  /**
147
270
  * Get the native→canonical event mapping for introspection and debugging.
148
271
  *