@cleocode/adapters 2026.4.11 → 2026.4.12

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 (159) hide show
  1. package/package.json +3 -3
  2. package/src/__tests__/claude-code-adapter.test.ts +1 -3
  3. package/src/__tests__/cursor-adapter.test.ts +1 -3
  4. package/src/__tests__/opencode-adapter.test.ts +1 -3
  5. package/src/providers/claude-code/__tests__/adapter.test.ts +0 -12
  6. package/src/providers/claude-code/adapter.ts +0 -1
  7. package/src/providers/claude-code/install.ts +0 -1
  8. package/src/providers/codex/adapter.ts +0 -1
  9. package/src/providers/codex/install.ts +0 -1
  10. package/src/providers/cursor/__tests__/adapter.test.ts +0 -12
  11. package/src/providers/cursor/adapter.ts +0 -1
  12. package/src/providers/cursor/install.ts +0 -1
  13. package/src/providers/gemini-cli/adapter.ts +0 -1
  14. package/src/providers/gemini-cli/install.ts +0 -1
  15. package/src/providers/kimi/adapter.ts +0 -1
  16. package/src/providers/kimi/install.ts +0 -1
  17. package/src/providers/opencode/__tests__/adapter.test.ts +0 -12
  18. package/src/providers/opencode/adapter.ts +0 -1
  19. package/src/providers/opencode/install.ts +0 -1
  20. package/dist/index.d.ts +0 -23
  21. package/dist/index.d.ts.map +0 -1
  22. package/dist/index.js +0 -3258
  23. package/dist/index.js.map +0 -7
  24. package/dist/providers/claude-code/adapter.d.ts +0 -95
  25. package/dist/providers/claude-code/adapter.d.ts.map +0 -1
  26. package/dist/providers/claude-code/adapter.js +0 -185
  27. package/dist/providers/claude-code/adapter.js.map +0 -1
  28. package/dist/providers/claude-code/context-monitor.d.ts +0 -35
  29. package/dist/providers/claude-code/context-monitor.d.ts.map +0 -1
  30. package/dist/providers/claude-code/context-monitor.js +0 -159
  31. package/dist/providers/claude-code/context-monitor.js.map +0 -1
  32. package/dist/providers/claude-code/hooks.d.ts +0 -146
  33. package/dist/providers/claude-code/hooks.d.ts.map +0 -1
  34. package/dist/providers/claude-code/hooks.js +0 -286
  35. package/dist/providers/claude-code/hooks.js.map +0 -1
  36. package/dist/providers/claude-code/index.d.ts +0 -39
  37. package/dist/providers/claude-code/index.d.ts.map +0 -1
  38. package/dist/providers/claude-code/index.js +0 -41
  39. package/dist/providers/claude-code/index.js.map +0 -1
  40. package/dist/providers/claude-code/install.d.ts +0 -67
  41. package/dist/providers/claude-code/install.d.ts.map +0 -1
  42. package/dist/providers/claude-code/install.js +0 -161
  43. package/dist/providers/claude-code/install.js.map +0 -1
  44. package/dist/providers/claude-code/paths.d.ts +0 -32
  45. package/dist/providers/claude-code/paths.d.ts.map +0 -1
  46. package/dist/providers/claude-code/paths.js +0 -41
  47. package/dist/providers/claude-code/paths.js.map +0 -1
  48. package/dist/providers/claude-code/spawn.d.ts +0 -67
  49. package/dist/providers/claude-code/spawn.d.ts.map +0 -1
  50. package/dist/providers/claude-code/spawn.js +0 -171
  51. package/dist/providers/claude-code/spawn.js.map +0 -1
  52. package/dist/providers/claude-code/statusline.d.ts +0 -68
  53. package/dist/providers/claude-code/statusline.d.ts.map +0 -1
  54. package/dist/providers/claude-code/statusline.js +0 -130
  55. package/dist/providers/claude-code/statusline.js.map +0 -1
  56. package/dist/providers/claude-code/task-sync.d.ts +0 -32
  57. package/dist/providers/claude-code/task-sync.d.ts.map +0 -1
  58. package/dist/providers/claude-code/task-sync.js +0 -119
  59. package/dist/providers/claude-code/task-sync.js.map +0 -1
  60. package/dist/providers/claude-code/transport.d.ts +0 -25
  61. package/dist/providers/claude-code/transport.d.ts.map +0 -1
  62. package/dist/providers/claude-code/transport.js +0 -29
  63. package/dist/providers/claude-code/transport.js.map +0 -1
  64. package/dist/providers/codex/adapter.d.ts +0 -83
  65. package/dist/providers/codex/adapter.d.ts.map +0 -1
  66. package/dist/providers/codex/adapter.js +0 -147
  67. package/dist/providers/codex/adapter.js.map +0 -1
  68. package/dist/providers/codex/hooks.d.ts +0 -91
  69. package/dist/providers/codex/hooks.d.ts.map +0 -1
  70. package/dist/providers/codex/hooks.js +0 -113
  71. package/dist/providers/codex/hooks.js.map +0 -1
  72. package/dist/providers/codex/index.d.ts +0 -37
  73. package/dist/providers/codex/index.d.ts.map +0 -1
  74. package/dist/providers/codex/index.js +0 -39
  75. package/dist/providers/codex/index.js.map +0 -1
  76. package/dist/providers/codex/install.d.ts +0 -65
  77. package/dist/providers/codex/install.d.ts.map +0 -1
  78. package/dist/providers/codex/install.js +0 -125
  79. package/dist/providers/codex/install.js.map +0 -1
  80. package/dist/providers/cursor/adapter.d.ts +0 -76
  81. package/dist/providers/cursor/adapter.d.ts.map +0 -1
  82. package/dist/providers/cursor/adapter.js +0 -152
  83. package/dist/providers/cursor/adapter.js.map +0 -1
  84. package/dist/providers/cursor/hooks.d.ts +0 -140
  85. package/dist/providers/cursor/hooks.d.ts.map +0 -1
  86. package/dist/providers/cursor/hooks.js +0 -208
  87. package/dist/providers/cursor/hooks.js.map +0 -1
  88. package/dist/providers/cursor/index.d.ts +0 -34
  89. package/dist/providers/cursor/index.d.ts.map +0 -1
  90. package/dist/providers/cursor/index.js +0 -36
  91. package/dist/providers/cursor/index.js.map +0 -1
  92. package/dist/providers/cursor/install.d.ts +0 -87
  93. package/dist/providers/cursor/install.d.ts.map +0 -1
  94. package/dist/providers/cursor/install.js +0 -181
  95. package/dist/providers/cursor/install.js.map +0 -1
  96. package/dist/providers/cursor/spawn.d.ts +0 -50
  97. package/dist/providers/cursor/spawn.d.ts.map +0 -1
  98. package/dist/providers/cursor/spawn.js +0 -59
  99. package/dist/providers/cursor/spawn.js.map +0 -1
  100. package/dist/providers/gemini-cli/adapter.d.ts +0 -84
  101. package/dist/providers/gemini-cli/adapter.d.ts.map +0 -1
  102. package/dist/providers/gemini-cli/adapter.js +0 -159
  103. package/dist/providers/gemini-cli/adapter.js.map +0 -1
  104. package/dist/providers/gemini-cli/hooks.d.ts +0 -99
  105. package/dist/providers/gemini-cli/hooks.d.ts.map +0 -1
  106. package/dist/providers/gemini-cli/hooks.js +0 -128
  107. package/dist/providers/gemini-cli/hooks.js.map +0 -1
  108. package/dist/providers/gemini-cli/index.d.ts +0 -37
  109. package/dist/providers/gemini-cli/index.d.ts.map +0 -1
  110. package/dist/providers/gemini-cli/index.js +0 -39
  111. package/dist/providers/gemini-cli/index.js.map +0 -1
  112. package/dist/providers/gemini-cli/install.d.ts +0 -65
  113. package/dist/providers/gemini-cli/install.d.ts.map +0 -1
  114. package/dist/providers/gemini-cli/install.js +0 -125
  115. package/dist/providers/gemini-cli/install.js.map +0 -1
  116. package/dist/providers/kimi/adapter.d.ts +0 -85
  117. package/dist/providers/kimi/adapter.d.ts.map +0 -1
  118. package/dist/providers/kimi/adapter.js +0 -146
  119. package/dist/providers/kimi/adapter.js.map +0 -1
  120. package/dist/providers/kimi/hooks.d.ts +0 -70
  121. package/dist/providers/kimi/hooks.d.ts.map +0 -1
  122. package/dist/providers/kimi/hooks.js +0 -79
  123. package/dist/providers/kimi/hooks.js.map +0 -1
  124. package/dist/providers/kimi/index.d.ts +0 -37
  125. package/dist/providers/kimi/index.d.ts.map +0 -1
  126. package/dist/providers/kimi/index.js +0 -39
  127. package/dist/providers/kimi/index.js.map +0 -1
  128. package/dist/providers/kimi/install.d.ts +0 -65
  129. package/dist/providers/kimi/install.d.ts.map +0 -1
  130. package/dist/providers/kimi/install.js +0 -125
  131. package/dist/providers/kimi/install.js.map +0 -1
  132. package/dist/providers/opencode/adapter.d.ts +0 -83
  133. package/dist/providers/opencode/adapter.d.ts.map +0 -1
  134. package/dist/providers/opencode/adapter.js +0 -167
  135. package/dist/providers/opencode/adapter.js.map +0 -1
  136. package/dist/providers/opencode/hooks.d.ts +0 -136
  137. package/dist/providers/opencode/hooks.d.ts.map +0 -1
  138. package/dist/providers/opencode/hooks.js +0 -206
  139. package/dist/providers/opencode/hooks.js.map +0 -1
  140. package/dist/providers/opencode/index.d.ts +0 -35
  141. package/dist/providers/opencode/index.d.ts.map +0 -1
  142. package/dist/providers/opencode/index.js +0 -37
  143. package/dist/providers/opencode/index.js.map +0 -1
  144. package/dist/providers/opencode/install.d.ts +0 -56
  145. package/dist/providers/opencode/install.d.ts.map +0 -1
  146. package/dist/providers/opencode/install.js +0 -116
  147. package/dist/providers/opencode/install.js.map +0 -1
  148. package/dist/providers/opencode/spawn.d.ts +0 -94
  149. package/dist/providers/opencode/spawn.d.ts.map +0 -1
  150. package/dist/providers/opencode/spawn.js +0 -241
  151. package/dist/providers/opencode/spawn.js.map +0 -1
  152. package/dist/providers/shared/transcript-reader.d.ts +0 -58
  153. package/dist/providers/shared/transcript-reader.d.ts.map +0 -1
  154. package/dist/providers/shared/transcript-reader.js +0 -124
  155. package/dist/providers/shared/transcript-reader.js.map +0 -1
  156. package/dist/registry.d.ts +0 -88
  157. package/dist/registry.d.ts.map +0 -1
  158. package/dist/registry.js +0 -88
  159. package/dist/registry.js.map +0 -1
package/dist/index.js DELETED
@@ -1,3258 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropNames = Object.getOwnPropertyNames;
3
- var __esm = (fn, res) => function __init() {
4
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
- };
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
-
11
- // packages/adapters/src/providers/claude-code/paths.ts
12
- import { homedir } from "node:os";
13
- import { join } from "node:path";
14
- var ClaudeCodePathProvider;
15
- var init_paths = __esm({
16
- "packages/adapters/src/providers/claude-code/paths.ts"() {
17
- "use strict";
18
- ClaudeCodePathProvider = class {
19
- /** Get the provider's root configuration directory. */
20
- getProviderDir() {
21
- return process.env["CLAUDE_HOME"] ?? join(homedir(), ".claude");
22
- }
23
- /** Get the path to the provider's settings file, or null if unavailable. */
24
- getSettingsPath() {
25
- return process.env["CLAUDE_SETTINGS"] ?? join(this.getProviderDir(), "settings.json");
26
- }
27
- /** Get the directory where agents are installed, or null if unsupported. */
28
- getAgentInstallDir() {
29
- return join(this.getProviderDir(), "agents");
30
- }
31
- /** Get the path to the provider's memory database, or null if unsupported. */
32
- getMemoryDbPath() {
33
- return process.env["CLAUDE_MEM_DB"] ?? join(homedir(), ".claude-mem", "claude-mem.db");
34
- }
35
- };
36
- }
37
- });
38
-
39
- // packages/adapters/src/providers/claude-code/context-monitor.ts
40
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
41
- import { mkdir } from "node:fs/promises";
42
- import { homedir as homedir2 } from "node:os";
43
- import { dirname, join as join2 } from "node:path";
44
- function getContextStatusFromPercentage(percentage) {
45
- if (percentage >= THRESHOLDS.EMERGENCY) return "emergency";
46
- if (percentage >= THRESHOLDS.CRITICAL) return "critical";
47
- if (percentage >= THRESHOLDS.CAUTION) return "caution";
48
- if (percentage >= THRESHOLDS.WARNING) return "warning";
49
- return "ok";
50
- }
51
- var THRESHOLDS, ClaudeCodeContextMonitorProvider;
52
- var init_context_monitor = __esm({
53
- "packages/adapters/src/providers/claude-code/context-monitor.ts"() {
54
- "use strict";
55
- init_paths();
56
- THRESHOLDS = {
57
- WARNING: 50,
58
- CAUTION: 70,
59
- CRITICAL: 85,
60
- EMERGENCY: 95
61
- };
62
- ClaudeCodeContextMonitorProvider = class {
63
- /** Path provider for resolving Claude Code directory locations. */
64
- pathProvider = new ClaudeCodePathProvider();
65
- /** Process raw context window JSON and return a formatted summary string. */
66
- async processContextInput(input, cwd) {
67
- const typed = input;
68
- const contextSize = typed.context_window?.context_window_size ?? 2e5;
69
- const usage = typed.context_window?.current_usage;
70
- if (!usage) return "-- no data";
71
- const inputTokens = usage.input_tokens ?? 0;
72
- const outputTokens = usage.output_tokens ?? 0;
73
- const cacheCreate = usage.cache_creation_input_tokens ?? 0;
74
- const totalTokens = inputTokens + outputTokens + cacheCreate;
75
- const percentage = Math.floor(totalTokens * 100 / contextSize);
76
- const status = getContextStatusFromPercentage(percentage);
77
- const cleoDir = cwd ? join2(cwd, ".cleo") : ".cleo";
78
- if (existsSync(cleoDir)) {
79
- const stateDir = join2(cleoDir, "context-states");
80
- const statePath = join2(stateDir, ".context-state.json");
81
- const state = {
82
- $schema: "https://cleo-dev.com/schemas/v1/context-state.schema.json",
83
- version: "1.0.0",
84
- timestamp: (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z"),
85
- staleAfterMs: 5e3,
86
- contextWindow: {
87
- maxTokens: contextSize,
88
- currentTokens: totalTokens,
89
- percentage,
90
- breakdown: {
91
- inputTokens,
92
- outputTokens,
93
- cacheCreationTokens: cacheCreate,
94
- cacheReadTokens: usage.cache_read_input_tokens ?? 0
95
- }
96
- },
97
- thresholds: {
98
- warning: THRESHOLDS.WARNING,
99
- caution: THRESHOLDS.CAUTION,
100
- critical: THRESHOLDS.CRITICAL,
101
- emergency: THRESHOLDS.EMERGENCY
102
- },
103
- status,
104
- cleoSessionId: ""
105
- };
106
- try {
107
- await mkdir(dirname(statePath), { recursive: true });
108
- writeFileSync(statePath, JSON.stringify(state, null, 2));
109
- } catch {
110
- }
111
- }
112
- return `${percentage}% | ${totalTokens}/${contextSize}`;
113
- }
114
- /** Check the current statusline integration status in Claude Code settings. */
115
- checkStatuslineIntegration() {
116
- const settingsPath = this.pathProvider.getSettingsPath();
117
- if (!settingsPath || !existsSync(settingsPath)) return "no_settings";
118
- try {
119
- const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
120
- const statusLine = settings.statusLine;
121
- if (!statusLine?.type) return "not_configured";
122
- if (statusLine.type !== "command") return "custom_no_cleo";
123
- const cmd = statusLine.command ?? "";
124
- if (cmd.includes("context-monitor.sh") || cmd.includes("cleo-statusline") || cmd.includes(".context-state.json") || cmd.includes("context-states")) {
125
- return "configured";
126
- }
127
- const scriptPath = cmd.startsWith("~") ? cmd.replace("~", homedir2()) : cmd;
128
- if (existsSync(scriptPath)) {
129
- try {
130
- const content = readFileSync(scriptPath, "utf-8");
131
- if (content.includes("context-state.json")) return "configured";
132
- } catch {
133
- }
134
- }
135
- return "custom_no_cleo";
136
- } catch {
137
- return "no_settings";
138
- }
139
- }
140
- /** Get the recommended statusline configuration object for Claude Code settings. */
141
- getStatuslineConfig() {
142
- return {
143
- statusLine: {
144
- type: "command",
145
- command: join2(homedir2(), ".cleo", "lib", "session", "context-monitor.sh")
146
- }
147
- };
148
- }
149
- /** Get human-readable setup instructions for enabling context monitoring. */
150
- getSetupInstructions() {
151
- const settingsPath = this.pathProvider.getSettingsPath() ?? "~/.claude/settings.json";
152
- return [
153
- "To enable context monitoring, add to your Claude Code settings:",
154
- `File: ${settingsPath}`,
155
- "",
156
- JSON.stringify(this.getStatuslineConfig(), null, 2),
157
- "",
158
- "This enables real-time context window tracking in the CLI."
159
- ].join("\n");
160
- }
161
- };
162
- }
163
- });
164
-
165
- // packages/adapters/src/providers/claude-code/hooks.ts
166
- import { readdir, readFile } from "node:fs/promises";
167
- import { join as join3 } from "node:path";
168
- var PROVIDER_ID, CLAUDE_CODE_EVENT_MAP, ClaudeCodeHookProvider;
169
- var init_hooks = __esm({
170
- "packages/adapters/src/providers/claude-code/hooks.ts"() {
171
- "use strict";
172
- PROVIDER_ID = "claude-code";
173
- CLAUDE_CODE_EVENT_MAP = {
174
- // CAAMP: toNative('SessionStart', 'claude-code') = 'SessionStart'
175
- SessionStart: "SessionStart",
176
- // CAAMP: toNative('SessionEnd', 'claude-code') = 'SessionEnd'
177
- SessionEnd: "SessionEnd",
178
- // CAAMP: toNative('PromptSubmit', 'claude-code') = 'UserPromptSubmit'
179
- UserPromptSubmit: "PromptSubmit",
180
- // CAAMP: toNative('ResponseComplete', 'claude-code') = 'Stop'
181
- Stop: "ResponseComplete",
182
- // CAAMP: toNative('PreToolUse', 'claude-code') = 'PreToolUse'
183
- PreToolUse: "PreToolUse",
184
- // CAAMP: toNative('PostToolUse', 'claude-code') = 'PostToolUse'
185
- PostToolUse: "PostToolUse",
186
- // CAAMP: toNative('PostToolUseFailure','claude-code') = 'PostToolUseFailure'
187
- PostToolUseFailure: "PostToolUseFailure",
188
- // CAAMP: toNative('PermissionRequest', 'claude-code') = 'PermissionRequest'
189
- PermissionRequest: "PermissionRequest",
190
- // CAAMP: toNative('SubagentStart', 'claude-code') = 'SubagentStart'
191
- SubagentStart: "SubagentStart",
192
- // CAAMP: toNative('SubagentStop', 'claude-code') = 'SubagentStop'
193
- SubagentStop: "SubagentStop",
194
- // CAAMP: toNative('PreCompact', 'claude-code') = 'PreCompact'
195
- PreCompact: "PreCompact",
196
- // CAAMP: toNative('PostCompact', 'claude-code') = 'PostCompact'
197
- PostCompact: "PostCompact",
198
- // CAAMP: toNative('Notification', 'claude-code') = 'Notification'
199
- Notification: "Notification",
200
- // CAAMP: toNative('ConfigChange', 'claude-code') = 'ConfigChange'
201
- ConfigChange: "ConfigChange"
202
- };
203
- ClaudeCodeHookProvider = class {
204
- /** Whether hooks have been registered for the current session. */
205
- registered = false;
206
- /**
207
- * Map a Claude Code native event name to a CAAMP canonical hook event name.
208
- *
209
- * Looks up the native event name in the map derived from
210
- * `getProviderHookProfile('claude-code').mappings` (CAAMP 1.9.1).
211
- * Returns null for unrecognised events (e.g. PreModel, PostModel which
212
- * Claude Code does not support).
213
- *
214
- * @param providerEvent - Claude Code native event (e.g. "UserPromptSubmit", "Stop")
215
- * @returns CAAMP canonical event name, or null if unmapped
216
- * @task T164
217
- */
218
- mapProviderEvent(providerEvent) {
219
- return CLAUDE_CODE_EVENT_MAP[providerEvent] ?? null;
220
- }
221
- /**
222
- * Register native hooks for a project.
223
- *
224
- * For Claude Code, hooks are registered via the config system
225
- * (`~/.claude/settings.json`), managed by the install provider.
226
- * This method marks hooks as registered without performing filesystem operations.
227
- *
228
- * Iterating supported events is handled at install time using
229
- * `getSupportedCanonicalEvents()` to enumerate all 14 supported hooks.
230
- *
231
- * @param _projectDir - Project directory (unused; Claude Code uses global config)
232
- * @task T164
233
- */
234
- async registerNativeHooks(_projectDir) {
235
- this.registered = true;
236
- }
237
- /**
238
- * Unregister native hooks.
239
- *
240
- * For Claude Code, this is a no-op since hooks are managed through the config
241
- * system. Unregistration happens via the install provider's uninstall method.
242
- *
243
- * @task T164
244
- */
245
- async unregisterNativeHooks() {
246
- this.registered = false;
247
- }
248
- /**
249
- * Check whether hooks have been registered via `registerNativeHooks`.
250
- */
251
- isRegistered() {
252
- return this.registered;
253
- }
254
- /**
255
- * Get the native→canonical event mapping for introspection and debugging.
256
- *
257
- * Returns the map derived from `getProviderHookProfile('claude-code').mappings`
258
- * (CAAMP 1.9.1). Use `getSupportedCanonicalEvents()` to enumerate canonical
259
- * names via live CAAMP APIs.
260
- *
261
- * @returns Immutable record of native event name → canonical event name
262
- */
263
- getEventMap() {
264
- return { ...CLAUDE_CODE_EVENT_MAP };
265
- }
266
- /**
267
- * Enumerate supported canonical events via CAAMP's `getSupportedEvents()`.
268
- *
269
- * Calls `getSupportedEvents('claude-code')` from the CAAMP normalizer to
270
- * get the authoritative list. Claude Code supports 14 of 16 canonical events
271
- * (PreModel and PostModel are not supported). Falls back to the values of
272
- * the static event map when CAAMP is unavailable at runtime.
273
- *
274
- * @returns Array of CAAMP canonical event names supported by Claude Code
275
- * @task T164
276
- */
277
- async getSupportedCanonicalEvents() {
278
- try {
279
- const { getSupportedEvents } = await import("@cleocode/caamp");
280
- return getSupportedEvents(PROVIDER_ID);
281
- } catch {
282
- return [...new Set(Object.values(CLAUDE_CODE_EVENT_MAP))];
283
- }
284
- }
285
- /**
286
- * Retrieve the full provider hook profile from CAAMP.
287
- *
288
- * Calls `getProviderHookProfile('claude-code')` from the CAAMP normalizer to
289
- * get the complete profile: hook system type (`config`), config path
290
- * (`~/.claude/settings.json`), handler types, and all event mappings.
291
- * Returns null when CAAMP is unavailable at runtime.
292
- *
293
- * @returns Provider hook profile or null if CAAMP is unavailable
294
- * @task T164
295
- */
296
- async getProviderProfile() {
297
- try {
298
- const { getProviderHookProfile } = await import("@cleocode/caamp");
299
- return getProviderHookProfile(PROVIDER_ID) ?? null;
300
- } catch {
301
- return null;
302
- }
303
- }
304
- /**
305
- * Translate a CAAMP canonical event to its Claude Code native name via CAAMP.
306
- *
307
- * Calls `toNative(canonical, 'claude-code')` from the CAAMP normalizer.
308
- * Returns null for unsupported events (PreModel, PostModel) or when
309
- * CAAMP is unavailable.
310
- *
311
- * @param canonical - CAAMP canonical event name (e.g. "PromptSubmit")
312
- * @returns Claude Code native event name or null
313
- * @task T164
314
- */
315
- async toNativeEvent(canonical) {
316
- try {
317
- const { toNative } = await import("@cleocode/caamp");
318
- return toNative(canonical, PROVIDER_ID);
319
- } catch {
320
- const entry = Object.entries(CLAUDE_CODE_EVENT_MAP).find(([, v]) => v === canonical);
321
- return entry?.[0] ?? null;
322
- }
323
- }
324
- /**
325
- * Extract a plain-text transcript from Claude Code session JSONL files.
326
- *
327
- * Reads the most recent .jsonl file under `~/.claude/projects/` and
328
- * extracts user/assistant turn text into a flat string for brain
329
- * observation extraction.
330
- *
331
- * Returns null when no session data is found or on any read error.
332
- *
333
- * @param _sessionId - CLEO session ID (unused; reads the most recent file)
334
- * @param _projectDir - Project directory (unused; Claude Code uses global paths)
335
- * @task T144 @epic T134
336
- */
337
- async getTranscript(_sessionId, _projectDir) {
338
- try {
339
- const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? "/root";
340
- const projectsDir = join3(homeDir, ".claude", "projects");
341
- let allFiles = [];
342
- try {
343
- const projectDirs = await readdir(projectsDir, { withFileTypes: true });
344
- for (const entry of projectDirs) {
345
- if (!entry.isDirectory()) continue;
346
- const subDir = join3(projectsDir, entry.name);
347
- try {
348
- const files = await readdir(subDir);
349
- for (const file of files) {
350
- if (!file.endsWith(".jsonl")) continue;
351
- const filePath = join3(subDir, file);
352
- allFiles.push({ path: filePath, mtime: 0 });
353
- }
354
- } catch {
355
- }
356
- }
357
- } catch {
358
- return null;
359
- }
360
- if (allFiles.length === 0) return null;
361
- allFiles = allFiles.sort((a, b) => b.path.localeCompare(a.path));
362
- const mostRecent = allFiles[0];
363
- if (!mostRecent) return null;
364
- const raw = await readFile(mostRecent.path, "utf-8");
365
- const lines = raw.split("\n").filter((l) => l.trim());
366
- const turns = [];
367
- for (const line of lines) {
368
- try {
369
- const entry = JSON.parse(line);
370
- const role = entry.role;
371
- const content = entry.content;
372
- if (role === "assistant" && typeof content === "string") {
373
- turns.push(`assistant: ${content}`);
374
- } else if (role === "user" && typeof content === "string") {
375
- turns.push(`user: ${content}`);
376
- }
377
- } catch {
378
- }
379
- }
380
- return turns.length > 0 ? turns.join("\n") : null;
381
- } catch {
382
- return null;
383
- }
384
- }
385
- };
386
- }
387
- });
388
-
389
- // packages/adapters/src/providers/claude-code/install.ts
390
- import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
391
- import { homedir as homedir3 } from "node:os";
392
- import { join as join4 } from "node:path";
393
- var INSTRUCTION_REFERENCES, ClaudeCodeInstallProvider;
394
- var init_install = __esm({
395
- "packages/adapters/src/providers/claude-code/install.ts"() {
396
- "use strict";
397
- INSTRUCTION_REFERENCES = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
398
- ClaudeCodeInstallProvider = class {
399
- /**
400
- * Install CLEO into a Claude Code project.
401
- *
402
- * @param options - Installation options including project directory
403
- * @returns Result describing what was installed
404
- */
405
- async install(options) {
406
- const { projectDir } = options;
407
- const installedAt = (/* @__PURE__ */ new Date()).toISOString();
408
- let instructionFileUpdated = false;
409
- const details = {};
410
- instructionFileUpdated = this.updateInstructionFile(projectDir);
411
- if (instructionFileUpdated) {
412
- details.instructionFile = join4(projectDir, "CLAUDE.md");
413
- }
414
- const pluginResult = this.registerPlugin();
415
- if (pluginResult) {
416
- details.plugin = pluginResult;
417
- }
418
- return {
419
- success: true,
420
- installedAt,
421
- instructionFileUpdated,
422
- mcpRegistered: false,
423
- details
424
- };
425
- }
426
- /**
427
- * Uninstall CLEO from the current Claude Code project.
428
- *
429
- * Does not remove CLAUDE.md references (they are harmless if CLEO is not present).
430
- */
431
- async uninstall() {
432
- }
433
- /**
434
- * Check whether CLEO is installed in the current environment.
435
- *
436
- * Checks for plugin enabled in ~/.claude/settings.json.
437
- */
438
- async isInstalled() {
439
- const settingsPath = join4(homedir3(), ".claude", "settings.json");
440
- if (existsSync2(settingsPath)) {
441
- try {
442
- const settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
443
- const plugins = settings.enabledPlugins;
444
- if (plugins && plugins["cleo@cleocode"] === true) {
445
- return true;
446
- }
447
- } catch {
448
- }
449
- }
450
- return false;
451
- }
452
- /**
453
- * Ensure CLAUDE.md contains @-references to CLEO instruction files.
454
- *
455
- * Creates CLAUDE.md if it does not exist. Appends any missing references.
456
- *
457
- * @param projectDir - Project root directory
458
- */
459
- async ensureInstructionReferences(projectDir) {
460
- this.updateInstructionFile(projectDir);
461
- }
462
- /**
463
- * Update CLAUDE.md with CLEO @-references.
464
- *
465
- * @returns true if the file was created or modified
466
- */
467
- updateInstructionFile(projectDir) {
468
- const claudeMdPath = join4(projectDir, "CLAUDE.md");
469
- let content = "";
470
- let existed = false;
471
- if (existsSync2(claudeMdPath)) {
472
- content = readFileSync2(claudeMdPath, "utf-8");
473
- existed = true;
474
- }
475
- const missingRefs = INSTRUCTION_REFERENCES.filter((ref) => !content.includes(ref));
476
- if (missingRefs.length === 0) {
477
- return false;
478
- }
479
- const refsBlock = missingRefs.join("\n");
480
- if (existed) {
481
- const separator = content.endsWith("\n") ? "" : "\n";
482
- content = content + separator + refsBlock + "\n";
483
- } else {
484
- content = refsBlock + "\n";
485
- }
486
- writeFileSync2(claudeMdPath, content, "utf-8");
487
- return true;
488
- }
489
- /**
490
- * Register the CLEO brain plugin in ~/.claude/settings.json.
491
- *
492
- * @returns Description of what was registered, or null if no change needed
493
- */
494
- registerPlugin() {
495
- const home = homedir3();
496
- const settingsPath = join4(home, ".claude", "settings.json");
497
- let settings = {};
498
- if (existsSync2(settingsPath)) {
499
- try {
500
- settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
501
- } catch {
502
- }
503
- }
504
- const enabledPlugins = settings.enabledPlugins ?? {};
505
- const pluginKey = "cleo@cleocode";
506
- if (enabledPlugins[pluginKey] === true) {
507
- return null;
508
- }
509
- if (enabledPlugins["claude-mem@thedotmack"] === true) {
510
- enabledPlugins["claude-mem@thedotmack"] = false;
511
- }
512
- enabledPlugins[pluginKey] = true;
513
- settings.enabledPlugins = enabledPlugins;
514
- mkdirSync(join4(home, ".claude"), { recursive: true });
515
- writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
516
- return `Enabled ${pluginKey} in ~/.claude/settings.json`;
517
- }
518
- };
519
- }
520
- });
521
-
522
- // packages/contracts/src/errors.ts
523
- function getErrorMessage(error, fallback = "Unknown error") {
524
- if (error instanceof Error) {
525
- return error.message;
526
- }
527
- if (typeof error === "string") {
528
- return error;
529
- }
530
- if (error !== null && typeof error === "object" && "message" in error && typeof error.message === "string") {
531
- return error.message;
532
- }
533
- return fallback;
534
- }
535
- var init_errors = __esm({
536
- "packages/contracts/src/errors.ts"() {
537
- "use strict";
538
- }
539
- });
540
-
541
- // packages/contracts/src/exit-codes.ts
542
- var init_exit_codes = __esm({
543
- "packages/contracts/src/exit-codes.ts"() {
544
- "use strict";
545
- }
546
- });
547
-
548
- // packages/contracts/src/facade.ts
549
- var init_facade = __esm({
550
- "packages/contracts/src/facade.ts"() {
551
- "use strict";
552
- }
553
- });
554
-
555
- // packages/contracts/src/lafs.ts
556
- var init_lafs = __esm({
557
- "packages/contracts/src/lafs.ts"() {
558
- "use strict";
559
- }
560
- });
561
-
562
- // packages/contracts/src/operations/issues.ts
563
- var init_issues = __esm({
564
- "packages/contracts/src/operations/issues.ts"() {
565
- "use strict";
566
- }
567
- });
568
-
569
- // packages/contracts/src/operations/lifecycle.ts
570
- var init_lifecycle = __esm({
571
- "packages/contracts/src/operations/lifecycle.ts"() {
572
- "use strict";
573
- }
574
- });
575
-
576
- // packages/contracts/src/operations/orchestrate.ts
577
- var init_orchestrate = __esm({
578
- "packages/contracts/src/operations/orchestrate.ts"() {
579
- "use strict";
580
- }
581
- });
582
-
583
- // packages/contracts/src/operations/release.ts
584
- var init_release = __esm({
585
- "packages/contracts/src/operations/release.ts"() {
586
- "use strict";
587
- }
588
- });
589
-
590
- // packages/contracts/src/operations/research.ts
591
- var init_research = __esm({
592
- "packages/contracts/src/operations/research.ts"() {
593
- "use strict";
594
- }
595
- });
596
-
597
- // packages/contracts/src/operations/session.ts
598
- var init_session = __esm({
599
- "packages/contracts/src/operations/session.ts"() {
600
- "use strict";
601
- }
602
- });
603
-
604
- // packages/contracts/src/operations/skills.ts
605
- var init_skills = __esm({
606
- "packages/contracts/src/operations/skills.ts"() {
607
- "use strict";
608
- }
609
- });
610
-
611
- // packages/contracts/src/operations/system.ts
612
- var init_system = __esm({
613
- "packages/contracts/src/operations/system.ts"() {
614
- "use strict";
615
- }
616
- });
617
-
618
- // packages/contracts/src/operations/tasks.ts
619
- var init_tasks = __esm({
620
- "packages/contracts/src/operations/tasks.ts"() {
621
- "use strict";
622
- }
623
- });
624
-
625
- // packages/contracts/src/operations/validate.ts
626
- var init_validate = __esm({
627
- "packages/contracts/src/operations/validate.ts"() {
628
- "use strict";
629
- }
630
- });
631
-
632
- // packages/contracts/src/operations/index.ts
633
- var init_operations = __esm({
634
- "packages/contracts/src/operations/index.ts"() {
635
- "use strict";
636
- init_issues();
637
- init_lifecycle();
638
- init_orchestrate();
639
- init_release();
640
- init_research();
641
- init_session();
642
- init_skills();
643
- init_system();
644
- init_tasks();
645
- init_validate();
646
- }
647
- });
648
-
649
- // packages/contracts/src/orchestration-hierarchy.ts
650
- var init_orchestration_hierarchy = __esm({
651
- "packages/contracts/src/orchestration-hierarchy.ts"() {
652
- "use strict";
653
- }
654
- });
655
-
656
- // packages/contracts/src/session.ts
657
- var init_session2 = __esm({
658
- "packages/contracts/src/session.ts"() {
659
- "use strict";
660
- }
661
- });
662
-
663
- // packages/contracts/src/status-registry.ts
664
- var init_status_registry = __esm({
665
- "packages/contracts/src/status-registry.ts"() {
666
- "use strict";
667
- }
668
- });
669
-
670
- // packages/contracts/src/index.ts
671
- var init_src = __esm({
672
- "packages/contracts/src/index.ts"() {
673
- init_errors();
674
- init_exit_codes();
675
- init_facade();
676
- init_lafs();
677
- init_operations();
678
- init_orchestration_hierarchy();
679
- init_session2();
680
- init_status_registry();
681
- }
682
- });
683
-
684
- // packages/adapters/src/providers/claude-code/spawn.ts
685
- import { exec, spawn as nodeSpawn } from "node:child_process";
686
- import { unlink, writeFile } from "node:fs/promises";
687
- import { promisify } from "node:util";
688
- var execAsync, ClaudeCodeSpawnProvider;
689
- var init_spawn = __esm({
690
- "packages/adapters/src/providers/claude-code/spawn.ts"() {
691
- "use strict";
692
- init_src();
693
- execAsync = promisify(exec);
694
- ClaudeCodeSpawnProvider = class {
695
- /** Map of instance IDs to tracked process info. */
696
- processMap = /* @__PURE__ */ new Map();
697
- /**
698
- * Check if the Claude CLI is available in PATH.
699
- *
700
- * @returns true if `claude` is found via `which`
701
- */
702
- async canSpawn() {
703
- try {
704
- await execAsync("which claude");
705
- return true;
706
- } catch {
707
- return false;
708
- }
709
- }
710
- /**
711
- * Spawn a subagent via Claude CLI.
712
- *
713
- * Writes the prompt to a temporary file and spawns a detached Claude
714
- * process. The process runs independently of the parent.
715
- *
716
- * @param context - Spawn context with taskId, prompt, and options
717
- * @returns Spawn result with instance ID and status
718
- */
719
- async spawn(context) {
720
- const instanceId = `claude-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
721
- const startTime = (/* @__PURE__ */ new Date()).toISOString();
722
- let tmpFile;
723
- try {
724
- tmpFile = `/tmp/claude-spawn-${instanceId}.txt`;
725
- await writeFile(tmpFile, context.prompt, "utf-8");
726
- const args = ["--allow-insecure", "--no-upgrade-check", tmpFile];
727
- const spawnOpts = {
728
- detached: true,
729
- stdio: "ignore"
730
- };
731
- if (context.workingDirectory) {
732
- spawnOpts.cwd = context.workingDirectory;
733
- }
734
- const child = nodeSpawn("claude", args, spawnOpts);
735
- child.unref();
736
- if (child.pid) {
737
- this.processMap.set(instanceId, {
738
- pid: child.pid,
739
- taskId: context.taskId,
740
- startTime
741
- });
742
- }
743
- const capturedTmpFile = tmpFile;
744
- child.on("exit", async () => {
745
- this.processMap.delete(instanceId);
746
- try {
747
- await unlink(capturedTmpFile);
748
- } catch {
749
- }
750
- });
751
- return {
752
- instanceId,
753
- taskId: context.taskId,
754
- providerId: "claude-code",
755
- status: "running",
756
- startTime
757
- };
758
- } catch (error) {
759
- console.error(`[ClaudeCodeSpawnProvider] Failed to spawn: ${getErrorMessage(error)}`);
760
- if (tmpFile) {
761
- try {
762
- await unlink(tmpFile);
763
- } catch {
764
- }
765
- }
766
- return {
767
- instanceId,
768
- taskId: context.taskId,
769
- providerId: "claude-code",
770
- status: "failed",
771
- startTime,
772
- endTime: (/* @__PURE__ */ new Date()).toISOString(),
773
- error: getErrorMessage(error)
774
- };
775
- }
776
- }
777
- /**
778
- * List currently running Claude subagent processes.
779
- *
780
- * Checks each tracked process via kill(pid, 0) to verify it is still alive.
781
- * Dead processes are automatically cleaned from the tracking map.
782
- *
783
- * @returns Array of spawn results for running processes
784
- */
785
- async listRunning() {
786
- const running = [];
787
- for (const [instanceId, tracked] of this.processMap.entries()) {
788
- try {
789
- process.kill(tracked.pid, 0);
790
- running.push({
791
- instanceId,
792
- taskId: tracked.taskId,
793
- providerId: "claude-code",
794
- status: "running",
795
- startTime: tracked.startTime
796
- });
797
- } catch {
798
- this.processMap.delete(instanceId);
799
- }
800
- }
801
- return running;
802
- }
803
- /**
804
- * Terminate a running spawn by instance ID.
805
- *
806
- * Sends SIGTERM to the tracked process. If the process is not found
807
- * or has already exited, this is a no-op.
808
- *
809
- * @param instanceId - ID of the spawn instance to terminate
810
- */
811
- async terminate(instanceId) {
812
- const tracked = this.processMap.get(instanceId);
813
- if (!tracked) return;
814
- try {
815
- process.kill(tracked.pid, "SIGTERM");
816
- } catch {
817
- }
818
- this.processMap.delete(instanceId);
819
- }
820
- };
821
- }
822
- });
823
-
824
- // packages/adapters/src/providers/claude-code/task-sync.ts
825
- import { readFile as readFile2, stat } from "node:fs/promises";
826
- import { join as join5 } from "node:path";
827
- function parseTaskId(content) {
828
- const match = content.match(/^\[T(\d+)\]/);
829
- return match ? `T${match[1]}` : null;
830
- }
831
- function stripPrefixes(content) {
832
- return content.replace(/^\[T\d+\]\s*/, "").replace(/^\[!\]\s*/, "").replace(/^\[BLOCKED\]\s*/, "");
833
- }
834
- function mapStatus(twStatus) {
835
- switch (twStatus) {
836
- case "completed":
837
- return "completed";
838
- case "in_progress":
839
- return "active";
840
- case "pending":
841
- return "pending";
842
- default:
843
- return "pending";
844
- }
845
- }
846
- function getTodoWriteFilePath(projectDir) {
847
- return join5(projectDir, ".cleo", "sync", "todowrite-state.json");
848
- }
849
- var ClaudeCodeTaskSyncProvider;
850
- var init_task_sync = __esm({
851
- "packages/adapters/src/providers/claude-code/task-sync.ts"() {
852
- "use strict";
853
- ClaudeCodeTaskSyncProvider = class {
854
- /** Optional override path for the TodoWrite state file (used in tests). */
855
- customFilePath;
856
- constructor(options) {
857
- this.customFilePath = options?.filePath;
858
- }
859
- /** Retrieve external tasks from Claude's TodoWrite state file. */
860
- async getExternalTasks(projectDir) {
861
- const filePath = this.customFilePath ?? getTodoWriteFilePath(projectDir);
862
- try {
863
- await stat(filePath);
864
- } catch {
865
- return [];
866
- }
867
- const raw = await readFile2(filePath, "utf-8");
868
- let state;
869
- try {
870
- state = JSON.parse(raw);
871
- } catch {
872
- return [];
873
- }
874
- if (!state.todos || !Array.isArray(state.todos)) {
875
- return [];
876
- }
877
- const tasks = [];
878
- let syntheticIndex = 0;
879
- for (const item of state.todos) {
880
- const cleoTaskId = parseTaskId(item.content);
881
- const title = cleoTaskId ? stripPrefixes(item.content).trim() : item.content.trim();
882
- if (!title) continue;
883
- tasks.push({
884
- externalId: cleoTaskId ?? `tw-new-${syntheticIndex++}`,
885
- title,
886
- status: mapStatus(item.status),
887
- providerMeta: {
888
- source: "todowrite",
889
- cleoTaskId,
890
- activeForm: item.activeForm,
891
- rawContent: item.content
892
- }
893
- });
894
- }
895
- return tasks;
896
- }
897
- };
898
- }
899
- });
900
-
901
- // packages/adapters/src/providers/claude-code/transport.ts
902
- var ClaudeCodeTransportProvider;
903
- var init_transport = __esm({
904
- "packages/adapters/src/providers/claude-code/transport.ts"() {
905
- "use strict";
906
- ClaudeCodeTransportProvider = class {
907
- /** Provider-specific transport name used for capability negotiation. */
908
- transportName = "claude-code";
909
- /** Create a transport instance for inter-agent messaging. */
910
- createTransport() {
911
- return null;
912
- }
913
- };
914
- }
915
- });
916
-
917
- // packages/adapters/src/providers/claude-code/adapter.ts
918
- import { exec as exec2 } from "node:child_process";
919
- import { existsSync as existsSync3 } from "node:fs";
920
- import { homedir as homedir4 } from "node:os";
921
- import { join as join6 } from "node:path";
922
- import { promisify as promisify2 } from "node:util";
923
- var execAsync2, ClaudeCodeAdapter;
924
- var init_adapter = __esm({
925
- "packages/adapters/src/providers/claude-code/adapter.ts"() {
926
- "use strict";
927
- init_context_monitor();
928
- init_hooks();
929
- init_install();
930
- init_paths();
931
- init_spawn();
932
- init_task_sync();
933
- init_transport();
934
- execAsync2 = promisify2(exec2);
935
- ClaudeCodeAdapter = class {
936
- /** Unique provider identifier. */
937
- id = "claude-code";
938
- /** Human-readable provider name. */
939
- name = "Claude Code";
940
- /** Adapter version string. */
941
- version = "1.0.0";
942
- /** Declared capabilities for this provider. */
943
- capabilities = {
944
- supportsHooks: true,
945
- // 14/16 canonical events — derived from getProviderHookProfile('claude-code') in CAAMP 1.9.1.
946
- // PreModel and PostModel are not supported by Claude Code.
947
- supportedHookEvents: [
948
- "SessionStart",
949
- "SessionEnd",
950
- "PromptSubmit",
951
- "ResponseComplete",
952
- "PreToolUse",
953
- "PostToolUse",
954
- "PostToolUseFailure",
955
- "PermissionRequest",
956
- "SubagentStart",
957
- "SubagentStop",
958
- "PreCompact",
959
- "PostCompact",
960
- "Notification",
961
- "ConfigChange"
962
- ],
963
- supportsSpawn: true,
964
- supportsInstall: true,
965
- supportsMcp: false,
966
- supportsInstructionFiles: true,
967
- instructionFilePattern: "CLAUDE.md",
968
- supportsContextMonitor: true,
969
- supportsStatusline: true,
970
- supportsProviderPaths: true,
971
- supportsTransport: true,
972
- supportsTaskSync: true
973
- };
974
- /** Hook provider for CAAMP event mapping and registration. */
975
- hooks;
976
- /** Spawn provider for launching subagent processes via `claude` CLI. */
977
- spawn;
978
- /** Install provider for managing instruction files and plugin registration. */
979
- install;
980
- /** Path provider for resolving Claude Code directory locations. */
981
- paths;
982
- /** Context monitor for tracking context window usage and statusline output. */
983
- contextMonitor;
984
- /** Transport provider for inter-agent communication. */
985
- transport;
986
- /** Task sync provider bridging Claude's TodoWrite format to CLEO tasks. */
987
- taskSync;
988
- /** Project directory this adapter was initialized with, or null. */
989
- projectDir = null;
990
- /** Whether {@link initialize} has been called. */
991
- initialized = false;
992
- constructor() {
993
- this.hooks = new ClaudeCodeHookProvider();
994
- this.spawn = new ClaudeCodeSpawnProvider();
995
- this.install = new ClaudeCodeInstallProvider();
996
- this.paths = new ClaudeCodePathProvider();
997
- this.contextMonitor = new ClaudeCodeContextMonitorProvider();
998
- this.transport = new ClaudeCodeTransportProvider();
999
- this.taskSync = new ClaudeCodeTaskSyncProvider();
1000
- }
1001
- /**
1002
- * Initialize the adapter for a given project directory.
1003
- *
1004
- * Validates the environment by checking for the Claude CLI
1005
- * and Claude Code configuration directory.
1006
- *
1007
- * @param projectDir - Root directory of the project
1008
- */
1009
- async initialize(projectDir) {
1010
- this.projectDir = projectDir;
1011
- this.initialized = true;
1012
- }
1013
- /**
1014
- * Dispose the adapter and clean up resources.
1015
- *
1016
- * Unregisters hooks and releases any tracked state.
1017
- */
1018
- async dispose() {
1019
- if (this.hooks.isRegistered()) {
1020
- await this.hooks.unregisterNativeHooks();
1021
- }
1022
- this.initialized = false;
1023
- this.projectDir = null;
1024
- }
1025
- /**
1026
- * Run a health check to verify Claude Code is accessible.
1027
- *
1028
- * Checks:
1029
- * 1. Adapter has been initialized
1030
- * 2. Claude CLI is available in PATH
1031
- * 3. ~/.claude/ configuration directory exists
1032
- *
1033
- * @returns Health status with details about each check
1034
- */
1035
- async healthCheck() {
1036
- const details = {};
1037
- if (!this.initialized) {
1038
- return {
1039
- healthy: false,
1040
- provider: this.id,
1041
- details: { error: "Adapter not initialized" }
1042
- };
1043
- }
1044
- let cliAvailable = false;
1045
- try {
1046
- const { stdout } = await execAsync2("which claude");
1047
- cliAvailable = stdout.trim().length > 0;
1048
- details.cliPath = stdout.trim();
1049
- } catch {
1050
- details.cliAvailable = false;
1051
- }
1052
- const claudeConfigDir = join6(homedir4(), ".claude");
1053
- const configExists = existsSync3(claudeConfigDir);
1054
- details.configDirExists = configExists;
1055
- const entrypointSet = process.env.CLAUDE_CODE_ENTRYPOINT !== void 0;
1056
- details.entrypointEnvSet = entrypointSet;
1057
- const healthy = cliAvailable;
1058
- details.cliAvailable = cliAvailable;
1059
- return {
1060
- healthy,
1061
- provider: this.id,
1062
- details
1063
- };
1064
- }
1065
- /**
1066
- * Check whether the adapter has been initialized.
1067
- */
1068
- isInitialized() {
1069
- return this.initialized;
1070
- }
1071
- /**
1072
- * Get the project directory this adapter was initialized with.
1073
- */
1074
- getProjectDir() {
1075
- return this.projectDir;
1076
- }
1077
- };
1078
- }
1079
- });
1080
-
1081
- // packages/adapters/src/providers/claude-code/statusline.ts
1082
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
1083
- import { homedir as homedir5 } from "node:os";
1084
- import { join as join7 } from "node:path";
1085
- function getClaudeSettingsPath() {
1086
- return process.env["CLAUDE_SETTINGS"] ?? join7(process.env["CLAUDE_HOME"] ?? join7(homedir5(), ".claude"), "settings.json");
1087
- }
1088
- function checkStatuslineIntegration() {
1089
- const settingsPath = getClaudeSettingsPath();
1090
- if (!existsSync4(settingsPath)) return "no_settings";
1091
- try {
1092
- const settings = JSON.parse(readFileSync3(settingsPath, "utf-8"));
1093
- const statusLine = settings.statusLine;
1094
- if (!statusLine?.type) return "not_configured";
1095
- if (statusLine.type !== "command") return "custom_no_cleo";
1096
- const cmd = statusLine.command ?? "";
1097
- if (cmd.includes("context-monitor.sh") || cmd.includes("cleo-statusline") || cmd.includes(".context-state.json") || cmd.includes("context-states")) {
1098
- return "configured";
1099
- }
1100
- const scriptPath = cmd.startsWith("~") ? cmd.replace("~", homedir5()) : cmd;
1101
- if (existsSync4(scriptPath)) {
1102
- try {
1103
- const content = readFileSync3(scriptPath, "utf-8");
1104
- if (content.includes("context-state.json")) return "configured";
1105
- } catch {
1106
- }
1107
- }
1108
- return "custom_no_cleo";
1109
- } catch {
1110
- return "no_settings";
1111
- }
1112
- }
1113
- function getStatuslineConfig(cleoHome) {
1114
- return {
1115
- statusLine: {
1116
- type: "command",
1117
- command: join7(cleoHome, "lib", "session", "context-monitor.sh")
1118
- }
1119
- };
1120
- }
1121
- function getSetupInstructions(cleoHome) {
1122
- const settingsPath = getClaudeSettingsPath();
1123
- return [
1124
- "To enable context monitoring, add to your Claude Code settings:",
1125
- `File: ${settingsPath}`,
1126
- "",
1127
- JSON.stringify(getStatuslineConfig(cleoHome), null, 2),
1128
- "",
1129
- "This enables real-time context window tracking in the CLI."
1130
- ].join("\n");
1131
- }
1132
- var init_statusline = __esm({
1133
- "packages/adapters/src/providers/claude-code/statusline.ts"() {
1134
- "use strict";
1135
- }
1136
- });
1137
-
1138
- // packages/adapters/src/providers/claude-code/index.ts
1139
- var claude_code_exports = {};
1140
- __export(claude_code_exports, {
1141
- ClaudeCodeAdapter: () => ClaudeCodeAdapter,
1142
- ClaudeCodeContextMonitorProvider: () => ClaudeCodeContextMonitorProvider,
1143
- ClaudeCodeHookProvider: () => ClaudeCodeHookProvider,
1144
- ClaudeCodeInstallProvider: () => ClaudeCodeInstallProvider,
1145
- ClaudeCodePathProvider: () => ClaudeCodePathProvider,
1146
- ClaudeCodeSpawnProvider: () => ClaudeCodeSpawnProvider,
1147
- ClaudeCodeTransportProvider: () => ClaudeCodeTransportProvider,
1148
- checkStatuslineIntegration: () => checkStatuslineIntegration,
1149
- createAdapter: () => createAdapter,
1150
- default: () => claude_code_default,
1151
- getSetupInstructions: () => getSetupInstructions,
1152
- getStatuslineConfig: () => getStatuslineConfig
1153
- });
1154
- function createAdapter() {
1155
- return new ClaudeCodeAdapter();
1156
- }
1157
- var claude_code_default;
1158
- var init_claude_code = __esm({
1159
- "packages/adapters/src/providers/claude-code/index.ts"() {
1160
- "use strict";
1161
- init_adapter();
1162
- init_adapter();
1163
- init_context_monitor();
1164
- init_hooks();
1165
- init_install();
1166
- init_paths();
1167
- init_spawn();
1168
- init_statusline();
1169
- init_transport();
1170
- claude_code_default = ClaudeCodeAdapter;
1171
- }
1172
- });
1173
-
1174
- // packages/adapters/src/providers/cursor/hooks.ts
1175
- var PROVIDER_ID2, CURSOR_EVENT_MAP, CursorHookProvider;
1176
- var init_hooks2 = __esm({
1177
- "packages/adapters/src/providers/cursor/hooks.ts"() {
1178
- "use strict";
1179
- PROVIDER_ID2 = "cursor";
1180
- CURSOR_EVENT_MAP = {
1181
- // CAAMP: toNative('SessionStart', 'cursor') = 'sessionStart'
1182
- sessionStart: "SessionStart",
1183
- // CAAMP: toNative('SessionEnd', 'cursor') = 'sessionEnd'
1184
- sessionEnd: "SessionEnd",
1185
- // CAAMP: toNative('PromptSubmit', 'cursor') = 'beforeSubmitPrompt'
1186
- beforeSubmitPrompt: "PromptSubmit",
1187
- // CAAMP: toNative('ResponseComplete', 'cursor') = 'stop'
1188
- stop: "ResponseComplete",
1189
- // CAAMP: toNative('PreToolUse', 'cursor') = 'preToolUse'
1190
- preToolUse: "PreToolUse",
1191
- // CAAMP: toNative('PostToolUse', 'cursor') = 'postToolUse'
1192
- postToolUse: "PostToolUse",
1193
- // CAAMP: toNative('PostToolUseFailure', 'cursor') = 'postToolUseFailure'
1194
- postToolUseFailure: "PostToolUseFailure",
1195
- // CAAMP: toNative('SubagentStart', 'cursor') = 'subagentStart'
1196
- subagentStart: "SubagentStart",
1197
- // CAAMP: toNative('SubagentStop', 'cursor') = 'subagentStop'
1198
- subagentStop: "SubagentStop",
1199
- // CAAMP: toNative('PreCompact', 'cursor') = 'preCompact'
1200
- preCompact: "PreCompact"
1201
- };
1202
- CursorHookProvider = class {
1203
- /** Whether hooks have been registered for the current session. */
1204
- registered = false;
1205
- /**
1206
- * Map a Cursor native event name to a CAAMP canonical hook event name.
1207
- *
1208
- * Looks up the native event name in the map derived from
1209
- * `getProviderHookProfile('cursor').mappings` (CAAMP 1.9.1). Cursor uses
1210
- * camelCase names (e.g. "preToolUse", "sessionStart").
1211
- *
1212
- * Returns null for unsupported events (PermissionRequest, PreModel,
1213
- * PostModel, PostCompact, Notification, ConfigChange).
1214
- *
1215
- * @param providerEvent - Cursor native event name (e.g. "preToolUse", "sessionStart")
1216
- * @returns CAAMP canonical event name, or null if unmapped
1217
- * @task T165
1218
- */
1219
- mapProviderEvent(providerEvent) {
1220
- return CURSOR_EVENT_MAP[providerEvent] ?? null;
1221
- }
1222
- /**
1223
- * Register native hooks for a project.
1224
- *
1225
- * For Cursor, hooks are registered via the config system
1226
- * (`.cursor/hooks.json`), managed by the install provider.
1227
- * This method marks hooks as registered without performing filesystem operations.
1228
- *
1229
- * Iterating supported events is handled at install time using
1230
- * `getSupportedCanonicalEvents()` to enumerate all 10 supported hooks.
1231
- *
1232
- * @param _projectDir - Project directory (unused; Cursor config manages registration)
1233
- * @task T165
1234
- */
1235
- async registerNativeHooks(_projectDir) {
1236
- this.registered = true;
1237
- }
1238
- /**
1239
- * Unregister native hooks.
1240
- *
1241
- * For Cursor, this is a no-op since hooks are managed through the config
1242
- * system. Unregistration happens via the install provider's uninstall method.
1243
- *
1244
- * @task T165
1245
- */
1246
- async unregisterNativeHooks() {
1247
- this.registered = false;
1248
- }
1249
- /**
1250
- * Check whether hooks have been registered via `registerNativeHooks`.
1251
- */
1252
- isRegistered() {
1253
- return this.registered;
1254
- }
1255
- /**
1256
- * Get the native→canonical event mapping for introspection and debugging.
1257
- *
1258
- * Returns the map derived from `getProviderHookProfile('cursor').mappings`
1259
- * (CAAMP 1.9.1). Use `getSupportedCanonicalEvents()` to enumerate canonical
1260
- * names via live CAAMP APIs.
1261
- *
1262
- * @returns Immutable record of native event name → canonical event name
1263
- */
1264
- getEventMap() {
1265
- return { ...CURSOR_EVENT_MAP };
1266
- }
1267
- /**
1268
- * Enumerate supported canonical events via CAAMP's `getSupportedEvents()`.
1269
- *
1270
- * Calls `getSupportedEvents('cursor')` from the CAAMP normalizer to get the
1271
- * authoritative list. Cursor supports 10 of 16 canonical events. Falls back
1272
- * to the values of the static event map when CAAMP is unavailable at runtime.
1273
- *
1274
- * @returns Array of CAAMP canonical event names supported by Cursor
1275
- * @task T165
1276
- */
1277
- async getSupportedCanonicalEvents() {
1278
- try {
1279
- const { getSupportedEvents } = await import("@cleocode/caamp");
1280
- return getSupportedEvents(PROVIDER_ID2);
1281
- } catch {
1282
- return [...new Set(Object.values(CURSOR_EVENT_MAP))];
1283
- }
1284
- }
1285
- /**
1286
- * Retrieve the full provider hook profile from CAAMP.
1287
- *
1288
- * Calls `getProviderHookProfile('cursor')` from the CAAMP normalizer to
1289
- * get the complete profile: hook system type (`config`), config path
1290
- * (`.cursor/hooks.json`), handler types (command, prompt), and all event
1291
- * mappings. Returns null when CAAMP is unavailable at runtime.
1292
- *
1293
- * @returns Provider hook profile or null if CAAMP is unavailable
1294
- * @task T165
1295
- */
1296
- async getProviderProfile() {
1297
- try {
1298
- const { getProviderHookProfile } = await import("@cleocode/caamp");
1299
- return getProviderHookProfile(PROVIDER_ID2) ?? null;
1300
- } catch {
1301
- return null;
1302
- }
1303
- }
1304
- /**
1305
- * Translate a CAAMP canonical event to its Cursor native name via CAAMP.
1306
- *
1307
- * Calls `toNative(canonical, 'cursor')` from the CAAMP normalizer.
1308
- * Returns null for unsupported events or when CAAMP is unavailable.
1309
- *
1310
- * @param canonical - CAAMP canonical event name (e.g. "PreToolUse")
1311
- * @returns Cursor native event name (e.g. "preToolUse") or null
1312
- * @task T165
1313
- */
1314
- async toNativeEvent(canonical) {
1315
- try {
1316
- const { toNative } = await import("@cleocode/caamp");
1317
- return toNative(canonical, PROVIDER_ID2);
1318
- } catch {
1319
- const entry = Object.entries(CURSOR_EVENT_MAP).find(([, v]) => v === canonical);
1320
- return entry?.[0] ?? null;
1321
- }
1322
- }
1323
- };
1324
- }
1325
- });
1326
-
1327
- // packages/adapters/src/providers/cursor/install.ts
1328
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
1329
- import { join as join12 } from "node:path";
1330
- var INSTRUCTION_REFERENCES3, CursorInstallProvider;
1331
- var init_install2 = __esm({
1332
- "packages/adapters/src/providers/cursor/install.ts"() {
1333
- "use strict";
1334
- INSTRUCTION_REFERENCES3 = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
1335
- CursorInstallProvider = class {
1336
- /**
1337
- * Install CLEO into a Cursor project.
1338
- *
1339
- * @param options - Installation options including project directory
1340
- * @returns Result describing what was installed
1341
- */
1342
- async install(options) {
1343
- const { projectDir } = options;
1344
- const installedAt = (/* @__PURE__ */ new Date()).toISOString();
1345
- let instructionFileUpdated = false;
1346
- const details = {};
1347
- instructionFileUpdated = this.updateInstructionFiles(projectDir);
1348
- if (instructionFileUpdated) {
1349
- details.instructionFiles = this.getUpdatedFileList(projectDir);
1350
- }
1351
- return {
1352
- success: true,
1353
- installedAt,
1354
- instructionFileUpdated,
1355
- mcpRegistered: false,
1356
- details
1357
- };
1358
- }
1359
- /**
1360
- * Uninstall CLEO from the current Cursor project.
1361
- *
1362
- * Does not remove instruction file references (they are harmless if CLEO is not present).
1363
- */
1364
- async uninstall() {
1365
- }
1366
- /**
1367
- * Check whether CLEO is installed in the current environment.
1368
- *
1369
- * Checks for .cursor/rules/cleo.mdc or .cursorrules with CLEO references.
1370
- */
1371
- async isInstalled() {
1372
- const mdcPath = join12(process.cwd(), ".cursor", "rules", "cleo.mdc");
1373
- if (existsSync7(mdcPath)) {
1374
- return true;
1375
- }
1376
- const rulesPath = join12(process.cwd(), ".cursorrules");
1377
- if (existsSync7(rulesPath)) {
1378
- try {
1379
- const content = readFileSync5(rulesPath, "utf-8");
1380
- if (INSTRUCTION_REFERENCES3.some((ref) => content.includes(ref))) {
1381
- return true;
1382
- }
1383
- } catch {
1384
- }
1385
- }
1386
- return false;
1387
- }
1388
- /**
1389
- * Ensure instruction files contain @-references to CLEO.
1390
- *
1391
- * Updates .cursorrules (legacy) and creates .cursor/rules/cleo.mdc (modern).
1392
- *
1393
- * @param projectDir - Project root directory
1394
- */
1395
- async ensureInstructionReferences(projectDir) {
1396
- this.updateInstructionFiles(projectDir);
1397
- }
1398
- /**
1399
- * Update instruction files with CLEO @-references.
1400
- *
1401
- * Handles both legacy (.cursorrules) and modern (.cursor/rules/cleo.mdc) formats.
1402
- *
1403
- * @returns true if any file was created or modified
1404
- */
1405
- updateInstructionFiles(projectDir) {
1406
- let updated = false;
1407
- if (this.updateLegacyRules(projectDir)) {
1408
- updated = true;
1409
- }
1410
- if (this.updateModernRules(projectDir)) {
1411
- updated = true;
1412
- }
1413
- return updated;
1414
- }
1415
- /**
1416
- * Update legacy .cursorrules file with @-references.
1417
- * Only modifies the file if it already exists (does not create it).
1418
- *
1419
- * @returns true if the file was modified
1420
- */
1421
- updateLegacyRules(projectDir) {
1422
- const rulesPath = join12(projectDir, ".cursorrules");
1423
- if (!existsSync7(rulesPath)) {
1424
- return false;
1425
- }
1426
- let content = readFileSync5(rulesPath, "utf-8");
1427
- const missingRefs = INSTRUCTION_REFERENCES3.filter((ref) => !content.includes(ref));
1428
- if (missingRefs.length === 0) {
1429
- return false;
1430
- }
1431
- const separator = content.endsWith("\n") ? "" : "\n";
1432
- content = content + separator + missingRefs.join("\n") + "\n";
1433
- writeFileSync4(rulesPath, content, "utf-8");
1434
- return true;
1435
- }
1436
- /**
1437
- * Create or update .cursor/rules/cleo.mdc with CLEO references.
1438
- *
1439
- * MDC (Markdown Component) format is Cursor's modern rule file format.
1440
- * Each .mdc file in .cursor/rules/ is loaded as a rule set.
1441
- *
1442
- * @returns true if the file was created or modified
1443
- */
1444
- updateModernRules(projectDir) {
1445
- const rulesDir = join12(projectDir, ".cursor", "rules");
1446
- const mdcPath = join12(rulesDir, "cleo.mdc");
1447
- const expectedContent = [
1448
- "---",
1449
- "description: CLEO task management protocol references",
1450
- 'globs: "**/*"',
1451
- "alwaysApply: true",
1452
- "---",
1453
- "",
1454
- ...INSTRUCTION_REFERENCES3,
1455
- ""
1456
- ].join("\n");
1457
- if (existsSync7(mdcPath)) {
1458
- const existing = readFileSync5(mdcPath, "utf-8");
1459
- if (existing === expectedContent) {
1460
- return false;
1461
- }
1462
- }
1463
- mkdirSync2(rulesDir, { recursive: true });
1464
- writeFileSync4(mdcPath, expectedContent, "utf-8");
1465
- return true;
1466
- }
1467
- /**
1468
- * Get list of instruction files that were updated.
1469
- */
1470
- getUpdatedFileList(projectDir) {
1471
- const files = [];
1472
- if (existsSync7(join12(projectDir, ".cursorrules"))) {
1473
- files.push(join12(projectDir, ".cursorrules"));
1474
- }
1475
- files.push(join12(projectDir, ".cursor", "rules", "cleo.mdc"));
1476
- return files;
1477
- }
1478
- };
1479
- }
1480
- });
1481
-
1482
- // packages/adapters/src/providers/cursor/adapter.ts
1483
- import { existsSync as existsSync8 } from "node:fs";
1484
- import { join as join13 } from "node:path";
1485
- var CursorAdapter;
1486
- var init_adapter2 = __esm({
1487
- "packages/adapters/src/providers/cursor/adapter.ts"() {
1488
- "use strict";
1489
- init_hooks2();
1490
- init_install2();
1491
- CursorAdapter = class {
1492
- /** Unique provider identifier. */
1493
- id = "cursor";
1494
- /** Human-readable provider name. */
1495
- name = "Cursor";
1496
- /** Adapter version string. */
1497
- version = "1.0.0";
1498
- /** Declared capabilities for this provider. */
1499
- capabilities = {
1500
- supportsHooks: true,
1501
- // 10/16 canonical events — derived from getProviderHookProfile('cursor') in CAAMP 1.9.1.
1502
- // PermissionRequest, PreModel, PostModel, PostCompact, Notification, ConfigChange are
1503
- // not supported by Cursor's hook system.
1504
- supportedHookEvents: [
1505
- "SessionStart",
1506
- "SessionEnd",
1507
- "PromptSubmit",
1508
- "ResponseComplete",
1509
- "PreToolUse",
1510
- "PostToolUse",
1511
- "PostToolUseFailure",
1512
- "SubagentStart",
1513
- "SubagentStop",
1514
- "PreCompact"
1515
- ],
1516
- supportsSpawn: false,
1517
- supportsInstall: true,
1518
- supportsMcp: false,
1519
- supportsInstructionFiles: true,
1520
- instructionFilePattern: ".cursor/rules/*.mdc",
1521
- supportsContextMonitor: false,
1522
- supportsStatusline: false,
1523
- supportsProviderPaths: true,
1524
- supportsTransport: false,
1525
- supportsTaskSync: false
1526
- };
1527
- /** Hook provider for CAAMP event mapping. */
1528
- hooks;
1529
- /** Install provider for managing rule files. */
1530
- install;
1531
- /** Project directory this adapter was initialized with, or null. */
1532
- projectDir = null;
1533
- /** Whether {@link initialize} has been called. */
1534
- initialized = false;
1535
- constructor() {
1536
- this.hooks = new CursorHookProvider();
1537
- this.install = new CursorInstallProvider();
1538
- }
1539
- /**
1540
- * Initialize the adapter for a given project directory.
1541
- *
1542
- * @param projectDir - Root directory of the project
1543
- */
1544
- async initialize(projectDir) {
1545
- this.projectDir = projectDir;
1546
- this.initialized = true;
1547
- }
1548
- /**
1549
- * Dispose the adapter and clean up resources.
1550
- */
1551
- async dispose() {
1552
- if (this.hooks.isRegistered()) {
1553
- await this.hooks.unregisterNativeHooks();
1554
- }
1555
- this.initialized = false;
1556
- this.projectDir = null;
1557
- }
1558
- /**
1559
- * Run a health check to verify Cursor is accessible.
1560
- *
1561
- * Checks:
1562
- * 1. Adapter has been initialized
1563
- * 2. .cursor/ configuration directory exists in the project
1564
- * 3. CURSOR_EDITOR env var is set
1565
- *
1566
- * @returns Health status with details about each check
1567
- */
1568
- async healthCheck() {
1569
- const details = {};
1570
- if (!this.initialized) {
1571
- return {
1572
- healthy: false,
1573
- provider: this.id,
1574
- details: { error: "Adapter not initialized" }
1575
- };
1576
- }
1577
- let configExists = false;
1578
- if (this.projectDir) {
1579
- const cursorConfigDir = join13(this.projectDir, ".cursor");
1580
- configExists = existsSync8(cursorConfigDir);
1581
- details.configDirExists = configExists;
1582
- }
1583
- const editorEnvSet = process.env.CURSOR_EDITOR !== void 0;
1584
- details.editorEnvSet = editorEnvSet;
1585
- if (this.projectDir) {
1586
- const legacyRulesExist = existsSync8(join13(this.projectDir, ".cursorrules"));
1587
- details.legacyRulesExist = legacyRulesExist;
1588
- }
1589
- const healthy = configExists || editorEnvSet;
1590
- details.detected = healthy;
1591
- return {
1592
- healthy,
1593
- provider: this.id,
1594
- details
1595
- };
1596
- }
1597
- /**
1598
- * Check whether the adapter has been initialized.
1599
- */
1600
- isInitialized() {
1601
- return this.initialized;
1602
- }
1603
- /**
1604
- * Get the project directory this adapter was initialized with.
1605
- */
1606
- getProjectDir() {
1607
- return this.projectDir;
1608
- }
1609
- };
1610
- }
1611
- });
1612
-
1613
- // packages/adapters/src/providers/cursor/index.ts
1614
- var cursor_exports = {};
1615
- __export(cursor_exports, {
1616
- CursorAdapter: () => CursorAdapter,
1617
- CursorHookProvider: () => CursorHookProvider,
1618
- CursorInstallProvider: () => CursorInstallProvider,
1619
- createAdapter: () => createAdapter3,
1620
- default: () => cursor_default
1621
- });
1622
- function createAdapter3() {
1623
- return new CursorAdapter();
1624
- }
1625
- var cursor_default;
1626
- var init_cursor = __esm({
1627
- "packages/adapters/src/providers/cursor/index.ts"() {
1628
- "use strict";
1629
- init_adapter2();
1630
- init_adapter2();
1631
- init_hooks2();
1632
- init_install2();
1633
- cursor_default = CursorAdapter;
1634
- }
1635
- });
1636
-
1637
- // packages/adapters/src/providers/opencode/hooks.ts
1638
- var PROVIDER_ID3, OPENCODE_EVENT_MAP, OpenCodeHookProvider;
1639
- var init_hooks3 = __esm({
1640
- "packages/adapters/src/providers/opencode/hooks.ts"() {
1641
- "use strict";
1642
- PROVIDER_ID3 = "opencode";
1643
- OPENCODE_EVENT_MAP = {
1644
- // CAAMP: toNative('SessionStart', 'opencode') = 'event:session.created'
1645
- "event:session.created": "SessionStart",
1646
- // CAAMP: toNative('SessionEnd', 'opencode') = 'event:session.deleted'
1647
- "event:session.deleted": "SessionEnd",
1648
- // CAAMP: toNative('PromptSubmit', 'opencode') = 'chat.message'
1649
- "chat.message": "PromptSubmit",
1650
- // CAAMP: toNative('ResponseComplete', 'opencode') = 'event:session.idle'
1651
- "event:session.idle": "ResponseComplete",
1652
- // CAAMP: toNative('PreToolUse', 'opencode') = 'tool.execute.before'
1653
- "tool.execute.before": "PreToolUse",
1654
- // CAAMP: toNative('PostToolUse', 'opencode') = 'tool.execute.after'
1655
- "tool.execute.after": "PostToolUse",
1656
- // CAAMP: toNative('PermissionRequest', 'opencode') = 'permission.ask'
1657
- "permission.ask": "PermissionRequest",
1658
- // CAAMP: toNative('PreModel', 'opencode') = 'chat.params'
1659
- "chat.params": "PreModel",
1660
- // CAAMP: toNative('PreCompact', 'opencode') = 'experimental.session.compacting'
1661
- "experimental.session.compacting": "PreCompact",
1662
- // CAAMP: toNative('PostCompact', 'opencode') = 'event:session.compacted'
1663
- "event:session.compacted": "PostCompact"
1664
- };
1665
- OpenCodeHookProvider = class {
1666
- /** Whether hooks have been registered for the current session. */
1667
- registered = false;
1668
- /**
1669
- * Map an OpenCode native event name to a CAAMP canonical hook event name.
1670
- *
1671
- * Looks up the native event name in the map derived from
1672
- * `getProviderHookProfile('opencode').mappings` (CAAMP 1.9.1).
1673
- * Returns null for unsupported events (PostToolUseFailure, SubagentStart,
1674
- * SubagentStop, Notification, ConfigChange).
1675
- *
1676
- * @param providerEvent - OpenCode native event (e.g. "event:session.created", "tool.execute.before")
1677
- * @returns CAAMP canonical event name, or null if unmapped
1678
- * @task T164
1679
- */
1680
- mapProviderEvent(providerEvent) {
1681
- return OPENCODE_EVENT_MAP[providerEvent] ?? null;
1682
- }
1683
- /**
1684
- * Register native hooks for a project.
1685
- *
1686
- * For OpenCode, hooks are registered via the plugin system
1687
- * (`.opencode/plugins/`), managed by the install provider.
1688
- * This method marks hooks as registered without performing filesystem operations.
1689
- *
1690
- * Iterating supported events is handled at install time using
1691
- * `getSupportedCanonicalEvents()` to enumerate all 10 supported hooks.
1692
- *
1693
- * @param _projectDir - Project directory (unused; config manages registration)
1694
- * @task T164
1695
- */
1696
- async registerNativeHooks(_projectDir) {
1697
- this.registered = true;
1698
- }
1699
- /**
1700
- * Unregister native hooks.
1701
- *
1702
- * For OpenCode, this is a no-op since hooks are managed through the plugin
1703
- * system. Unregistration happens via the install provider's uninstall method.
1704
- *
1705
- * @task T164
1706
- */
1707
- async unregisterNativeHooks() {
1708
- this.registered = false;
1709
- }
1710
- /**
1711
- * Check whether hooks have been registered via `registerNativeHooks`.
1712
- */
1713
- isRegistered() {
1714
- return this.registered;
1715
- }
1716
- /**
1717
- * Get the native→canonical event mapping for introspection and debugging.
1718
- *
1719
- * Returns the map derived from `getProviderHookProfile('opencode').mappings`
1720
- * (CAAMP 1.9.1). Use `getSupportedCanonicalEvents()` to enumerate canonical
1721
- * names via live CAAMP APIs.
1722
- *
1723
- * @returns Immutable record of native event name → canonical event name
1724
- */
1725
- getEventMap() {
1726
- return { ...OPENCODE_EVENT_MAP };
1727
- }
1728
- /**
1729
- * Enumerate supported canonical events via CAAMP's `getSupportedEvents()`.
1730
- *
1731
- * Calls `getSupportedEvents('opencode')` from the CAAMP normalizer to get the
1732
- * authoritative list. OpenCode supports 10 of 16 canonical events via its
1733
- * plugin system. Falls back to the values of the static event map when
1734
- * CAAMP is unavailable at runtime.
1735
- *
1736
- * @returns Array of CAAMP canonical event names supported by OpenCode
1737
- * @task T164
1738
- */
1739
- async getSupportedCanonicalEvents() {
1740
- try {
1741
- const { getSupportedEvents } = await import("@cleocode/caamp");
1742
- return getSupportedEvents(PROVIDER_ID3);
1743
- } catch {
1744
- return [...new Set(Object.values(OPENCODE_EVENT_MAP))];
1745
- }
1746
- }
1747
- /**
1748
- * Retrieve the full provider hook profile from CAAMP.
1749
- *
1750
- * Calls `getProviderHookProfile('opencode')` from the CAAMP normalizer to
1751
- * get the complete profile: hook system type (`plugin`), config path
1752
- * (`.opencode/plugins/`), handler types, and all event mappings.
1753
- * Returns null when CAAMP is unavailable at runtime.
1754
- *
1755
- * @returns Provider hook profile or null if CAAMP is unavailable
1756
- * @task T164
1757
- */
1758
- async getProviderProfile() {
1759
- try {
1760
- const { getProviderHookProfile } = await import("@cleocode/caamp");
1761
- return getProviderHookProfile(PROVIDER_ID3) ?? null;
1762
- } catch {
1763
- return null;
1764
- }
1765
- }
1766
- /**
1767
- * Translate a CAAMP canonical event to its OpenCode native name via CAAMP.
1768
- *
1769
- * Calls `toNative(canonical, 'opencode')` from the CAAMP normalizer.
1770
- * Returns null for unsupported events or when CAAMP is unavailable.
1771
- *
1772
- * @param canonical - CAAMP canonical event name (e.g. "PreToolUse")
1773
- * @returns OpenCode native event name or null
1774
- * @task T164
1775
- */
1776
- async toNativeEvent(canonical) {
1777
- try {
1778
- const { toNative } = await import("@cleocode/caamp");
1779
- return toNative(canonical, PROVIDER_ID3);
1780
- } catch {
1781
- const entry = Object.entries(OPENCODE_EVENT_MAP).find(([, v]) => v === canonical);
1782
- return entry?.[0] ?? null;
1783
- }
1784
- }
1785
- };
1786
- }
1787
- });
1788
-
1789
- // packages/adapters/src/providers/opencode/install.ts
1790
- import { existsSync as existsSync13, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "node:fs";
1791
- import { join as join19 } from "node:path";
1792
- var INSTRUCTION_REFERENCES6, OpenCodeInstallProvider;
1793
- var init_install3 = __esm({
1794
- "packages/adapters/src/providers/opencode/install.ts"() {
1795
- "use strict";
1796
- INSTRUCTION_REFERENCES6 = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
1797
- OpenCodeInstallProvider = class {
1798
- /**
1799
- * Install CLEO into an OpenCode project.
1800
- *
1801
- * @param options - Installation options including project directory
1802
- * @returns Result describing what was installed
1803
- */
1804
- async install(options) {
1805
- const { projectDir } = options;
1806
- const installedAt = (/* @__PURE__ */ new Date()).toISOString();
1807
- let instructionFileUpdated = false;
1808
- const details = {};
1809
- instructionFileUpdated = this.updateInstructionFile(projectDir);
1810
- if (instructionFileUpdated) {
1811
- details.instructionFile = join19(projectDir, "AGENTS.md");
1812
- }
1813
- return {
1814
- success: true,
1815
- installedAt,
1816
- instructionFileUpdated,
1817
- mcpRegistered: false,
1818
- details
1819
- };
1820
- }
1821
- /**
1822
- * Uninstall CLEO from the current OpenCode project.
1823
- *
1824
- * Does not remove AGENTS.md references (they are harmless if CLEO is not present).
1825
- */
1826
- async uninstall() {
1827
- }
1828
- /**
1829
- * Check whether CLEO is installed in the current environment.
1830
- *
1831
- * Checks for CLEO references in AGENTS.md.
1832
- */
1833
- async isInstalled() {
1834
- const agentsMdPath = join19(process.cwd(), "AGENTS.md");
1835
- if (existsSync13(agentsMdPath)) {
1836
- try {
1837
- const content = readFileSync8(agentsMdPath, "utf-8");
1838
- if (INSTRUCTION_REFERENCES6.some((ref) => content.includes(ref))) {
1839
- return true;
1840
- }
1841
- } catch {
1842
- }
1843
- }
1844
- return false;
1845
- }
1846
- /**
1847
- * Ensure AGENTS.md contains @-references to CLEO instruction files.
1848
- *
1849
- * Creates AGENTS.md if it does not exist. Appends any missing references.
1850
- *
1851
- * @param projectDir - Project root directory
1852
- */
1853
- async ensureInstructionReferences(projectDir) {
1854
- this.updateInstructionFile(projectDir);
1855
- }
1856
- /**
1857
- * Update AGENTS.md with CLEO @-references.
1858
- *
1859
- * @returns true if the file was created or modified
1860
- */
1861
- updateInstructionFile(projectDir) {
1862
- const agentsMdPath = join19(projectDir, "AGENTS.md");
1863
- let content = "";
1864
- let existed = false;
1865
- if (existsSync13(agentsMdPath)) {
1866
- content = readFileSync8(agentsMdPath, "utf-8");
1867
- existed = true;
1868
- }
1869
- const missingRefs = INSTRUCTION_REFERENCES6.filter((ref) => !content.includes(ref));
1870
- if (missingRefs.length === 0) {
1871
- return false;
1872
- }
1873
- const refsBlock = missingRefs.join("\n");
1874
- if (existed) {
1875
- const separator = content.endsWith("\n") ? "" : "\n";
1876
- content = content + separator + refsBlock + "\n";
1877
- } else {
1878
- content = refsBlock + "\n";
1879
- }
1880
- writeFileSync7(agentsMdPath, content, "utf-8");
1881
- return true;
1882
- }
1883
- };
1884
- }
1885
- });
1886
-
1887
- // packages/adapters/src/providers/opencode/spawn.ts
1888
- import { exec as exec6, spawn as nodeSpawn2 } from "node:child_process";
1889
- import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
1890
- import { join as join20 } from "node:path";
1891
- import { promisify as promisify6 } from "node:util";
1892
- function buildOpenCodeAgentMarkdown(description, instructions) {
1893
- const normalizedDesc = description.replace(/\s+/g, " ").trim();
1894
- return [
1895
- "---",
1896
- `description: ${JSON.stringify(normalizedDesc)}`,
1897
- "mode: subagent",
1898
- "hidden: true",
1899
- "---",
1900
- "",
1901
- instructions.trim(),
1902
- ""
1903
- ].join("\n");
1904
- }
1905
- async function ensureSubagentDefinition(workingDirectory) {
1906
- const agentDir = join20(workingDirectory, ".opencode", "agent");
1907
- const agentPath = join20(agentDir, `${OPENCODE_SUBAGENT_NAME}.md`);
1908
- const description = "CLEO task executor with protocol compliance.";
1909
- const instructions = [
1910
- "# CLEO Subagent",
1911
- "",
1912
- "You are a CLEO subagent executing a delegated task.",
1913
- "Follow the CLEO protocol and complete the assigned work.",
1914
- "",
1915
- "@~/.cleo/templates/CLEO-INJECTION.md"
1916
- ].join("\n");
1917
- const content = buildOpenCodeAgentMarkdown(description, instructions);
1918
- await mkdir2(agentDir, { recursive: true });
1919
- let existing = null;
1920
- try {
1921
- existing = await readFile4(agentPath, "utf-8");
1922
- } catch {
1923
- existing = null;
1924
- }
1925
- if (existing !== content) {
1926
- await writeFile2(agentPath, content, "utf-8");
1927
- }
1928
- return OPENCODE_SUBAGENT_NAME;
1929
- }
1930
- var execAsync6, OPENCODE_SUBAGENT_NAME, OPENCODE_FALLBACK_AGENT, OpenCodeSpawnProvider;
1931
- var init_spawn2 = __esm({
1932
- "packages/adapters/src/providers/opencode/spawn.ts"() {
1933
- "use strict";
1934
- execAsync6 = promisify6(exec6);
1935
- OPENCODE_SUBAGENT_NAME = "cleo-subagent";
1936
- OPENCODE_FALLBACK_AGENT = "general";
1937
- OpenCodeSpawnProvider = class {
1938
- /** Map of instance IDs to tracked process info. */
1939
- processMap = /* @__PURE__ */ new Map();
1940
- /**
1941
- * Check if the OpenCode CLI is available in PATH.
1942
- *
1943
- * @returns true if `opencode` is found via `which`
1944
- */
1945
- async canSpawn() {
1946
- try {
1947
- await execAsync6("which opencode");
1948
- return true;
1949
- } catch {
1950
- return false;
1951
- }
1952
- }
1953
- /**
1954
- * Spawn a subagent via OpenCode CLI.
1955
- *
1956
- * Ensures the CLEO subagent definition exists in the project's
1957
- * .opencode/agent/ directory, then spawns a detached OpenCode
1958
- * process. The process runs independently of the parent.
1959
- *
1960
- * @param context - Spawn context with taskId, prompt, and options
1961
- * @returns Spawn result with instance ID and status
1962
- */
1963
- async spawn(context) {
1964
- const instanceId = `opencode-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1965
- const startTime = (/* @__PURE__ */ new Date()).toISOString();
1966
- const workingDirectory = context.workingDirectory ?? process.cwd();
1967
- try {
1968
- let agentName;
1969
- try {
1970
- agentName = await ensureSubagentDefinition(workingDirectory);
1971
- } catch {
1972
- agentName = OPENCODE_FALLBACK_AGENT;
1973
- }
1974
- const child = nodeSpawn2(
1975
- "opencode",
1976
- [
1977
- "run",
1978
- "--format",
1979
- "json",
1980
- "--agent",
1981
- agentName,
1982
- "--title",
1983
- `CLEO ${context.taskId}`,
1984
- context.prompt
1985
- ],
1986
- {
1987
- cwd: workingDirectory,
1988
- detached: true,
1989
- stdio: "ignore"
1990
- }
1991
- );
1992
- child.unref();
1993
- if (child.pid) {
1994
- this.processMap.set(instanceId, {
1995
- pid: child.pid,
1996
- taskId: context.taskId,
1997
- startTime
1998
- });
1999
- }
2000
- child.on("exit", () => {
2001
- this.processMap.delete(instanceId);
2002
- });
2003
- return {
2004
- instanceId,
2005
- taskId: context.taskId,
2006
- providerId: "opencode",
2007
- status: "running",
2008
- startTime
2009
- };
2010
- } catch {
2011
- return {
2012
- instanceId,
2013
- taskId: context.taskId,
2014
- providerId: "opencode",
2015
- status: "failed",
2016
- startTime,
2017
- endTime: (/* @__PURE__ */ new Date()).toISOString()
2018
- };
2019
- }
2020
- }
2021
- /**
2022
- * List currently running OpenCode subagent processes.
2023
- *
2024
- * Checks each tracked process via kill(pid, 0) to verify it is still alive.
2025
- * Dead processes are automatically cleaned from the tracking map.
2026
- *
2027
- * @returns Array of spawn results for running processes
2028
- */
2029
- async listRunning() {
2030
- const running = [];
2031
- for (const [instanceId, tracked] of this.processMap.entries()) {
2032
- try {
2033
- process.kill(tracked.pid, 0);
2034
- running.push({
2035
- instanceId,
2036
- taskId: tracked.taskId,
2037
- providerId: "opencode",
2038
- status: "running",
2039
- startTime: tracked.startTime
2040
- });
2041
- } catch {
2042
- this.processMap.delete(instanceId);
2043
- }
2044
- }
2045
- return running;
2046
- }
2047
- /**
2048
- * Terminate a running spawn by instance ID.
2049
- *
2050
- * Sends SIGTERM to the tracked process. If the process is not found
2051
- * or has already exited, this is a no-op.
2052
- *
2053
- * @param instanceId - ID of the spawn instance to terminate
2054
- */
2055
- async terminate(instanceId) {
2056
- const tracked = this.processMap.get(instanceId);
2057
- if (!tracked) return;
2058
- try {
2059
- process.kill(tracked.pid, "SIGTERM");
2060
- } catch {
2061
- }
2062
- this.processMap.delete(instanceId);
2063
- }
2064
- };
2065
- }
2066
- });
2067
-
2068
- // packages/adapters/src/providers/opencode/adapter.ts
2069
- import { exec as exec7 } from "node:child_process";
2070
- import { existsSync as existsSync14 } from "node:fs";
2071
- import { join as join21 } from "node:path";
2072
- import { promisify as promisify7 } from "node:util";
2073
- var execAsync7, OpenCodeAdapter;
2074
- var init_adapter3 = __esm({
2075
- "packages/adapters/src/providers/opencode/adapter.ts"() {
2076
- "use strict";
2077
- init_hooks3();
2078
- init_install3();
2079
- init_spawn2();
2080
- execAsync7 = promisify7(exec7);
2081
- OpenCodeAdapter = class {
2082
- /** Unique provider identifier. */
2083
- id = "opencode";
2084
- /** Human-readable provider name. */
2085
- name = "OpenCode";
2086
- /** Adapter version string. */
2087
- version = "1.0.0";
2088
- /** Declared capabilities for this provider. */
2089
- capabilities = {
2090
- supportsHooks: true,
2091
- // 10/16 canonical events — derived from getProviderHookProfile('opencode') in CAAMP 1.9.1.
2092
- // PostToolUseFailure, SubagentStart, SubagentStop, Notification, ConfigChange are
2093
- // not supported by OpenCode's plugin system.
2094
- supportedHookEvents: [
2095
- "SessionStart",
2096
- "SessionEnd",
2097
- "PromptSubmit",
2098
- "ResponseComplete",
2099
- "PreToolUse",
2100
- "PostToolUse",
2101
- "PermissionRequest",
2102
- "PreModel",
2103
- "PreCompact",
2104
- "PostCompact"
2105
- ],
2106
- supportsSpawn: true,
2107
- supportsInstall: true,
2108
- supportsMcp: false,
2109
- supportsInstructionFiles: true,
2110
- instructionFilePattern: "AGENTS.md",
2111
- supportsContextMonitor: false,
2112
- supportsStatusline: false,
2113
- supportsProviderPaths: true,
2114
- supportsTransport: false,
2115
- supportsTaskSync: false
2116
- };
2117
- /** Hook provider for CAAMP event mapping via OpenCode's plugin system. */
2118
- hooks;
2119
- /** Spawn provider for launching subagent processes via `opencode run`. */
2120
- spawn;
2121
- /** Install provider for managing AGENTS.md instruction files. */
2122
- install;
2123
- /** Project directory this adapter was initialized with, or null. */
2124
- projectDir = null;
2125
- /** Whether {@link initialize} has been called. */
2126
- initialized = false;
2127
- constructor() {
2128
- this.hooks = new OpenCodeHookProvider();
2129
- this.spawn = new OpenCodeSpawnProvider();
2130
- this.install = new OpenCodeInstallProvider();
2131
- }
2132
- /**
2133
- * Initialize the adapter for a given project directory.
2134
- *
2135
- * Validates the environment by checking for the OpenCode CLI
2136
- * and OpenCode configuration directory.
2137
- *
2138
- * @param projectDir - Root directory of the project
2139
- */
2140
- async initialize(projectDir) {
2141
- this.projectDir = projectDir;
2142
- this.initialized = true;
2143
- }
2144
- /**
2145
- * Dispose the adapter and clean up resources.
2146
- *
2147
- * Unregisters hooks and releases any tracked state.
2148
- */
2149
- async dispose() {
2150
- if (this.hooks.isRegistered()) {
2151
- await this.hooks.unregisterNativeHooks();
2152
- }
2153
- this.initialized = false;
2154
- this.projectDir = null;
2155
- }
2156
- /**
2157
- * Run a health check to verify OpenCode is accessible.
2158
- *
2159
- * Checks:
2160
- * 1. Adapter has been initialized
2161
- * 2. OpenCode CLI is available in PATH
2162
- * 3. .opencode/ configuration directory exists in the project
2163
- *
2164
- * @returns Health status with details about each check
2165
- */
2166
- async healthCheck() {
2167
- const details = {};
2168
- if (!this.initialized) {
2169
- return {
2170
- healthy: false,
2171
- provider: this.id,
2172
- details: { error: "Adapter not initialized" }
2173
- };
2174
- }
2175
- let cliAvailable = false;
2176
- try {
2177
- const { stdout } = await execAsync7("which opencode");
2178
- cliAvailable = stdout.trim().length > 0;
2179
- details.cliPath = stdout.trim();
2180
- } catch {
2181
- details.cliAvailable = false;
2182
- }
2183
- if (this.projectDir) {
2184
- const openCodeConfigDir = join21(this.projectDir, ".opencode");
2185
- const configExists = existsSync14(openCodeConfigDir);
2186
- details.configDirExists = configExists;
2187
- }
2188
- const versionEnvSet = process.env.OPENCODE_VERSION !== void 0;
2189
- details.versionEnvSet = versionEnvSet;
2190
- const healthy = cliAvailable;
2191
- details.cliAvailable = cliAvailable;
2192
- return {
2193
- healthy,
2194
- provider: this.id,
2195
- details
2196
- };
2197
- }
2198
- /**
2199
- * Check whether the adapter has been initialized.
2200
- */
2201
- isInitialized() {
2202
- return this.initialized;
2203
- }
2204
- /**
2205
- * Get the project directory this adapter was initialized with.
2206
- */
2207
- getProjectDir() {
2208
- return this.projectDir;
2209
- }
2210
- };
2211
- }
2212
- });
2213
-
2214
- // packages/adapters/src/providers/opencode/index.ts
2215
- var opencode_exports = {};
2216
- __export(opencode_exports, {
2217
- OpenCodeAdapter: () => OpenCodeAdapter,
2218
- OpenCodeHookProvider: () => OpenCodeHookProvider,
2219
- OpenCodeInstallProvider: () => OpenCodeInstallProvider,
2220
- OpenCodeSpawnProvider: () => OpenCodeSpawnProvider,
2221
- createAdapter: () => createAdapter6,
2222
- default: () => opencode_default
2223
- });
2224
- function createAdapter6() {
2225
- return new OpenCodeAdapter();
2226
- }
2227
- var opencode_default;
2228
- var init_opencode = __esm({
2229
- "packages/adapters/src/providers/opencode/index.ts"() {
2230
- "use strict";
2231
- init_adapter3();
2232
- init_adapter3();
2233
- init_hooks3();
2234
- init_install3();
2235
- init_spawn2();
2236
- opencode_default = OpenCodeAdapter;
2237
- }
2238
- });
2239
-
2240
- // packages/adapters/src/index.ts
2241
- init_claude_code();
2242
-
2243
- // packages/adapters/src/providers/codex/adapter.ts
2244
- import { exec as exec3 } from "node:child_process";
2245
- import { existsSync as existsSync6 } from "node:fs";
2246
- import { homedir as homedir7 } from "node:os";
2247
- import { join as join11 } from "node:path";
2248
- import { promisify as promisify3 } from "node:util";
2249
-
2250
- // packages/adapters/src/providers/codex/hooks.ts
2251
- import { homedir as homedir6 } from "node:os";
2252
- import { join as join9 } from "node:path";
2253
-
2254
- // packages/adapters/src/providers/shared/transcript-reader.ts
2255
- import { readdir as readdir2, readFile as readFile3 } from "node:fs/promises";
2256
- import { join as join8 } from "node:path";
2257
- function parseTranscriptLines(raw) {
2258
- const turns = [];
2259
- const lines = raw.split("\n").filter((l) => l.trim());
2260
- for (const line of lines) {
2261
- try {
2262
- const entry = JSON.parse(line);
2263
- const role = entry.role;
2264
- const content = entry.content;
2265
- if (typeof role === "string" && typeof content === "string") {
2266
- turns.push({ role, content });
2267
- }
2268
- } catch {
2269
- }
2270
- }
2271
- return turns;
2272
- }
2273
- async function readLatestTranscript(providerDir) {
2274
- let allFiles = [];
2275
- try {
2276
- const entries = await readdir2(providerDir, { withFileTypes: true });
2277
- for (const entry of entries) {
2278
- if (!entry.isFile()) continue;
2279
- const name = entry.name;
2280
- if (name.endsWith(".json") || name.endsWith(".jsonl")) {
2281
- allFiles.push(join8(providerDir, name));
2282
- }
2283
- }
2284
- } catch {
2285
- return null;
2286
- }
2287
- if (allFiles.length === 0) return null;
2288
- allFiles = allFiles.sort((a, b) => b.localeCompare(a));
2289
- const mostRecent = allFiles[0];
2290
- if (!mostRecent) return null;
2291
- try {
2292
- const raw = await readFile3(mostRecent, "utf-8");
2293
- const turns = parseTranscriptLines(raw);
2294
- return turns.length > 0 ? turns.map((t) => `${t.role}: ${t.content}`).join("\n") : null;
2295
- } catch {
2296
- return null;
2297
- }
2298
- }
2299
-
2300
- // packages/adapters/src/providers/codex/hooks.ts
2301
- var CODEX_EVENT_MAP = {
2302
- SessionStart: "SessionStart",
2303
- PromptSubmit: "UserPromptSubmit",
2304
- ResponseComplete: "Stop"
2305
- };
2306
- var CodexHookProvider = class {
2307
- /** Whether hooks have been registered for the current session. */
2308
- registered = false;
2309
- /**
2310
- * Map a Codex CLI native event name to a CAAMP hook event name.
2311
- *
2312
- * @param providerEvent - Codex CLI event name (e.g. "SessionStart", "PromptSubmit")
2313
- * @returns CAAMP event name or null if unmapped
2314
- * @task T162
2315
- */
2316
- mapProviderEvent(providerEvent) {
2317
- return CODEX_EVENT_MAP[providerEvent] ?? null;
2318
- }
2319
- /**
2320
- * Register native hooks for a project.
2321
- *
2322
- * For Codex CLI, hooks are registered via the config system
2323
- * (~/.codex/), which is handled by the install provider.
2324
- * This method marks hooks as registered without performing
2325
- * filesystem operations.
2326
- *
2327
- * @param _projectDir - Project directory (unused; hooks are global)
2328
- * @task T162
2329
- */
2330
- async registerNativeHooks(_projectDir) {
2331
- this.registered = true;
2332
- }
2333
- /**
2334
- * Unregister native hooks.
2335
- *
2336
- * For Codex CLI, this is a no-op since hooks are managed through
2337
- * the config system. Unregistration happens via the install
2338
- * provider's uninstall method.
2339
- * @task T162
2340
- */
2341
- async unregisterNativeHooks() {
2342
- this.registered = false;
2343
- }
2344
- /**
2345
- * Check whether hooks have been registered via registerNativeHooks.
2346
- * @task T162
2347
- */
2348
- isRegistered() {
2349
- return this.registered;
2350
- }
2351
- /**
2352
- * Get the full event mapping for introspection/debugging.
2353
- * @task T162
2354
- */
2355
- getEventMap() {
2356
- return { ...CODEX_EVENT_MAP };
2357
- }
2358
- /**
2359
- * Extract a plain-text transcript from Codex CLI session data.
2360
- *
2361
- * Reads the most recent JSON/JSONL session file under `~/.codex/`
2362
- * and returns its turns as a flat string for brain observation extraction.
2363
- *
2364
- * Returns null when no session data is found or on any read error.
2365
- *
2366
- * @param _sessionId - CLEO session ID (unused; reads the most recent file)
2367
- * @param _projectDir - Project directory (unused; Codex CLI uses global paths)
2368
- * @task T162 @epic T134
2369
- */
2370
- async getTranscript(_sessionId, _projectDir) {
2371
- return readLatestTranscript(join9(homedir6(), ".codex"));
2372
- }
2373
- };
2374
-
2375
- // packages/adapters/src/providers/codex/install.ts
2376
- import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
2377
- import { join as join10 } from "node:path";
2378
- var INSTRUCTION_REFERENCES2 = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
2379
- var CodexInstallProvider = class {
2380
- /**
2381
- * Install CLEO into a Codex CLI environment.
2382
- *
2383
- * @param options - Installation options including project directory
2384
- * @returns Result describing what was installed
2385
- * @task T162
2386
- */
2387
- async install(options) {
2388
- const { projectDir } = options;
2389
- const installedAt = (/* @__PURE__ */ new Date()).toISOString();
2390
- let instructionFileUpdated = false;
2391
- const details = {};
2392
- instructionFileUpdated = this.updateInstructionFile(projectDir);
2393
- if (instructionFileUpdated) {
2394
- details.instructionFile = join10(projectDir, "AGENTS.md");
2395
- }
2396
- return {
2397
- success: true,
2398
- installedAt,
2399
- instructionFileUpdated,
2400
- mcpRegistered: false,
2401
- details
2402
- };
2403
- }
2404
- /**
2405
- * Uninstall CLEO from the Codex CLI environment.
2406
- *
2407
- * Does not remove AGENTS.md references (they are harmless if CLEO is not present).
2408
- * @task T162
2409
- */
2410
- async uninstall() {
2411
- }
2412
- /**
2413
- * Check whether CLEO is installed in the Codex CLI environment.
2414
- *
2415
- * Checks for CLEO references in AGENTS.md.
2416
- * @task T162
2417
- */
2418
- async isInstalled() {
2419
- const agentsMdPath = join10(process.cwd(), "AGENTS.md");
2420
- if (existsSync5(agentsMdPath)) {
2421
- try {
2422
- const content = readFileSync4(agentsMdPath, "utf-8");
2423
- if (INSTRUCTION_REFERENCES2.some((ref) => content.includes(ref))) {
2424
- return true;
2425
- }
2426
- } catch {
2427
- }
2428
- }
2429
- return false;
2430
- }
2431
- /**
2432
- * Ensure AGENTS.md contains @-references to CLEO instruction files.
2433
- *
2434
- * Creates AGENTS.md if it does not exist. Appends any missing references.
2435
- *
2436
- * @param projectDir - Project root directory
2437
- * @task T162
2438
- */
2439
- async ensureInstructionReferences(projectDir) {
2440
- this.updateInstructionFile(projectDir);
2441
- }
2442
- /**
2443
- * Update AGENTS.md with CLEO @-references.
2444
- *
2445
- * @param projectDir - Project root directory
2446
- * @returns true if the file was created or modified
2447
- */
2448
- updateInstructionFile(projectDir) {
2449
- const agentsMdPath = join10(projectDir, "AGENTS.md");
2450
- let content = "";
2451
- let existed = false;
2452
- if (existsSync5(agentsMdPath)) {
2453
- content = readFileSync4(agentsMdPath, "utf-8");
2454
- existed = true;
2455
- }
2456
- const missingRefs = INSTRUCTION_REFERENCES2.filter((ref) => !content.includes(ref));
2457
- if (missingRefs.length === 0) {
2458
- return false;
2459
- }
2460
- const refsBlock = missingRefs.join("\n");
2461
- if (existed) {
2462
- const separator = content.endsWith("\n") ? "" : "\n";
2463
- content = content + separator + refsBlock + "\n";
2464
- } else {
2465
- content = refsBlock + "\n";
2466
- }
2467
- writeFileSync3(agentsMdPath, content, "utf-8");
2468
- return true;
2469
- }
2470
- };
2471
-
2472
- // packages/adapters/src/providers/codex/adapter.ts
2473
- var execAsync3 = promisify3(exec3);
2474
- var CodexAdapter = class {
2475
- /** Unique provider identifier. */
2476
- id = "codex";
2477
- /** Human-readable provider name. */
2478
- name = "Codex";
2479
- /** Adapter version string. */
2480
- version = "1.0.0";
2481
- /** Declared capabilities for this provider. */
2482
- capabilities = {
2483
- supportsHooks: true,
2484
- supportedHookEvents: ["SessionStart", "UserPromptSubmit", "Stop"],
2485
- supportsSpawn: false,
2486
- supportsInstall: true,
2487
- supportsMcp: false,
2488
- supportsInstructionFiles: false,
2489
- supportsContextMonitor: false,
2490
- supportsStatusline: false,
2491
- supportsProviderPaths: false,
2492
- supportsTransport: false,
2493
- supportsTaskSync: false
2494
- };
2495
- /** Hook provider for CAAMP event mapping. */
2496
- hooks;
2497
- /** Install provider for managing instruction files. */
2498
- install;
2499
- /** Project directory this adapter was initialized with, or null. */
2500
- projectDir = null;
2501
- /** Whether {@link initialize} has been called. */
2502
- initialized = false;
2503
- constructor() {
2504
- this.hooks = new CodexHookProvider();
2505
- this.install = new CodexInstallProvider();
2506
- }
2507
- /**
2508
- * Initialize the adapter for a given project directory.
2509
- *
2510
- * @param projectDir - Root directory of the project
2511
- * @task T162
2512
- */
2513
- async initialize(projectDir) {
2514
- this.projectDir = projectDir;
2515
- this.initialized = true;
2516
- }
2517
- /**
2518
- * Dispose the adapter and clean up resources.
2519
- *
2520
- * Unregisters hooks and releases any tracked state.
2521
- * @task T162
2522
- */
2523
- async dispose() {
2524
- if (this.hooks.isRegistered()) {
2525
- await this.hooks.unregisterNativeHooks();
2526
- }
2527
- this.initialized = false;
2528
- this.projectDir = null;
2529
- }
2530
- /**
2531
- * Run a health check to verify Codex CLI is accessible.
2532
- *
2533
- * Checks:
2534
- * 1. Adapter has been initialized
2535
- * 2. Codex CLI binary is available in PATH
2536
- * 3. ~/.codex/ configuration directory exists
2537
- *
2538
- * @returns Health status with details about each check
2539
- * @task T162
2540
- */
2541
- async healthCheck() {
2542
- const details = {};
2543
- if (!this.initialized) {
2544
- return {
2545
- healthy: false,
2546
- provider: this.id,
2547
- details: { error: "Adapter not initialized" }
2548
- };
2549
- }
2550
- let cliAvailable = false;
2551
- try {
2552
- const { stdout } = await execAsync3("which codex");
2553
- cliAvailable = stdout.trim().length > 0;
2554
- details.cliPath = stdout.trim();
2555
- } catch {
2556
- details.cliAvailable = false;
2557
- }
2558
- const codexConfigDir = join11(homedir7(), ".codex");
2559
- const configExists = existsSync6(codexConfigDir);
2560
- details.configDirExists = configExists;
2561
- const healthy = cliAvailable;
2562
- details.cliAvailable = cliAvailable;
2563
- return {
2564
- healthy,
2565
- provider: this.id,
2566
- details
2567
- };
2568
- }
2569
- /**
2570
- * Check whether the adapter has been initialized.
2571
- * @task T162
2572
- */
2573
- isInitialized() {
2574
- return this.initialized;
2575
- }
2576
- /**
2577
- * Get the project directory this adapter was initialized with.
2578
- * @task T162
2579
- */
2580
- getProjectDir() {
2581
- return this.projectDir;
2582
- }
2583
- };
2584
-
2585
- // packages/adapters/src/providers/codex/index.ts
2586
- function createAdapter2() {
2587
- return new CodexAdapter();
2588
- }
2589
-
2590
- // packages/adapters/src/index.ts
2591
- init_cursor();
2592
-
2593
- // packages/adapters/src/providers/gemini-cli/adapter.ts
2594
- import { exec as exec4 } from "node:child_process";
2595
- import { existsSync as existsSync10 } from "node:fs";
2596
- import { homedir as homedir9 } from "node:os";
2597
- import { join as join16 } from "node:path";
2598
- import { promisify as promisify4 } from "node:util";
2599
-
2600
- // packages/adapters/src/providers/gemini-cli/hooks.ts
2601
- import { homedir as homedir8 } from "node:os";
2602
- import { join as join14 } from "node:path";
2603
- var GEMINI_CLI_EVENT_MAP = {
2604
- SessionStart: "SessionStart",
2605
- SessionEnd: "SessionEnd",
2606
- PromptSubmit: "BeforeAgent",
2607
- ResponseComplete: "AfterAgent",
2608
- PreToolUse: "BeforeTool",
2609
- PostToolUse: "AfterTool",
2610
- PreModel: "BeforeModel",
2611
- PostModel: "AfterModel",
2612
- PreCompact: "PreCompress",
2613
- Notification: "Notification"
2614
- };
2615
- var GeminiCliHookProvider = class {
2616
- /** Whether hooks have been registered for the current session. */
2617
- registered = false;
2618
- /**
2619
- * Map a Gemini CLI native event name to a CAAMP hook event name.
2620
- *
2621
- * @param providerEvent - Gemini CLI event name (e.g. "SessionStart", "PreToolUse")
2622
- * @returns CAAMP event name or null if unmapped
2623
- * @task T161
2624
- */
2625
- mapProviderEvent(providerEvent) {
2626
- return GEMINI_CLI_EVENT_MAP[providerEvent] ?? null;
2627
- }
2628
- /**
2629
- * Register native hooks for a project.
2630
- *
2631
- * For Gemini CLI, hooks are registered via the config system
2632
- * (~/.gemini/), which is handled by the install provider.
2633
- * This method marks hooks as registered without performing
2634
- * filesystem operations.
2635
- *
2636
- * @param _projectDir - Project directory (unused; hooks are global)
2637
- * @task T161
2638
- */
2639
- async registerNativeHooks(_projectDir) {
2640
- this.registered = true;
2641
- }
2642
- /**
2643
- * Unregister native hooks.
2644
- *
2645
- * For Gemini CLI, this is a no-op since hooks are managed through
2646
- * the config system. Unregistration happens via the install
2647
- * provider's uninstall method.
2648
- * @task T161
2649
- */
2650
- async unregisterNativeHooks() {
2651
- this.registered = false;
2652
- }
2653
- /**
2654
- * Check whether hooks have been registered via registerNativeHooks.
2655
- * @task T161
2656
- */
2657
- isRegistered() {
2658
- return this.registered;
2659
- }
2660
- /**
2661
- * Get the full event mapping for introspection/debugging.
2662
- * @task T161
2663
- */
2664
- getEventMap() {
2665
- return { ...GEMINI_CLI_EVENT_MAP };
2666
- }
2667
- /**
2668
- * Extract a plain-text transcript from Gemini CLI session data.
2669
- *
2670
- * Reads the most recent JSON/JSONL session file under `~/.gemini/`
2671
- * and returns its turns as a flat string for brain observation extraction.
2672
- *
2673
- * Returns null when no session data is found or on any read error.
2674
- *
2675
- * @param _sessionId - CLEO session ID (unused; reads the most recent file)
2676
- * @param _projectDir - Project directory (unused; Gemini CLI uses global paths)
2677
- * @task T161 @epic T134
2678
- */
2679
- async getTranscript(_sessionId, _projectDir) {
2680
- return readLatestTranscript(join14(homedir8(), ".gemini"));
2681
- }
2682
- };
2683
-
2684
- // packages/adapters/src/providers/gemini-cli/install.ts
2685
- import { existsSync as existsSync9, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
2686
- import { join as join15 } from "node:path";
2687
- var INSTRUCTION_REFERENCES4 = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
2688
- var GeminiCliInstallProvider = class {
2689
- /**
2690
- * Install CLEO into a Gemini CLI environment.
2691
- *
2692
- * @param options - Installation options including project directory
2693
- * @returns Result describing what was installed
2694
- * @task T161
2695
- */
2696
- async install(options) {
2697
- const { projectDir } = options;
2698
- const installedAt = (/* @__PURE__ */ new Date()).toISOString();
2699
- let instructionFileUpdated = false;
2700
- const details = {};
2701
- instructionFileUpdated = this.updateInstructionFile(projectDir);
2702
- if (instructionFileUpdated) {
2703
- details.instructionFile = join15(projectDir, "AGENTS.md");
2704
- }
2705
- return {
2706
- success: true,
2707
- installedAt,
2708
- instructionFileUpdated,
2709
- mcpRegistered: false,
2710
- details
2711
- };
2712
- }
2713
- /**
2714
- * Uninstall CLEO from the Gemini CLI environment.
2715
- *
2716
- * Does not remove AGENTS.md references (they are harmless if CLEO is not present).
2717
- * @task T161
2718
- */
2719
- async uninstall() {
2720
- }
2721
- /**
2722
- * Check whether CLEO is installed in the Gemini CLI environment.
2723
- *
2724
- * Checks for CLEO references in AGENTS.md.
2725
- * @task T161
2726
- */
2727
- async isInstalled() {
2728
- const agentsMdPath = join15(process.cwd(), "AGENTS.md");
2729
- if (existsSync9(agentsMdPath)) {
2730
- try {
2731
- const content = readFileSync6(agentsMdPath, "utf-8");
2732
- if (INSTRUCTION_REFERENCES4.some((ref) => content.includes(ref))) {
2733
- return true;
2734
- }
2735
- } catch {
2736
- }
2737
- }
2738
- return false;
2739
- }
2740
- /**
2741
- * Ensure AGENTS.md contains @-references to CLEO instruction files.
2742
- *
2743
- * Creates AGENTS.md if it does not exist. Appends any missing references.
2744
- *
2745
- * @param projectDir - Project root directory
2746
- * @task T161
2747
- */
2748
- async ensureInstructionReferences(projectDir) {
2749
- this.updateInstructionFile(projectDir);
2750
- }
2751
- /**
2752
- * Update AGENTS.md with CLEO @-references.
2753
- *
2754
- * @param projectDir - Project root directory
2755
- * @returns true if the file was created or modified
2756
- */
2757
- updateInstructionFile(projectDir) {
2758
- const agentsMdPath = join15(projectDir, "AGENTS.md");
2759
- let content = "";
2760
- let existed = false;
2761
- if (existsSync9(agentsMdPath)) {
2762
- content = readFileSync6(agentsMdPath, "utf-8");
2763
- existed = true;
2764
- }
2765
- const missingRefs = INSTRUCTION_REFERENCES4.filter((ref) => !content.includes(ref));
2766
- if (missingRefs.length === 0) {
2767
- return false;
2768
- }
2769
- const refsBlock = missingRefs.join("\n");
2770
- if (existed) {
2771
- const separator = content.endsWith("\n") ? "" : "\n";
2772
- content = content + separator + refsBlock + "\n";
2773
- } else {
2774
- content = refsBlock + "\n";
2775
- }
2776
- writeFileSync5(agentsMdPath, content, "utf-8");
2777
- return true;
2778
- }
2779
- };
2780
-
2781
- // packages/adapters/src/providers/gemini-cli/adapter.ts
2782
- var execAsync4 = promisify4(exec4);
2783
- var GeminiCliAdapter = class {
2784
- /** Unique provider identifier. */
2785
- id = "gemini-cli";
2786
- /** Human-readable provider name. */
2787
- name = "Gemini CLI";
2788
- /** Adapter version string. */
2789
- version = "1.0.0";
2790
- /** Declared capabilities for this provider. */
2791
- capabilities = {
2792
- supportsHooks: true,
2793
- supportedHookEvents: [
2794
- "SessionStart",
2795
- "SessionEnd",
2796
- "BeforeAgent",
2797
- "AfterAgent",
2798
- "BeforeTool",
2799
- "AfterTool",
2800
- "BeforeModel",
2801
- "AfterModel",
2802
- "PreCompress",
2803
- "Notification"
2804
- ],
2805
- supportsSpawn: false,
2806
- supportsInstall: true,
2807
- supportsMcp: false,
2808
- supportsInstructionFiles: false,
2809
- supportsContextMonitor: false,
2810
- supportsStatusline: false,
2811
- supportsProviderPaths: false,
2812
- supportsTransport: false,
2813
- supportsTaskSync: false
2814
- };
2815
- /** Hook provider for CAAMP event mapping. */
2816
- hooks;
2817
- /** Install provider for managing instruction files. */
2818
- install;
2819
- /** Project directory this adapter was initialized with, or null. */
2820
- projectDir = null;
2821
- /** Whether {@link initialize} has been called. */
2822
- initialized = false;
2823
- constructor() {
2824
- this.hooks = new GeminiCliHookProvider();
2825
- this.install = new GeminiCliInstallProvider();
2826
- }
2827
- /**
2828
- * Initialize the adapter for a given project directory.
2829
- *
2830
- * @param projectDir - Root directory of the project
2831
- * @task T161
2832
- */
2833
- async initialize(projectDir) {
2834
- this.projectDir = projectDir;
2835
- this.initialized = true;
2836
- }
2837
- /**
2838
- * Dispose the adapter and clean up resources.
2839
- *
2840
- * Unregisters hooks and releases any tracked state.
2841
- * @task T161
2842
- */
2843
- async dispose() {
2844
- if (this.hooks.isRegistered()) {
2845
- await this.hooks.unregisterNativeHooks();
2846
- }
2847
- this.initialized = false;
2848
- this.projectDir = null;
2849
- }
2850
- /**
2851
- * Run a health check to verify Gemini CLI is accessible.
2852
- *
2853
- * Checks:
2854
- * 1. Adapter has been initialized
2855
- * 2. Gemini CLI binary is available in PATH
2856
- * 3. ~/.gemini/ configuration directory exists
2857
- *
2858
- * @returns Health status with details about each check
2859
- * @task T161
2860
- */
2861
- async healthCheck() {
2862
- const details = {};
2863
- if (!this.initialized) {
2864
- return {
2865
- healthy: false,
2866
- provider: this.id,
2867
- details: { error: "Adapter not initialized" }
2868
- };
2869
- }
2870
- let cliAvailable = false;
2871
- try {
2872
- const { stdout } = await execAsync4("which gemini");
2873
- cliAvailable = stdout.trim().length > 0;
2874
- details.cliPath = stdout.trim();
2875
- } catch {
2876
- details.cliAvailable = false;
2877
- }
2878
- const geminiConfigDir = join16(homedir9(), ".gemini");
2879
- const configExists = existsSync10(geminiConfigDir);
2880
- details.configDirExists = configExists;
2881
- const healthy = cliAvailable;
2882
- details.cliAvailable = cliAvailable;
2883
- return {
2884
- healthy,
2885
- provider: this.id,
2886
- details
2887
- };
2888
- }
2889
- /**
2890
- * Check whether the adapter has been initialized.
2891
- * @task T161
2892
- */
2893
- isInitialized() {
2894
- return this.initialized;
2895
- }
2896
- /**
2897
- * Get the project directory this adapter was initialized with.
2898
- * @task T161
2899
- */
2900
- getProjectDir() {
2901
- return this.projectDir;
2902
- }
2903
- };
2904
-
2905
- // packages/adapters/src/providers/gemini-cli/index.ts
2906
- function createAdapter4() {
2907
- return new GeminiCliAdapter();
2908
- }
2909
-
2910
- // packages/adapters/src/providers/kimi/adapter.ts
2911
- import { exec as exec5 } from "node:child_process";
2912
- import { existsSync as existsSync12 } from "node:fs";
2913
- import { homedir as homedir10 } from "node:os";
2914
- import { join as join18 } from "node:path";
2915
- import { promisify as promisify5 } from "node:util";
2916
-
2917
- // packages/adapters/src/providers/kimi/hooks.ts
2918
- var KimiHookProvider = class {
2919
- /** Whether hooks have been registered (always a no-op for Kimi). */
2920
- registered = false;
2921
- /**
2922
- * Map a Kimi native event name to a CAAMP hook event name.
2923
- *
2924
- * Kimi has no hook system, so this always returns null.
2925
- *
2926
- * @param _providerEvent - Unused; Kimi emits no hookable events
2927
- * @returns Always null
2928
- * @task T163
2929
- */
2930
- mapProviderEvent(_providerEvent) {
2931
- return null;
2932
- }
2933
- /**
2934
- * Register native hooks for a project.
2935
- *
2936
- * Kimi has no hook system. This method is a no-op and only
2937
- * tracks registration state for interface compliance.
2938
- *
2939
- * @param _projectDir - Project directory (unused)
2940
- * @task T163
2941
- */
2942
- async registerNativeHooks(_projectDir) {
2943
- this.registered = true;
2944
- }
2945
- /**
2946
- * Unregister native hooks.
2947
- *
2948
- * Kimi has no hook system. This method is a no-op.
2949
- * @task T163
2950
- */
2951
- async unregisterNativeHooks() {
2952
- this.registered = false;
2953
- }
2954
- /**
2955
- * Check whether hooks have been registered via registerNativeHooks.
2956
- * @task T163
2957
- */
2958
- isRegistered() {
2959
- return this.registered;
2960
- }
2961
- /**
2962
- * Get the full event mapping for introspection/debugging.
2963
- *
2964
- * Returns an empty map since Kimi has no hookable events.
2965
- * @task T163
2966
- */
2967
- getEventMap() {
2968
- return {};
2969
- }
2970
- };
2971
-
2972
- // packages/adapters/src/providers/kimi/install.ts
2973
- import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "node:fs";
2974
- import { join as join17 } from "node:path";
2975
- var INSTRUCTION_REFERENCES5 = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
2976
- var KimiInstallProvider = class {
2977
- /**
2978
- * Install CLEO into a Kimi environment.
2979
- *
2980
- * @param options - Installation options including project directory
2981
- * @returns Result describing what was installed
2982
- * @task T163
2983
- */
2984
- async install(options) {
2985
- const { projectDir } = options;
2986
- const installedAt = (/* @__PURE__ */ new Date()).toISOString();
2987
- let instructionFileUpdated = false;
2988
- const details = {};
2989
- instructionFileUpdated = this.updateInstructionFile(projectDir);
2990
- if (instructionFileUpdated) {
2991
- details.instructionFile = join17(projectDir, "AGENTS.md");
2992
- }
2993
- return {
2994
- success: true,
2995
- installedAt,
2996
- instructionFileUpdated,
2997
- mcpRegistered: false,
2998
- details
2999
- };
3000
- }
3001
- /**
3002
- * Uninstall CLEO from the Kimi environment.
3003
- *
3004
- * Does not remove AGENTS.md references (they are harmless if CLEO is not present).
3005
- * @task T163
3006
- */
3007
- async uninstall() {
3008
- }
3009
- /**
3010
- * Check whether CLEO is installed in the Kimi environment.
3011
- *
3012
- * Checks for CLEO references in AGENTS.md.
3013
- * @task T163
3014
- */
3015
- async isInstalled() {
3016
- const agentsMdPath = join17(process.cwd(), "AGENTS.md");
3017
- if (existsSync11(agentsMdPath)) {
3018
- try {
3019
- const content = readFileSync7(agentsMdPath, "utf-8");
3020
- if (INSTRUCTION_REFERENCES5.some((ref) => content.includes(ref))) {
3021
- return true;
3022
- }
3023
- } catch {
3024
- }
3025
- }
3026
- return false;
3027
- }
3028
- /**
3029
- * Ensure AGENTS.md contains @-references to CLEO instruction files.
3030
- *
3031
- * Creates AGENTS.md if it does not exist. Appends any missing references.
3032
- *
3033
- * @param projectDir - Project root directory
3034
- * @task T163
3035
- */
3036
- async ensureInstructionReferences(projectDir) {
3037
- this.updateInstructionFile(projectDir);
3038
- }
3039
- /**
3040
- * Update AGENTS.md with CLEO @-references.
3041
- *
3042
- * @param projectDir - Project root directory
3043
- * @returns true if the file was created or modified
3044
- */
3045
- updateInstructionFile(projectDir) {
3046
- const agentsMdPath = join17(projectDir, "AGENTS.md");
3047
- let content = "";
3048
- let existed = false;
3049
- if (existsSync11(agentsMdPath)) {
3050
- content = readFileSync7(agentsMdPath, "utf-8");
3051
- existed = true;
3052
- }
3053
- const missingRefs = INSTRUCTION_REFERENCES5.filter((ref) => !content.includes(ref));
3054
- if (missingRefs.length === 0) {
3055
- return false;
3056
- }
3057
- const refsBlock = missingRefs.join("\n");
3058
- if (existed) {
3059
- const separator = content.endsWith("\n") ? "" : "\n";
3060
- content = content + separator + refsBlock + "\n";
3061
- } else {
3062
- content = refsBlock + "\n";
3063
- }
3064
- writeFileSync6(agentsMdPath, content, "utf-8");
3065
- return true;
3066
- }
3067
- };
3068
-
3069
- // packages/adapters/src/providers/kimi/adapter.ts
3070
- var execAsync5 = promisify5(exec5);
3071
- var KimiAdapter = class {
3072
- /** Unique provider identifier. */
3073
- id = "kimi";
3074
- /** Human-readable provider name. */
3075
- name = "Kimi";
3076
- /** Adapter version string. */
3077
- version = "1.0.0";
3078
- /** Declared capabilities for this provider. */
3079
- capabilities = {
3080
- supportsHooks: false,
3081
- supportedHookEvents: [],
3082
- supportsSpawn: false,
3083
- supportsInstall: true,
3084
- supportsMcp: false,
3085
- supportsInstructionFiles: false,
3086
- supportsContextMonitor: false,
3087
- supportsStatusline: false,
3088
- supportsProviderPaths: false,
3089
- supportsTransport: false,
3090
- supportsTaskSync: false
3091
- };
3092
- /** Hook provider (no-op since Kimi has no event system). */
3093
- hooks;
3094
- /** Install provider for managing instruction files. */
3095
- install;
3096
- /** Project directory this adapter was initialized with, or null. */
3097
- projectDir = null;
3098
- /** Whether {@link initialize} has been called. */
3099
- initialized = false;
3100
- constructor() {
3101
- this.hooks = new KimiHookProvider();
3102
- this.install = new KimiInstallProvider();
3103
- }
3104
- /**
3105
- * Initialize the adapter for a given project directory.
3106
- *
3107
- * @param projectDir - Root directory of the project
3108
- * @task T163
3109
- */
3110
- async initialize(projectDir) {
3111
- this.projectDir = projectDir;
3112
- this.initialized = true;
3113
- }
3114
- /**
3115
- * Dispose the adapter and clean up resources.
3116
- *
3117
- * Releases tracked state. No hooks to unregister since Kimi
3118
- * has no native hook system.
3119
- * @task T163
3120
- */
3121
- async dispose() {
3122
- this.initialized = false;
3123
- this.projectDir = null;
3124
- }
3125
- /**
3126
- * Run a health check to verify Kimi is accessible.
3127
- *
3128
- * Checks:
3129
- * 1. Adapter has been initialized
3130
- * 2. Kimi CLI binary is available in PATH
3131
- * 3. ~/.kimi/ configuration directory exists
3132
- *
3133
- * @returns Health status with details about each check
3134
- * @task T163
3135
- */
3136
- async healthCheck() {
3137
- const details = {};
3138
- if (!this.initialized) {
3139
- return {
3140
- healthy: false,
3141
- provider: this.id,
3142
- details: { error: "Adapter not initialized" }
3143
- };
3144
- }
3145
- let cliAvailable = false;
3146
- try {
3147
- const { stdout } = await execAsync5("which kimi");
3148
- cliAvailable = stdout.trim().length > 0;
3149
- details.cliPath = stdout.trim();
3150
- } catch {
3151
- details.cliAvailable = false;
3152
- }
3153
- const kimiConfigDir = join18(homedir10(), ".kimi");
3154
- const configExists = existsSync12(kimiConfigDir);
3155
- details.configDirExists = configExists;
3156
- const healthy = cliAvailable;
3157
- details.cliAvailable = cliAvailable;
3158
- return {
3159
- healthy,
3160
- provider: this.id,
3161
- details
3162
- };
3163
- }
3164
- /**
3165
- * Check whether the adapter has been initialized.
3166
- * @task T163
3167
- */
3168
- isInitialized() {
3169
- return this.initialized;
3170
- }
3171
- /**
3172
- * Get the project directory this adapter was initialized with.
3173
- * @task T163
3174
- */
3175
- getProjectDir() {
3176
- return this.projectDir;
3177
- }
3178
- };
3179
-
3180
- // packages/adapters/src/providers/kimi/index.ts
3181
- function createAdapter5() {
3182
- return new KimiAdapter();
3183
- }
3184
-
3185
- // packages/adapters/src/index.ts
3186
- init_opencode();
3187
-
3188
- // packages/adapters/src/registry.ts
3189
- import { readFileSync as readFileSync9 } from "node:fs";
3190
- import { dirname as dirname2, join as join22, resolve } from "node:path";
3191
- import { fileURLToPath } from "node:url";
3192
- var PROVIDER_IDS = ["claude-code", "opencode", "cursor"];
3193
- function getProviderManifests() {
3194
- const manifests = [];
3195
- const baseDir = resolve(dirname2(fileURLToPath(import.meta.url)), "providers");
3196
- for (const providerId of PROVIDER_IDS) {
3197
- try {
3198
- const manifestPath = join22(baseDir, providerId, "manifest.json");
3199
- const raw = readFileSync9(manifestPath, "utf-8");
3200
- manifests.push(JSON.parse(raw));
3201
- } catch {
3202
- }
3203
- }
3204
- return manifests;
3205
- }
3206
- async function discoverProviders() {
3207
- const providers = /* @__PURE__ */ new Map();
3208
- providers.set("claude-code", async () => {
3209
- const { ClaudeCodeAdapter: ClaudeCodeAdapter2 } = await Promise.resolve().then(() => (init_claude_code(), claude_code_exports));
3210
- return new ClaudeCodeAdapter2();
3211
- });
3212
- providers.set("opencode", async () => {
3213
- const { OpenCodeAdapter: OpenCodeAdapter2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
3214
- return new OpenCodeAdapter2();
3215
- });
3216
- providers.set("cursor", async () => {
3217
- const { CursorAdapter: CursorAdapter2 } = await Promise.resolve().then(() => (init_cursor(), cursor_exports));
3218
- return new CursorAdapter2();
3219
- });
3220
- return providers;
3221
- }
3222
- export {
3223
- ClaudeCodeAdapter,
3224
- ClaudeCodeContextMonitorProvider,
3225
- ClaudeCodeHookProvider,
3226
- ClaudeCodeInstallProvider,
3227
- ClaudeCodePathProvider,
3228
- ClaudeCodeSpawnProvider,
3229
- ClaudeCodeTransportProvider,
3230
- CodexAdapter,
3231
- CodexHookProvider,
3232
- CodexInstallProvider,
3233
- CursorAdapter,
3234
- CursorHookProvider,
3235
- CursorInstallProvider,
3236
- GeminiCliAdapter,
3237
- GeminiCliHookProvider,
3238
- GeminiCliInstallProvider,
3239
- KimiAdapter,
3240
- KimiHookProvider,
3241
- KimiInstallProvider,
3242
- OpenCodeAdapter,
3243
- OpenCodeHookProvider,
3244
- OpenCodeInstallProvider,
3245
- OpenCodeSpawnProvider,
3246
- checkStatuslineIntegration,
3247
- createAdapter as createClaudeCodeAdapter,
3248
- createAdapter2 as createCodexAdapter,
3249
- createAdapter3 as createCursorAdapter,
3250
- createAdapter4 as createGeminiCliAdapter,
3251
- createAdapter5 as createKimiAdapter,
3252
- createAdapter6 as createOpenCodeAdapter,
3253
- discoverProviders,
3254
- getProviderManifests,
3255
- getSetupInstructions,
3256
- getStatuslineConfig
3257
- };
3258
- //# sourceMappingURL=index.js.map