@cleocode/adapters 2026.3.76 → 2026.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +732 -630
- package/dist/index.js.map +4 -4
- package/dist/providers/claude-code/adapter.d.ts +21 -1
- package/dist/providers/claude-code/adapter.d.ts.map +1 -1
- package/dist/providers/claude-code/context-monitor.d.ts +11 -0
- package/dist/providers/claude-code/context-monitor.d.ts.map +1 -1
- package/dist/providers/claude-code/hooks.d.ts +7 -0
- package/dist/providers/claude-code/hooks.d.ts.map +1 -1
- package/dist/providers/claude-code/index.d.ts +16 -1
- package/dist/providers/claude-code/index.d.ts.map +1 -1
- package/dist/providers/claude-code/install.d.ts +10 -18
- package/dist/providers/claude-code/install.d.ts.map +1 -1
- package/dist/providers/claude-code/paths.d.ts +8 -0
- package/dist/providers/claude-code/paths.d.ts.map +1 -1
- package/dist/providers/claude-code/spawn.d.ts +7 -0
- package/dist/providers/claude-code/spawn.d.ts.map +1 -1
- package/dist/providers/claude-code/statusline.d.ts +44 -0
- package/dist/providers/claude-code/statusline.d.ts.map +1 -1
- package/dist/providers/claude-code/task-sync.d.ts +8 -0
- package/dist/providers/claude-code/task-sync.d.ts.map +1 -1
- package/dist/providers/claude-code/transport.d.ts +11 -0
- package/dist/providers/claude-code/transport.d.ts.map +1 -1
- package/dist/providers/codex/adapter.d.ts +14 -1
- package/dist/providers/codex/adapter.d.ts.map +1 -1
- package/dist/providers/codex/hooks.d.ts +6 -0
- package/dist/providers/codex/hooks.d.ts.map +1 -1
- package/dist/providers/codex/index.d.ts +16 -1
- package/dist/providers/codex/index.d.ts.map +1 -1
- package/dist/providers/codex/install.d.ts +8 -17
- package/dist/providers/codex/install.d.ts.map +1 -1
- package/dist/providers/cursor/adapter.d.ts +15 -1
- package/dist/providers/cursor/adapter.d.ts.map +1 -1
- package/dist/providers/cursor/hooks.d.ts +7 -0
- package/dist/providers/cursor/hooks.d.ts.map +1 -1
- package/dist/providers/cursor/index.d.ts +16 -1
- package/dist/providers/cursor/index.d.ts.map +1 -1
- package/dist/providers/cursor/install.d.ts +10 -17
- package/dist/providers/cursor/install.d.ts.map +1 -1
- package/dist/providers/gemini-cli/adapter.d.ts +15 -1
- package/dist/providers/gemini-cli/adapter.d.ts.map +1 -1
- package/dist/providers/gemini-cli/hooks.d.ts +7 -0
- package/dist/providers/gemini-cli/hooks.d.ts.map +1 -1
- package/dist/providers/gemini-cli/index.d.ts +16 -1
- package/dist/providers/gemini-cli/index.d.ts.map +1 -1
- package/dist/providers/gemini-cli/install.d.ts +8 -17
- package/dist/providers/gemini-cli/install.d.ts.map +1 -1
- package/dist/providers/kimi/adapter.d.ts +15 -2
- package/dist/providers/kimi/adapter.d.ts.map +1 -1
- package/dist/providers/kimi/hooks.d.ts +6 -0
- package/dist/providers/kimi/hooks.d.ts.map +1 -1
- package/dist/providers/kimi/index.d.ts +16 -1
- package/dist/providers/kimi/index.d.ts.map +1 -1
- package/dist/providers/kimi/install.d.ts +7 -22
- package/dist/providers/kimi/install.d.ts.map +1 -1
- package/dist/providers/opencode/adapter.d.ts +17 -1
- package/dist/providers/opencode/adapter.d.ts.map +1 -1
- package/dist/providers/opencode/hooks.d.ts +9 -0
- package/dist/providers/opencode/hooks.d.ts.map +1 -1
- package/dist/providers/opencode/index.d.ts +16 -1
- package/dist/providers/opencode/index.d.ts.map +1 -1
- package/dist/providers/opencode/install.d.ts +8 -17
- package/dist/providers/opencode/install.d.ts.map +1 -1
- package/dist/providers/opencode/spawn.d.ts +23 -1
- package/dist/providers/opencode/spawn.d.ts.map +1 -1
- package/dist/providers/shared/transcript-reader.d.ts +15 -0
- package/dist/providers/shared/transcript-reader.d.ts.map +1 -1
- package/dist/registry.d.ts +54 -2
- package/dist/registry.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/claude-code-adapter.test.js +21 -30
- package/src/__tests__/claude-code-adapter.test.js.map +1 -1
- package/src/__tests__/claude-code-adapter.test.ts +21 -32
- package/src/__tests__/cursor-adapter.test.js +25 -29
- package/src/__tests__/cursor-adapter.test.js.map +1 -1
- package/src/__tests__/cursor-adapter.test.ts +26 -33
- package/src/__tests__/opencode-adapter.test.js +47 -46
- package/src/__tests__/opencode-adapter.test.js.map +1 -1
- package/src/__tests__/opencode-adapter.test.ts +51 -49
- package/src/index.ts +9 -1
- package/src/providers/claude-code/__tests__/adapter.test.js +50 -23
- package/src/providers/claude-code/__tests__/adapter.test.js.map +1 -1
- package/src/providers/claude-code/__tests__/adapter.test.ts +52 -23
- package/src/providers/claude-code/adapter.ts +22 -2
- package/src/providers/claude-code/context-monitor.ts +11 -0
- package/src/providers/claude-code/hooks.ts +7 -0
- package/src/providers/claude-code/index.ts +16 -1
- package/src/providers/claude-code/install.ts +15 -96
- package/src/providers/claude-code/manifest.json +1 -1
- package/src/providers/claude-code/paths.ts +8 -0
- package/src/providers/claude-code/spawn.ts +7 -0
- package/src/providers/claude-code/statusline.ts +44 -0
- package/src/providers/claude-code/task-sync.ts +8 -0
- package/src/providers/claude-code/transport.ts +11 -0
- package/src/providers/codex/adapter.ts +15 -2
- package/src/providers/codex/hooks.ts +6 -0
- package/src/providers/codex/index.ts +16 -1
- package/src/providers/codex/install.ts +17 -81
- package/src/providers/codex/manifest.json +1 -1
- package/src/providers/cursor/__tests__/adapter.test.js +37 -12
- package/src/providers/cursor/__tests__/adapter.test.js.map +1 -1
- package/src/providers/cursor/__tests__/adapter.test.ts +43 -12
- package/src/providers/cursor/adapter.ts +16 -2
- package/src/providers/cursor/hooks.ts +7 -0
- package/src/providers/cursor/index.ts +16 -1
- package/src/providers/cursor/install.ts +23 -88
- package/src/providers/cursor/manifest.json +1 -1
- package/src/providers/gemini-cli/adapter.ts +16 -2
- package/src/providers/gemini-cli/hooks.ts +7 -0
- package/src/providers/gemini-cli/index.ts +16 -1
- package/src/providers/gemini-cli/install.ts +17 -81
- package/src/providers/gemini-cli/manifest.json +1 -1
- package/src/providers/kimi/adapter.ts +16 -3
- package/src/providers/kimi/hooks.ts +6 -0
- package/src/providers/kimi/index.ts +16 -1
- package/src/providers/kimi/install.ts +16 -86
- package/src/providers/kimi/manifest.json +1 -1
- package/src/providers/opencode/__tests__/adapter.test.js +48 -35
- package/src/providers/opencode/__tests__/adapter.test.js.map +1 -1
- package/src/providers/opencode/__tests__/adapter.test.ts +49 -34
- package/src/providers/opencode/adapter.ts +18 -2
- package/src/providers/opencode/hooks.ts +9 -0
- package/src/providers/opencode/index.ts +16 -1
- package/src/providers/opencode/install.ts +17 -90
- package/src/providers/opencode/manifest.json +1 -1
- package/src/providers/opencode/spawn.ts +23 -1
- package/src/providers/shared/transcript-reader.ts +15 -0
- package/src/registry.ts +54 -2
- package/src/__tests__/claude-code-adapter.test.d.ts +0 -10
- package/src/__tests__/cursor-adapter.test.d.ts +0 -10
- package/src/__tests__/opencode-adapter.test.d.ts +0 -10
- package/src/index.d.ts +0 -35
- package/src/index.d.ts.map +0 -1
- package/src/index.js +0 -13
- package/src/index.js.map +0 -1
- package/src/providers/claude-code/__tests__/adapter.test.d.ts +0 -7
- package/src/providers/claude-code/adapter.d.ts +0 -79
- package/src/providers/claude-code/adapter.d.ts.map +0 -1
- package/src/providers/claude-code/adapter.js +0 -154
- package/src/providers/claude-code/adapter.js.map +0 -1
- package/src/providers/claude-code/context-monitor.d.ts +0 -24
- package/src/providers/claude-code/context-monitor.d.ts.map +0 -1
- package/src/providers/claude-code/context-monitor.js +0 -148
- package/src/providers/claude-code/context-monitor.js.map +0 -1
- package/src/providers/claude-code/hooks.d.ts +0 -59
- package/src/providers/claude-code/hooks.d.ts.map +0 -1
- package/src/providers/claude-code/hooks.js +0 -77
- package/src/providers/claude-code/hooks.js.map +0 -1
- package/src/providers/claude-code/index.d.ts +0 -28
- package/src/providers/claude-code/index.d.ts.map +0 -1
- package/src/providers/claude-code/index.js +0 -26
- package/src/providers/claude-code/index.js.map +0 -1
- package/src/providers/claude-code/install.d.ts +0 -75
- package/src/providers/claude-code/install.d.ts.map +0 -1
- package/src/providers/claude-code/install.js +0 -234
- package/src/providers/claude-code/install.js.map +0 -1
- package/src/providers/claude-code/paths.d.ts +0 -24
- package/src/providers/claude-code/paths.d.ts.map +0 -1
- package/src/providers/claude-code/paths.js +0 -33
- package/src/providers/claude-code/paths.js.map +0 -1
- package/src/providers/claude-code/spawn.d.ts +0 -60
- package/src/providers/claude-code/spawn.d.ts.map +0 -1
- package/src/providers/claude-code/spawn.js +0 -164
- package/src/providers/claude-code/spawn.js.map +0 -1
- package/src/providers/claude-code/statusline.d.ts +0 -23
- package/src/providers/claude-code/statusline.d.ts.map +0 -1
- package/src/providers/claude-code/statusline.js +0 -86
- package/src/providers/claude-code/statusline.js.map +0 -1
- package/src/providers/claude-code/task-sync.js +0 -122
- package/src/providers/claude-code/task-sync.js.map +0 -1
- package/src/providers/claude-code/transport.d.ts +0 -14
- package/src/providers/claude-code/transport.d.ts.map +0 -1
- package/src/providers/claude-code/transport.js +0 -18
- package/src/providers/claude-code/transport.js.map +0 -1
- package/src/providers/cursor/__tests__/adapter.test.d.ts +0 -7
- package/src/providers/cursor/adapter.d.ts +0 -66
- package/src/providers/cursor/adapter.d.ts.map +0 -1
- package/src/providers/cursor/adapter.js +0 -124
- package/src/providers/cursor/adapter.js.map +0 -1
- package/src/providers/cursor/hooks.d.ts +0 -48
- package/src/providers/cursor/hooks.d.ts.map +0 -1
- package/src/providers/cursor/hooks.js +0 -55
- package/src/providers/cursor/hooks.js.map +0 -1
- package/src/providers/cursor/index.d.ts +0 -19
- package/src/providers/cursor/index.d.ts.map +0 -1
- package/src/providers/cursor/index.js +0 -21
- package/src/providers/cursor/index.js.map +0 -1
- package/src/providers/cursor/install.d.ts +0 -94
- package/src/providers/cursor/install.d.ts.map +0 -1
- package/src/providers/cursor/install.js +0 -238
- package/src/providers/cursor/install.js.map +0 -1
- package/src/providers/cursor/spawn.d.ts +0 -50
- package/src/providers/cursor/spawn.d.ts.map +0 -1
- package/src/providers/cursor/spawn.js +0 -59
- package/src/providers/cursor/spawn.js.map +0 -1
- package/src/providers/opencode/__tests__/adapter.test.d.ts +0 -7
- package/src/providers/opencode/adapter.d.ts +0 -71
- package/src/providers/opencode/adapter.d.ts.map +0 -1
- package/src/providers/opencode/adapter.js +0 -144
- package/src/providers/opencode/adapter.js.map +0 -1
- package/src/providers/opencode/hooks.d.ts +0 -66
- package/src/providers/opencode/hooks.d.ts.map +0 -1
- package/src/providers/opencode/hooks.js +0 -89
- package/src/providers/opencode/hooks.js.map +0 -1
- package/src/providers/opencode/index.d.ts +0 -20
- package/src/providers/opencode/index.d.ts.map +0 -1
- package/src/providers/opencode/index.js +0 -22
- package/src/providers/opencode/index.js.map +0 -1
- package/src/providers/opencode/install.d.ts +0 -65
- package/src/providers/opencode/install.d.ts.map +0 -1
- package/src/providers/opencode/install.js +0 -180
- package/src/providers/opencode/install.js.map +0 -1
- package/src/providers/opencode/spawn.d.ts +0 -75
- package/src/providers/opencode/spawn.d.ts.map +0 -1
- package/src/providers/opencode/spawn.js +0 -219
- package/src/providers/opencode/spawn.js.map +0 -1
- package/src/registry.d.ts +0 -36
- package/src/registry.d.ts.map +0 -1
- package/src/registry.js +0 -55
- package/src/registry.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -8,23 +8,27 @@ var __export = (target, all) => {
|
|
|
8
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
// packages/adapters/src/providers/claude-code/paths.
|
|
11
|
+
// packages/adapters/src/providers/claude-code/paths.ts
|
|
12
12
|
import { homedir } from "node:os";
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
var ClaudeCodePathProvider;
|
|
15
15
|
var init_paths = __esm({
|
|
16
|
-
"packages/adapters/src/providers/claude-code/paths.
|
|
16
|
+
"packages/adapters/src/providers/claude-code/paths.ts"() {
|
|
17
17
|
"use strict";
|
|
18
18
|
ClaudeCodePathProvider = class {
|
|
19
|
+
/** Get the provider's root configuration directory. */
|
|
19
20
|
getProviderDir() {
|
|
20
21
|
return process.env["CLAUDE_HOME"] ?? join(homedir(), ".claude");
|
|
21
22
|
}
|
|
23
|
+
/** Get the path to the provider's settings file, or null if unavailable. */
|
|
22
24
|
getSettingsPath() {
|
|
23
25
|
return process.env["CLAUDE_SETTINGS"] ?? join(this.getProviderDir(), "settings.json");
|
|
24
26
|
}
|
|
27
|
+
/** Get the directory where agents are installed, or null if unsupported. */
|
|
25
28
|
getAgentInstallDir() {
|
|
26
29
|
return join(this.getProviderDir(), "agents");
|
|
27
30
|
}
|
|
31
|
+
/** Get the path to the provider's memory database, or null if unsupported. */
|
|
28
32
|
getMemoryDbPath() {
|
|
29
33
|
return process.env["CLAUDE_MEM_DB"] ?? join(homedir(), ".claude-mem", "claude-mem.db");
|
|
30
34
|
}
|
|
@@ -32,25 +36,21 @@ var init_paths = __esm({
|
|
|
32
36
|
}
|
|
33
37
|
});
|
|
34
38
|
|
|
35
|
-
// packages/adapters/src/providers/claude-code/context-monitor.
|
|
39
|
+
// packages/adapters/src/providers/claude-code/context-monitor.ts
|
|
36
40
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
37
41
|
import { mkdir } from "node:fs/promises";
|
|
38
42
|
import { homedir as homedir2 } from "node:os";
|
|
39
43
|
import { dirname, join as join2 } from "node:path";
|
|
40
44
|
function getContextStatusFromPercentage(percentage) {
|
|
41
|
-
if (percentage >= THRESHOLDS.EMERGENCY)
|
|
42
|
-
|
|
43
|
-
if (percentage >= THRESHOLDS.
|
|
44
|
-
|
|
45
|
-
if (percentage >= THRESHOLDS.CAUTION)
|
|
46
|
-
return "caution";
|
|
47
|
-
if (percentage >= THRESHOLDS.WARNING)
|
|
48
|
-
return "warning";
|
|
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
49
|
return "ok";
|
|
50
50
|
}
|
|
51
51
|
var THRESHOLDS, ClaudeCodeContextMonitorProvider;
|
|
52
52
|
var init_context_monitor = __esm({
|
|
53
|
-
"packages/adapters/src/providers/claude-code/context-monitor.
|
|
53
|
+
"packages/adapters/src/providers/claude-code/context-monitor.ts"() {
|
|
54
54
|
"use strict";
|
|
55
55
|
init_paths();
|
|
56
56
|
THRESHOLDS = {
|
|
@@ -60,13 +60,14 @@ var init_context_monitor = __esm({
|
|
|
60
60
|
EMERGENCY: 95
|
|
61
61
|
};
|
|
62
62
|
ClaudeCodeContextMonitorProvider = class {
|
|
63
|
+
/** Path provider for resolving Claude Code directory locations. */
|
|
63
64
|
pathProvider = new ClaudeCodePathProvider();
|
|
65
|
+
/** Process raw context window JSON and return a formatted summary string. */
|
|
64
66
|
async processContextInput(input, cwd) {
|
|
65
67
|
const typed = input;
|
|
66
68
|
const contextSize = typed.context_window?.context_window_size ?? 2e5;
|
|
67
69
|
const usage = typed.context_window?.current_usage;
|
|
68
|
-
if (!usage)
|
|
69
|
-
return "-- no data";
|
|
70
|
+
if (!usage) return "-- no data";
|
|
70
71
|
const inputTokens = usage.input_tokens ?? 0;
|
|
71
72
|
const outputTokens = usage.output_tokens ?? 0;
|
|
72
73
|
const cacheCreate = usage.cache_creation_input_tokens ?? 0;
|
|
@@ -110,17 +111,15 @@ var init_context_monitor = __esm({
|
|
|
110
111
|
}
|
|
111
112
|
return `${percentage}% | ${totalTokens}/${contextSize}`;
|
|
112
113
|
}
|
|
114
|
+
/** Check the current statusline integration status in Claude Code settings. */
|
|
113
115
|
checkStatuslineIntegration() {
|
|
114
116
|
const settingsPath = this.pathProvider.getSettingsPath();
|
|
115
|
-
if (!settingsPath || !existsSync(settingsPath))
|
|
116
|
-
return "no_settings";
|
|
117
|
+
if (!settingsPath || !existsSync(settingsPath)) return "no_settings";
|
|
117
118
|
try {
|
|
118
119
|
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
119
120
|
const statusLine = settings.statusLine;
|
|
120
|
-
if (!statusLine?.type)
|
|
121
|
-
|
|
122
|
-
if (statusLine.type !== "command")
|
|
123
|
-
return "custom_no_cleo";
|
|
121
|
+
if (!statusLine?.type) return "not_configured";
|
|
122
|
+
if (statusLine.type !== "command") return "custom_no_cleo";
|
|
124
123
|
const cmd = statusLine.command ?? "";
|
|
125
124
|
if (cmd.includes("context-monitor.sh") || cmd.includes("cleo-statusline") || cmd.includes(".context-state.json") || cmd.includes("context-states")) {
|
|
126
125
|
return "configured";
|
|
@@ -129,8 +128,7 @@ var init_context_monitor = __esm({
|
|
|
129
128
|
if (existsSync(scriptPath)) {
|
|
130
129
|
try {
|
|
131
130
|
const content = readFileSync(scriptPath, "utf-8");
|
|
132
|
-
if (content.includes("context-state.json"))
|
|
133
|
-
return "configured";
|
|
131
|
+
if (content.includes("context-state.json")) return "configured";
|
|
134
132
|
} catch {
|
|
135
133
|
}
|
|
136
134
|
}
|
|
@@ -139,6 +137,7 @@ var init_context_monitor = __esm({
|
|
|
139
137
|
return "no_settings";
|
|
140
138
|
}
|
|
141
139
|
}
|
|
140
|
+
/** Get the recommended statusline configuration object for Claude Code settings. */
|
|
142
141
|
getStatuslineConfig() {
|
|
143
142
|
return {
|
|
144
143
|
statusLine: {
|
|
@@ -147,6 +146,7 @@ var init_context_monitor = __esm({
|
|
|
147
146
|
}
|
|
148
147
|
};
|
|
149
148
|
}
|
|
149
|
+
/** Get human-readable setup instructions for enabling context monitoring. */
|
|
150
150
|
getSetupInstructions() {
|
|
151
151
|
const settingsPath = this.pathProvider.getSettingsPath() ?? "~/.claude/settings.json";
|
|
152
152
|
return [
|
|
@@ -162,24 +162,58 @@ var init_context_monitor = __esm({
|
|
|
162
162
|
}
|
|
163
163
|
});
|
|
164
164
|
|
|
165
|
-
// packages/adapters/src/providers/claude-code/hooks.
|
|
166
|
-
|
|
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;
|
|
167
169
|
var init_hooks = __esm({
|
|
168
|
-
"packages/adapters/src/providers/claude-code/hooks.
|
|
170
|
+
"packages/adapters/src/providers/claude-code/hooks.ts"() {
|
|
169
171
|
"use strict";
|
|
172
|
+
PROVIDER_ID = "claude-code";
|
|
170
173
|
CLAUDE_CODE_EVENT_MAP = {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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"
|
|
175
202
|
};
|
|
176
203
|
ClaudeCodeHookProvider = class {
|
|
204
|
+
/** Whether hooks have been registered for the current session. */
|
|
177
205
|
registered = false;
|
|
178
206
|
/**
|
|
179
|
-
* Map a Claude Code native event name to a CAAMP hook event name.
|
|
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).
|
|
180
213
|
*
|
|
181
|
-
* @param providerEvent - Claude Code event
|
|
182
|
-
* @returns CAAMP event name or null if unmapped
|
|
214
|
+
* @param providerEvent - Claude Code native event (e.g. "UserPromptSubmit", "Stop")
|
|
215
|
+
* @returns CAAMP canonical event name, or null if unmapped
|
|
216
|
+
* @task T164
|
|
183
217
|
*/
|
|
184
218
|
mapProviderEvent(providerEvent) {
|
|
185
219
|
return CLAUDE_CODE_EVENT_MAP[providerEvent] ?? null;
|
|
@@ -187,12 +221,15 @@ var init_hooks = __esm({
|
|
|
187
221
|
/**
|
|
188
222
|
* Register native hooks for a project.
|
|
189
223
|
*
|
|
190
|
-
* For Claude Code, hooks are registered via the
|
|
191
|
-
* (
|
|
192
|
-
*
|
|
193
|
-
* is managed through the plugin install lifecycle.
|
|
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.
|
|
194
227
|
*
|
|
195
|
-
*
|
|
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
|
|
196
233
|
*/
|
|
197
234
|
async registerNativeHooks(_projectDir) {
|
|
198
235
|
this.registered = true;
|
|
@@ -200,111 +237,206 @@ var init_hooks = __esm({
|
|
|
200
237
|
/**
|
|
201
238
|
* Unregister native hooks.
|
|
202
239
|
*
|
|
203
|
-
* For Claude Code, this is a no-op since hooks are managed through
|
|
204
|
-
*
|
|
205
|
-
*
|
|
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
|
|
206
244
|
*/
|
|
207
245
|
async unregisterNativeHooks() {
|
|
208
246
|
this.registered = false;
|
|
209
247
|
}
|
|
210
248
|
/**
|
|
211
|
-
* Check whether hooks have been registered via registerNativeHooks
|
|
249
|
+
* Check whether hooks have been registered via `registerNativeHooks`.
|
|
212
250
|
*/
|
|
213
251
|
isRegistered() {
|
|
214
252
|
return this.registered;
|
|
215
253
|
}
|
|
216
254
|
/**
|
|
217
|
-
* Get the
|
|
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
|
|
218
262
|
*/
|
|
219
263
|
getEventMap() {
|
|
220
264
|
return { ...CLAUDE_CODE_EVENT_MAP };
|
|
221
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
|
+
}
|
|
222
385
|
};
|
|
223
386
|
}
|
|
224
387
|
});
|
|
225
388
|
|
|
226
|
-
// packages/adapters/src/providers/claude-code/install.
|
|
389
|
+
// packages/adapters/src/providers/claude-code/install.ts
|
|
227
390
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
228
391
|
import { homedir as homedir3 } from "node:os";
|
|
229
|
-
import { join as
|
|
230
|
-
var INSTRUCTION_REFERENCES,
|
|
392
|
+
import { join as join4 } from "node:path";
|
|
393
|
+
var INSTRUCTION_REFERENCES, ClaudeCodeInstallProvider;
|
|
231
394
|
var init_install = __esm({
|
|
232
|
-
"packages/adapters/src/providers/claude-code/install.
|
|
395
|
+
"packages/adapters/src/providers/claude-code/install.ts"() {
|
|
233
396
|
"use strict";
|
|
234
397
|
INSTRUCTION_REFERENCES = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
|
|
235
|
-
MCP_SERVER_KEY = "cleo";
|
|
236
398
|
ClaudeCodeInstallProvider = class {
|
|
237
|
-
installedProjectDir = null;
|
|
238
399
|
/**
|
|
239
400
|
* Install CLEO into a Claude Code project.
|
|
240
401
|
*
|
|
241
|
-
* @param options - Installation options including project directory
|
|
402
|
+
* @param options - Installation options including project directory
|
|
242
403
|
* @returns Result describing what was installed
|
|
243
404
|
*/
|
|
244
405
|
async install(options) {
|
|
245
|
-
const { projectDir
|
|
406
|
+
const { projectDir } = options;
|
|
246
407
|
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
247
408
|
let instructionFileUpdated = false;
|
|
248
|
-
let mcpRegistered = false;
|
|
249
409
|
const details = {};
|
|
250
|
-
if (mcpServerPath) {
|
|
251
|
-
mcpRegistered = this.registerMcpServer(projectDir, mcpServerPath);
|
|
252
|
-
if (mcpRegistered) {
|
|
253
|
-
details.mcpConfigPath = join3(projectDir, ".mcp.json");
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
410
|
instructionFileUpdated = this.updateInstructionFile(projectDir);
|
|
257
411
|
if (instructionFileUpdated) {
|
|
258
|
-
details.instructionFile =
|
|
412
|
+
details.instructionFile = join4(projectDir, "CLAUDE.md");
|
|
259
413
|
}
|
|
260
414
|
const pluginResult = this.registerPlugin();
|
|
261
415
|
if (pluginResult) {
|
|
262
416
|
details.plugin = pluginResult;
|
|
263
417
|
}
|
|
264
|
-
this.installedProjectDir = projectDir;
|
|
265
418
|
return {
|
|
266
419
|
success: true,
|
|
267
420
|
installedAt,
|
|
268
421
|
instructionFileUpdated,
|
|
269
|
-
mcpRegistered,
|
|
422
|
+
mcpRegistered: false,
|
|
270
423
|
details
|
|
271
424
|
};
|
|
272
425
|
}
|
|
273
426
|
/**
|
|
274
427
|
* Uninstall CLEO from the current Claude Code project.
|
|
275
428
|
*
|
|
276
|
-
* Removes the MCP server registration from .mcp.json.
|
|
277
429
|
* Does not remove CLAUDE.md references (they are harmless if CLEO is not present).
|
|
278
430
|
*/
|
|
279
431
|
async uninstall() {
|
|
280
|
-
if (!this.installedProjectDir)
|
|
281
|
-
return;
|
|
282
|
-
const mcpPath = join3(this.installedProjectDir, ".mcp.json");
|
|
283
|
-
if (existsSync2(mcpPath)) {
|
|
284
|
-
try {
|
|
285
|
-
const raw = readFileSync2(mcpPath, "utf-8");
|
|
286
|
-
const config = JSON.parse(raw);
|
|
287
|
-
const mcpServers = config.mcpServers;
|
|
288
|
-
if (mcpServers && MCP_SERVER_KEY in mcpServers) {
|
|
289
|
-
delete mcpServers[MCP_SERVER_KEY];
|
|
290
|
-
writeFileSync2(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
291
|
-
}
|
|
292
|
-
} catch {
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
this.installedProjectDir = null;
|
|
296
432
|
}
|
|
297
433
|
/**
|
|
298
434
|
* Check whether CLEO is installed in the current environment.
|
|
299
435
|
*
|
|
300
|
-
* Checks for
|
|
301
|
-
* 1. MCP server registered in .mcp.json
|
|
302
|
-
* 2. Plugin enabled in ~/.claude/settings.json
|
|
303
|
-
*
|
|
304
|
-
* Returns true if either condition is met (partial install counts).
|
|
436
|
+
* Checks for plugin enabled in ~/.claude/settings.json.
|
|
305
437
|
*/
|
|
306
438
|
async isInstalled() {
|
|
307
|
-
const settingsPath =
|
|
439
|
+
const settingsPath = join4(homedir3(), ".claude", "settings.json");
|
|
308
440
|
if (existsSync2(settingsPath)) {
|
|
309
441
|
try {
|
|
310
442
|
const settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
|
|
@@ -315,17 +447,6 @@ var init_install = __esm({
|
|
|
315
447
|
} catch {
|
|
316
448
|
}
|
|
317
449
|
}
|
|
318
|
-
const mcpPath = join3(process.cwd(), ".mcp.json");
|
|
319
|
-
if (existsSync2(mcpPath)) {
|
|
320
|
-
try {
|
|
321
|
-
const config = JSON.parse(readFileSync2(mcpPath, "utf-8"));
|
|
322
|
-
const mcpServers = config.mcpServers;
|
|
323
|
-
if (mcpServers && MCP_SERVER_KEY in mcpServers) {
|
|
324
|
-
return true;
|
|
325
|
-
}
|
|
326
|
-
} catch {
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
450
|
return false;
|
|
330
451
|
}
|
|
331
452
|
/**
|
|
@@ -338,38 +459,13 @@ var init_install = __esm({
|
|
|
338
459
|
async ensureInstructionReferences(projectDir) {
|
|
339
460
|
this.updateInstructionFile(projectDir);
|
|
340
461
|
}
|
|
341
|
-
/**
|
|
342
|
-
* Register the CLEO MCP server in .mcp.json.
|
|
343
|
-
*
|
|
344
|
-
* @returns true if registration was performed or updated
|
|
345
|
-
*/
|
|
346
|
-
registerMcpServer(projectDir, mcpServerPath) {
|
|
347
|
-
const mcpPath = join3(projectDir, ".mcp.json");
|
|
348
|
-
let config = {};
|
|
349
|
-
if (existsSync2(mcpPath)) {
|
|
350
|
-
try {
|
|
351
|
-
config = JSON.parse(readFileSync2(mcpPath, "utf-8"));
|
|
352
|
-
} catch {
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
356
|
-
config.mcpServers = {};
|
|
357
|
-
}
|
|
358
|
-
const mcpServers = config.mcpServers;
|
|
359
|
-
mcpServers[MCP_SERVER_KEY] = {
|
|
360
|
-
command: "node",
|
|
361
|
-
args: [mcpServerPath]
|
|
362
|
-
};
|
|
363
|
-
writeFileSync2(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
364
|
-
return true;
|
|
365
|
-
}
|
|
366
462
|
/**
|
|
367
463
|
* Update CLAUDE.md with CLEO @-references.
|
|
368
464
|
*
|
|
369
465
|
* @returns true if the file was created or modified
|
|
370
466
|
*/
|
|
371
467
|
updateInstructionFile(projectDir) {
|
|
372
|
-
const claudeMdPath =
|
|
468
|
+
const claudeMdPath = join4(projectDir, "CLAUDE.md");
|
|
373
469
|
let content = "";
|
|
374
470
|
let existed = false;
|
|
375
471
|
if (existsSync2(claudeMdPath)) {
|
|
@@ -397,7 +493,7 @@ var init_install = __esm({
|
|
|
397
493
|
*/
|
|
398
494
|
registerPlugin() {
|
|
399
495
|
const home = homedir3();
|
|
400
|
-
const settingsPath =
|
|
496
|
+
const settingsPath = join4(home, ".claude", "settings.json");
|
|
401
497
|
let settings = {};
|
|
402
498
|
if (existsSync2(settingsPath)) {
|
|
403
499
|
try {
|
|
@@ -415,7 +511,7 @@ var init_install = __esm({
|
|
|
415
511
|
}
|
|
416
512
|
enabledPlugins[pluginKey] = true;
|
|
417
513
|
settings.enabledPlugins = enabledPlugins;
|
|
418
|
-
mkdirSync(
|
|
514
|
+
mkdirSync(join4(home, ".claude"), { recursive: true });
|
|
419
515
|
writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
420
516
|
return `Enabled ${pluginKey} in ~/.claude/settings.json`;
|
|
421
517
|
}
|
|
@@ -550,6 +646,13 @@ var init_operations = __esm({
|
|
|
550
646
|
}
|
|
551
647
|
});
|
|
552
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
|
+
|
|
553
656
|
// packages/contracts/src/session.ts
|
|
554
657
|
var init_session2 = __esm({
|
|
555
658
|
"packages/contracts/src/session.ts"() {
|
|
@@ -579,19 +682,20 @@ var init_src = __esm({
|
|
|
579
682
|
init_facade();
|
|
580
683
|
init_lafs();
|
|
581
684
|
init_operations();
|
|
685
|
+
init_orchestration_hierarchy();
|
|
582
686
|
init_session2();
|
|
583
687
|
init_status_registry();
|
|
584
688
|
init_wasm();
|
|
585
689
|
}
|
|
586
690
|
});
|
|
587
691
|
|
|
588
|
-
// packages/adapters/src/providers/claude-code/spawn.
|
|
692
|
+
// packages/adapters/src/providers/claude-code/spawn.ts
|
|
589
693
|
import { exec, spawn as nodeSpawn } from "node:child_process";
|
|
590
694
|
import { unlink, writeFile } from "node:fs/promises";
|
|
591
695
|
import { promisify } from "node:util";
|
|
592
696
|
var execAsync, ClaudeCodeSpawnProvider;
|
|
593
697
|
var init_spawn = __esm({
|
|
594
|
-
"packages/adapters/src/providers/claude-code/spawn.
|
|
698
|
+
"packages/adapters/src/providers/claude-code/spawn.ts"() {
|
|
595
699
|
"use strict";
|
|
596
700
|
init_src();
|
|
597
701
|
execAsync = promisify(exec);
|
|
@@ -714,8 +818,7 @@ var init_spawn = __esm({
|
|
|
714
818
|
*/
|
|
715
819
|
async terminate(instanceId) {
|
|
716
820
|
const tracked = this.processMap.get(instanceId);
|
|
717
|
-
if (!tracked)
|
|
718
|
-
return;
|
|
821
|
+
if (!tracked) return;
|
|
719
822
|
try {
|
|
720
823
|
process.kill(tracked.pid, "SIGTERM");
|
|
721
824
|
} catch {
|
|
@@ -726,9 +829,9 @@ var init_spawn = __esm({
|
|
|
726
829
|
}
|
|
727
830
|
});
|
|
728
831
|
|
|
729
|
-
// packages/adapters/src/providers/claude-code/task-sync.
|
|
730
|
-
import { readFile
|
|
731
|
-
import { join as
|
|
832
|
+
// packages/adapters/src/providers/claude-code/task-sync.ts
|
|
833
|
+
import { readFile as readFile2, stat } from "node:fs/promises";
|
|
834
|
+
import { join as join5 } from "node:path";
|
|
732
835
|
function parseTaskId(content) {
|
|
733
836
|
const match = content.match(/^\[T(\d+)\]/);
|
|
734
837
|
return match ? `T${match[1]}` : null;
|
|
@@ -749,17 +852,19 @@ function mapStatus(twStatus) {
|
|
|
749
852
|
}
|
|
750
853
|
}
|
|
751
854
|
function getTodoWriteFilePath(projectDir) {
|
|
752
|
-
return
|
|
855
|
+
return join5(projectDir, ".cleo", "sync", "todowrite-state.json");
|
|
753
856
|
}
|
|
754
857
|
var ClaudeCodeTaskSyncProvider;
|
|
755
858
|
var init_task_sync = __esm({
|
|
756
|
-
"packages/adapters/src/providers/claude-code/task-sync.
|
|
859
|
+
"packages/adapters/src/providers/claude-code/task-sync.ts"() {
|
|
757
860
|
"use strict";
|
|
758
861
|
ClaudeCodeTaskSyncProvider = class {
|
|
862
|
+
/** Optional override path for the TodoWrite state file (used in tests). */
|
|
759
863
|
customFilePath;
|
|
760
864
|
constructor(options) {
|
|
761
865
|
this.customFilePath = options?.filePath;
|
|
762
866
|
}
|
|
867
|
+
/** Retrieve external tasks from Claude's TodoWrite state file. */
|
|
763
868
|
async getExternalTasks(projectDir) {
|
|
764
869
|
const filePath = this.customFilePath ?? getTodoWriteFilePath(projectDir);
|
|
765
870
|
try {
|
|
@@ -767,7 +872,7 @@ var init_task_sync = __esm({
|
|
|
767
872
|
} catch {
|
|
768
873
|
return [];
|
|
769
874
|
}
|
|
770
|
-
const raw = await
|
|
875
|
+
const raw = await readFile2(filePath, "utf-8");
|
|
771
876
|
let state;
|
|
772
877
|
try {
|
|
773
878
|
state = JSON.parse(raw);
|
|
@@ -782,15 +887,14 @@ var init_task_sync = __esm({
|
|
|
782
887
|
for (const item of state.todos) {
|
|
783
888
|
const cleoTaskId = parseTaskId(item.content);
|
|
784
889
|
const title = cleoTaskId ? stripPrefixes(item.content).trim() : item.content.trim();
|
|
785
|
-
if (!title)
|
|
786
|
-
continue;
|
|
890
|
+
if (!title) continue;
|
|
787
891
|
tasks.push({
|
|
788
892
|
externalId: cleoTaskId ?? `tw-new-${syntheticIndex++}`,
|
|
789
|
-
cleoTaskId,
|
|
790
893
|
title,
|
|
791
894
|
status: mapStatus(item.status),
|
|
792
895
|
providerMeta: {
|
|
793
896
|
source: "todowrite",
|
|
897
|
+
cleoTaskId,
|
|
794
898
|
activeForm: item.activeForm,
|
|
795
899
|
rawContent: item.content
|
|
796
900
|
}
|
|
@@ -798,24 +902,19 @@ var init_task_sync = __esm({
|
|
|
798
902
|
}
|
|
799
903
|
return tasks;
|
|
800
904
|
}
|
|
801
|
-
async cleanup(projectDir) {
|
|
802
|
-
const filePath = this.customFilePath ?? getTodoWriteFilePath(projectDir);
|
|
803
|
-
try {
|
|
804
|
-
await rm(filePath);
|
|
805
|
-
} catch {
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
905
|
};
|
|
809
906
|
}
|
|
810
907
|
});
|
|
811
908
|
|
|
812
|
-
// packages/adapters/src/providers/claude-code/transport.
|
|
909
|
+
// packages/adapters/src/providers/claude-code/transport.ts
|
|
813
910
|
var ClaudeCodeTransportProvider;
|
|
814
911
|
var init_transport = __esm({
|
|
815
|
-
"packages/adapters/src/providers/claude-code/transport.
|
|
912
|
+
"packages/adapters/src/providers/claude-code/transport.ts"() {
|
|
816
913
|
"use strict";
|
|
817
914
|
ClaudeCodeTransportProvider = class {
|
|
915
|
+
/** Provider-specific transport name used for capability negotiation. */
|
|
818
916
|
transportName = "claude-code";
|
|
917
|
+
/** Create a transport instance for inter-agent messaging. */
|
|
819
918
|
createTransport() {
|
|
820
919
|
return null;
|
|
821
920
|
}
|
|
@@ -823,15 +922,15 @@ var init_transport = __esm({
|
|
|
823
922
|
}
|
|
824
923
|
});
|
|
825
924
|
|
|
826
|
-
// packages/adapters/src/providers/claude-code/adapter.
|
|
925
|
+
// packages/adapters/src/providers/claude-code/adapter.ts
|
|
827
926
|
import { exec as exec2 } from "node:child_process";
|
|
828
927
|
import { existsSync as existsSync3 } from "node:fs";
|
|
829
928
|
import { homedir as homedir4 } from "node:os";
|
|
830
|
-
import { join as
|
|
929
|
+
import { join as join6 } from "node:path";
|
|
831
930
|
import { promisify as promisify2 } from "node:util";
|
|
832
931
|
var execAsync2, ClaudeCodeAdapter;
|
|
833
932
|
var init_adapter = __esm({
|
|
834
|
-
"packages/adapters/src/providers/claude-code/adapter.
|
|
933
|
+
"packages/adapters/src/providers/claude-code/adapter.ts"() {
|
|
835
934
|
"use strict";
|
|
836
935
|
init_context_monitor();
|
|
837
936
|
init_hooks();
|
|
@@ -842,21 +941,36 @@ var init_adapter = __esm({
|
|
|
842
941
|
init_transport();
|
|
843
942
|
execAsync2 = promisify2(exec2);
|
|
844
943
|
ClaudeCodeAdapter = class {
|
|
944
|
+
/** Unique provider identifier. */
|
|
845
945
|
id = "claude-code";
|
|
946
|
+
/** Human-readable provider name. */
|
|
846
947
|
name = "Claude Code";
|
|
948
|
+
/** Adapter version string. */
|
|
847
949
|
version = "1.0.0";
|
|
950
|
+
/** Declared capabilities for this provider. */
|
|
848
951
|
capabilities = {
|
|
849
952
|
supportsHooks: true,
|
|
953
|
+
// 14/16 canonical events — derived from getProviderHookProfile('claude-code') in CAAMP 1.9.1.
|
|
954
|
+
// PreModel and PostModel are not supported by Claude Code.
|
|
850
955
|
supportedHookEvents: [
|
|
851
|
-
"
|
|
852
|
-
"
|
|
853
|
-
"
|
|
854
|
-
"
|
|
855
|
-
"
|
|
956
|
+
"SessionStart",
|
|
957
|
+
"SessionEnd",
|
|
958
|
+
"PromptSubmit",
|
|
959
|
+
"ResponseComplete",
|
|
960
|
+
"PreToolUse",
|
|
961
|
+
"PostToolUse",
|
|
962
|
+
"PostToolUseFailure",
|
|
963
|
+
"PermissionRequest",
|
|
964
|
+
"SubagentStart",
|
|
965
|
+
"SubagentStop",
|
|
966
|
+
"PreCompact",
|
|
967
|
+
"PostCompact",
|
|
968
|
+
"Notification",
|
|
969
|
+
"ConfigChange"
|
|
856
970
|
],
|
|
857
971
|
supportsSpawn: true,
|
|
858
972
|
supportsInstall: true,
|
|
859
|
-
supportsMcp:
|
|
973
|
+
supportsMcp: false,
|
|
860
974
|
supportsInstructionFiles: true,
|
|
861
975
|
instructionFilePattern: "CLAUDE.md",
|
|
862
976
|
supportsContextMonitor: true,
|
|
@@ -865,14 +979,23 @@ var init_adapter = __esm({
|
|
|
865
979
|
supportsTransport: true,
|
|
866
980
|
supportsTaskSync: true
|
|
867
981
|
};
|
|
982
|
+
/** Hook provider for CAAMP event mapping and registration. */
|
|
868
983
|
hooks;
|
|
984
|
+
/** Spawn provider for launching subagent processes via `claude` CLI. */
|
|
869
985
|
spawn;
|
|
986
|
+
/** Install provider for managing instruction files and plugin registration. */
|
|
870
987
|
install;
|
|
988
|
+
/** Path provider for resolving Claude Code directory locations. */
|
|
871
989
|
paths;
|
|
990
|
+
/** Context monitor for tracking context window usage and statusline output. */
|
|
872
991
|
contextMonitor;
|
|
992
|
+
/** Transport provider for inter-agent communication. */
|
|
873
993
|
transport;
|
|
994
|
+
/** Task sync provider bridging Claude's TodoWrite format to CLEO tasks. */
|
|
874
995
|
taskSync;
|
|
996
|
+
/** Project directory this adapter was initialized with, or null. */
|
|
875
997
|
projectDir = null;
|
|
998
|
+
/** Whether {@link initialize} has been called. */
|
|
876
999
|
initialized = false;
|
|
877
1000
|
constructor() {
|
|
878
1001
|
this.hooks = new ClaudeCodeHookProvider();
|
|
@@ -934,7 +1057,7 @@ var init_adapter = __esm({
|
|
|
934
1057
|
} catch {
|
|
935
1058
|
details.cliAvailable = false;
|
|
936
1059
|
}
|
|
937
|
-
const claudeConfigDir =
|
|
1060
|
+
const claudeConfigDir = join6(homedir4(), ".claude");
|
|
938
1061
|
const configExists = existsSync3(claudeConfigDir);
|
|
939
1062
|
details.configDirExists = configExists;
|
|
940
1063
|
const entrypointSet = process.env.CLAUDE_CODE_ENTRYPOINT !== void 0;
|
|
@@ -963,24 +1086,21 @@ var init_adapter = __esm({
|
|
|
963
1086
|
}
|
|
964
1087
|
});
|
|
965
1088
|
|
|
966
|
-
// packages/adapters/src/providers/claude-code/statusline.
|
|
1089
|
+
// packages/adapters/src/providers/claude-code/statusline.ts
|
|
967
1090
|
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
|
|
968
1091
|
import { homedir as homedir5 } from "node:os";
|
|
969
|
-
import { join as
|
|
1092
|
+
import { join as join7 } from "node:path";
|
|
970
1093
|
function getClaudeSettingsPath() {
|
|
971
|
-
return process.env["CLAUDE_SETTINGS"] ??
|
|
1094
|
+
return process.env["CLAUDE_SETTINGS"] ?? join7(process.env["CLAUDE_HOME"] ?? join7(homedir5(), ".claude"), "settings.json");
|
|
972
1095
|
}
|
|
973
1096
|
function checkStatuslineIntegration() {
|
|
974
1097
|
const settingsPath = getClaudeSettingsPath();
|
|
975
|
-
if (!existsSync4(settingsPath))
|
|
976
|
-
return "no_settings";
|
|
1098
|
+
if (!existsSync4(settingsPath)) return "no_settings";
|
|
977
1099
|
try {
|
|
978
1100
|
const settings = JSON.parse(readFileSync3(settingsPath, "utf-8"));
|
|
979
1101
|
const statusLine = settings.statusLine;
|
|
980
|
-
if (!statusLine?.type)
|
|
981
|
-
|
|
982
|
-
if (statusLine.type !== "command")
|
|
983
|
-
return "custom_no_cleo";
|
|
1102
|
+
if (!statusLine?.type) return "not_configured";
|
|
1103
|
+
if (statusLine.type !== "command") return "custom_no_cleo";
|
|
984
1104
|
const cmd = statusLine.command ?? "";
|
|
985
1105
|
if (cmd.includes("context-monitor.sh") || cmd.includes("cleo-statusline") || cmd.includes(".context-state.json") || cmd.includes("context-states")) {
|
|
986
1106
|
return "configured";
|
|
@@ -989,8 +1109,7 @@ function checkStatuslineIntegration() {
|
|
|
989
1109
|
if (existsSync4(scriptPath)) {
|
|
990
1110
|
try {
|
|
991
1111
|
const content = readFileSync3(scriptPath, "utf-8");
|
|
992
|
-
if (content.includes("context-state.json"))
|
|
993
|
-
return "configured";
|
|
1112
|
+
if (content.includes("context-state.json")) return "configured";
|
|
994
1113
|
} catch {
|
|
995
1114
|
}
|
|
996
1115
|
}
|
|
@@ -1003,7 +1122,7 @@ function getStatuslineConfig(cleoHome) {
|
|
|
1003
1122
|
return {
|
|
1004
1123
|
statusLine: {
|
|
1005
1124
|
type: "command",
|
|
1006
|
-
command:
|
|
1125
|
+
command: join7(cleoHome, "lib", "session", "context-monitor.sh")
|
|
1007
1126
|
}
|
|
1008
1127
|
};
|
|
1009
1128
|
}
|
|
@@ -1019,12 +1138,12 @@ function getSetupInstructions(cleoHome) {
|
|
|
1019
1138
|
].join("\n");
|
|
1020
1139
|
}
|
|
1021
1140
|
var init_statusline = __esm({
|
|
1022
|
-
"packages/adapters/src/providers/claude-code/statusline.
|
|
1141
|
+
"packages/adapters/src/providers/claude-code/statusline.ts"() {
|
|
1023
1142
|
"use strict";
|
|
1024
1143
|
}
|
|
1025
1144
|
});
|
|
1026
1145
|
|
|
1027
|
-
// packages/adapters/src/providers/claude-code/index.
|
|
1146
|
+
// packages/adapters/src/providers/claude-code/index.ts
|
|
1028
1147
|
var claude_code_exports = {};
|
|
1029
1148
|
__export(claude_code_exports, {
|
|
1030
1149
|
ClaudeCodeAdapter: () => ClaudeCodeAdapter,
|
|
@@ -1045,7 +1164,7 @@ function createAdapter() {
|
|
|
1045
1164
|
}
|
|
1046
1165
|
var claude_code_default;
|
|
1047
1166
|
var init_claude_code = __esm({
|
|
1048
|
-
"packages/adapters/src/providers/claude-code/index.
|
|
1167
|
+
"packages/adapters/src/providers/claude-code/index.ts"() {
|
|
1049
1168
|
"use strict";
|
|
1050
1169
|
init_adapter();
|
|
1051
1170
|
init_adapter();
|
|
@@ -1060,30 +1179,66 @@ var init_claude_code = __esm({
|
|
|
1060
1179
|
}
|
|
1061
1180
|
});
|
|
1062
1181
|
|
|
1063
|
-
// packages/adapters/src/providers/cursor/hooks.
|
|
1064
|
-
var CursorHookProvider;
|
|
1182
|
+
// packages/adapters/src/providers/cursor/hooks.ts
|
|
1183
|
+
var PROVIDER_ID2, CURSOR_EVENT_MAP, CursorHookProvider;
|
|
1065
1184
|
var init_hooks2 = __esm({
|
|
1066
|
-
"packages/adapters/src/providers/cursor/hooks.
|
|
1185
|
+
"packages/adapters/src/providers/cursor/hooks.ts"() {
|
|
1067
1186
|
"use strict";
|
|
1187
|
+
PROVIDER_ID2 = "cursor";
|
|
1188
|
+
CURSOR_EVENT_MAP = {
|
|
1189
|
+
// CAAMP: toNative('SessionStart', 'cursor') = 'sessionStart'
|
|
1190
|
+
sessionStart: "SessionStart",
|
|
1191
|
+
// CAAMP: toNative('SessionEnd', 'cursor') = 'sessionEnd'
|
|
1192
|
+
sessionEnd: "SessionEnd",
|
|
1193
|
+
// CAAMP: toNative('PromptSubmit', 'cursor') = 'beforeSubmitPrompt'
|
|
1194
|
+
beforeSubmitPrompt: "PromptSubmit",
|
|
1195
|
+
// CAAMP: toNative('ResponseComplete', 'cursor') = 'stop'
|
|
1196
|
+
stop: "ResponseComplete",
|
|
1197
|
+
// CAAMP: toNative('PreToolUse', 'cursor') = 'preToolUse'
|
|
1198
|
+
preToolUse: "PreToolUse",
|
|
1199
|
+
// CAAMP: toNative('PostToolUse', 'cursor') = 'postToolUse'
|
|
1200
|
+
postToolUse: "PostToolUse",
|
|
1201
|
+
// CAAMP: toNative('PostToolUseFailure', 'cursor') = 'postToolUseFailure'
|
|
1202
|
+
postToolUseFailure: "PostToolUseFailure",
|
|
1203
|
+
// CAAMP: toNative('SubagentStart', 'cursor') = 'subagentStart'
|
|
1204
|
+
subagentStart: "SubagentStart",
|
|
1205
|
+
// CAAMP: toNative('SubagentStop', 'cursor') = 'subagentStop'
|
|
1206
|
+
subagentStop: "SubagentStop",
|
|
1207
|
+
// CAAMP: toNative('PreCompact', 'cursor') = 'preCompact'
|
|
1208
|
+
preCompact: "PreCompact"
|
|
1209
|
+
};
|
|
1068
1210
|
CursorHookProvider = class {
|
|
1211
|
+
/** Whether hooks have been registered for the current session. */
|
|
1069
1212
|
registered = false;
|
|
1070
1213
|
/**
|
|
1071
|
-
* Map a
|
|
1214
|
+
* Map a Cursor native event name to a CAAMP canonical hook event name.
|
|
1072
1215
|
*
|
|
1073
|
-
*
|
|
1216
|
+
* Looks up the native event name in the map derived from
|
|
1217
|
+
* `getProviderHookProfile('cursor').mappings` (CAAMP 1.9.1). Cursor uses
|
|
1218
|
+
* camelCase names (e.g. "preToolUse", "sessionStart").
|
|
1074
1219
|
*
|
|
1075
|
-
*
|
|
1076
|
-
*
|
|
1220
|
+
* Returns null for unsupported events (PermissionRequest, PreModel,
|
|
1221
|
+
* PostModel, PostCompact, Notification, ConfigChange).
|
|
1222
|
+
*
|
|
1223
|
+
* @param providerEvent - Cursor native event name (e.g. "preToolUse", "sessionStart")
|
|
1224
|
+
* @returns CAAMP canonical event name, or null if unmapped
|
|
1225
|
+
* @task T165
|
|
1077
1226
|
*/
|
|
1078
|
-
mapProviderEvent(
|
|
1079
|
-
return null;
|
|
1227
|
+
mapProviderEvent(providerEvent) {
|
|
1228
|
+
return CURSOR_EVENT_MAP[providerEvent] ?? null;
|
|
1080
1229
|
}
|
|
1081
1230
|
/**
|
|
1082
1231
|
* Register native hooks for a project.
|
|
1083
1232
|
*
|
|
1084
|
-
*
|
|
1233
|
+
* For Cursor, hooks are registered via the config system
|
|
1234
|
+
* (`.cursor/hooks.json`), managed by the install provider.
|
|
1235
|
+
* This method marks hooks as registered without performing filesystem operations.
|
|
1085
1236
|
*
|
|
1086
|
-
*
|
|
1237
|
+
* Iterating supported events is handled at install time using
|
|
1238
|
+
* `getSupportedCanonicalEvents()` to enumerate all 10 supported hooks.
|
|
1239
|
+
*
|
|
1240
|
+
* @param _projectDir - Project directory (unused; Cursor config manages registration)
|
|
1241
|
+
* @task T165
|
|
1087
1242
|
*/
|
|
1088
1243
|
async registerNativeHooks(_projectDir) {
|
|
1089
1244
|
this.registered = true;
|
|
@@ -1091,99 +1246,146 @@ var init_hooks2 = __esm({
|
|
|
1091
1246
|
/**
|
|
1092
1247
|
* Unregister native hooks.
|
|
1093
1248
|
*
|
|
1094
|
-
*
|
|
1249
|
+
* For Cursor, this is a no-op since hooks are managed through the config
|
|
1250
|
+
* system. Unregistration happens via the install provider's uninstall method.
|
|
1251
|
+
*
|
|
1252
|
+
* @task T165
|
|
1095
1253
|
*/
|
|
1096
1254
|
async unregisterNativeHooks() {
|
|
1097
1255
|
this.registered = false;
|
|
1098
1256
|
}
|
|
1099
1257
|
/**
|
|
1100
|
-
* Check whether hooks have been registered
|
|
1258
|
+
* Check whether hooks have been registered via `registerNativeHooks`.
|
|
1101
1259
|
*/
|
|
1102
1260
|
isRegistered() {
|
|
1103
1261
|
return this.registered;
|
|
1104
1262
|
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Get the native→canonical event mapping for introspection and debugging.
|
|
1265
|
+
*
|
|
1266
|
+
* Returns the map derived from `getProviderHookProfile('cursor').mappings`
|
|
1267
|
+
* (CAAMP 1.9.1). Use `getSupportedCanonicalEvents()` to enumerate canonical
|
|
1268
|
+
* names via live CAAMP APIs.
|
|
1269
|
+
*
|
|
1270
|
+
* @returns Immutable record of native event name → canonical event name
|
|
1271
|
+
*/
|
|
1272
|
+
getEventMap() {
|
|
1273
|
+
return { ...CURSOR_EVENT_MAP };
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* Enumerate supported canonical events via CAAMP's `getSupportedEvents()`.
|
|
1277
|
+
*
|
|
1278
|
+
* Calls `getSupportedEvents('cursor')` from the CAAMP normalizer to get the
|
|
1279
|
+
* authoritative list. Cursor supports 10 of 16 canonical events. Falls back
|
|
1280
|
+
* to the values of the static event map when CAAMP is unavailable at runtime.
|
|
1281
|
+
*
|
|
1282
|
+
* @returns Array of CAAMP canonical event names supported by Cursor
|
|
1283
|
+
* @task T165
|
|
1284
|
+
*/
|
|
1285
|
+
async getSupportedCanonicalEvents() {
|
|
1286
|
+
try {
|
|
1287
|
+
const { getSupportedEvents } = await import("@cleocode/caamp");
|
|
1288
|
+
return getSupportedEvents(PROVIDER_ID2);
|
|
1289
|
+
} catch {
|
|
1290
|
+
return [...new Set(Object.values(CURSOR_EVENT_MAP))];
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Retrieve the full provider hook profile from CAAMP.
|
|
1295
|
+
*
|
|
1296
|
+
* Calls `getProviderHookProfile('cursor')` from the CAAMP normalizer to
|
|
1297
|
+
* get the complete profile: hook system type (`config`), config path
|
|
1298
|
+
* (`.cursor/hooks.json`), handler types (command, prompt), and all event
|
|
1299
|
+
* mappings. Returns null when CAAMP is unavailable at runtime.
|
|
1300
|
+
*
|
|
1301
|
+
* @returns Provider hook profile or null if CAAMP is unavailable
|
|
1302
|
+
* @task T165
|
|
1303
|
+
*/
|
|
1304
|
+
async getProviderProfile() {
|
|
1305
|
+
try {
|
|
1306
|
+
const { getProviderHookProfile } = await import("@cleocode/caamp");
|
|
1307
|
+
return getProviderHookProfile(PROVIDER_ID2) ?? null;
|
|
1308
|
+
} catch {
|
|
1309
|
+
return null;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* Translate a CAAMP canonical event to its Cursor native name via CAAMP.
|
|
1314
|
+
*
|
|
1315
|
+
* Calls `toNative(canonical, 'cursor')` from the CAAMP normalizer.
|
|
1316
|
+
* Returns null for unsupported events or when CAAMP is unavailable.
|
|
1317
|
+
*
|
|
1318
|
+
* @param canonical - CAAMP canonical event name (e.g. "PreToolUse")
|
|
1319
|
+
* @returns Cursor native event name (e.g. "preToolUse") or null
|
|
1320
|
+
* @task T165
|
|
1321
|
+
*/
|
|
1322
|
+
async toNativeEvent(canonical) {
|
|
1323
|
+
try {
|
|
1324
|
+
const { toNative } = await import("@cleocode/caamp");
|
|
1325
|
+
return toNative(canonical, PROVIDER_ID2);
|
|
1326
|
+
} catch {
|
|
1327
|
+
const entry = Object.entries(CURSOR_EVENT_MAP).find(([, v]) => v === canonical);
|
|
1328
|
+
return entry?.[0] ?? null;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1105
1331
|
};
|
|
1106
1332
|
}
|
|
1107
1333
|
});
|
|
1108
1334
|
|
|
1109
|
-
// packages/adapters/src/providers/cursor/install.
|
|
1110
|
-
import { existsSync as existsSync7, mkdirSync as
|
|
1111
|
-
import { join as
|
|
1112
|
-
var INSTRUCTION_REFERENCES3,
|
|
1335
|
+
// packages/adapters/src/providers/cursor/install.ts
|
|
1336
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1337
|
+
import { join as join12 } from "node:path";
|
|
1338
|
+
var INSTRUCTION_REFERENCES3, CursorInstallProvider;
|
|
1113
1339
|
var init_install2 = __esm({
|
|
1114
|
-
"packages/adapters/src/providers/cursor/install.
|
|
1340
|
+
"packages/adapters/src/providers/cursor/install.ts"() {
|
|
1115
1341
|
"use strict";
|
|
1116
1342
|
INSTRUCTION_REFERENCES3 = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
|
|
1117
|
-
MCP_SERVER_KEY3 = "cleo";
|
|
1118
1343
|
CursorInstallProvider = class {
|
|
1119
|
-
installedProjectDir = null;
|
|
1120
1344
|
/**
|
|
1121
1345
|
* Install CLEO into a Cursor project.
|
|
1122
1346
|
*
|
|
1123
|
-
* @param options - Installation options including project directory
|
|
1347
|
+
* @param options - Installation options including project directory
|
|
1124
1348
|
* @returns Result describing what was installed
|
|
1125
1349
|
*/
|
|
1126
1350
|
async install(options) {
|
|
1127
|
-
const { projectDir
|
|
1351
|
+
const { projectDir } = options;
|
|
1128
1352
|
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1129
1353
|
let instructionFileUpdated = false;
|
|
1130
|
-
let mcpRegistered = false;
|
|
1131
1354
|
const details = {};
|
|
1132
|
-
if (mcpServerPath) {
|
|
1133
|
-
mcpRegistered = this.registerMcpServer(projectDir, mcpServerPath);
|
|
1134
|
-
if (mcpRegistered) {
|
|
1135
|
-
details.mcpConfigPath = join11(projectDir, ".cursor", "mcp.json");
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
1355
|
instructionFileUpdated = this.updateInstructionFiles(projectDir);
|
|
1139
1356
|
if (instructionFileUpdated) {
|
|
1140
1357
|
details.instructionFiles = this.getUpdatedFileList(projectDir);
|
|
1141
1358
|
}
|
|
1142
|
-
this.installedProjectDir = projectDir;
|
|
1143
1359
|
return {
|
|
1144
1360
|
success: true,
|
|
1145
1361
|
installedAt,
|
|
1146
1362
|
instructionFileUpdated,
|
|
1147
|
-
mcpRegistered,
|
|
1363
|
+
mcpRegistered: false,
|
|
1148
1364
|
details
|
|
1149
1365
|
};
|
|
1150
1366
|
}
|
|
1151
1367
|
/**
|
|
1152
1368
|
* Uninstall CLEO from the current Cursor project.
|
|
1153
1369
|
*
|
|
1154
|
-
* Removes the MCP server registration from .cursor/mcp.json.
|
|
1155
1370
|
* Does not remove instruction file references (they are harmless if CLEO is not present).
|
|
1156
1371
|
*/
|
|
1157
1372
|
async uninstall() {
|
|
1158
|
-
if (!this.installedProjectDir)
|
|
1159
|
-
return;
|
|
1160
|
-
const mcpPath = join11(this.installedProjectDir, ".cursor", "mcp.json");
|
|
1161
|
-
if (existsSync7(mcpPath)) {
|
|
1162
|
-
try {
|
|
1163
|
-
const raw = readFileSync5(mcpPath, "utf-8");
|
|
1164
|
-
const config = JSON.parse(raw);
|
|
1165
|
-
const mcpServers = config.mcpServers;
|
|
1166
|
-
if (mcpServers && MCP_SERVER_KEY3 in mcpServers) {
|
|
1167
|
-
delete mcpServers[MCP_SERVER_KEY3];
|
|
1168
|
-
writeFileSync4(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
1169
|
-
}
|
|
1170
|
-
} catch {
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
this.installedProjectDir = null;
|
|
1174
1373
|
}
|
|
1175
1374
|
/**
|
|
1176
1375
|
* Check whether CLEO is installed in the current environment.
|
|
1177
1376
|
*
|
|
1178
|
-
* Checks for
|
|
1377
|
+
* Checks for .cursor/rules/cleo.mdc or .cursorrules with CLEO references.
|
|
1179
1378
|
*/
|
|
1180
1379
|
async isInstalled() {
|
|
1181
|
-
const
|
|
1182
|
-
if (existsSync7(
|
|
1380
|
+
const mdcPath = join12(process.cwd(), ".cursor", "rules", "cleo.mdc");
|
|
1381
|
+
if (existsSync7(mdcPath)) {
|
|
1382
|
+
return true;
|
|
1383
|
+
}
|
|
1384
|
+
const rulesPath = join12(process.cwd(), ".cursorrules");
|
|
1385
|
+
if (existsSync7(rulesPath)) {
|
|
1183
1386
|
try {
|
|
1184
|
-
const
|
|
1185
|
-
|
|
1186
|
-
if (mcpServers && MCP_SERVER_KEY3 in mcpServers) {
|
|
1387
|
+
const content = readFileSync5(rulesPath, "utf-8");
|
|
1388
|
+
if (INSTRUCTION_REFERENCES3.some((ref) => content.includes(ref))) {
|
|
1187
1389
|
return true;
|
|
1188
1390
|
}
|
|
1189
1391
|
} catch {
|
|
@@ -1201,36 +1403,6 @@ var init_install2 = __esm({
|
|
|
1201
1403
|
async ensureInstructionReferences(projectDir) {
|
|
1202
1404
|
this.updateInstructionFiles(projectDir);
|
|
1203
1405
|
}
|
|
1204
|
-
/**
|
|
1205
|
-
* Register the CLEO MCP server in .cursor/mcp.json.
|
|
1206
|
-
*
|
|
1207
|
-
* Cursor stores MCP server configuration in .cursor/mcp.json
|
|
1208
|
-
* under the mcpServers key.
|
|
1209
|
-
*
|
|
1210
|
-
* @returns true if registration was performed or updated
|
|
1211
|
-
*/
|
|
1212
|
-
registerMcpServer(projectDir, mcpServerPath) {
|
|
1213
|
-
const cursorDir = join11(projectDir, ".cursor");
|
|
1214
|
-
const mcpPath = join11(cursorDir, "mcp.json");
|
|
1215
|
-
let config = {};
|
|
1216
|
-
mkdirSync3(cursorDir, { recursive: true });
|
|
1217
|
-
if (existsSync7(mcpPath)) {
|
|
1218
|
-
try {
|
|
1219
|
-
config = JSON.parse(readFileSync5(mcpPath, "utf-8"));
|
|
1220
|
-
} catch {
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
1224
|
-
config.mcpServers = {};
|
|
1225
|
-
}
|
|
1226
|
-
const mcpServers = config.mcpServers;
|
|
1227
|
-
mcpServers[MCP_SERVER_KEY3] = {
|
|
1228
|
-
command: "node",
|
|
1229
|
-
args: [mcpServerPath]
|
|
1230
|
-
};
|
|
1231
|
-
writeFileSync4(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
1232
|
-
return true;
|
|
1233
|
-
}
|
|
1234
1406
|
/**
|
|
1235
1407
|
* Update instruction files with CLEO @-references.
|
|
1236
1408
|
*
|
|
@@ -1255,7 +1427,7 @@ var init_install2 = __esm({
|
|
|
1255
1427
|
* @returns true if the file was modified
|
|
1256
1428
|
*/
|
|
1257
1429
|
updateLegacyRules(projectDir) {
|
|
1258
|
-
const rulesPath =
|
|
1430
|
+
const rulesPath = join12(projectDir, ".cursorrules");
|
|
1259
1431
|
if (!existsSync7(rulesPath)) {
|
|
1260
1432
|
return false;
|
|
1261
1433
|
}
|
|
@@ -1278,8 +1450,8 @@ var init_install2 = __esm({
|
|
|
1278
1450
|
* @returns true if the file was created or modified
|
|
1279
1451
|
*/
|
|
1280
1452
|
updateModernRules(projectDir) {
|
|
1281
|
-
const rulesDir =
|
|
1282
|
-
const mdcPath =
|
|
1453
|
+
const rulesDir = join12(projectDir, ".cursor", "rules");
|
|
1454
|
+
const mdcPath = join12(rulesDir, "cleo.mdc");
|
|
1283
1455
|
const expectedContent = [
|
|
1284
1456
|
"---",
|
|
1285
1457
|
"description: CLEO task management protocol references",
|
|
@@ -1296,7 +1468,7 @@ var init_install2 = __esm({
|
|
|
1296
1468
|
return false;
|
|
1297
1469
|
}
|
|
1298
1470
|
}
|
|
1299
|
-
|
|
1471
|
+
mkdirSync2(rulesDir, { recursive: true });
|
|
1300
1472
|
writeFileSync4(mdcPath, expectedContent, "utf-8");
|
|
1301
1473
|
return true;
|
|
1302
1474
|
}
|
|
@@ -1305,35 +1477,53 @@ var init_install2 = __esm({
|
|
|
1305
1477
|
*/
|
|
1306
1478
|
getUpdatedFileList(projectDir) {
|
|
1307
1479
|
const files = [];
|
|
1308
|
-
if (existsSync7(
|
|
1309
|
-
files.push(
|
|
1480
|
+
if (existsSync7(join12(projectDir, ".cursorrules"))) {
|
|
1481
|
+
files.push(join12(projectDir, ".cursorrules"));
|
|
1310
1482
|
}
|
|
1311
|
-
files.push(
|
|
1483
|
+
files.push(join12(projectDir, ".cursor", "rules", "cleo.mdc"));
|
|
1312
1484
|
return files;
|
|
1313
1485
|
}
|
|
1314
1486
|
};
|
|
1315
1487
|
}
|
|
1316
1488
|
});
|
|
1317
1489
|
|
|
1318
|
-
// packages/adapters/src/providers/cursor/adapter.
|
|
1490
|
+
// packages/adapters/src/providers/cursor/adapter.ts
|
|
1319
1491
|
import { existsSync as existsSync8 } from "node:fs";
|
|
1320
|
-
import { join as
|
|
1492
|
+
import { join as join13 } from "node:path";
|
|
1321
1493
|
var CursorAdapter;
|
|
1322
1494
|
var init_adapter2 = __esm({
|
|
1323
|
-
"packages/adapters/src/providers/cursor/adapter.
|
|
1495
|
+
"packages/adapters/src/providers/cursor/adapter.ts"() {
|
|
1324
1496
|
"use strict";
|
|
1325
1497
|
init_hooks2();
|
|
1326
1498
|
init_install2();
|
|
1327
1499
|
CursorAdapter = class {
|
|
1500
|
+
/** Unique provider identifier. */
|
|
1328
1501
|
id = "cursor";
|
|
1502
|
+
/** Human-readable provider name. */
|
|
1329
1503
|
name = "Cursor";
|
|
1504
|
+
/** Adapter version string. */
|
|
1330
1505
|
version = "1.0.0";
|
|
1506
|
+
/** Declared capabilities for this provider. */
|
|
1331
1507
|
capabilities = {
|
|
1332
|
-
supportsHooks:
|
|
1333
|
-
|
|
1508
|
+
supportsHooks: true,
|
|
1509
|
+
// 10/16 canonical events — derived from getProviderHookProfile('cursor') in CAAMP 1.9.1.
|
|
1510
|
+
// PermissionRequest, PreModel, PostModel, PostCompact, Notification, ConfigChange are
|
|
1511
|
+
// not supported by Cursor's hook system.
|
|
1512
|
+
supportedHookEvents: [
|
|
1513
|
+
"SessionStart",
|
|
1514
|
+
"SessionEnd",
|
|
1515
|
+
"PromptSubmit",
|
|
1516
|
+
"ResponseComplete",
|
|
1517
|
+
"PreToolUse",
|
|
1518
|
+
"PostToolUse",
|
|
1519
|
+
"PostToolUseFailure",
|
|
1520
|
+
"SubagentStart",
|
|
1521
|
+
"SubagentStop",
|
|
1522
|
+
"PreCompact"
|
|
1523
|
+
],
|
|
1334
1524
|
supportsSpawn: false,
|
|
1335
1525
|
supportsInstall: true,
|
|
1336
|
-
supportsMcp:
|
|
1526
|
+
supportsMcp: false,
|
|
1337
1527
|
supportsInstructionFiles: true,
|
|
1338
1528
|
instructionFilePattern: ".cursor/rules/*.mdc",
|
|
1339
1529
|
supportsContextMonitor: false,
|
|
@@ -1342,9 +1532,13 @@ var init_adapter2 = __esm({
|
|
|
1342
1532
|
supportsTransport: false,
|
|
1343
1533
|
supportsTaskSync: false
|
|
1344
1534
|
};
|
|
1535
|
+
/** Hook provider for CAAMP event mapping. */
|
|
1345
1536
|
hooks;
|
|
1537
|
+
/** Install provider for managing rule files. */
|
|
1346
1538
|
install;
|
|
1539
|
+
/** Project directory this adapter was initialized with, or null. */
|
|
1347
1540
|
projectDir = null;
|
|
1541
|
+
/** Whether {@link initialize} has been called. */
|
|
1348
1542
|
initialized = false;
|
|
1349
1543
|
constructor() {
|
|
1350
1544
|
this.hooks = new CursorHookProvider();
|
|
@@ -1390,14 +1584,14 @@ var init_adapter2 = __esm({
|
|
|
1390
1584
|
}
|
|
1391
1585
|
let configExists = false;
|
|
1392
1586
|
if (this.projectDir) {
|
|
1393
|
-
const cursorConfigDir =
|
|
1587
|
+
const cursorConfigDir = join13(this.projectDir, ".cursor");
|
|
1394
1588
|
configExists = existsSync8(cursorConfigDir);
|
|
1395
1589
|
details.configDirExists = configExists;
|
|
1396
1590
|
}
|
|
1397
1591
|
const editorEnvSet = process.env.CURSOR_EDITOR !== void 0;
|
|
1398
1592
|
details.editorEnvSet = editorEnvSet;
|
|
1399
1593
|
if (this.projectDir) {
|
|
1400
|
-
const legacyRulesExist = existsSync8(
|
|
1594
|
+
const legacyRulesExist = existsSync8(join13(this.projectDir, ".cursorrules"));
|
|
1401
1595
|
details.legacyRulesExist = legacyRulesExist;
|
|
1402
1596
|
}
|
|
1403
1597
|
const healthy = configExists || editorEnvSet;
|
|
@@ -1424,7 +1618,7 @@ var init_adapter2 = __esm({
|
|
|
1424
1618
|
}
|
|
1425
1619
|
});
|
|
1426
1620
|
|
|
1427
|
-
// packages/adapters/src/providers/cursor/index.
|
|
1621
|
+
// packages/adapters/src/providers/cursor/index.ts
|
|
1428
1622
|
var cursor_exports = {};
|
|
1429
1623
|
__export(cursor_exports, {
|
|
1430
1624
|
CursorAdapter: () => CursorAdapter,
|
|
@@ -1438,7 +1632,7 @@ function createAdapter3() {
|
|
|
1438
1632
|
}
|
|
1439
1633
|
var cursor_default;
|
|
1440
1634
|
var init_cursor = __esm({
|
|
1441
|
-
"packages/adapters/src/providers/cursor/index.
|
|
1635
|
+
"packages/adapters/src/providers/cursor/index.ts"() {
|
|
1442
1636
|
"use strict";
|
|
1443
1637
|
init_adapter2();
|
|
1444
1638
|
init_adapter2();
|
|
@@ -1448,26 +1642,48 @@ var init_cursor = __esm({
|
|
|
1448
1642
|
}
|
|
1449
1643
|
});
|
|
1450
1644
|
|
|
1451
|
-
// packages/adapters/src/providers/opencode/hooks.
|
|
1452
|
-
var OPENCODE_EVENT_MAP, OpenCodeHookProvider;
|
|
1645
|
+
// packages/adapters/src/providers/opencode/hooks.ts
|
|
1646
|
+
var PROVIDER_ID3, OPENCODE_EVENT_MAP, OpenCodeHookProvider;
|
|
1453
1647
|
var init_hooks3 = __esm({
|
|
1454
|
-
"packages/adapters/src/providers/opencode/hooks.
|
|
1648
|
+
"packages/adapters/src/providers/opencode/hooks.ts"() {
|
|
1455
1649
|
"use strict";
|
|
1650
|
+
PROVIDER_ID3 = "opencode";
|
|
1456
1651
|
OPENCODE_EVENT_MAP = {
|
|
1457
|
-
|
|
1458
|
-
"session.
|
|
1459
|
-
|
|
1460
|
-
"
|
|
1461
|
-
|
|
1462
|
-
"
|
|
1652
|
+
// CAAMP: toNative('SessionStart', 'opencode') = 'event:session.created'
|
|
1653
|
+
"event:session.created": "SessionStart",
|
|
1654
|
+
// CAAMP: toNative('SessionEnd', 'opencode') = 'event:session.deleted'
|
|
1655
|
+
"event:session.deleted": "SessionEnd",
|
|
1656
|
+
// CAAMP: toNative('PromptSubmit', 'opencode') = 'chat.message'
|
|
1657
|
+
"chat.message": "PromptSubmit",
|
|
1658
|
+
// CAAMP: toNative('ResponseComplete', 'opencode') = 'event:session.idle'
|
|
1659
|
+
"event:session.idle": "ResponseComplete",
|
|
1660
|
+
// CAAMP: toNative('PreToolUse', 'opencode') = 'tool.execute.before'
|
|
1661
|
+
"tool.execute.before": "PreToolUse",
|
|
1662
|
+
// CAAMP: toNative('PostToolUse', 'opencode') = 'tool.execute.after'
|
|
1663
|
+
"tool.execute.after": "PostToolUse",
|
|
1664
|
+
// CAAMP: toNative('PermissionRequest', 'opencode') = 'permission.ask'
|
|
1665
|
+
"permission.ask": "PermissionRequest",
|
|
1666
|
+
// CAAMP: toNative('PreModel', 'opencode') = 'chat.params'
|
|
1667
|
+
"chat.params": "PreModel",
|
|
1668
|
+
// CAAMP: toNative('PreCompact', 'opencode') = 'experimental.session.compacting'
|
|
1669
|
+
"experimental.session.compacting": "PreCompact",
|
|
1670
|
+
// CAAMP: toNative('PostCompact', 'opencode') = 'event:session.compacted'
|
|
1671
|
+
"event:session.compacted": "PostCompact"
|
|
1463
1672
|
};
|
|
1464
1673
|
OpenCodeHookProvider = class {
|
|
1674
|
+
/** Whether hooks have been registered for the current session. */
|
|
1465
1675
|
registered = false;
|
|
1466
1676
|
/**
|
|
1467
|
-
* Map an OpenCode native event name to a CAAMP hook event name.
|
|
1677
|
+
* Map an OpenCode native event name to a CAAMP canonical hook event name.
|
|
1468
1678
|
*
|
|
1469
|
-
*
|
|
1470
|
-
*
|
|
1679
|
+
* Looks up the native event name in the map derived from
|
|
1680
|
+
* `getProviderHookProfile('opencode').mappings` (CAAMP 1.9.1).
|
|
1681
|
+
* Returns null for unsupported events (PostToolUseFailure, SubagentStart,
|
|
1682
|
+
* SubagentStop, Notification, ConfigChange).
|
|
1683
|
+
*
|
|
1684
|
+
* @param providerEvent - OpenCode native event (e.g. "event:session.created", "tool.execute.before")
|
|
1685
|
+
* @returns CAAMP canonical event name, or null if unmapped
|
|
1686
|
+
* @task T164
|
|
1471
1687
|
*/
|
|
1472
1688
|
mapProviderEvent(providerEvent) {
|
|
1473
1689
|
return OPENCODE_EVENT_MAP[providerEvent] ?? null;
|
|
@@ -1475,12 +1691,15 @@ var init_hooks3 = __esm({
|
|
|
1475
1691
|
/**
|
|
1476
1692
|
* Register native hooks for a project.
|
|
1477
1693
|
*
|
|
1478
|
-
* For OpenCode, hooks are registered via the
|
|
1479
|
-
* (
|
|
1480
|
-
* This method marks hooks as registered without performing
|
|
1481
|
-
*
|
|
1694
|
+
* For OpenCode, hooks are registered via the plugin system
|
|
1695
|
+
* (`.opencode/plugins/`), managed by the install provider.
|
|
1696
|
+
* This method marks hooks as registered without performing filesystem operations.
|
|
1697
|
+
*
|
|
1698
|
+
* Iterating supported events is handled at install time using
|
|
1699
|
+
* `getSupportedCanonicalEvents()` to enumerate all 10 supported hooks.
|
|
1482
1700
|
*
|
|
1483
1701
|
* @param _projectDir - Project directory (unused; config manages registration)
|
|
1702
|
+
* @task T164
|
|
1484
1703
|
*/
|
|
1485
1704
|
async registerNativeHooks(_projectDir) {
|
|
1486
1705
|
this.registered = true;
|
|
@@ -1488,108 +1707,143 @@ var init_hooks3 = __esm({
|
|
|
1488
1707
|
/**
|
|
1489
1708
|
* Unregister native hooks.
|
|
1490
1709
|
*
|
|
1491
|
-
* For OpenCode, this is a no-op since hooks are managed through
|
|
1492
|
-
*
|
|
1493
|
-
*
|
|
1710
|
+
* For OpenCode, this is a no-op since hooks are managed through the plugin
|
|
1711
|
+
* system. Unregistration happens via the install provider's uninstall method.
|
|
1712
|
+
*
|
|
1713
|
+
* @task T164
|
|
1494
1714
|
*/
|
|
1495
1715
|
async unregisterNativeHooks() {
|
|
1496
1716
|
this.registered = false;
|
|
1497
1717
|
}
|
|
1498
1718
|
/**
|
|
1499
|
-
* Check whether hooks have been registered via registerNativeHooks
|
|
1719
|
+
* Check whether hooks have been registered via `registerNativeHooks`.
|
|
1500
1720
|
*/
|
|
1501
1721
|
isRegistered() {
|
|
1502
1722
|
return this.registered;
|
|
1503
1723
|
}
|
|
1504
1724
|
/**
|
|
1505
|
-
* Get the
|
|
1725
|
+
* Get the native→canonical event mapping for introspection and debugging.
|
|
1726
|
+
*
|
|
1727
|
+
* Returns the map derived from `getProviderHookProfile('opencode').mappings`
|
|
1728
|
+
* (CAAMP 1.9.1). Use `getSupportedCanonicalEvents()` to enumerate canonical
|
|
1729
|
+
* names via live CAAMP APIs.
|
|
1730
|
+
*
|
|
1731
|
+
* @returns Immutable record of native event name → canonical event name
|
|
1506
1732
|
*/
|
|
1507
1733
|
getEventMap() {
|
|
1508
1734
|
return { ...OPENCODE_EVENT_MAP };
|
|
1509
1735
|
}
|
|
1736
|
+
/**
|
|
1737
|
+
* Enumerate supported canonical events via CAAMP's `getSupportedEvents()`.
|
|
1738
|
+
*
|
|
1739
|
+
* Calls `getSupportedEvents('opencode')` from the CAAMP normalizer to get the
|
|
1740
|
+
* authoritative list. OpenCode supports 10 of 16 canonical events via its
|
|
1741
|
+
* plugin system. Falls back to the values of the static event map when
|
|
1742
|
+
* CAAMP is unavailable at runtime.
|
|
1743
|
+
*
|
|
1744
|
+
* @returns Array of CAAMP canonical event names supported by OpenCode
|
|
1745
|
+
* @task T164
|
|
1746
|
+
*/
|
|
1747
|
+
async getSupportedCanonicalEvents() {
|
|
1748
|
+
try {
|
|
1749
|
+
const { getSupportedEvents } = await import("@cleocode/caamp");
|
|
1750
|
+
return getSupportedEvents(PROVIDER_ID3);
|
|
1751
|
+
} catch {
|
|
1752
|
+
return [...new Set(Object.values(OPENCODE_EVENT_MAP))];
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
/**
|
|
1756
|
+
* Retrieve the full provider hook profile from CAAMP.
|
|
1757
|
+
*
|
|
1758
|
+
* Calls `getProviderHookProfile('opencode')` from the CAAMP normalizer to
|
|
1759
|
+
* get the complete profile: hook system type (`plugin`), config path
|
|
1760
|
+
* (`.opencode/plugins/`), handler types, and all event mappings.
|
|
1761
|
+
* Returns null when CAAMP is unavailable at runtime.
|
|
1762
|
+
*
|
|
1763
|
+
* @returns Provider hook profile or null if CAAMP is unavailable
|
|
1764
|
+
* @task T164
|
|
1765
|
+
*/
|
|
1766
|
+
async getProviderProfile() {
|
|
1767
|
+
try {
|
|
1768
|
+
const { getProviderHookProfile } = await import("@cleocode/caamp");
|
|
1769
|
+
return getProviderHookProfile(PROVIDER_ID3) ?? null;
|
|
1770
|
+
} catch {
|
|
1771
|
+
return null;
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
/**
|
|
1775
|
+
* Translate a CAAMP canonical event to its OpenCode native name via CAAMP.
|
|
1776
|
+
*
|
|
1777
|
+
* Calls `toNative(canonical, 'opencode')` from the CAAMP normalizer.
|
|
1778
|
+
* Returns null for unsupported events or when CAAMP is unavailable.
|
|
1779
|
+
*
|
|
1780
|
+
* @param canonical - CAAMP canonical event name (e.g. "PreToolUse")
|
|
1781
|
+
* @returns OpenCode native event name or null
|
|
1782
|
+
* @task T164
|
|
1783
|
+
*/
|
|
1784
|
+
async toNativeEvent(canonical) {
|
|
1785
|
+
try {
|
|
1786
|
+
const { toNative } = await import("@cleocode/caamp");
|
|
1787
|
+
return toNative(canonical, PROVIDER_ID3);
|
|
1788
|
+
} catch {
|
|
1789
|
+
const entry = Object.entries(OPENCODE_EVENT_MAP).find(([, v]) => v === canonical);
|
|
1790
|
+
return entry?.[0] ?? null;
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1510
1793
|
};
|
|
1511
1794
|
}
|
|
1512
1795
|
});
|
|
1513
1796
|
|
|
1514
|
-
// packages/adapters/src/providers/opencode/install.
|
|
1515
|
-
import { existsSync as existsSync13,
|
|
1516
|
-
import { join as
|
|
1517
|
-
var INSTRUCTION_REFERENCES6,
|
|
1797
|
+
// packages/adapters/src/providers/opencode/install.ts
|
|
1798
|
+
import { existsSync as existsSync13, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "node:fs";
|
|
1799
|
+
import { join as join19 } from "node:path";
|
|
1800
|
+
var INSTRUCTION_REFERENCES6, OpenCodeInstallProvider;
|
|
1518
1801
|
var init_install3 = __esm({
|
|
1519
|
-
"packages/adapters/src/providers/opencode/install.
|
|
1802
|
+
"packages/adapters/src/providers/opencode/install.ts"() {
|
|
1520
1803
|
"use strict";
|
|
1521
1804
|
INSTRUCTION_REFERENCES6 = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
|
|
1522
|
-
MCP_SERVER_KEY6 = "cleo";
|
|
1523
1805
|
OpenCodeInstallProvider = class {
|
|
1524
|
-
installedProjectDir = null;
|
|
1525
1806
|
/**
|
|
1526
1807
|
* Install CLEO into an OpenCode project.
|
|
1527
1808
|
*
|
|
1528
|
-
* @param options - Installation options including project directory
|
|
1809
|
+
* @param options - Installation options including project directory
|
|
1529
1810
|
* @returns Result describing what was installed
|
|
1530
1811
|
*/
|
|
1531
1812
|
async install(options) {
|
|
1532
|
-
const { projectDir
|
|
1813
|
+
const { projectDir } = options;
|
|
1533
1814
|
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1534
1815
|
let instructionFileUpdated = false;
|
|
1535
|
-
let mcpRegistered = false;
|
|
1536
1816
|
const details = {};
|
|
1537
|
-
if (mcpServerPath) {
|
|
1538
|
-
mcpRegistered = this.registerMcpServer(projectDir, mcpServerPath);
|
|
1539
|
-
if (mcpRegistered) {
|
|
1540
|
-
details.mcpConfigPath = join18(projectDir, ".opencode", "config.json");
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
1817
|
instructionFileUpdated = this.updateInstructionFile(projectDir);
|
|
1544
1818
|
if (instructionFileUpdated) {
|
|
1545
|
-
details.instructionFile =
|
|
1819
|
+
details.instructionFile = join19(projectDir, "AGENTS.md");
|
|
1546
1820
|
}
|
|
1547
|
-
this.installedProjectDir = projectDir;
|
|
1548
1821
|
return {
|
|
1549
1822
|
success: true,
|
|
1550
1823
|
installedAt,
|
|
1551
1824
|
instructionFileUpdated,
|
|
1552
|
-
mcpRegistered,
|
|
1825
|
+
mcpRegistered: false,
|
|
1553
1826
|
details
|
|
1554
1827
|
};
|
|
1555
1828
|
}
|
|
1556
1829
|
/**
|
|
1557
1830
|
* Uninstall CLEO from the current OpenCode project.
|
|
1558
1831
|
*
|
|
1559
|
-
* Removes the MCP server registration from .opencode/config.json.
|
|
1560
1832
|
* Does not remove AGENTS.md references (they are harmless if CLEO is not present).
|
|
1561
1833
|
*/
|
|
1562
1834
|
async uninstall() {
|
|
1563
|
-
if (!this.installedProjectDir)
|
|
1564
|
-
return;
|
|
1565
|
-
const configPath = join18(this.installedProjectDir, ".opencode", "config.json");
|
|
1566
|
-
if (existsSync13(configPath)) {
|
|
1567
|
-
try {
|
|
1568
|
-
const raw = readFileSync8(configPath, "utf-8");
|
|
1569
|
-
const config = JSON.parse(raw);
|
|
1570
|
-
const mcpServers = config.mcpServers;
|
|
1571
|
-
if (mcpServers && MCP_SERVER_KEY6 in mcpServers) {
|
|
1572
|
-
delete mcpServers[MCP_SERVER_KEY6];
|
|
1573
|
-
writeFileSync7(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
1574
|
-
}
|
|
1575
|
-
} catch {
|
|
1576
|
-
}
|
|
1577
|
-
}
|
|
1578
|
-
this.installedProjectDir = null;
|
|
1579
1835
|
}
|
|
1580
1836
|
/**
|
|
1581
1837
|
* Check whether CLEO is installed in the current environment.
|
|
1582
1838
|
*
|
|
1583
|
-
* Checks for
|
|
1584
|
-
* Returns true if the CLEO MCP server entry is found.
|
|
1839
|
+
* Checks for CLEO references in AGENTS.md.
|
|
1585
1840
|
*/
|
|
1586
1841
|
async isInstalled() {
|
|
1587
|
-
const
|
|
1588
|
-
if (existsSync13(
|
|
1842
|
+
const agentsMdPath = join19(process.cwd(), "AGENTS.md");
|
|
1843
|
+
if (existsSync13(agentsMdPath)) {
|
|
1589
1844
|
try {
|
|
1590
|
-
const
|
|
1591
|
-
|
|
1592
|
-
if (mcpServers && MCP_SERVER_KEY6 in mcpServers) {
|
|
1845
|
+
const content = readFileSync8(agentsMdPath, "utf-8");
|
|
1846
|
+
if (INSTRUCTION_REFERENCES6.some((ref) => content.includes(ref))) {
|
|
1593
1847
|
return true;
|
|
1594
1848
|
}
|
|
1595
1849
|
} catch {
|
|
@@ -1607,43 +1861,13 @@ var init_install3 = __esm({
|
|
|
1607
1861
|
async ensureInstructionReferences(projectDir) {
|
|
1608
1862
|
this.updateInstructionFile(projectDir);
|
|
1609
1863
|
}
|
|
1610
|
-
/**
|
|
1611
|
-
* Register the CLEO MCP server in .opencode/config.json.
|
|
1612
|
-
*
|
|
1613
|
-
* OpenCode stores its MCP server configuration in .opencode/config.json
|
|
1614
|
-
* under the mcpServers key.
|
|
1615
|
-
*
|
|
1616
|
-
* @returns true if registration was performed or updated
|
|
1617
|
-
*/
|
|
1618
|
-
registerMcpServer(projectDir, mcpServerPath) {
|
|
1619
|
-
const openCodeDir = join18(projectDir, ".opencode");
|
|
1620
|
-
const configPath = join18(openCodeDir, "config.json");
|
|
1621
|
-
let config = {};
|
|
1622
|
-
mkdirSync6(openCodeDir, { recursive: true });
|
|
1623
|
-
if (existsSync13(configPath)) {
|
|
1624
|
-
try {
|
|
1625
|
-
config = JSON.parse(readFileSync8(configPath, "utf-8"));
|
|
1626
|
-
} catch {
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
1630
|
-
config.mcpServers = {};
|
|
1631
|
-
}
|
|
1632
|
-
const mcpServers = config.mcpServers;
|
|
1633
|
-
mcpServers[MCP_SERVER_KEY6] = {
|
|
1634
|
-
command: "node",
|
|
1635
|
-
args: [mcpServerPath]
|
|
1636
|
-
};
|
|
1637
|
-
writeFileSync7(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
1638
|
-
return true;
|
|
1639
|
-
}
|
|
1640
1864
|
/**
|
|
1641
1865
|
* Update AGENTS.md with CLEO @-references.
|
|
1642
1866
|
*
|
|
1643
1867
|
* @returns true if the file was created or modified
|
|
1644
1868
|
*/
|
|
1645
1869
|
updateInstructionFile(projectDir) {
|
|
1646
|
-
const agentsMdPath =
|
|
1870
|
+
const agentsMdPath = join19(projectDir, "AGENTS.md");
|
|
1647
1871
|
let content = "";
|
|
1648
1872
|
let existed = false;
|
|
1649
1873
|
if (existsSync13(agentsMdPath)) {
|
|
@@ -1668,10 +1892,10 @@ var init_install3 = __esm({
|
|
|
1668
1892
|
}
|
|
1669
1893
|
});
|
|
1670
1894
|
|
|
1671
|
-
// packages/adapters/src/providers/opencode/spawn.
|
|
1895
|
+
// packages/adapters/src/providers/opencode/spawn.ts
|
|
1672
1896
|
import { exec as exec6, spawn as nodeSpawn2 } from "node:child_process";
|
|
1673
|
-
import { mkdir as mkdir2, readFile as
|
|
1674
|
-
import { join as
|
|
1897
|
+
import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
|
|
1898
|
+
import { join as join20 } from "node:path";
|
|
1675
1899
|
import { promisify as promisify6 } from "node:util";
|
|
1676
1900
|
function buildOpenCodeAgentMarkdown(description, instructions) {
|
|
1677
1901
|
const normalizedDesc = description.replace(/\s+/g, " ").trim();
|
|
@@ -1687,8 +1911,8 @@ function buildOpenCodeAgentMarkdown(description, instructions) {
|
|
|
1687
1911
|
].join("\n");
|
|
1688
1912
|
}
|
|
1689
1913
|
async function ensureSubagentDefinition(workingDirectory) {
|
|
1690
|
-
const agentDir =
|
|
1691
|
-
const agentPath =
|
|
1914
|
+
const agentDir = join20(workingDirectory, ".opencode", "agent");
|
|
1915
|
+
const agentPath = join20(agentDir, `${OPENCODE_SUBAGENT_NAME}.md`);
|
|
1692
1916
|
const description = "CLEO task executor with protocol compliance.";
|
|
1693
1917
|
const instructions = [
|
|
1694
1918
|
"# CLEO Subagent",
|
|
@@ -1702,7 +1926,7 @@ async function ensureSubagentDefinition(workingDirectory) {
|
|
|
1702
1926
|
await mkdir2(agentDir, { recursive: true });
|
|
1703
1927
|
let existing = null;
|
|
1704
1928
|
try {
|
|
1705
|
-
existing = await
|
|
1929
|
+
existing = await readFile4(agentPath, "utf-8");
|
|
1706
1930
|
} catch {
|
|
1707
1931
|
existing = null;
|
|
1708
1932
|
}
|
|
@@ -1713,7 +1937,7 @@ async function ensureSubagentDefinition(workingDirectory) {
|
|
|
1713
1937
|
}
|
|
1714
1938
|
var execAsync6, OPENCODE_SUBAGENT_NAME, OPENCODE_FALLBACK_AGENT, OpenCodeSpawnProvider;
|
|
1715
1939
|
var init_spawn2 = __esm({
|
|
1716
|
-
"packages/adapters/src/providers/opencode/spawn.
|
|
1940
|
+
"packages/adapters/src/providers/opencode/spawn.ts"() {
|
|
1717
1941
|
"use strict";
|
|
1718
1942
|
execAsync6 = promisify6(exec6);
|
|
1719
1943
|
OPENCODE_SUBAGENT_NAME = "cleo-subagent";
|
|
@@ -1755,20 +1979,24 @@ var init_spawn2 = __esm({
|
|
|
1755
1979
|
} catch {
|
|
1756
1980
|
agentName = OPENCODE_FALLBACK_AGENT;
|
|
1757
1981
|
}
|
|
1758
|
-
const child = nodeSpawn2(
|
|
1759
|
-
"
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1982
|
+
const child = nodeSpawn2(
|
|
1983
|
+
"opencode",
|
|
1984
|
+
[
|
|
1985
|
+
"run",
|
|
1986
|
+
"--format",
|
|
1987
|
+
"json",
|
|
1988
|
+
"--agent",
|
|
1989
|
+
agentName,
|
|
1990
|
+
"--title",
|
|
1991
|
+
`CLEO ${context.taskId}`,
|
|
1992
|
+
context.prompt
|
|
1993
|
+
],
|
|
1994
|
+
{
|
|
1995
|
+
cwd: workingDirectory,
|
|
1996
|
+
detached: true,
|
|
1997
|
+
stdio: "ignore"
|
|
1998
|
+
}
|
|
1999
|
+
);
|
|
1772
2000
|
child.unref();
|
|
1773
2001
|
if (child.pid) {
|
|
1774
2002
|
this.processMap.set(instanceId, {
|
|
@@ -1834,8 +2062,7 @@ var init_spawn2 = __esm({
|
|
|
1834
2062
|
*/
|
|
1835
2063
|
async terminate(instanceId) {
|
|
1836
2064
|
const tracked = this.processMap.get(instanceId);
|
|
1837
|
-
if (!tracked)
|
|
1838
|
-
return;
|
|
2065
|
+
if (!tracked) return;
|
|
1839
2066
|
try {
|
|
1840
2067
|
process.kill(tracked.pid, "SIGTERM");
|
|
1841
2068
|
} catch {
|
|
@@ -1846,36 +2073,47 @@ var init_spawn2 = __esm({
|
|
|
1846
2073
|
}
|
|
1847
2074
|
});
|
|
1848
2075
|
|
|
1849
|
-
// packages/adapters/src/providers/opencode/adapter.
|
|
2076
|
+
// packages/adapters/src/providers/opencode/adapter.ts
|
|
1850
2077
|
import { exec as exec7 } from "node:child_process";
|
|
1851
2078
|
import { existsSync as existsSync14 } from "node:fs";
|
|
1852
|
-
import { join as
|
|
2079
|
+
import { join as join21 } from "node:path";
|
|
1853
2080
|
import { promisify as promisify7 } from "node:util";
|
|
1854
2081
|
var execAsync7, OpenCodeAdapter;
|
|
1855
2082
|
var init_adapter3 = __esm({
|
|
1856
|
-
"packages/adapters/src/providers/opencode/adapter.
|
|
2083
|
+
"packages/adapters/src/providers/opencode/adapter.ts"() {
|
|
1857
2084
|
"use strict";
|
|
1858
2085
|
init_hooks3();
|
|
1859
2086
|
init_install3();
|
|
1860
2087
|
init_spawn2();
|
|
1861
2088
|
execAsync7 = promisify7(exec7);
|
|
1862
2089
|
OpenCodeAdapter = class {
|
|
2090
|
+
/** Unique provider identifier. */
|
|
1863
2091
|
id = "opencode";
|
|
2092
|
+
/** Human-readable provider name. */
|
|
1864
2093
|
name = "OpenCode";
|
|
2094
|
+
/** Adapter version string. */
|
|
1865
2095
|
version = "1.0.0";
|
|
2096
|
+
/** Declared capabilities for this provider. */
|
|
1866
2097
|
capabilities = {
|
|
1867
2098
|
supportsHooks: true,
|
|
2099
|
+
// 10/16 canonical events — derived from getProviderHookProfile('opencode') in CAAMP 1.9.1.
|
|
2100
|
+
// PostToolUseFailure, SubagentStart, SubagentStop, Notification, ConfigChange are
|
|
2101
|
+
// not supported by OpenCode's plugin system.
|
|
1868
2102
|
supportedHookEvents: [
|
|
1869
|
-
"
|
|
1870
|
-
"
|
|
1871
|
-
"
|
|
1872
|
-
"
|
|
1873
|
-
"
|
|
1874
|
-
"
|
|
2103
|
+
"SessionStart",
|
|
2104
|
+
"SessionEnd",
|
|
2105
|
+
"PromptSubmit",
|
|
2106
|
+
"ResponseComplete",
|
|
2107
|
+
"PreToolUse",
|
|
2108
|
+
"PostToolUse",
|
|
2109
|
+
"PermissionRequest",
|
|
2110
|
+
"PreModel",
|
|
2111
|
+
"PreCompact",
|
|
2112
|
+
"PostCompact"
|
|
1875
2113
|
],
|
|
1876
2114
|
supportsSpawn: true,
|
|
1877
2115
|
supportsInstall: true,
|
|
1878
|
-
supportsMcp:
|
|
2116
|
+
supportsMcp: false,
|
|
1879
2117
|
supportsInstructionFiles: true,
|
|
1880
2118
|
instructionFilePattern: "AGENTS.md",
|
|
1881
2119
|
supportsContextMonitor: false,
|
|
@@ -1884,10 +2122,15 @@ var init_adapter3 = __esm({
|
|
|
1884
2122
|
supportsTransport: false,
|
|
1885
2123
|
supportsTaskSync: false
|
|
1886
2124
|
};
|
|
2125
|
+
/** Hook provider for CAAMP event mapping via OpenCode's plugin system. */
|
|
1887
2126
|
hooks;
|
|
2127
|
+
/** Spawn provider for launching subagent processes via `opencode run`. */
|
|
1888
2128
|
spawn;
|
|
2129
|
+
/** Install provider for managing AGENTS.md instruction files. */
|
|
1889
2130
|
install;
|
|
2131
|
+
/** Project directory this adapter was initialized with, or null. */
|
|
1890
2132
|
projectDir = null;
|
|
2133
|
+
/** Whether {@link initialize} has been called. */
|
|
1891
2134
|
initialized = false;
|
|
1892
2135
|
constructor() {
|
|
1893
2136
|
this.hooks = new OpenCodeHookProvider();
|
|
@@ -1946,7 +2189,7 @@ var init_adapter3 = __esm({
|
|
|
1946
2189
|
details.cliAvailable = false;
|
|
1947
2190
|
}
|
|
1948
2191
|
if (this.projectDir) {
|
|
1949
|
-
const openCodeConfigDir =
|
|
2192
|
+
const openCodeConfigDir = join21(this.projectDir, ".opencode");
|
|
1950
2193
|
const configExists = existsSync14(openCodeConfigDir);
|
|
1951
2194
|
details.configDirExists = configExists;
|
|
1952
2195
|
}
|
|
@@ -1976,7 +2219,7 @@ var init_adapter3 = __esm({
|
|
|
1976
2219
|
}
|
|
1977
2220
|
});
|
|
1978
2221
|
|
|
1979
|
-
// packages/adapters/src/providers/opencode/index.
|
|
2222
|
+
// packages/adapters/src/providers/opencode/index.ts
|
|
1980
2223
|
var opencode_exports = {};
|
|
1981
2224
|
__export(opencode_exports, {
|
|
1982
2225
|
OpenCodeAdapter: () => OpenCodeAdapter,
|
|
@@ -1991,7 +2234,7 @@ function createAdapter6() {
|
|
|
1991
2234
|
}
|
|
1992
2235
|
var opencode_default;
|
|
1993
2236
|
var init_opencode = __esm({
|
|
1994
|
-
"packages/adapters/src/providers/opencode/index.
|
|
2237
|
+
"packages/adapters/src/providers/opencode/index.ts"() {
|
|
1995
2238
|
"use strict";
|
|
1996
2239
|
init_adapter3();
|
|
1997
2240
|
init_adapter3();
|
|
@@ -2008,17 +2251,17 @@ init_claude_code();
|
|
|
2008
2251
|
// packages/adapters/src/providers/codex/adapter.ts
|
|
2009
2252
|
import { exec as exec3 } from "node:child_process";
|
|
2010
2253
|
import { existsSync as existsSync6 } from "node:fs";
|
|
2011
|
-
import { homedir as
|
|
2012
|
-
import { join as
|
|
2254
|
+
import { homedir as homedir7 } from "node:os";
|
|
2255
|
+
import { join as join11 } from "node:path";
|
|
2013
2256
|
import { promisify as promisify3 } from "node:util";
|
|
2014
2257
|
|
|
2015
2258
|
// packages/adapters/src/providers/codex/hooks.ts
|
|
2016
2259
|
import { homedir as homedir6 } from "node:os";
|
|
2017
|
-
import { join as
|
|
2260
|
+
import { join as join9 } from "node:path";
|
|
2018
2261
|
|
|
2019
2262
|
// packages/adapters/src/providers/shared/transcript-reader.ts
|
|
2020
|
-
import { readdir, readFile as
|
|
2021
|
-
import { join as
|
|
2263
|
+
import { readdir as readdir2, readFile as readFile3 } from "node:fs/promises";
|
|
2264
|
+
import { join as join8 } from "node:path";
|
|
2022
2265
|
function parseTranscriptLines(raw) {
|
|
2023
2266
|
const turns = [];
|
|
2024
2267
|
const lines = raw.split("\n").filter((l) => l.trim());
|
|
@@ -2038,12 +2281,12 @@ function parseTranscriptLines(raw) {
|
|
|
2038
2281
|
async function readLatestTranscript(providerDir) {
|
|
2039
2282
|
let allFiles = [];
|
|
2040
2283
|
try {
|
|
2041
|
-
const entries = await
|
|
2284
|
+
const entries = await readdir2(providerDir, { withFileTypes: true });
|
|
2042
2285
|
for (const entry of entries) {
|
|
2043
2286
|
if (!entry.isFile()) continue;
|
|
2044
2287
|
const name = entry.name;
|
|
2045
2288
|
if (name.endsWith(".json") || name.endsWith(".jsonl")) {
|
|
2046
|
-
allFiles.push(
|
|
2289
|
+
allFiles.push(join8(providerDir, name));
|
|
2047
2290
|
}
|
|
2048
2291
|
}
|
|
2049
2292
|
} catch {
|
|
@@ -2054,7 +2297,7 @@ async function readLatestTranscript(providerDir) {
|
|
|
2054
2297
|
const mostRecent = allFiles[0];
|
|
2055
2298
|
if (!mostRecent) return null;
|
|
2056
2299
|
try {
|
|
2057
|
-
const raw = await
|
|
2300
|
+
const raw = await readFile3(mostRecent, "utf-8");
|
|
2058
2301
|
const turns = parseTranscriptLines(raw);
|
|
2059
2302
|
return turns.length > 0 ? turns.map((t) => `${t.role}: ${t.content}`).join("\n") : null;
|
|
2060
2303
|
} catch {
|
|
@@ -2069,6 +2312,7 @@ var CODEX_EVENT_MAP = {
|
|
|
2069
2312
|
ResponseComplete: "Stop"
|
|
2070
2313
|
};
|
|
2071
2314
|
var CodexHookProvider = class {
|
|
2315
|
+
/** Whether hooks have been registered for the current session. */
|
|
2072
2316
|
registered = false;
|
|
2073
2317
|
/**
|
|
2074
2318
|
* Map a Codex CLI native event name to a CAAMP hook event name.
|
|
@@ -2132,84 +2376,59 @@ var CodexHookProvider = class {
|
|
|
2132
2376
|
* @task T162 @epic T134
|
|
2133
2377
|
*/
|
|
2134
2378
|
async getTranscript(_sessionId, _projectDir) {
|
|
2135
|
-
return readLatestTranscript(
|
|
2379
|
+
return readLatestTranscript(join9(homedir6(), ".codex"));
|
|
2136
2380
|
}
|
|
2137
2381
|
};
|
|
2138
2382
|
|
|
2139
2383
|
// packages/adapters/src/providers/codex/install.ts
|
|
2140
|
-
import { existsSync as existsSync5,
|
|
2141
|
-
import {
|
|
2142
|
-
import { join as join9 } from "node:path";
|
|
2384
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
2385
|
+
import { join as join10 } from "node:path";
|
|
2143
2386
|
var INSTRUCTION_REFERENCES2 = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
|
|
2144
|
-
var MCP_SERVER_KEY2 = "cleo";
|
|
2145
2387
|
var CodexInstallProvider = class {
|
|
2146
2388
|
/**
|
|
2147
2389
|
* Install CLEO into a Codex CLI environment.
|
|
2148
2390
|
*
|
|
2149
|
-
* @param options - Installation options including project directory
|
|
2391
|
+
* @param options - Installation options including project directory
|
|
2150
2392
|
* @returns Result describing what was installed
|
|
2151
2393
|
* @task T162
|
|
2152
2394
|
*/
|
|
2153
2395
|
async install(options) {
|
|
2154
|
-
const { projectDir
|
|
2396
|
+
const { projectDir } = options;
|
|
2155
2397
|
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2156
2398
|
let instructionFileUpdated = false;
|
|
2157
|
-
let mcpRegistered = false;
|
|
2158
2399
|
const details = {};
|
|
2159
|
-
if (mcpServerPath) {
|
|
2160
|
-
mcpRegistered = this.registerMcpServer(mcpServerPath);
|
|
2161
|
-
if (mcpRegistered) {
|
|
2162
|
-
details.mcpConfigPath = join9(homedir7(), ".codex", "config.json");
|
|
2163
|
-
}
|
|
2164
|
-
}
|
|
2165
2400
|
instructionFileUpdated = this.updateInstructionFile(projectDir);
|
|
2166
2401
|
if (instructionFileUpdated) {
|
|
2167
|
-
details.instructionFile =
|
|
2402
|
+
details.instructionFile = join10(projectDir, "AGENTS.md");
|
|
2168
2403
|
}
|
|
2169
2404
|
return {
|
|
2170
2405
|
success: true,
|
|
2171
2406
|
installedAt,
|
|
2172
2407
|
instructionFileUpdated,
|
|
2173
|
-
mcpRegistered,
|
|
2408
|
+
mcpRegistered: false,
|
|
2174
2409
|
details
|
|
2175
2410
|
};
|
|
2176
2411
|
}
|
|
2177
2412
|
/**
|
|
2178
2413
|
* Uninstall CLEO from the Codex CLI environment.
|
|
2179
2414
|
*
|
|
2180
|
-
* Removes the MCP server registration from ~/.codex/config.json.
|
|
2181
2415
|
* Does not remove AGENTS.md references (they are harmless if CLEO is not present).
|
|
2182
2416
|
* @task T162
|
|
2183
2417
|
*/
|
|
2184
2418
|
async uninstall() {
|
|
2185
|
-
const configPath = join9(homedir7(), ".codex", "config.json");
|
|
2186
|
-
if (existsSync5(configPath)) {
|
|
2187
|
-
try {
|
|
2188
|
-
const raw = readFileSync4(configPath, "utf-8");
|
|
2189
|
-
const config = JSON.parse(raw);
|
|
2190
|
-
const mcpServers = config.mcpServers;
|
|
2191
|
-
if (mcpServers && MCP_SERVER_KEY2 in mcpServers) {
|
|
2192
|
-
delete mcpServers[MCP_SERVER_KEY2];
|
|
2193
|
-
writeFileSync3(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
2194
|
-
}
|
|
2195
|
-
} catch {
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2198
2419
|
}
|
|
2199
2420
|
/**
|
|
2200
2421
|
* Check whether CLEO is installed in the Codex CLI environment.
|
|
2201
2422
|
*
|
|
2202
|
-
* Checks for
|
|
2203
|
-
* Returns true if the CLEO MCP server entry is found.
|
|
2423
|
+
* Checks for CLEO references in AGENTS.md.
|
|
2204
2424
|
* @task T162
|
|
2205
2425
|
*/
|
|
2206
2426
|
async isInstalled() {
|
|
2207
|
-
const
|
|
2208
|
-
if (existsSync5(
|
|
2427
|
+
const agentsMdPath = join10(process.cwd(), "AGENTS.md");
|
|
2428
|
+
if (existsSync5(agentsMdPath)) {
|
|
2209
2429
|
try {
|
|
2210
|
-
const
|
|
2211
|
-
|
|
2212
|
-
if (mcpServers && MCP_SERVER_KEY2 in mcpServers) {
|
|
2430
|
+
const content = readFileSync4(agentsMdPath, "utf-8");
|
|
2431
|
+
if (INSTRUCTION_REFERENCES2.some((ref) => content.includes(ref))) {
|
|
2213
2432
|
return true;
|
|
2214
2433
|
}
|
|
2215
2434
|
} catch {
|
|
@@ -2228,37 +2447,6 @@ var CodexInstallProvider = class {
|
|
|
2228
2447
|
async ensureInstructionReferences(projectDir) {
|
|
2229
2448
|
this.updateInstructionFile(projectDir);
|
|
2230
2449
|
}
|
|
2231
|
-
/**
|
|
2232
|
-
* Register the CLEO MCP server in ~/.codex/config.json.
|
|
2233
|
-
*
|
|
2234
|
-
* Codex CLI stores its MCP server configuration in ~/.codex/config.json
|
|
2235
|
-
* under the mcpServers key.
|
|
2236
|
-
*
|
|
2237
|
-
* @param mcpServerPath - Absolute path to the MCP server entry point
|
|
2238
|
-
* @returns true if registration was performed or updated
|
|
2239
|
-
*/
|
|
2240
|
-
registerMcpServer(mcpServerPath) {
|
|
2241
|
-
const codexDir = join9(homedir7(), ".codex");
|
|
2242
|
-
const configPath = join9(codexDir, "config.json");
|
|
2243
|
-
let config = {};
|
|
2244
|
-
mkdirSync2(codexDir, { recursive: true });
|
|
2245
|
-
if (existsSync5(configPath)) {
|
|
2246
|
-
try {
|
|
2247
|
-
config = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
2248
|
-
} catch {
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
2252
|
-
config.mcpServers = {};
|
|
2253
|
-
}
|
|
2254
|
-
const mcpServers = config.mcpServers;
|
|
2255
|
-
mcpServers[MCP_SERVER_KEY2] = {
|
|
2256
|
-
command: "node",
|
|
2257
|
-
args: [mcpServerPath]
|
|
2258
|
-
};
|
|
2259
|
-
writeFileSync3(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
2260
|
-
return true;
|
|
2261
|
-
}
|
|
2262
2450
|
/**
|
|
2263
2451
|
* Update AGENTS.md with CLEO @-references.
|
|
2264
2452
|
*
|
|
@@ -2266,7 +2454,7 @@ var CodexInstallProvider = class {
|
|
|
2266
2454
|
* @returns true if the file was created or modified
|
|
2267
2455
|
*/
|
|
2268
2456
|
updateInstructionFile(projectDir) {
|
|
2269
|
-
const agentsMdPath =
|
|
2457
|
+
const agentsMdPath = join10(projectDir, "AGENTS.md");
|
|
2270
2458
|
let content = "";
|
|
2271
2459
|
let existed = false;
|
|
2272
2460
|
if (existsSync5(agentsMdPath)) {
|
|
@@ -2292,15 +2480,19 @@ var CodexInstallProvider = class {
|
|
|
2292
2480
|
// packages/adapters/src/providers/codex/adapter.ts
|
|
2293
2481
|
var execAsync3 = promisify3(exec3);
|
|
2294
2482
|
var CodexAdapter = class {
|
|
2483
|
+
/** Unique provider identifier. */
|
|
2295
2484
|
id = "codex";
|
|
2485
|
+
/** Human-readable provider name. */
|
|
2296
2486
|
name = "Codex";
|
|
2487
|
+
/** Adapter version string. */
|
|
2297
2488
|
version = "1.0.0";
|
|
2489
|
+
/** Declared capabilities for this provider. */
|
|
2298
2490
|
capabilities = {
|
|
2299
2491
|
supportsHooks: true,
|
|
2300
2492
|
supportedHookEvents: ["SessionStart", "UserPromptSubmit", "Stop"],
|
|
2301
2493
|
supportsSpawn: false,
|
|
2302
2494
|
supportsInstall: true,
|
|
2303
|
-
supportsMcp:
|
|
2495
|
+
supportsMcp: false,
|
|
2304
2496
|
supportsInstructionFiles: false,
|
|
2305
2497
|
supportsContextMonitor: false,
|
|
2306
2498
|
supportsStatusline: false,
|
|
@@ -2308,9 +2500,13 @@ var CodexAdapter = class {
|
|
|
2308
2500
|
supportsTransport: false,
|
|
2309
2501
|
supportsTaskSync: false
|
|
2310
2502
|
};
|
|
2503
|
+
/** Hook provider for CAAMP event mapping. */
|
|
2311
2504
|
hooks;
|
|
2505
|
+
/** Install provider for managing instruction files. */
|
|
2312
2506
|
install;
|
|
2507
|
+
/** Project directory this adapter was initialized with, or null. */
|
|
2313
2508
|
projectDir = null;
|
|
2509
|
+
/** Whether {@link initialize} has been called. */
|
|
2314
2510
|
initialized = false;
|
|
2315
2511
|
constructor() {
|
|
2316
2512
|
this.hooks = new CodexHookProvider();
|
|
@@ -2367,7 +2563,7 @@ var CodexAdapter = class {
|
|
|
2367
2563
|
} catch {
|
|
2368
2564
|
details.cliAvailable = false;
|
|
2369
2565
|
}
|
|
2370
|
-
const codexConfigDir =
|
|
2566
|
+
const codexConfigDir = join11(homedir7(), ".codex");
|
|
2371
2567
|
const configExists = existsSync6(codexConfigDir);
|
|
2372
2568
|
details.configDirExists = configExists;
|
|
2373
2569
|
const healthy = cliAvailable;
|
|
@@ -2405,13 +2601,13 @@ init_cursor();
|
|
|
2405
2601
|
// packages/adapters/src/providers/gemini-cli/adapter.ts
|
|
2406
2602
|
import { exec as exec4 } from "node:child_process";
|
|
2407
2603
|
import { existsSync as existsSync10 } from "node:fs";
|
|
2408
|
-
import { homedir as
|
|
2409
|
-
import { join as
|
|
2604
|
+
import { homedir as homedir9 } from "node:os";
|
|
2605
|
+
import { join as join16 } from "node:path";
|
|
2410
2606
|
import { promisify as promisify4 } from "node:util";
|
|
2411
2607
|
|
|
2412
2608
|
// packages/adapters/src/providers/gemini-cli/hooks.ts
|
|
2413
|
-
import { homedir as
|
|
2414
|
-
import { join as
|
|
2609
|
+
import { homedir as homedir8 } from "node:os";
|
|
2610
|
+
import { join as join14 } from "node:path";
|
|
2415
2611
|
var GEMINI_CLI_EVENT_MAP = {
|
|
2416
2612
|
SessionStart: "SessionStart",
|
|
2417
2613
|
SessionEnd: "SessionEnd",
|
|
@@ -2425,6 +2621,7 @@ var GEMINI_CLI_EVENT_MAP = {
|
|
|
2425
2621
|
Notification: "Notification"
|
|
2426
2622
|
};
|
|
2427
2623
|
var GeminiCliHookProvider = class {
|
|
2624
|
+
/** Whether hooks have been registered for the current session. */
|
|
2428
2625
|
registered = false;
|
|
2429
2626
|
/**
|
|
2430
2627
|
* Map a Gemini CLI native event name to a CAAMP hook event name.
|
|
@@ -2488,84 +2685,59 @@ var GeminiCliHookProvider = class {
|
|
|
2488
2685
|
* @task T161 @epic T134
|
|
2489
2686
|
*/
|
|
2490
2687
|
async getTranscript(_sessionId, _projectDir) {
|
|
2491
|
-
return readLatestTranscript(
|
|
2688
|
+
return readLatestTranscript(join14(homedir8(), ".gemini"));
|
|
2492
2689
|
}
|
|
2493
2690
|
};
|
|
2494
2691
|
|
|
2495
2692
|
// packages/adapters/src/providers/gemini-cli/install.ts
|
|
2496
|
-
import { existsSync as existsSync9,
|
|
2497
|
-
import {
|
|
2498
|
-
import { join as join14 } from "node:path";
|
|
2693
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
|
|
2694
|
+
import { join as join15 } from "node:path";
|
|
2499
2695
|
var INSTRUCTION_REFERENCES4 = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
|
|
2500
|
-
var MCP_SERVER_KEY4 = "cleo";
|
|
2501
2696
|
var GeminiCliInstallProvider = class {
|
|
2502
2697
|
/**
|
|
2503
2698
|
* Install CLEO into a Gemini CLI environment.
|
|
2504
2699
|
*
|
|
2505
|
-
* @param options - Installation options including project directory
|
|
2700
|
+
* @param options - Installation options including project directory
|
|
2506
2701
|
* @returns Result describing what was installed
|
|
2507
2702
|
* @task T161
|
|
2508
2703
|
*/
|
|
2509
2704
|
async install(options) {
|
|
2510
|
-
const { projectDir
|
|
2705
|
+
const { projectDir } = options;
|
|
2511
2706
|
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2512
2707
|
let instructionFileUpdated = false;
|
|
2513
|
-
let mcpRegistered = false;
|
|
2514
2708
|
const details = {};
|
|
2515
|
-
if (mcpServerPath) {
|
|
2516
|
-
mcpRegistered = this.registerMcpServer(mcpServerPath);
|
|
2517
|
-
if (mcpRegistered) {
|
|
2518
|
-
details.mcpConfigPath = join14(homedir10(), ".gemini", "settings.json");
|
|
2519
|
-
}
|
|
2520
|
-
}
|
|
2521
2709
|
instructionFileUpdated = this.updateInstructionFile(projectDir);
|
|
2522
2710
|
if (instructionFileUpdated) {
|
|
2523
|
-
details.instructionFile =
|
|
2711
|
+
details.instructionFile = join15(projectDir, "AGENTS.md");
|
|
2524
2712
|
}
|
|
2525
2713
|
return {
|
|
2526
2714
|
success: true,
|
|
2527
2715
|
installedAt,
|
|
2528
2716
|
instructionFileUpdated,
|
|
2529
|
-
mcpRegistered,
|
|
2717
|
+
mcpRegistered: false,
|
|
2530
2718
|
details
|
|
2531
2719
|
};
|
|
2532
2720
|
}
|
|
2533
2721
|
/**
|
|
2534
2722
|
* Uninstall CLEO from the Gemini CLI environment.
|
|
2535
2723
|
*
|
|
2536
|
-
* Removes the MCP server registration from ~/.gemini/settings.json.
|
|
2537
2724
|
* Does not remove AGENTS.md references (they are harmless if CLEO is not present).
|
|
2538
2725
|
* @task T161
|
|
2539
2726
|
*/
|
|
2540
2727
|
async uninstall() {
|
|
2541
|
-
const settingsPath = join14(homedir10(), ".gemini", "settings.json");
|
|
2542
|
-
if (existsSync9(settingsPath)) {
|
|
2543
|
-
try {
|
|
2544
|
-
const raw = readFileSync6(settingsPath, "utf-8");
|
|
2545
|
-
const config = JSON.parse(raw);
|
|
2546
|
-
const mcpServers = config.mcpServers;
|
|
2547
|
-
if (mcpServers && MCP_SERVER_KEY4 in mcpServers) {
|
|
2548
|
-
delete mcpServers[MCP_SERVER_KEY4];
|
|
2549
|
-
writeFileSync5(settingsPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
2550
|
-
}
|
|
2551
|
-
} catch {
|
|
2552
|
-
}
|
|
2553
|
-
}
|
|
2554
2728
|
}
|
|
2555
2729
|
/**
|
|
2556
2730
|
* Check whether CLEO is installed in the Gemini CLI environment.
|
|
2557
2731
|
*
|
|
2558
|
-
* Checks for
|
|
2559
|
-
* Returns true if the CLEO MCP server entry is found.
|
|
2732
|
+
* Checks for CLEO references in AGENTS.md.
|
|
2560
2733
|
* @task T161
|
|
2561
2734
|
*/
|
|
2562
2735
|
async isInstalled() {
|
|
2563
|
-
const
|
|
2564
|
-
if (existsSync9(
|
|
2736
|
+
const agentsMdPath = join15(process.cwd(), "AGENTS.md");
|
|
2737
|
+
if (existsSync9(agentsMdPath)) {
|
|
2565
2738
|
try {
|
|
2566
|
-
const
|
|
2567
|
-
|
|
2568
|
-
if (mcpServers && MCP_SERVER_KEY4 in mcpServers) {
|
|
2739
|
+
const content = readFileSync6(agentsMdPath, "utf-8");
|
|
2740
|
+
if (INSTRUCTION_REFERENCES4.some((ref) => content.includes(ref))) {
|
|
2569
2741
|
return true;
|
|
2570
2742
|
}
|
|
2571
2743
|
} catch {
|
|
@@ -2584,37 +2756,6 @@ var GeminiCliInstallProvider = class {
|
|
|
2584
2756
|
async ensureInstructionReferences(projectDir) {
|
|
2585
2757
|
this.updateInstructionFile(projectDir);
|
|
2586
2758
|
}
|
|
2587
|
-
/**
|
|
2588
|
-
* Register the CLEO MCP server in ~/.gemini/settings.json.
|
|
2589
|
-
*
|
|
2590
|
-
* Gemini CLI stores its MCP server configuration in ~/.gemini/settings.json
|
|
2591
|
-
* under the mcpServers key.
|
|
2592
|
-
*
|
|
2593
|
-
* @param mcpServerPath - Absolute path to the MCP server entry point
|
|
2594
|
-
* @returns true if registration was performed or updated
|
|
2595
|
-
*/
|
|
2596
|
-
registerMcpServer(mcpServerPath) {
|
|
2597
|
-
const geminiDir = join14(homedir10(), ".gemini");
|
|
2598
|
-
const settingsPath = join14(geminiDir, "settings.json");
|
|
2599
|
-
let config = {};
|
|
2600
|
-
mkdirSync4(geminiDir, { recursive: true });
|
|
2601
|
-
if (existsSync9(settingsPath)) {
|
|
2602
|
-
try {
|
|
2603
|
-
config = JSON.parse(readFileSync6(settingsPath, "utf-8"));
|
|
2604
|
-
} catch {
|
|
2605
|
-
}
|
|
2606
|
-
}
|
|
2607
|
-
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
2608
|
-
config.mcpServers = {};
|
|
2609
|
-
}
|
|
2610
|
-
const mcpServers = config.mcpServers;
|
|
2611
|
-
mcpServers[MCP_SERVER_KEY4] = {
|
|
2612
|
-
command: "node",
|
|
2613
|
-
args: [mcpServerPath]
|
|
2614
|
-
};
|
|
2615
|
-
writeFileSync5(settingsPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
2616
|
-
return true;
|
|
2617
|
-
}
|
|
2618
2759
|
/**
|
|
2619
2760
|
* Update AGENTS.md with CLEO @-references.
|
|
2620
2761
|
*
|
|
@@ -2622,7 +2763,7 @@ var GeminiCliInstallProvider = class {
|
|
|
2622
2763
|
* @returns true if the file was created or modified
|
|
2623
2764
|
*/
|
|
2624
2765
|
updateInstructionFile(projectDir) {
|
|
2625
|
-
const agentsMdPath =
|
|
2766
|
+
const agentsMdPath = join15(projectDir, "AGENTS.md");
|
|
2626
2767
|
let content = "";
|
|
2627
2768
|
let existed = false;
|
|
2628
2769
|
if (existsSync9(agentsMdPath)) {
|
|
@@ -2648,9 +2789,13 @@ var GeminiCliInstallProvider = class {
|
|
|
2648
2789
|
// packages/adapters/src/providers/gemini-cli/adapter.ts
|
|
2649
2790
|
var execAsync4 = promisify4(exec4);
|
|
2650
2791
|
var GeminiCliAdapter = class {
|
|
2792
|
+
/** Unique provider identifier. */
|
|
2651
2793
|
id = "gemini-cli";
|
|
2794
|
+
/** Human-readable provider name. */
|
|
2652
2795
|
name = "Gemini CLI";
|
|
2796
|
+
/** Adapter version string. */
|
|
2653
2797
|
version = "1.0.0";
|
|
2798
|
+
/** Declared capabilities for this provider. */
|
|
2654
2799
|
capabilities = {
|
|
2655
2800
|
supportsHooks: true,
|
|
2656
2801
|
supportedHookEvents: [
|
|
@@ -2667,7 +2812,7 @@ var GeminiCliAdapter = class {
|
|
|
2667
2812
|
],
|
|
2668
2813
|
supportsSpawn: false,
|
|
2669
2814
|
supportsInstall: true,
|
|
2670
|
-
supportsMcp:
|
|
2815
|
+
supportsMcp: false,
|
|
2671
2816
|
supportsInstructionFiles: false,
|
|
2672
2817
|
supportsContextMonitor: false,
|
|
2673
2818
|
supportsStatusline: false,
|
|
@@ -2675,9 +2820,13 @@ var GeminiCliAdapter = class {
|
|
|
2675
2820
|
supportsTransport: false,
|
|
2676
2821
|
supportsTaskSync: false
|
|
2677
2822
|
};
|
|
2823
|
+
/** Hook provider for CAAMP event mapping. */
|
|
2678
2824
|
hooks;
|
|
2825
|
+
/** Install provider for managing instruction files. */
|
|
2679
2826
|
install;
|
|
2827
|
+
/** Project directory this adapter was initialized with, or null. */
|
|
2680
2828
|
projectDir = null;
|
|
2829
|
+
/** Whether {@link initialize} has been called. */
|
|
2681
2830
|
initialized = false;
|
|
2682
2831
|
constructor() {
|
|
2683
2832
|
this.hooks = new GeminiCliHookProvider();
|
|
@@ -2734,7 +2883,7 @@ var GeminiCliAdapter = class {
|
|
|
2734
2883
|
} catch {
|
|
2735
2884
|
details.cliAvailable = false;
|
|
2736
2885
|
}
|
|
2737
|
-
const geminiConfigDir =
|
|
2886
|
+
const geminiConfigDir = join16(homedir9(), ".gemini");
|
|
2738
2887
|
const configExists = existsSync10(geminiConfigDir);
|
|
2739
2888
|
details.configDirExists = configExists;
|
|
2740
2889
|
const healthy = cliAvailable;
|
|
@@ -2769,12 +2918,13 @@ function createAdapter4() {
|
|
|
2769
2918
|
// packages/adapters/src/providers/kimi/adapter.ts
|
|
2770
2919
|
import { exec as exec5 } from "node:child_process";
|
|
2771
2920
|
import { existsSync as existsSync12 } from "node:fs";
|
|
2772
|
-
import { homedir as
|
|
2773
|
-
import { join as
|
|
2921
|
+
import { homedir as homedir10 } from "node:os";
|
|
2922
|
+
import { join as join18 } from "node:path";
|
|
2774
2923
|
import { promisify as promisify5 } from "node:util";
|
|
2775
2924
|
|
|
2776
2925
|
// packages/adapters/src/providers/kimi/hooks.ts
|
|
2777
2926
|
var KimiHookProvider = class {
|
|
2927
|
+
/** Whether hooks have been registered (always a no-op for Kimi). */
|
|
2778
2928
|
registered = false;
|
|
2779
2929
|
/**
|
|
2780
2930
|
* Map a Kimi native event name to a CAAMP hook event name.
|
|
@@ -2828,79 +2978,54 @@ var KimiHookProvider = class {
|
|
|
2828
2978
|
};
|
|
2829
2979
|
|
|
2830
2980
|
// packages/adapters/src/providers/kimi/install.ts
|
|
2831
|
-
import { existsSync as existsSync11,
|
|
2832
|
-
import {
|
|
2833
|
-
import { join as join16 } from "node:path";
|
|
2981
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "node:fs";
|
|
2982
|
+
import { join as join17 } from "node:path";
|
|
2834
2983
|
var INSTRUCTION_REFERENCES5 = ["@~/.cleo/templates/CLEO-INJECTION.md", "@.cleo/memory-bridge.md"];
|
|
2835
|
-
var MCP_SERVER_KEY5 = "cleo";
|
|
2836
2984
|
var KimiInstallProvider = class {
|
|
2837
2985
|
/**
|
|
2838
2986
|
* Install CLEO into a Kimi environment.
|
|
2839
2987
|
*
|
|
2840
|
-
* @param options - Installation options including project directory
|
|
2988
|
+
* @param options - Installation options including project directory
|
|
2841
2989
|
* @returns Result describing what was installed
|
|
2842
2990
|
* @task T163
|
|
2843
2991
|
*/
|
|
2844
2992
|
async install(options) {
|
|
2845
|
-
const { projectDir
|
|
2993
|
+
const { projectDir } = options;
|
|
2846
2994
|
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2847
2995
|
let instructionFileUpdated = false;
|
|
2848
|
-
let mcpRegistered = false;
|
|
2849
2996
|
const details = {};
|
|
2850
|
-
if (mcpServerPath) {
|
|
2851
|
-
mcpRegistered = this.registerMcpServer(mcpServerPath);
|
|
2852
|
-
if (mcpRegistered) {
|
|
2853
|
-
details.mcpConfigPath = join16(homedir12(), ".kimi", "mcp.json");
|
|
2854
|
-
}
|
|
2855
|
-
}
|
|
2856
2997
|
instructionFileUpdated = this.updateInstructionFile(projectDir);
|
|
2857
2998
|
if (instructionFileUpdated) {
|
|
2858
|
-
details.instructionFile =
|
|
2999
|
+
details.instructionFile = join17(projectDir, "AGENTS.md");
|
|
2859
3000
|
}
|
|
2860
3001
|
return {
|
|
2861
3002
|
success: true,
|
|
2862
3003
|
installedAt,
|
|
2863
3004
|
instructionFileUpdated,
|
|
2864
|
-
mcpRegistered,
|
|
3005
|
+
mcpRegistered: false,
|
|
2865
3006
|
details
|
|
2866
3007
|
};
|
|
2867
3008
|
}
|
|
2868
3009
|
/**
|
|
2869
3010
|
* Uninstall CLEO from the Kimi environment.
|
|
2870
3011
|
*
|
|
2871
|
-
* Removes the MCP server registration from ~/.kimi/mcp.json.
|
|
2872
3012
|
* Does not remove AGENTS.md references (they are harmless if CLEO is not present).
|
|
2873
3013
|
* @task T163
|
|
2874
3014
|
*/
|
|
2875
3015
|
async uninstall() {
|
|
2876
|
-
const mcpPath = join16(homedir12(), ".kimi", "mcp.json");
|
|
2877
|
-
if (existsSync11(mcpPath)) {
|
|
2878
|
-
try {
|
|
2879
|
-
const raw = readFileSync7(mcpPath, "utf-8");
|
|
2880
|
-
const config = JSON.parse(raw);
|
|
2881
|
-
const mcpServers = config.mcpServers;
|
|
2882
|
-
if (mcpServers && MCP_SERVER_KEY5 in mcpServers) {
|
|
2883
|
-
delete mcpServers[MCP_SERVER_KEY5];
|
|
2884
|
-
writeFileSync6(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
2885
|
-
}
|
|
2886
|
-
} catch {
|
|
2887
|
-
}
|
|
2888
|
-
}
|
|
2889
3016
|
}
|
|
2890
3017
|
/**
|
|
2891
3018
|
* Check whether CLEO is installed in the Kimi environment.
|
|
2892
3019
|
*
|
|
2893
|
-
* Checks for
|
|
2894
|
-
* Returns true if the CLEO MCP server entry is found.
|
|
3020
|
+
* Checks for CLEO references in AGENTS.md.
|
|
2895
3021
|
* @task T163
|
|
2896
3022
|
*/
|
|
2897
3023
|
async isInstalled() {
|
|
2898
|
-
const
|
|
2899
|
-
if (existsSync11(
|
|
3024
|
+
const agentsMdPath = join17(process.cwd(), "AGENTS.md");
|
|
3025
|
+
if (existsSync11(agentsMdPath)) {
|
|
2900
3026
|
try {
|
|
2901
|
-
const
|
|
2902
|
-
|
|
2903
|
-
if (mcpServers && MCP_SERVER_KEY5 in mcpServers) {
|
|
3027
|
+
const content = readFileSync7(agentsMdPath, "utf-8");
|
|
3028
|
+
if (INSTRUCTION_REFERENCES5.some((ref) => content.includes(ref))) {
|
|
2904
3029
|
return true;
|
|
2905
3030
|
}
|
|
2906
3031
|
} catch {
|
|
@@ -2919,37 +3044,6 @@ var KimiInstallProvider = class {
|
|
|
2919
3044
|
async ensureInstructionReferences(projectDir) {
|
|
2920
3045
|
this.updateInstructionFile(projectDir);
|
|
2921
3046
|
}
|
|
2922
|
-
/**
|
|
2923
|
-
* Register the CLEO MCP server in ~/.kimi/mcp.json.
|
|
2924
|
-
*
|
|
2925
|
-
* Kimi stores its MCP server configuration in ~/.kimi/mcp.json
|
|
2926
|
-
* under the mcpServers key.
|
|
2927
|
-
*
|
|
2928
|
-
* @param mcpServerPath - Absolute path to the MCP server entry point
|
|
2929
|
-
* @returns true if registration was performed or updated
|
|
2930
|
-
*/
|
|
2931
|
-
registerMcpServer(mcpServerPath) {
|
|
2932
|
-
const kimiDir = join16(homedir12(), ".kimi");
|
|
2933
|
-
const mcpPath = join16(kimiDir, "mcp.json");
|
|
2934
|
-
let config = {};
|
|
2935
|
-
mkdirSync5(kimiDir, { recursive: true });
|
|
2936
|
-
if (existsSync11(mcpPath)) {
|
|
2937
|
-
try {
|
|
2938
|
-
config = JSON.parse(readFileSync7(mcpPath, "utf-8"));
|
|
2939
|
-
} catch {
|
|
2940
|
-
}
|
|
2941
|
-
}
|
|
2942
|
-
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
2943
|
-
config.mcpServers = {};
|
|
2944
|
-
}
|
|
2945
|
-
const mcpServers = config.mcpServers;
|
|
2946
|
-
mcpServers[MCP_SERVER_KEY5] = {
|
|
2947
|
-
command: "node",
|
|
2948
|
-
args: [mcpServerPath]
|
|
2949
|
-
};
|
|
2950
|
-
writeFileSync6(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
2951
|
-
return true;
|
|
2952
|
-
}
|
|
2953
3047
|
/**
|
|
2954
3048
|
* Update AGENTS.md with CLEO @-references.
|
|
2955
3049
|
*
|
|
@@ -2957,7 +3051,7 @@ var KimiInstallProvider = class {
|
|
|
2957
3051
|
* @returns true if the file was created or modified
|
|
2958
3052
|
*/
|
|
2959
3053
|
updateInstructionFile(projectDir) {
|
|
2960
|
-
const agentsMdPath =
|
|
3054
|
+
const agentsMdPath = join17(projectDir, "AGENTS.md");
|
|
2961
3055
|
let content = "";
|
|
2962
3056
|
let existed = false;
|
|
2963
3057
|
if (existsSync11(agentsMdPath)) {
|
|
@@ -2983,15 +3077,19 @@ var KimiInstallProvider = class {
|
|
|
2983
3077
|
// packages/adapters/src/providers/kimi/adapter.ts
|
|
2984
3078
|
var execAsync5 = promisify5(exec5);
|
|
2985
3079
|
var KimiAdapter = class {
|
|
3080
|
+
/** Unique provider identifier. */
|
|
2986
3081
|
id = "kimi";
|
|
3082
|
+
/** Human-readable provider name. */
|
|
2987
3083
|
name = "Kimi";
|
|
3084
|
+
/** Adapter version string. */
|
|
2988
3085
|
version = "1.0.0";
|
|
3086
|
+
/** Declared capabilities for this provider. */
|
|
2989
3087
|
capabilities = {
|
|
2990
3088
|
supportsHooks: false,
|
|
2991
3089
|
supportedHookEvents: [],
|
|
2992
3090
|
supportsSpawn: false,
|
|
2993
3091
|
supportsInstall: true,
|
|
2994
|
-
supportsMcp:
|
|
3092
|
+
supportsMcp: false,
|
|
2995
3093
|
supportsInstructionFiles: false,
|
|
2996
3094
|
supportsContextMonitor: false,
|
|
2997
3095
|
supportsStatusline: false,
|
|
@@ -2999,9 +3097,13 @@ var KimiAdapter = class {
|
|
|
2999
3097
|
supportsTransport: false,
|
|
3000
3098
|
supportsTaskSync: false
|
|
3001
3099
|
};
|
|
3100
|
+
/** Hook provider (no-op since Kimi has no event system). */
|
|
3002
3101
|
hooks;
|
|
3102
|
+
/** Install provider for managing instruction files. */
|
|
3003
3103
|
install;
|
|
3104
|
+
/** Project directory this adapter was initialized with, or null. */
|
|
3004
3105
|
projectDir = null;
|
|
3106
|
+
/** Whether {@link initialize} has been called. */
|
|
3005
3107
|
initialized = false;
|
|
3006
3108
|
constructor() {
|
|
3007
3109
|
this.hooks = new KimiHookProvider();
|
|
@@ -3056,7 +3158,7 @@ var KimiAdapter = class {
|
|
|
3056
3158
|
} catch {
|
|
3057
3159
|
details.cliAvailable = false;
|
|
3058
3160
|
}
|
|
3059
|
-
const kimiConfigDir =
|
|
3161
|
+
const kimiConfigDir = join18(homedir10(), ".kimi");
|
|
3060
3162
|
const configExists = existsSync12(kimiConfigDir);
|
|
3061
3163
|
details.configDirExists = configExists;
|
|
3062
3164
|
const healthy = cliAvailable;
|
|
@@ -3091,9 +3193,9 @@ function createAdapter5() {
|
|
|
3091
3193
|
// packages/adapters/src/index.ts
|
|
3092
3194
|
init_opencode();
|
|
3093
3195
|
|
|
3094
|
-
// packages/adapters/src/registry.
|
|
3196
|
+
// packages/adapters/src/registry.ts
|
|
3095
3197
|
import { readFileSync as readFileSync9 } from "node:fs";
|
|
3096
|
-
import { dirname as dirname2, join as
|
|
3198
|
+
import { dirname as dirname2, join as join22, resolve } from "node:path";
|
|
3097
3199
|
import { fileURLToPath } from "node:url";
|
|
3098
3200
|
var PROVIDER_IDS = ["claude-code", "opencode", "cursor"];
|
|
3099
3201
|
function getProviderManifests() {
|
|
@@ -3101,7 +3203,7 @@ function getProviderManifests() {
|
|
|
3101
3203
|
const baseDir = resolve(dirname2(fileURLToPath(import.meta.url)), "providers");
|
|
3102
3204
|
for (const providerId of PROVIDER_IDS) {
|
|
3103
3205
|
try {
|
|
3104
|
-
const manifestPath =
|
|
3206
|
+
const manifestPath = join22(baseDir, providerId, "manifest.json");
|
|
3105
3207
|
const raw = readFileSync9(manifestPath, "utf-8");
|
|
3106
3208
|
manifests.push(JSON.parse(raw));
|
|
3107
3209
|
} catch {
|