context-mode 1.0.88 → 1.0.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.openclaw-plugin/openclaw.plugin.json +1 -1
  4. package/.openclaw-plugin/package.json +1 -1
  5. package/README.md +184 -60
  6. package/build/adapters/antigravity/index.d.ts +3 -5
  7. package/build/adapters/antigravity/index.js +7 -35
  8. package/build/adapters/base.d.ts +27 -0
  9. package/build/adapters/base.js +59 -0
  10. package/build/adapters/claude-code/index.d.ts +9 -25
  11. package/build/adapters/claude-code/index.js +27 -141
  12. package/build/adapters/claude-code-base.d.ts +49 -0
  13. package/build/adapters/claude-code-base.js +113 -0
  14. package/build/adapters/client-map.js +5 -0
  15. package/build/adapters/codex/hooks.d.ts +21 -14
  16. package/build/adapters/codex/hooks.js +22 -15
  17. package/build/adapters/codex/index.d.ts +6 -10
  18. package/build/adapters/codex/index.js +13 -43
  19. package/build/adapters/copilot-base.d.ts +78 -0
  20. package/build/adapters/copilot-base.js +281 -0
  21. package/build/adapters/cursor/index.d.ts +3 -5
  22. package/build/adapters/cursor/index.js +6 -34
  23. package/build/adapters/detect.d.ts +7 -0
  24. package/build/adapters/detect.js +57 -56
  25. package/build/adapters/gemini-cli/index.d.ts +3 -5
  26. package/build/adapters/gemini-cli/index.js +7 -35
  27. package/build/adapters/jetbrains-copilot/config.d.ts +8 -0
  28. package/build/adapters/jetbrains-copilot/config.js +8 -0
  29. package/build/adapters/jetbrains-copilot/hooks.d.ts +51 -0
  30. package/build/adapters/jetbrains-copilot/hooks.js +82 -0
  31. package/build/adapters/jetbrains-copilot/index.d.ts +24 -0
  32. package/build/adapters/jetbrains-copilot/index.js +119 -0
  33. package/build/adapters/kiro/hooks.d.ts +14 -0
  34. package/build/adapters/kiro/hooks.js +23 -0
  35. package/build/adapters/kiro/index.d.ts +3 -5
  36. package/build/adapters/kiro/index.js +10 -38
  37. package/build/adapters/openclaw/index.d.ts +3 -4
  38. package/build/adapters/openclaw/index.js +6 -22
  39. package/build/adapters/opencode/index.d.ts +2 -3
  40. package/build/adapters/opencode/index.js +5 -16
  41. package/build/adapters/qwen-code/index.d.ts +39 -0
  42. package/build/adapters/qwen-code/index.js +199 -0
  43. package/build/adapters/types.d.ts +1 -1
  44. package/build/adapters/vscode-copilot/index.d.ts +16 -46
  45. package/build/adapters/vscode-copilot/index.js +29 -320
  46. package/build/adapters/zed/index.d.ts +3 -5
  47. package/build/adapters/zed/index.js +7 -35
  48. package/build/cli.js +113 -47
  49. package/build/lifecycle.d.ts +23 -0
  50. package/build/lifecycle.js +54 -13
  51. package/build/opencode-plugin.d.ts +19 -7
  52. package/build/opencode-plugin.js +19 -7
  53. package/build/pi-extension.js +24 -7
  54. package/build/runtime.js +24 -9
  55. package/build/security.d.ts +17 -1
  56. package/build/security.js +40 -6
  57. package/build/server.js +129 -21
  58. package/build/session/analytics.d.ts +8 -7
  59. package/build/session/analytics.js +95 -75
  60. package/build/session/db.d.ts +10 -1
  61. package/build/session/db.js +67 -8
  62. package/build/session/extract.js +10 -2
  63. package/build/session/project-attribution.d.ts +73 -0
  64. package/build/session/project-attribution.js +231 -0
  65. package/build/store.d.ts +7 -0
  66. package/build/store.js +117 -18
  67. package/build/truncate.d.ts +6 -0
  68. package/build/truncate.js +51 -29
  69. package/build/types.d.ts +8 -0
  70. package/cli.bundle.mjs +157 -136
  71. package/configs/antigravity/GEMINI.md +31 -36
  72. package/configs/claude-code/CLAUDE.md +31 -37
  73. package/configs/codex/AGENTS.md +35 -49
  74. package/configs/cursor/context-mode.mdc +24 -25
  75. package/configs/gemini-cli/GEMINI.md +30 -36
  76. package/configs/jetbrains-copilot/copilot-instructions.md +59 -0
  77. package/configs/jetbrains-copilot/hooks.json +16 -0
  78. package/configs/jetbrains-copilot/mcp.json +8 -0
  79. package/configs/kilo/AGENTS.md +30 -36
  80. package/configs/kiro/KIRO.md +30 -36
  81. package/configs/kiro/agent.json +1 -1
  82. package/configs/openclaw/AGENTS.md +30 -36
  83. package/configs/opencode/AGENTS.md +30 -36
  84. package/configs/pi/AGENTS.md +31 -36
  85. package/configs/qwen-code/QWEN.md +63 -0
  86. package/configs/vscode-copilot/copilot-instructions.md +30 -36
  87. package/configs/zed/AGENTS.md +31 -36
  88. package/hooks/codex/posttooluse.mjs +7 -7
  89. package/hooks/codex/pretooluse.mjs +3 -3
  90. package/hooks/codex/sessionstart.mjs +2 -1
  91. package/hooks/core/formatters.mjs +24 -0
  92. package/hooks/core/routing.mjs +40 -15
  93. package/hooks/core/tool-naming.mjs +2 -0
  94. package/hooks/cursor/posttooluse.mjs +7 -7
  95. package/hooks/cursor/pretooluse.mjs +3 -3
  96. package/hooks/cursor/sessionstart.mjs +2 -1
  97. package/hooks/cursor/stop.mjs +2 -2
  98. package/hooks/ensure-deps.mjs +22 -10
  99. package/hooks/gemini-cli/aftertool.mjs +8 -8
  100. package/hooks/gemini-cli/beforetool.mjs +3 -2
  101. package/hooks/gemini-cli/precompress.mjs +2 -2
  102. package/hooks/gemini-cli/sessionstart.mjs +12 -4
  103. package/hooks/jetbrains-copilot/posttooluse.mjs +61 -0
  104. package/hooks/jetbrains-copilot/precompact.mjs +54 -0
  105. package/hooks/jetbrains-copilot/pretooluse.mjs +27 -0
  106. package/hooks/jetbrains-copilot/sessionstart.mjs +119 -0
  107. package/hooks/kiro/posttooluse.mjs +6 -7
  108. package/hooks/kiro/pretooluse.mjs +3 -2
  109. package/hooks/posttooluse.mjs +8 -8
  110. package/hooks/precompact.mjs +3 -4
  111. package/hooks/pretooluse.mjs +43 -20
  112. package/hooks/routing-block.mjs +35 -33
  113. package/hooks/session-attribution.bundle.mjs +1 -0
  114. package/hooks/session-db.bundle.mjs +27 -8
  115. package/hooks/session-extract.bundle.mjs +2 -1
  116. package/hooks/session-helpers.mjs +44 -3
  117. package/hooks/session-loaders.mjs +37 -0
  118. package/hooks/session-snapshot.bundle.mjs +14 -14
  119. package/hooks/sessionstart.mjs +5 -5
  120. package/hooks/userpromptsubmit.mjs +26 -9
  121. package/hooks/vscode-copilot/posttooluse.mjs +8 -8
  122. package/hooks/vscode-copilot/precompact.mjs +2 -2
  123. package/hooks/vscode-copilot/pretooluse.mjs +3 -2
  124. package/hooks/vscode-copilot/sessionstart.mjs +2 -2
  125. package/insight/server.mjs +262 -32
  126. package/insight/src/lib/api.ts +2 -1
  127. package/insight/src/routes/index.tsx +16 -3
  128. package/insight/src/routes/search.tsx +1 -1
  129. package/openclaw.plugin.json +1 -1
  130. package/package.json +11 -2
  131. package/server.bundle.mjs +117 -99
  132. package/skills/ctx-insight/SKILL.md +1 -1
@@ -15,11 +15,29 @@
15
15
  * - Codex CLI: CODEX_CI, CODEX_THREAD_ID | ~/.codex/
16
16
  * - Cursor: CURSOR_TRACE_ID (MCP), CURSOR_CLI (terminal) | ~/.cursor/
17
17
  * - VS Code Copilot: VSCODE_PID, VSCODE_CWD | ~/.vscode/
18
+ * - JetBrains Copilot: IDEA_INITIAL_DIRECTORY, IDEA_HOME, JETBRAINS_CLIENT_ID | ~/.config/JetBrains/
18
19
  */
19
20
  import { existsSync } from "node:fs";
20
21
  import { resolve } from "node:path";
21
22
  import { homedir } from "node:os";
22
23
  import { CLIENT_NAME_TO_PLATFORM } from "./client-map.js";
24
+ /**
25
+ * High-confidence env vars per platform, checked in priority order.
26
+ * Single source of truth — consumed by detectPlatform() below and by
27
+ * tests that need to clear platform-related env vars deterministically.
28
+ */
29
+ export const PLATFORM_ENV_VARS = [
30
+ ["claude-code", ["CLAUDE_PROJECT_DIR", "CLAUDE_SESSION_ID"]],
31
+ ["gemini-cli", ["GEMINI_PROJECT_DIR", "GEMINI_CLI"]],
32
+ ["openclaw", ["OPENCLAW_HOME", "OPENCLAW_CLI"]],
33
+ ["kilo", ["KILO", "KILO_PID"]],
34
+ ["opencode", ["OPENCODE", "OPENCODE_PID"]],
35
+ ["codex", ["CODEX_CI", "CODEX_THREAD_ID"]],
36
+ ["cursor", ["CURSOR_TRACE_ID", "CURSOR_CLI"]],
37
+ ["vscode-copilot", ["VSCODE_PID", "VSCODE_CWD"]],
38
+ ["jetbrains-copilot", ["IDEA_INITIAL_DIRECTORY", "IDEA_HOME", "JETBRAINS_CLIENT_ID"]],
39
+ ["qwen-code", ["QWEN_PROJECT_DIR", "QWEN_SESSION_ID"]],
40
+ ];
23
41
  /**
24
42
  * Detect the current platform by checking env vars and config dirs.
25
43
  *
@@ -37,13 +55,21 @@ export function detectPlatform(clientInfo) {
37
55
  reason: `MCP clientInfo.name="${clientInfo.name}"`,
38
56
  };
39
57
  }
58
+ // Qwen Code uses dynamic client names: qwen-cli-mcp-client-<serverName>
59
+ if (clientInfo.name.startsWith("qwen-cli-mcp-client")) {
60
+ return {
61
+ platform: "qwen-code",
62
+ confidence: "high",
63
+ reason: `MCP clientInfo.name="${clientInfo.name}" (qwen-cli pattern)`,
64
+ };
65
+ }
40
66
  }
41
67
  // ── Explicit platform override ────────────────────────
42
68
  const platformOverride = process.env.CONTEXT_MODE_PLATFORM;
43
69
  if (platformOverride) {
44
70
  const validPlatforms = [
45
71
  "claude-code", "gemini-cli", "kilo", "opencode", "codex",
46
- "vscode-copilot", "cursor", "antigravity", "kiro", "pi", "zed",
72
+ "vscode-copilot", "jetbrains-copilot", "cursor", "antigravity", "kiro", "pi", "zed", "qwen-code",
47
73
  ];
48
74
  if (validPlatforms.includes(platformOverride)) {
49
75
  return {
@@ -54,61 +80,14 @@ export function detectPlatform(clientInfo) {
54
80
  }
55
81
  }
56
82
  // ── High confidence: environment variables ─────────────
57
- if (process.env.CLAUDE_PROJECT_DIR || process.env.CLAUDE_SESSION_ID) {
58
- return {
59
- platform: "claude-code",
60
- confidence: "high",
61
- reason: "CLAUDE_PROJECT_DIR or CLAUDE_SESSION_ID env var set",
62
- };
63
- }
64
- if (process.env.GEMINI_PROJECT_DIR || process.env.GEMINI_CLI) {
65
- return {
66
- platform: "gemini-cli",
67
- confidence: "high",
68
- reason: "GEMINI_PROJECT_DIR or GEMINI_CLI env var set",
69
- };
70
- }
71
- if (process.env.OPENCLAW_HOME || process.env.OPENCLAW_CLI) {
72
- return {
73
- platform: "openclaw",
74
- confidence: "high",
75
- reason: "OPENCLAW_HOME or OPENCLAW_CLI env var set",
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
- }
85
- if (process.env.OPENCODE || process.env.OPENCODE_PID) {
86
- return {
87
- platform: "opencode",
88
- confidence: "high",
89
- reason: "OPENCODE or OPENCODE_PID env var set",
90
- };
91
- }
92
- if (process.env.CODEX_CI || process.env.CODEX_THREAD_ID) {
93
- return {
94
- platform: "codex",
95
- confidence: "high",
96
- reason: "CODEX_CI or CODEX_THREAD_ID env var set",
97
- };
98
- }
99
- if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CLI) {
100
- return {
101
- platform: "cursor",
102
- confidence: "high",
103
- reason: "CURSOR_TRACE_ID or CURSOR_CLI env var set",
104
- };
105
- }
106
- if (process.env.VSCODE_PID || process.env.VSCODE_CWD) {
107
- return {
108
- platform: "vscode-copilot",
109
- confidence: "high",
110
- reason: "VSCODE_PID or VSCODE_CWD env var set",
111
- };
83
+ for (const [platform, vars] of PLATFORM_ENV_VARS) {
84
+ if (vars.some((v) => process.env[v])) {
85
+ return {
86
+ platform,
87
+ confidence: "high",
88
+ reason: `${vars.join(" or ")} env var set`,
89
+ };
90
+ }
112
91
  }
113
92
  // ── Medium confidence: config directory existence ──────
114
93
  const home = homedir();
@@ -154,6 +133,13 @@ export function detectPlatform(clientInfo) {
154
133
  reason: "~/.pi/ directory exists",
155
134
  };
156
135
  }
136
+ if (existsSync(resolve(home, ".qwen"))) {
137
+ return {
138
+ platform: "qwen-code",
139
+ confidence: "medium",
140
+ reason: "~/.qwen/ directory exists",
141
+ };
142
+ }
157
143
  if (existsSync(resolve(home, ".openclaw"))) {
158
144
  return {
159
145
  platform: "openclaw",
@@ -168,6 +154,13 @@ export function detectPlatform(clientInfo) {
168
154
  reason: "~/.config/kilo/ directory exists",
169
155
  };
170
156
  }
157
+ if (existsSync(resolve(home, ".config", "JetBrains"))) {
158
+ return {
159
+ platform: "jetbrains-copilot",
160
+ confidence: "medium",
161
+ reason: "~/.config/JetBrains/ directory exists",
162
+ };
163
+ }
171
164
  if (existsSync(resolve(home, ".config", "opencode"))) {
172
165
  return {
173
166
  platform: "opencode",
@@ -221,6 +214,10 @@ export async function getAdapter(platform) {
221
214
  const { VSCodeCopilotAdapter } = await import("./vscode-copilot/index.js");
222
215
  return new VSCodeCopilotAdapter();
223
216
  }
217
+ case "jetbrains-copilot": {
218
+ const { JetBrainsCopilotAdapter } = await import("./jetbrains-copilot/index.js");
219
+ return new JetBrainsCopilotAdapter();
220
+ }
224
221
  case "cursor": {
225
222
  const { CursorAdapter } = await import("./cursor/index.js");
226
223
  return new CursorAdapter();
@@ -237,6 +234,10 @@ export async function getAdapter(platform) {
237
234
  const { ZedAdapter } = await import("./zed/index.js");
238
235
  return new ZedAdapter();
239
236
  }
237
+ case "qwen-code": {
238
+ const { QwenCodeAdapter } = await import("./qwen-code/index.js");
239
+ return new QwenCodeAdapter();
240
+ }
240
241
  default: {
241
242
  // Unsupported platform — fall back to Claude Code adapter
242
243
  // (MCP server works everywhere, hooks may not)
@@ -18,8 +18,10 @@
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 { BaseAdapter } from "../base.js";
21
22
  import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
22
- export declare class GeminiCLIAdapter implements HookAdapter {
23
+ export declare class GeminiCLIAdapter extends BaseAdapter implements HookAdapter {
24
+ constructor();
23
25
  readonly name = "Gemini CLI";
24
26
  readonly paradigm: HookParadigm;
25
27
  readonly capabilities: PlatformCapabilities;
@@ -32,9 +34,6 @@ export declare class GeminiCLIAdapter implements HookAdapter {
32
34
  formatPreCompactResponse(response: PreCompactResponse): unknown;
33
35
  formatSessionStartResponse(response: SessionStartResponse): unknown;
34
36
  getSettingsPath(): string;
35
- getSessionDir(): string;
36
- getSessionDBPath(projectDir: string): string;
37
- getSessionEventsPath(projectDir: string): string;
38
37
  generateHookConfig(pluginRoot: string): HookRegistration;
39
38
  readSettings(): Record<string, unknown> | null;
40
39
  writeSettings(settings: Record<string, unknown>): void;
@@ -42,7 +41,6 @@ export declare class GeminiCLIAdapter implements HookAdapter {
42
41
  checkPluginRegistration(): DiagnosticResult;
43
42
  getInstalledVersion(): string;
44
43
  configureAllHooks(pluginRoot: string): string[];
45
- backupSettings(): string | null;
46
44
  setHookPermissions(pluginRoot: string): string[];
47
45
  updatePluginRegistry(pluginRoot: string, version: string): void;
48
46
  /** Get the project directory from environment variables. */
@@ -18,10 +18,10 @@
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 { createHash } from "node:crypto";
22
- import { readFileSync, writeFileSync, mkdirSync, copyFileSync, accessSync, chmodSync, constants, } from "node:fs";
21
+ import { readFileSync, writeFileSync, mkdirSync, accessSync, chmodSync, constants, } from "node:fs";
23
22
  import { resolve, join } from "node:path";
24
23
  import { homedir } from "node:os";
24
+ import { BaseAdapter } from "../base.js";
25
25
  // ─────────────────────────────────────────────────────────
26
26
  // Hook constants (re-exported from hooks.ts)
27
27
  // ─────────────────────────────────────────────────────────
@@ -29,7 +29,10 @@ import { HOOK_TYPES as GEMINI_HOOK_NAMES, HOOK_SCRIPTS as GEMINI_HOOK_SCRIPTS, b
29
29
  // ─────────────────────────────────────────────────────────
30
30
  // Adapter implementation
31
31
  // ─────────────────────────────────────────────────────────
32
- export class GeminiCLIAdapter {
32
+ export class GeminiCLIAdapter extends BaseAdapter {
33
+ constructor() {
34
+ super([".gemini"]);
35
+ }
33
36
  name = "Gemini CLI";
34
37
  paradigm = "json-stdio";
35
38
  capabilities = {
@@ -157,30 +160,11 @@ export class GeminiCLIAdapter {
157
160
  getSettingsPath() {
158
161
  return resolve(homedir(), ".gemini", "settings.json");
159
162
  }
160
- getSessionDir() {
161
- const dir = join(homedir(), ".gemini", "context-mode", "sessions");
162
- mkdirSync(dir, { recursive: true });
163
- return dir;
164
- }
165
- getSessionDBPath(projectDir) {
166
- const hash = createHash("sha256")
167
- .update(projectDir)
168
- .digest("hex")
169
- .slice(0, 16);
170
- return join(this.getSessionDir(), `${hash}.db`);
171
- }
172
- getSessionEventsPath(projectDir) {
173
- const hash = createHash("sha256")
174
- .update(projectDir)
175
- .digest("hex")
176
- .slice(0, 16);
177
- return join(this.getSessionDir(), `${hash}-events.md`);
178
- }
179
163
  generateHookConfig(pluginRoot) {
180
164
  return {
181
165
  [GEMINI_HOOK_NAMES.BEFORE_TOOL]: [
182
166
  {
183
- matcher: "",
167
+ matcher: "run_shell_command|read_file|read_many_files|grep_search|search_file_content|web_fetch|activate_skill|mcp__plugin_context-mode",
184
168
  hooks: [
185
169
  {
186
170
  type: "command",
@@ -378,18 +362,6 @@ export class GeminiCLIAdapter {
378
362
  this.writeSettings(settings);
379
363
  return changes;
380
364
  }
381
- backupSettings() {
382
- const settingsPath = this.getSettingsPath();
383
- try {
384
- accessSync(settingsPath, constants.R_OK);
385
- const backupPath = settingsPath + ".bak";
386
- copyFileSync(settingsPath, backupPath);
387
- return backupPath;
388
- }
389
- catch {
390
- return null;
391
- }
392
- }
393
365
  setHookPermissions(pluginRoot) {
394
366
  const set = [];
395
367
  const hooksDir = join(pluginRoot, "hooks", "gemini-cli");
@@ -0,0 +1,8 @@
1
+ /**
2
+ * adapters/jetbrains-copilot/config — Thin re-exports from JetBrainsCopilotAdapter.
3
+ *
4
+ * This module exists for backward compatibility. All logic lives in the
5
+ * adapter class (index.ts). New code should use getAdapter() from detect.ts.
6
+ */
7
+ export { JetBrainsCopilotAdapter } from "./index.js";
8
+ export { HOOK_TYPES, HOOK_SCRIPTS, REQUIRED_HOOKS, OPTIONAL_HOOKS } from "./hooks.js";
@@ -0,0 +1,8 @@
1
+ /**
2
+ * adapters/jetbrains-copilot/config — Thin re-exports from JetBrainsCopilotAdapter.
3
+ *
4
+ * This module exists for backward compatibility. All logic lives in the
5
+ * adapter class (index.ts). New code should use getAdapter() from detect.ts.
6
+ */
7
+ export { JetBrainsCopilotAdapter } from "./index.js";
8
+ export { HOOK_TYPES, HOOK_SCRIPTS, REQUIRED_HOOKS, OPTIONAL_HOOKS } from "./hooks.js";
@@ -0,0 +1,51 @@
1
+ /**
2
+ * adapters/jetbrains-copilot/hooks — JetBrains Copilot hook definitions and matchers.
3
+ *
4
+ * Defines the hook types, matchers, and registration format specific to
5
+ * JetBrains Copilot's hook system. This module is used by:
6
+ * - CLI setup/upgrade commands (to configure hooks)
7
+ * - Doctor command (to validate hook configuration)
8
+ * - Hook config generation
9
+ *
10
+ * JetBrains Copilot hook system reference:
11
+ * - Hooks are registered in .github/hooks/*.json
12
+ * - Hook names: PreToolUse, PostToolUse, PreCompact, SessionStart (PascalCase)
13
+ * - Additional hooks: Stop, SubagentStart, SubagentStop
14
+ * - CRITICAL: matchers are parsed but IGNORED (all hooks fire on all tools)
15
+ * - Input: JSON on stdin
16
+ * - Output: JSON on stdout (or empty for passthrough)
17
+ * - JetBrains Copilot shares the same hook paradigm as VS Code Copilot
18
+ */
19
+ /** JetBrains Copilot hook types. */
20
+ export declare const HOOK_TYPES: {
21
+ readonly PRE_TOOL_USE: "PreToolUse";
22
+ readonly POST_TOOL_USE: "PostToolUse";
23
+ readonly PRE_COMPACT: "PreCompact";
24
+ readonly SESSION_START: "SessionStart";
25
+ readonly STOP: "Stop";
26
+ readonly SUBAGENT_START: "SubagentStart";
27
+ readonly SUBAGENT_STOP: "SubagentStop";
28
+ };
29
+ export type HookType = (typeof HOOK_TYPES)[keyof typeof HOOK_TYPES];
30
+ /** Map of hook types to their script file names. */
31
+ export declare const HOOK_SCRIPTS: Record<string, string>;
32
+ /** Required hooks that must be configured for context-mode to function. */
33
+ export declare const REQUIRED_HOOKS: HookType[];
34
+ /** Optional hooks that enhance functionality but aren't critical. */
35
+ export declare const OPTIONAL_HOOKS: HookType[];
36
+ /**
37
+ * Check if a hook entry points to a context-mode hook script.
38
+ * Matches both legacy format (node .../pretooluse.mjs) and
39
+ * CLI dispatcher format (context-mode hook jetbrains-copilot pretooluse).
40
+ */
41
+ export declare function isContextModeHook(entry: {
42
+ hooks?: Array<{
43
+ command?: string;
44
+ }>;
45
+ }, hookType: HookType): boolean;
46
+ /**
47
+ * Build the hook command string for a given hook type.
48
+ * Uses absolute node path to avoid PATH issues (homebrew, nvm, volta, etc.).
49
+ * Falls back to CLI dispatcher if pluginRoot is not provided.
50
+ */
51
+ export declare function buildHookCommand(hookType: HookType, pluginRoot?: string): string;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * adapters/jetbrains-copilot/hooks — JetBrains Copilot hook definitions and matchers.
3
+ *
4
+ * Defines the hook types, matchers, and registration format specific to
5
+ * JetBrains Copilot's hook system. This module is used by:
6
+ * - CLI setup/upgrade commands (to configure hooks)
7
+ * - Doctor command (to validate hook configuration)
8
+ * - Hook config generation
9
+ *
10
+ * JetBrains Copilot hook system reference:
11
+ * - Hooks are registered in .github/hooks/*.json
12
+ * - Hook names: PreToolUse, PostToolUse, PreCompact, SessionStart (PascalCase)
13
+ * - Additional hooks: Stop, SubagentStart, SubagentStop
14
+ * - CRITICAL: matchers are parsed but IGNORED (all hooks fire on all tools)
15
+ * - Input: JSON on stdin
16
+ * - Output: JSON on stdout (or empty for passthrough)
17
+ * - JetBrains Copilot shares the same hook paradigm as VS Code Copilot
18
+ */
19
+ // ─────────────────────────────────────────────────────────
20
+ // Hook type constants
21
+ // ─────────────────────────────────────────────────────────
22
+ /** JetBrains Copilot hook types. */
23
+ export const HOOK_TYPES = {
24
+ PRE_TOOL_USE: "PreToolUse",
25
+ POST_TOOL_USE: "PostToolUse",
26
+ PRE_COMPACT: "PreCompact",
27
+ SESSION_START: "SessionStart",
28
+ // Additional hooks (shared with VS Code Copilot)
29
+ STOP: "Stop",
30
+ SUBAGENT_START: "SubagentStart",
31
+ SUBAGENT_STOP: "SubagentStop",
32
+ };
33
+ // ─────────────────────────────────────────────────────────
34
+ // Hook script file names
35
+ // ─────────────────────────────────────────────────────────
36
+ /** Map of hook types to their script file names. */
37
+ export const HOOK_SCRIPTS = {
38
+ [HOOK_TYPES.PRE_TOOL_USE]: "pretooluse.mjs",
39
+ [HOOK_TYPES.POST_TOOL_USE]: "posttooluse.mjs",
40
+ [HOOK_TYPES.PRE_COMPACT]: "precompact.mjs",
41
+ [HOOK_TYPES.SESSION_START]: "sessionstart.mjs",
42
+ };
43
+ // ─────────────────────────────────────────────────────────
44
+ // Hook validation
45
+ // ─────────────────────────────────────────────────────────
46
+ /** Required hooks that must be configured for context-mode to function. */
47
+ export const REQUIRED_HOOKS = [
48
+ HOOK_TYPES.PRE_TOOL_USE,
49
+ HOOK_TYPES.SESSION_START,
50
+ ];
51
+ /** Optional hooks that enhance functionality but aren't critical. */
52
+ export const OPTIONAL_HOOKS = [
53
+ HOOK_TYPES.POST_TOOL_USE,
54
+ HOOK_TYPES.PRE_COMPACT,
55
+ ];
56
+ /**
57
+ * Check if a hook entry points to a context-mode hook script.
58
+ * Matches both legacy format (node .../pretooluse.mjs) and
59
+ * CLI dispatcher format (context-mode hook jetbrains-copilot pretooluse).
60
+ */
61
+ export function isContextModeHook(entry, hookType) {
62
+ const scriptName = HOOK_SCRIPTS[hookType];
63
+ if (!scriptName)
64
+ return false;
65
+ const cliCommand = buildHookCommand(hookType);
66
+ return (entry.hooks?.some((h) => h.command?.includes(scriptName) || h.command?.includes(cliCommand)) ?? false);
67
+ }
68
+ /**
69
+ * Build the hook command string for a given hook type.
70
+ * Uses absolute node path to avoid PATH issues (homebrew, nvm, volta, etc.).
71
+ * Falls back to CLI dispatcher if pluginRoot is not provided.
72
+ */
73
+ export function buildHookCommand(hookType, pluginRoot) {
74
+ const scriptName = HOOK_SCRIPTS[hookType];
75
+ if (!scriptName) {
76
+ throw new Error(`No script defined for hook type: ${hookType}`);
77
+ }
78
+ if (pluginRoot) {
79
+ return `node "${pluginRoot}/hooks/jetbrains-copilot/${scriptName}"`;
80
+ }
81
+ return `context-mode hook jetbrains-copilot ${hookType.toLowerCase()}`;
82
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * adapters/jetbrains-copilot — JetBrains Copilot platform adapter.
3
+ *
4
+ * Extends CopilotBaseAdapter with JetBrains-specific logic:
5
+ * - extractSessionId: JETBRAINS_CLIENT_ID / IDEA_HOME fallbacks
6
+ * - getProjectDir: IDEA_INITIAL_DIRECTORY
7
+ * - checkPluginRegistration: WARN (IDE Settings UI, not CLI-inspectable)
8
+ * - getInstalledVersion: checks hook config existence
9
+ * - validateHooks: JetBrains-specific warnings
10
+ */
11
+ import { CopilotBaseAdapter } from "../copilot-base.js";
12
+ import type { CopilotHookInput, CopilotHookModule } from "../copilot-base.js";
13
+ import type { DiagnosticResult } from "../types.js";
14
+ export declare class JetBrainsCopilotAdapter extends CopilotBaseAdapter {
15
+ constructor();
16
+ readonly name = "JetBrains Copilot";
17
+ protected readonly hookModule: CopilotHookModule;
18
+ protected readonly hookSubdir = "jetbrains-copilot";
19
+ protected extractSessionId(input: CopilotHookInput): string;
20
+ protected getProjectDir(): string;
21
+ validateHooks(pluginRoot: string): DiagnosticResult[];
22
+ checkPluginRegistration(): DiagnosticResult;
23
+ getInstalledVersion(): string;
24
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * adapters/jetbrains-copilot — JetBrains Copilot platform adapter.
3
+ *
4
+ * Extends CopilotBaseAdapter with JetBrains-specific logic:
5
+ * - extractSessionId: JETBRAINS_CLIENT_ID / IDEA_HOME fallbacks
6
+ * - getProjectDir: IDEA_INITIAL_DIRECTORY
7
+ * - checkPluginRegistration: WARN (IDE Settings UI, not CLI-inspectable)
8
+ * - getInstalledVersion: checks hook config existence
9
+ * - validateHooks: JetBrains-specific warnings
10
+ */
11
+ import { readFileSync, } from "node:fs";
12
+ import { CopilotBaseAdapter } from "../copilot-base.js";
13
+ // ─────────────────────────────────────────────────────────
14
+ // Hook constants (re-exported from hooks.ts)
15
+ // ─────────────────────────────────────────────────────────
16
+ import { HOOK_TYPES as JETBRAINS_HOOK_NAMES, HOOK_SCRIPTS as JETBRAINS_HOOK_SCRIPTS, buildHookCommand as buildJetBrainsHookCommand, } from "./hooks.js";
17
+ // ─────────────────────────────────────────────────────────
18
+ // Adapter implementation
19
+ // ─────────────────────────────────────────────────────────
20
+ export class JetBrainsCopilotAdapter extends CopilotBaseAdapter {
21
+ constructor() {
22
+ super([".config", "JetBrains"]);
23
+ }
24
+ name = "JetBrains Copilot";
25
+ hookModule = {
26
+ HOOK_TYPES: JETBRAINS_HOOK_NAMES,
27
+ HOOK_SCRIPTS: JETBRAINS_HOOK_SCRIPTS,
28
+ buildHookCommand: buildJetBrainsHookCommand,
29
+ };
30
+ hookSubdir = "jetbrains-copilot";
31
+ // ── Platform-specific overrides ────────────────────────
32
+ extractSessionId(input) {
33
+ if (input.sessionId)
34
+ return input.sessionId;
35
+ if (process.env.JETBRAINS_CLIENT_ID) {
36
+ return `jetbrains-${process.env.JETBRAINS_CLIENT_ID}`;
37
+ }
38
+ if (process.env.IDEA_HOME)
39
+ return `idea-${process.pid}`;
40
+ return `pid-${process.ppid}`;
41
+ }
42
+ getProjectDir() {
43
+ return process.env.IDEA_INITIAL_DIRECTORY || process.env.CLAUDE_PROJECT_DIR || process.cwd();
44
+ }
45
+ // ── Diagnostics (doctor) ─────────────────────────────────
46
+ validateHooks(pluginRoot) {
47
+ const results = [];
48
+ try {
49
+ const raw = readFileSync(this.getSettingsPath(), "utf-8");
50
+ const config = JSON.parse(raw);
51
+ const hooks = config.hooks;
52
+ if (hooks?.[JETBRAINS_HOOK_NAMES.PRE_TOOL_USE]) {
53
+ results.push({
54
+ check: "PreToolUse hook",
55
+ status: "pass",
56
+ message: "PreToolUse hook configured in .github/hooks/context-mode.json",
57
+ });
58
+ }
59
+ else {
60
+ results.push({
61
+ check: "PreToolUse hook",
62
+ status: "fail",
63
+ message: "PreToolUse not found in .github/hooks/context-mode.json",
64
+ fix: "context-mode upgrade",
65
+ });
66
+ }
67
+ if (hooks?.[JETBRAINS_HOOK_NAMES.SESSION_START]) {
68
+ results.push({
69
+ check: "SessionStart hook",
70
+ status: "pass",
71
+ message: "SessionStart hook configured in .github/hooks/context-mode.json",
72
+ });
73
+ }
74
+ else {
75
+ results.push({
76
+ check: "SessionStart hook",
77
+ status: "fail",
78
+ message: "SessionStart not found in .github/hooks/context-mode.json",
79
+ fix: "context-mode upgrade",
80
+ });
81
+ }
82
+ }
83
+ catch {
84
+ results.push({
85
+ check: "Hook configuration",
86
+ status: "fail",
87
+ message: "Could not read .github/hooks/context-mode.json",
88
+ fix: "context-mode upgrade",
89
+ });
90
+ }
91
+ results.push({
92
+ check: "Hook scripts",
93
+ status: "warn",
94
+ message: `JetBrains hook wrappers should resolve to ${pluginRoot}/hooks/jetbrains-copilot/*.mjs`,
95
+ });
96
+ return results;
97
+ }
98
+ checkPluginRegistration() {
99
+ // JetBrains Copilot stores MCP server registration via the IDE Settings UI
100
+ // (Settings > Tools > GitHub Copilot > MCP > Configure), not in a
101
+ // project-scoped file we can inspect.
102
+ return {
103
+ check: "MCP registration",
104
+ status: "warn",
105
+ message: "JetBrains stores MCP config via Settings UI — not CLI-inspectable",
106
+ fix: "Verify in IDE: Settings > Tools > GitHub Copilot > MCP > ensure a context-mode server entry exists",
107
+ };
108
+ }
109
+ getInstalledVersion() {
110
+ // JetBrains Copilot registers MCP servers via Settings UI (not
111
+ // CLI-inspectable). All we can check is whether hook config has been
112
+ // written to .github/hooks/context-mode.json by `context-mode upgrade`.
113
+ const settings = this.readSettings();
114
+ const hooks = settings?.hooks;
115
+ if (hooks && Object.keys(hooks).length > 0)
116
+ return "configured";
117
+ return "unknown";
118
+ }
119
+ }
@@ -18,6 +18,20 @@ export declare const HOOK_TYPES: {
18
18
  };
19
19
  export type HookType = (typeof HOOK_TYPES)[keyof typeof HOOK_TYPES];
20
20
  export declare const HOOK_SCRIPTS: Record<string, string>;
21
+ /**
22
+ * Tools that context-mode's PreToolUse hook intercepts on Kiro.
23
+ *
24
+ * Kiro native tool names (from TOOL_ALIASES in routing.mjs):
25
+ * execute_bash → Bash, fs_read → Read, fs_write → Write
26
+ *
27
+ * MCP tools surface as @context-mode/ctx_* in Kiro.
28
+ */
29
+ export declare const PRE_TOOL_USE_MATCHERS: readonly ["execute_bash", "fs_read", "@context-mode/ctx_execute", "@context-mode/ctx_execute_file", "@context-mode/ctx_batch_execute"];
30
+ /**
31
+ * Combined matcher pattern for Kiro hook config (pipe-separated).
32
+ * Used by generateHookConfig and configureAllHooks.
33
+ */
34
+ export declare const PRE_TOOL_USE_MATCHER_PATTERN: string;
21
35
  export declare const REQUIRED_HOOKS: string[];
22
36
  export declare const OPTIONAL_HOOKS: string[];
23
37
  /**
@@ -20,6 +20,29 @@ export const HOOK_SCRIPTS = {
20
20
  [HOOK_TYPES.PRE_TOOL_USE]: "pretooluse.mjs",
21
21
  [HOOK_TYPES.POST_TOOL_USE]: "posttooluse.mjs",
22
22
  };
23
+ // ─────────────────────────────────────────────────────────
24
+ // PreToolUse matchers
25
+ // ─────────────────────────────────────────────────────────
26
+ /**
27
+ * Tools that context-mode's PreToolUse hook intercepts on Kiro.
28
+ *
29
+ * Kiro native tool names (from TOOL_ALIASES in routing.mjs):
30
+ * execute_bash → Bash, fs_read → Read, fs_write → Write
31
+ *
32
+ * MCP tools surface as @context-mode/ctx_* in Kiro.
33
+ */
34
+ export const PRE_TOOL_USE_MATCHERS = [
35
+ "execute_bash",
36
+ "fs_read",
37
+ "@context-mode/ctx_execute",
38
+ "@context-mode/ctx_execute_file",
39
+ "@context-mode/ctx_batch_execute",
40
+ ];
41
+ /**
42
+ * Combined matcher pattern for Kiro hook config (pipe-separated).
43
+ * Used by generateHookConfig and configureAllHooks.
44
+ */
45
+ export const PRE_TOOL_USE_MATCHER_PATTERN = PRE_TOOL_USE_MATCHERS.join("|");
23
46
  export const REQUIRED_HOOKS = [
24
47
  HOOK_TYPES.PRE_TOOL_USE,
25
48
  ];
@@ -17,8 +17,10 @@
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 { BaseAdapter } from "../base.js";
20
21
  import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
21
- export declare class KiroAdapter implements HookAdapter {
22
+ export declare class KiroAdapter extends BaseAdapter implements HookAdapter {
23
+ constructor();
22
24
  readonly name = "Kiro";
23
25
  readonly paradigm: HookParadigm;
24
26
  readonly capabilities: PlatformCapabilities;
@@ -31,9 +33,6 @@ export declare class KiroAdapter implements HookAdapter {
31
33
  formatPreCompactResponse(_response: PreCompactResponse): unknown;
32
34
  formatSessionStartResponse(_response: SessionStartResponse): unknown;
33
35
  getSettingsPath(): string;
34
- getSessionDir(): string;
35
- getSessionDBPath(projectDir: string): string;
36
- getSessionEventsPath(projectDir: string): string;
37
36
  generateHookConfig(pluginRoot: string): HookRegistration;
38
37
  readSettings(): Record<string, unknown> | null;
39
38
  writeSettings(settings: Record<string, unknown>): void;
@@ -41,7 +40,6 @@ export declare class KiroAdapter implements HookAdapter {
41
40
  checkPluginRegistration(): DiagnosticResult;
42
41
  getInstalledVersion(): string;
43
42
  configureAllHooks(pluginRoot: string): string[];
44
- backupSettings(): string | null;
45
43
  setHookPermissions(_pluginRoot: string): string[];
46
44
  updatePluginRegistry(_pluginRoot: string, _version: string): void;
47
45
  getRoutingInstructions(): string;