context-mode 1.0.53 → 1.0.56
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/README.md +103 -32
- package/build/adapters/antigravity/index.d.ts +1 -3
- package/build/adapters/antigravity/index.js +0 -30
- package/build/adapters/claude-code/hooks.d.ts +18 -0
- package/build/adapters/claude-code/hooks.js +23 -0
- package/build/adapters/claude-code/index.d.ts +1 -3
- package/build/adapters/claude-code/index.js +48 -35
- package/build/adapters/client-map.js +1 -0
- package/build/adapters/codex/index.d.ts +1 -3
- package/build/adapters/codex/index.js +1 -31
- package/build/adapters/cursor/index.d.ts +1 -3
- package/build/adapters/cursor/index.js +0 -11
- package/build/adapters/detect.d.ts +1 -0
- package/build/adapters/detect.js +18 -2
- package/build/adapters/gemini-cli/index.d.ts +1 -3
- package/build/adapters/gemini-cli/index.js +0 -30
- package/build/adapters/kiro/index.d.ts +1 -3
- package/build/adapters/kiro/index.js +0 -30
- package/build/adapters/openclaw/index.d.ts +1 -3
- package/build/adapters/openclaw/index.js +0 -38
- package/build/adapters/opencode/index.d.ts +5 -4
- package/build/adapters/opencode/index.js +37 -41
- package/build/adapters/types.d.ts +1 -14
- package/build/adapters/vscode-copilot/index.d.ts +1 -3
- package/build/adapters/vscode-copilot/index.js +0 -32
- package/build/adapters/zed/index.d.ts +1 -3
- package/build/adapters/zed/index.js +0 -30
- package/build/cli.js +12 -28
- package/build/executor.d.ts +0 -1
- package/build/executor.js +28 -16
- package/build/openclaw-plugin.js +12 -34
- package/build/opencode-plugin.d.ts +1 -0
- package/build/opencode-plugin.js +5 -9
- package/build/runtime.js +29 -11
- package/build/server.d.ts +2 -0
- package/build/server.js +69 -61
- package/build/store.d.ts +4 -3
- package/build/store.js +101 -34
- package/build/truncate.d.ts +4 -17
- package/build/truncate.js +4 -52
- package/cli.bundle.mjs +184 -157
- package/configs/codex/AGENTS.md +19 -0
- package/configs/kilo/AGENTS.md +58 -0
- package/configs/kilo/kilo.json +10 -0
- package/hooks/core/tool-naming.mjs +1 -0
- package/hooks/ensure-deps.mjs +80 -2
- package/hooks/pretooluse.mjs +25 -20
- package/hooks/routing-block.mjs +10 -1
- package/hooks/session-snapshot.bundle.mjs +13 -13
- package/hooks/sessionstart.mjs +25 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +159 -129
- package/skills/context-mode-ops/SKILL.md +111 -0
- package/skills/context-mode-ops/agent-teams.md +198 -0
- package/skills/context-mode-ops/communication.md +224 -0
- package/skills/context-mode-ops/release.md +199 -0
- package/skills/context-mode-ops/review-pr.md +269 -0
- package/skills/context-mode-ops/tdd.md +329 -0
- package/skills/context-mode-ops/triage-issue.md +218 -0
- package/skills/context-mode-ops/validation.md +238 -0
- package/start.mjs +5 -52
package/build/adapters/detect.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* Verified env vars per platform (from source code audit):
|
|
10
10
|
* - Claude Code: CLAUDE_PROJECT_DIR, CLAUDE_SESSION_ID | ~/.claude/
|
|
11
11
|
* - Gemini CLI: GEMINI_PROJECT_DIR (hooks), GEMINI_CLI (MCP) | ~/.gemini/
|
|
12
|
+
* - KiloCode: KILO, KILO_PID | ~/.config/kilo/
|
|
12
13
|
* - OpenCode: OPENCODE, OPENCODE_PID | ~/.config/opencode/
|
|
13
14
|
* - OpenClaw: OPENCLAW_HOME, OPENCLAW_CLI | ~/.openclaw/
|
|
14
15
|
* - Codex CLI: CODEX_CI, CODEX_THREAD_ID | ~/.codex/
|
|
@@ -41,7 +42,7 @@ export function detectPlatform(clientInfo) {
|
|
|
41
42
|
const platformOverride = process.env.CONTEXT_MODE_PLATFORM;
|
|
42
43
|
if (platformOverride) {
|
|
43
44
|
const validPlatforms = [
|
|
44
|
-
"claude-code", "gemini-cli", "opencode", "codex",
|
|
45
|
+
"claude-code", "gemini-cli", "kilo", "opencode", "codex",
|
|
45
46
|
"vscode-copilot", "cursor", "antigravity", "kiro", "pi", "zed",
|
|
46
47
|
];
|
|
47
48
|
if (validPlatforms.includes(platformOverride)) {
|
|
@@ -74,6 +75,13 @@ export function detectPlatform(clientInfo) {
|
|
|
74
75
|
reason: "OPENCLAW_HOME or OPENCLAW_CLI env var set",
|
|
75
76
|
};
|
|
76
77
|
}
|
|
78
|
+
if (process.env.KILO || process.env.KILO_PID) {
|
|
79
|
+
return {
|
|
80
|
+
platform: "kilo",
|
|
81
|
+
confidence: "high",
|
|
82
|
+
reason: "KILO or KILO_PID env var set",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
77
85
|
if (process.env.OPENCODE || process.env.OPENCODE_PID) {
|
|
78
86
|
return {
|
|
79
87
|
platform: "opencode",
|
|
@@ -153,6 +161,13 @@ export function detectPlatform(clientInfo) {
|
|
|
153
161
|
reason: "~/.openclaw/ directory exists",
|
|
154
162
|
};
|
|
155
163
|
}
|
|
164
|
+
if (existsSync(resolve(home, ".config", "kilo"))) {
|
|
165
|
+
return {
|
|
166
|
+
platform: "kilo",
|
|
167
|
+
confidence: "medium",
|
|
168
|
+
reason: "~/.config/kilo/ directory exists",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
156
171
|
if (existsSync(resolve(home, ".config", "opencode"))) {
|
|
157
172
|
return {
|
|
158
173
|
platform: "opencode",
|
|
@@ -189,9 +204,10 @@ export async function getAdapter(platform) {
|
|
|
189
204
|
const { GeminiCLIAdapter } = await import("./gemini-cli/index.js");
|
|
190
205
|
return new GeminiCLIAdapter();
|
|
191
206
|
}
|
|
207
|
+
case "kilo":
|
|
192
208
|
case "opencode": {
|
|
193
209
|
const { OpenCodeAdapter } = await import("./opencode/index.js");
|
|
194
|
-
return new OpenCodeAdapter();
|
|
210
|
+
return new OpenCodeAdapter(target);
|
|
195
211
|
}
|
|
196
212
|
case "openclaw": {
|
|
197
213
|
const { OpenClawAdapter } = await import("./openclaw/index.js");
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* - Project dir env: GEMINI_PROJECT_DIR (also CLAUDE_PROJECT_DIR alias)
|
|
19
19
|
* - Session dir: ~/.gemini/context-mode/sessions/
|
|
20
20
|
*/
|
|
21
|
-
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration
|
|
21
|
+
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
|
|
22
22
|
export declare class GeminiCLIAdapter implements HookAdapter {
|
|
23
23
|
readonly name = "Gemini CLI";
|
|
24
24
|
readonly paradigm: HookParadigm;
|
|
@@ -45,8 +45,6 @@ export declare class GeminiCLIAdapter implements HookAdapter {
|
|
|
45
45
|
backupSettings(): string | null;
|
|
46
46
|
setHookPermissions(pluginRoot: string): string[];
|
|
47
47
|
updatePluginRegistry(pluginRoot: string, version: string): void;
|
|
48
|
-
getRoutingInstructionsConfig(): RoutingInstructionsConfig;
|
|
49
|
-
writeRoutingInstructions(projectDir: string, pluginRoot: string): string | null;
|
|
50
48
|
/** Get the project directory from environment variables. */
|
|
51
49
|
private getProjectDir;
|
|
52
50
|
/**
|
|
@@ -421,36 +421,6 @@ export class GeminiCLIAdapter {
|
|
|
421
421
|
/* best effort */
|
|
422
422
|
}
|
|
423
423
|
}
|
|
424
|
-
// ── Routing Instructions (soft enforcement) ────────────
|
|
425
|
-
getRoutingInstructionsConfig() {
|
|
426
|
-
return {
|
|
427
|
-
fileName: "GEMINI.md",
|
|
428
|
-
globalPath: resolve(homedir(), ".gemini", "GEMINI.md"),
|
|
429
|
-
projectRelativePath: "GEMINI.md",
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
writeRoutingInstructions(projectDir, pluginRoot) {
|
|
433
|
-
const config = this.getRoutingInstructionsConfig();
|
|
434
|
-
const targetPath = resolve(projectDir, config.projectRelativePath);
|
|
435
|
-
const sourcePath = resolve(pluginRoot, "configs", "gemini-cli", config.fileName);
|
|
436
|
-
try {
|
|
437
|
-
const content = readFileSync(sourcePath, "utf-8");
|
|
438
|
-
try {
|
|
439
|
-
const existing = readFileSync(targetPath, "utf-8");
|
|
440
|
-
if (existing.includes("context-mode"))
|
|
441
|
-
return null;
|
|
442
|
-
writeFileSync(targetPath, existing.trimEnd() + "\n\n" + content, "utf-8");
|
|
443
|
-
return targetPath;
|
|
444
|
-
}
|
|
445
|
-
catch {
|
|
446
|
-
writeFileSync(targetPath, content, "utf-8");
|
|
447
|
-
return targetPath;
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
catch {
|
|
451
|
-
return null;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
424
|
// ── Internal helpers ───────────────────────────────────
|
|
455
425
|
/** Get the project directory from environment variables. */
|
|
456
426
|
getProjectDir() {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* - clientInfo.name: https://github.com/kirodotdev/Kiro/issues/5205 ("Kiro CLI")
|
|
18
18
|
* - CLI hooks: https://kiro.dev/docs/cli/custom-agents/configuration-reference#hooks-field
|
|
19
19
|
*/
|
|
20
|
-
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration
|
|
20
|
+
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
|
|
21
21
|
export declare class KiroAdapter implements HookAdapter {
|
|
22
22
|
readonly name = "Kiro";
|
|
23
23
|
readonly paradigm: HookParadigm;
|
|
@@ -44,7 +44,5 @@ export declare class KiroAdapter implements HookAdapter {
|
|
|
44
44
|
backupSettings(): string | null;
|
|
45
45
|
setHookPermissions(_pluginRoot: string): string[];
|
|
46
46
|
updatePluginRegistry(_pluginRoot: string, _version: string): void;
|
|
47
|
-
getRoutingInstructionsConfig(): RoutingInstructionsConfig;
|
|
48
|
-
writeRoutingInstructions(projectDir: string, pluginRoot: string): string | null;
|
|
49
47
|
getRoutingInstructions(): string;
|
|
50
48
|
}
|
|
@@ -283,36 +283,6 @@ export class KiroAdapter {
|
|
|
283
283
|
updatePluginRegistry(_pluginRoot, _version) {
|
|
284
284
|
// Kiro plugin registry is managed via mcp.json
|
|
285
285
|
}
|
|
286
|
-
// ── Routing Instructions (soft enforcement) ────────────
|
|
287
|
-
getRoutingInstructionsConfig() {
|
|
288
|
-
return {
|
|
289
|
-
fileName: "KIRO.md",
|
|
290
|
-
globalPath: resolve(homedir(), ".kiro", "KIRO.md"),
|
|
291
|
-
projectRelativePath: "KIRO.md",
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
writeRoutingInstructions(projectDir, pluginRoot) {
|
|
295
|
-
const config = this.getRoutingInstructionsConfig();
|
|
296
|
-
const targetPath = resolve(projectDir, config.projectRelativePath);
|
|
297
|
-
const sourcePath = resolve(pluginRoot, "configs", "kiro", config.fileName);
|
|
298
|
-
try {
|
|
299
|
-
const content = readFileSync(sourcePath, "utf-8");
|
|
300
|
-
try {
|
|
301
|
-
const existing = readFileSync(targetPath, "utf-8");
|
|
302
|
-
if (existing.includes("context-mode"))
|
|
303
|
-
return null;
|
|
304
|
-
writeFileSync(targetPath, existing.trimEnd() + "\n\n" + content, "utf-8");
|
|
305
|
-
return targetPath;
|
|
306
|
-
}
|
|
307
|
-
catch {
|
|
308
|
-
writeFileSync(targetPath, content, "utf-8");
|
|
309
|
-
return targetPath;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
catch {
|
|
313
|
-
return null;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
286
|
getRoutingInstructions() {
|
|
317
287
|
const instructionsPath = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "configs", "kiro", "KIRO.md");
|
|
318
288
|
try {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* - Config: openclaw.json plugins.entries, ~/.openclaw/extensions/
|
|
16
16
|
* - Session dir: ~/.openclaw/context-mode/sessions/
|
|
17
17
|
*/
|
|
18
|
-
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration
|
|
18
|
+
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
|
|
19
19
|
export declare class OpenClawAdapter implements HookAdapter {
|
|
20
20
|
readonly name = "OpenClaw";
|
|
21
21
|
readonly paradigm: HookParadigm;
|
|
@@ -42,8 +42,6 @@ export declare class OpenClawAdapter implements HookAdapter {
|
|
|
42
42
|
backupSettings(): string | null;
|
|
43
43
|
setHookPermissions(_pluginRoot: string): string[];
|
|
44
44
|
updatePluginRegistry(_pluginRoot: string, _version: string): void;
|
|
45
|
-
getRoutingInstructionsConfig(): RoutingInstructionsConfig;
|
|
46
|
-
writeRoutingInstructions(projectDir: string, pluginRoot: string): string | null;
|
|
47
45
|
/**
|
|
48
46
|
* Extract session ID from OpenClaw hook input.
|
|
49
47
|
*/
|
|
@@ -409,44 +409,6 @@ export class OpenClawAdapter {
|
|
|
409
409
|
updatePluginRegistry(_pluginRoot, _version) {
|
|
410
410
|
// OpenClaw manages plugins through npm/openclaw.json — no separate registry
|
|
411
411
|
}
|
|
412
|
-
// ── Routing Instructions (soft enforcement) ────────────
|
|
413
|
-
getRoutingInstructionsConfig() {
|
|
414
|
-
return {
|
|
415
|
-
fileName: "AGENTS.md",
|
|
416
|
-
globalPath: resolve(homedir(), ".openclaw", "AGENTS.md"),
|
|
417
|
-
projectRelativePath: "AGENTS.md",
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
writeRoutingInstructions(projectDir, pluginRoot) {
|
|
421
|
-
const config = this.getRoutingInstructionsConfig();
|
|
422
|
-
const targetPath = resolve(projectDir, config.projectRelativePath);
|
|
423
|
-
const sourcePath = resolve(pluginRoot, "configs", "openclaw", config.fileName);
|
|
424
|
-
try {
|
|
425
|
-
let content;
|
|
426
|
-
try {
|
|
427
|
-
content = readFileSync(sourcePath, "utf-8");
|
|
428
|
-
}
|
|
429
|
-
catch {
|
|
430
|
-
// Fall back to opencode config if openclaw-specific doesn't exist yet
|
|
431
|
-
const fallbackPath = resolve(pluginRoot, "configs", "opencode", config.fileName);
|
|
432
|
-
content = readFileSync(fallbackPath, "utf-8");
|
|
433
|
-
}
|
|
434
|
-
try {
|
|
435
|
-
const existing = readFileSync(targetPath, "utf-8");
|
|
436
|
-
if (existing.includes("context-mode"))
|
|
437
|
-
return null;
|
|
438
|
-
writeFileSync(targetPath, existing.trimEnd() + "\n\n" + content, "utf-8");
|
|
439
|
-
return targetPath;
|
|
440
|
-
}
|
|
441
|
-
catch {
|
|
442
|
-
writeFileSync(targetPath, content, "utf-8");
|
|
443
|
-
return targetPath;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
catch {
|
|
447
|
-
return null;
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
412
|
// ── Internal helpers ───────────────────────────────────
|
|
451
413
|
/**
|
|
452
414
|
* Extract session ID from OpenClaw hook input.
|
|
@@ -15,12 +15,15 @@
|
|
|
15
15
|
* - Config: opencode.json plugin array, .opencode/plugins/*.ts
|
|
16
16
|
* - Session dir: ~/.config/opencode/context-mode/sessions/
|
|
17
17
|
*/
|
|
18
|
-
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration,
|
|
18
|
+
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration, PlatformId } from "../types.js";
|
|
19
|
+
export type AdapterPlatformType = Extract<PlatformId, "opencode" | "kilo">;
|
|
19
20
|
export declare class OpenCodeAdapter implements HookAdapter {
|
|
20
|
-
|
|
21
|
+
get name(): string;
|
|
21
22
|
readonly paradigm: HookParadigm;
|
|
22
23
|
private settingsPath?;
|
|
23
24
|
readonly capabilities: PlatformCapabilities;
|
|
25
|
+
private platform;
|
|
26
|
+
constructor(platform?: AdapterPlatformType);
|
|
24
27
|
parsePreToolUseInput(raw: unknown): PreToolUseEvent;
|
|
25
28
|
parsePostToolUseInput(raw: unknown): PostToolUseEvent;
|
|
26
29
|
parsePreCompactInput(raw: unknown): PreCompactEvent;
|
|
@@ -44,8 +47,6 @@ export declare class OpenCodeAdapter implements HookAdapter {
|
|
|
44
47
|
backupSettings(): string | null;
|
|
45
48
|
setHookPermissions(_pluginRoot: string): string[];
|
|
46
49
|
updatePluginRegistry(_pluginRoot: string, _version: string): void;
|
|
47
|
-
getRoutingInstructionsConfig(): RoutingInstructionsConfig;
|
|
48
|
-
writeRoutingInstructions(projectDir: string, pluginRoot: string): string | null;
|
|
49
50
|
/**
|
|
50
51
|
* Extract session ID from OpenCode hook input.
|
|
51
52
|
* OpenCode uses camelCase sessionID.
|
|
@@ -16,6 +16,13 @@
|
|
|
16
16
|
* - Session dir: ~/.config/opencode/context-mode/sessions/
|
|
17
17
|
*/
|
|
18
18
|
import { createHash } from "node:crypto";
|
|
19
|
+
/** Strip JSONC comments (// and /* */) and trailing commas for JSON.parse. */
|
|
20
|
+
function stripJsonComments(str) {
|
|
21
|
+
return str
|
|
22
|
+
.replace(/\/\/.*$/gm, "")
|
|
23
|
+
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
24
|
+
.replace(/,(\s*[}\]])/g, "$1");
|
|
25
|
+
}
|
|
19
26
|
import { readFileSync, writeFileSync, mkdirSync, copyFileSync, accessSync, constants, } from "node:fs";
|
|
20
27
|
import { resolve, join } from "node:path";
|
|
21
28
|
import { homedir } from "node:os";
|
|
@@ -23,22 +30,25 @@ import { homedir } from "node:os";
|
|
|
23
30
|
// Hook constants (re-exported from hooks.ts)
|
|
24
31
|
// ─────────────────────────────────────────────────────────
|
|
25
32
|
import { HOOK_TYPES as OPENCODE_HOOK_NAMES } from "./hooks.js";
|
|
26
|
-
// ─────────────────────────────────────────────────────────
|
|
27
|
-
// Adapter implementation
|
|
28
|
-
// ─────────────────────────────────────────────────────────
|
|
29
33
|
export class OpenCodeAdapter {
|
|
30
|
-
name
|
|
34
|
+
get name() {
|
|
35
|
+
return this.platform === "kilo" ? "KiloCode" : "OpenCode";
|
|
36
|
+
}
|
|
31
37
|
paradigm = "ts-plugin";
|
|
32
38
|
settingsPath;
|
|
33
39
|
capabilities = {
|
|
34
40
|
preToolUse: true,
|
|
35
41
|
postToolUse: true,
|
|
36
42
|
preCompact: true, // experimental
|
|
37
|
-
sessionStart:
|
|
43
|
+
sessionStart: false,
|
|
38
44
|
canModifyArgs: true,
|
|
39
45
|
canModifyOutput: true, // with TUI bug caveat for bash (#13575)
|
|
40
46
|
canInjectSessionContext: false,
|
|
41
47
|
};
|
|
48
|
+
platform;
|
|
49
|
+
constructor(platform = "opencode") {
|
|
50
|
+
this.platform = platform;
|
|
51
|
+
}
|
|
42
52
|
// ── Input parsing ──────────────────────────────────────
|
|
43
53
|
parsePreToolUseInput(raw) {
|
|
44
54
|
const input = raw;
|
|
@@ -134,17 +144,28 @@ export class OpenCodeAdapter {
|
|
|
134
144
|
}
|
|
135
145
|
// ── Configuration ──────────────────────────────────────
|
|
136
146
|
getSettingsPath() {
|
|
137
|
-
|
|
147
|
+
// OpenCode uses opencode.json in the project root or .opencode/opencode.json
|
|
148
|
+
return this.settingsPath ?? resolve(`${this.platform}.json`);
|
|
138
149
|
}
|
|
139
150
|
paths() {
|
|
151
|
+
if (this.platform === "kilo") {
|
|
152
|
+
return [
|
|
153
|
+
resolve("kilo.json"),
|
|
154
|
+
resolve(".kilocode", "kilo.json"),
|
|
155
|
+
join(homedir(), ".config", "kilo", "kilo.json"),
|
|
156
|
+
];
|
|
157
|
+
}
|
|
140
158
|
return [
|
|
141
159
|
resolve("opencode.json"),
|
|
160
|
+
resolve("opencode.jsonc"),
|
|
142
161
|
resolve(".opencode", "opencode.json"),
|
|
162
|
+
resolve(".opencode", "opencode.jsonc"),
|
|
143
163
|
join(homedir(), ".config", "opencode", "opencode.json"),
|
|
164
|
+
join(homedir(), ".config", "opencode", "opencode.jsonc"),
|
|
144
165
|
];
|
|
145
166
|
}
|
|
146
167
|
getSessionDir() {
|
|
147
|
-
const dir = join(homedir(), ".config",
|
|
168
|
+
const dir = join(homedir(), ".config", this.platform, "context-mode", "sessions");
|
|
148
169
|
mkdirSync(dir, { recursive: true });
|
|
149
170
|
return dir;
|
|
150
171
|
}
|
|
@@ -203,12 +224,16 @@ export class OpenCodeAdapter {
|
|
|
203
224
|
};
|
|
204
225
|
}
|
|
205
226
|
readSettings() {
|
|
227
|
+
// Try project-local paths first, then global config
|
|
228
|
+
// const paths = this.getConfigFilePaths();
|
|
229
|
+
// for (const configPath of paths) {
|
|
206
230
|
this.settingsPath = undefined;
|
|
207
231
|
for (const configPath of this.paths()) {
|
|
208
232
|
try {
|
|
209
233
|
const raw = readFileSync(configPath, "utf-8");
|
|
210
234
|
this.settingsPath = configPath;
|
|
211
|
-
|
|
235
|
+
const text = configPath.endsWith(".jsonc") ? stripJsonComments(raw) : raw;
|
|
236
|
+
return JSON.parse(text);
|
|
212
237
|
}
|
|
213
238
|
catch {
|
|
214
239
|
continue;
|
|
@@ -217,6 +242,7 @@ export class OpenCodeAdapter {
|
|
|
217
242
|
return null;
|
|
218
243
|
}
|
|
219
244
|
writeSettings(settings) {
|
|
245
|
+
// Write to opencode.json/kilo.json in current directory
|
|
220
246
|
writeFileSync(this.getSettingsPath(), JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
221
247
|
}
|
|
222
248
|
// ── Diagnostics (doctor) ─────────────────────────────────
|
|
@@ -227,7 +253,7 @@ export class OpenCodeAdapter {
|
|
|
227
253
|
results.push({
|
|
228
254
|
check: "Plugin configuration",
|
|
229
255
|
status: "fail",
|
|
230
|
-
message:
|
|
256
|
+
message: `Could not read ${this.platform}.json or ${this.platform}.jsonc`,
|
|
231
257
|
fix: "context-mode upgrade",
|
|
232
258
|
});
|
|
233
259
|
return results;
|
|
@@ -269,7 +295,7 @@ export class OpenCodeAdapter {
|
|
|
269
295
|
return {
|
|
270
296
|
check: "Plugin registration",
|
|
271
297
|
status: "warn",
|
|
272
|
-
message:
|
|
298
|
+
message: `Could not read ${this.platform}.json or ${this.platform}.jsonc`,
|
|
273
299
|
};
|
|
274
300
|
}
|
|
275
301
|
const plugins = settings.plugin;
|
|
@@ -293,7 +319,7 @@ export class OpenCodeAdapter {
|
|
|
293
319
|
getInstalledVersion() {
|
|
294
320
|
// Check ~/.cache/opencode/node_modules/ for context-mode
|
|
295
321
|
try {
|
|
296
|
-
const pkgPath = resolve(homedir(), ".cache",
|
|
322
|
+
const pkgPath = resolve(homedir(), ".cache", this.platform, "node_modules", "context-mode", "package.json");
|
|
297
323
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
298
324
|
if (typeof pkg.version === "string")
|
|
299
325
|
return pkg.version;
|
|
@@ -343,36 +369,6 @@ export class OpenCodeAdapter {
|
|
|
343
369
|
updatePluginRegistry(_pluginRoot, _version) {
|
|
344
370
|
// OpenCode manages plugins through npm/opencode.json — no separate registry
|
|
345
371
|
}
|
|
346
|
-
// ── Routing Instructions (soft enforcement) ────────────
|
|
347
|
-
getRoutingInstructionsConfig() {
|
|
348
|
-
return {
|
|
349
|
-
fileName: "AGENTS.md",
|
|
350
|
-
globalPath: resolve(homedir(), ".config", "opencode", "AGENTS.md"),
|
|
351
|
-
projectRelativePath: "AGENTS.md",
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
writeRoutingInstructions(projectDir, pluginRoot) {
|
|
355
|
-
const config = this.getRoutingInstructionsConfig();
|
|
356
|
-
const targetPath = resolve(projectDir, config.projectRelativePath);
|
|
357
|
-
const sourcePath = resolve(pluginRoot, "configs", "opencode", config.fileName);
|
|
358
|
-
try {
|
|
359
|
-
const content = readFileSync(sourcePath, "utf-8");
|
|
360
|
-
try {
|
|
361
|
-
const existing = readFileSync(targetPath, "utf-8");
|
|
362
|
-
if (existing.includes("context-mode"))
|
|
363
|
-
return null;
|
|
364
|
-
writeFileSync(targetPath, existing.trimEnd() + "\n\n" + content, "utf-8");
|
|
365
|
-
return targetPath;
|
|
366
|
-
}
|
|
367
|
-
catch {
|
|
368
|
-
writeFileSync(targetPath, content, "utf-8");
|
|
369
|
-
return targetPath;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
catch {
|
|
373
|
-
return null;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
372
|
// ── Internal helpers ───────────────────────────────────
|
|
377
373
|
/**
|
|
378
374
|
* Extract session ID from OpenCode hook input.
|
|
@@ -180,19 +180,6 @@ export interface HookAdapter {
|
|
|
180
180
|
setHookPermissions(pluginRoot: string): string[];
|
|
181
181
|
/** Update platform's plugin registry to point to given path and version. */
|
|
182
182
|
updatePluginRegistry(pluginRoot: string, version: string): void;
|
|
183
|
-
/** Get the routing instructions file config for this platform. */
|
|
184
|
-
getRoutingInstructionsConfig(): RoutingInstructionsConfig;
|
|
185
|
-
/** Write routing instructions file to project directory if not present. Returns path written or null if already exists. */
|
|
186
|
-
writeRoutingInstructions(projectDir: string, pluginRoot: string): string | null;
|
|
187
|
-
}
|
|
188
|
-
/** Configuration for platform-specific routing instruction files. */
|
|
189
|
-
export interface RoutingInstructionsConfig {
|
|
190
|
-
/** File name the platform reads (e.g., "CLAUDE.md", "GEMINI.md", "AGENTS.md"). */
|
|
191
|
-
fileName: string;
|
|
192
|
-
/** Global path for this platform (e.g., "~/.claude/CLAUDE.md"). */
|
|
193
|
-
globalPath: string;
|
|
194
|
-
/** Project-level path relative to project root (e.g., "GEMINI.md", ".github/copilot-instructions.md"). */
|
|
195
|
-
projectRelativePath: string;
|
|
196
183
|
}
|
|
197
184
|
/** Result from a platform-specific diagnostic check. */
|
|
198
185
|
export interface DiagnosticResult {
|
|
@@ -206,7 +193,7 @@ export interface DiagnosticResult {
|
|
|
206
193
|
fix?: string;
|
|
207
194
|
}
|
|
208
195
|
/** Supported platform identifiers. */
|
|
209
|
-
export type PlatformId = "claude-code" | "gemini-cli" | "opencode" | "openclaw" | "codex" | "vscode-copilot" | "cursor" | "antigravity" | "kiro" | "pi" | "zed" | "unknown";
|
|
196
|
+
export type PlatformId = "claude-code" | "gemini-cli" | "opencode" | "kilo" | "openclaw" | "codex" | "vscode-copilot" | "cursor" | "antigravity" | "kiro" | "pi" | "zed" | "unknown";
|
|
210
197
|
/** Detection signal used to identify which platform is running. */
|
|
211
198
|
export interface DetectionSignal {
|
|
212
199
|
/** Platform identifier. */
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* - Session dir: ~/.vscode/context-mode/sessions/ (fallback)
|
|
22
22
|
* - Preview status — API may change
|
|
23
23
|
*/
|
|
24
|
-
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration
|
|
24
|
+
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
|
|
25
25
|
export declare class VSCodeCopilotAdapter implements HookAdapter {
|
|
26
26
|
readonly name = "VS Code Copilot";
|
|
27
27
|
readonly paradigm: HookParadigm;
|
|
@@ -48,8 +48,6 @@ export declare class VSCodeCopilotAdapter implements HookAdapter {
|
|
|
48
48
|
backupSettings(): string | null;
|
|
49
49
|
setHookPermissions(pluginRoot: string): string[];
|
|
50
50
|
updatePluginRegistry(_pluginRoot: string, _version: string): void;
|
|
51
|
-
getRoutingInstructionsConfig(): RoutingInstructionsConfig;
|
|
52
|
-
writeRoutingInstructions(projectDir: string, pluginRoot: string): string | null;
|
|
53
51
|
/**
|
|
54
52
|
* Extract session ID from VS Code Copilot hook input.
|
|
55
53
|
* VS Code Copilot uses camelCase sessionId (NOT session_id).
|
|
@@ -465,38 +465,6 @@ export class VSCodeCopilotAdapter {
|
|
|
465
465
|
// VS Code manages extensions through its own marketplace/extension system.
|
|
466
466
|
// No manual registry update needed.
|
|
467
467
|
}
|
|
468
|
-
// ── Routing Instructions (soft enforcement) ────────────
|
|
469
|
-
getRoutingInstructionsConfig() {
|
|
470
|
-
return {
|
|
471
|
-
fileName: "copilot-instructions.md",
|
|
472
|
-
globalPath: "", // VS Code Copilot uses org-level, not global file
|
|
473
|
-
projectRelativePath: join(".github", "copilot-instructions.md"),
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
writeRoutingInstructions(projectDir, pluginRoot) {
|
|
477
|
-
const config = this.getRoutingInstructionsConfig();
|
|
478
|
-
const targetPath = resolve(projectDir, config.projectRelativePath);
|
|
479
|
-
const sourcePath = resolve(pluginRoot, "configs", "vscode-copilot", config.fileName);
|
|
480
|
-
try {
|
|
481
|
-
const content = readFileSync(sourcePath, "utf-8");
|
|
482
|
-
// Ensure .github directory exists
|
|
483
|
-
mkdirSync(resolve(projectDir, ".github"), { recursive: true });
|
|
484
|
-
try {
|
|
485
|
-
const existing = readFileSync(targetPath, "utf-8");
|
|
486
|
-
if (existing.includes("context-mode"))
|
|
487
|
-
return null;
|
|
488
|
-
writeFileSync(targetPath, existing.trimEnd() + "\n\n" + content, "utf-8");
|
|
489
|
-
return targetPath;
|
|
490
|
-
}
|
|
491
|
-
catch {
|
|
492
|
-
writeFileSync(targetPath, content, "utf-8");
|
|
493
|
-
return targetPath;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
catch {
|
|
497
|
-
return null;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
468
|
// ── Internal helpers ───────────────────────────────────
|
|
501
469
|
/**
|
|
502
470
|
* Extract session ID from VS Code Copilot hook input.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - All capabilities are false — MCP is the only integration path
|
|
11
11
|
* - Session dir: ~/.config/zed/context-mode/sessions/
|
|
12
12
|
*/
|
|
13
|
-
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration
|
|
13
|
+
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
|
|
14
14
|
export declare class ZedAdapter implements HookAdapter {
|
|
15
15
|
readonly name = "Zed";
|
|
16
16
|
readonly paradigm: HookParadigm;
|
|
@@ -37,7 +37,5 @@ export declare class ZedAdapter implements HookAdapter {
|
|
|
37
37
|
backupSettings(): string | null;
|
|
38
38
|
setHookPermissions(_pluginRoot: string): string[];
|
|
39
39
|
updatePluginRegistry(_pluginRoot: string, _version: string): void;
|
|
40
|
-
getRoutingInstructionsConfig(): RoutingInstructionsConfig;
|
|
41
|
-
writeRoutingInstructions(projectDir: string, pluginRoot: string): string | null;
|
|
42
40
|
getRoutingInstructions(): string;
|
|
43
41
|
}
|
|
@@ -175,36 +175,6 @@ export class ZedAdapter {
|
|
|
175
175
|
updatePluginRegistry(_pluginRoot, _version) {
|
|
176
176
|
// Zed has no plugin registry
|
|
177
177
|
}
|
|
178
|
-
// ── Routing Instructions (soft enforcement) ────────────
|
|
179
|
-
getRoutingInstructionsConfig() {
|
|
180
|
-
return {
|
|
181
|
-
fileName: "AGENTS.md",
|
|
182
|
-
globalPath: resolve(homedir(), ".config", "zed", "AGENTS.md"),
|
|
183
|
-
projectRelativePath: "AGENTS.md",
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
writeRoutingInstructions(projectDir, pluginRoot) {
|
|
187
|
-
const config = this.getRoutingInstructionsConfig();
|
|
188
|
-
const targetPath = resolve(projectDir, config.projectRelativePath);
|
|
189
|
-
const sourcePath = resolve(pluginRoot, "configs", "zed", config.fileName);
|
|
190
|
-
try {
|
|
191
|
-
const content = readFileSync(sourcePath, "utf-8");
|
|
192
|
-
try {
|
|
193
|
-
const existing = readFileSync(targetPath, "utf-8");
|
|
194
|
-
if (existing.includes("context-mode"))
|
|
195
|
-
return null;
|
|
196
|
-
writeFileSync(targetPath, existing.trimEnd() + "\n\n" + content, "utf-8");
|
|
197
|
-
return targetPath;
|
|
198
|
-
}
|
|
199
|
-
catch {
|
|
200
|
-
writeFileSync(targetPath, content, "utf-8");
|
|
201
|
-
return targetPath;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
catch {
|
|
205
|
-
return null;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
178
|
getRoutingInstructions() {
|
|
209
179
|
const instructionsPath = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "configs", "zed", "AGENTS.md");
|
|
210
180
|
try {
|