context-mode 1.0.89 → 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 (128) 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 +12 -140
  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 +13 -0
  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/runtime.js +24 -9
  54. package/build/security.d.ts +17 -1
  55. package/build/security.js +40 -6
  56. package/build/server.js +41 -9
  57. package/build/session/analytics.d.ts +8 -7
  58. package/build/session/analytics.js +95 -75
  59. package/build/session/db.d.ts +10 -1
  60. package/build/session/db.js +67 -8
  61. package/build/session/extract.js +10 -2
  62. package/build/session/project-attribution.d.ts +73 -0
  63. package/build/session/project-attribution.js +231 -0
  64. package/build/store.d.ts +4 -0
  65. package/build/store.js +58 -9
  66. package/build/types.d.ts +8 -0
  67. package/cli.bundle.mjs +135 -121
  68. package/configs/antigravity/GEMINI.md +31 -36
  69. package/configs/claude-code/CLAUDE.md +31 -37
  70. package/configs/codex/AGENTS.md +35 -49
  71. package/configs/cursor/context-mode.mdc +24 -25
  72. package/configs/gemini-cli/GEMINI.md +30 -36
  73. package/configs/jetbrains-copilot/copilot-instructions.md +59 -0
  74. package/configs/jetbrains-copilot/hooks.json +16 -0
  75. package/configs/jetbrains-copilot/mcp.json +8 -0
  76. package/configs/kilo/AGENTS.md +30 -36
  77. package/configs/kiro/KIRO.md +30 -36
  78. package/configs/kiro/agent.json +1 -1
  79. package/configs/openclaw/AGENTS.md +30 -36
  80. package/configs/opencode/AGENTS.md +30 -36
  81. package/configs/pi/AGENTS.md +31 -36
  82. package/configs/qwen-code/QWEN.md +63 -0
  83. package/configs/vscode-copilot/copilot-instructions.md +30 -36
  84. package/configs/zed/AGENTS.md +31 -36
  85. package/hooks/codex/posttooluse.mjs +7 -7
  86. package/hooks/codex/pretooluse.mjs +3 -3
  87. package/hooks/codex/sessionstart.mjs +2 -1
  88. package/hooks/core/formatters.mjs +24 -0
  89. package/hooks/core/routing.mjs +40 -15
  90. package/hooks/core/tool-naming.mjs +2 -0
  91. package/hooks/cursor/posttooluse.mjs +7 -7
  92. package/hooks/cursor/pretooluse.mjs +3 -3
  93. package/hooks/cursor/sessionstart.mjs +2 -1
  94. package/hooks/cursor/stop.mjs +2 -2
  95. package/hooks/ensure-deps.mjs +22 -10
  96. package/hooks/gemini-cli/aftertool.mjs +8 -8
  97. package/hooks/gemini-cli/beforetool.mjs +3 -2
  98. package/hooks/gemini-cli/precompress.mjs +2 -2
  99. package/hooks/gemini-cli/sessionstart.mjs +12 -4
  100. package/hooks/jetbrains-copilot/posttooluse.mjs +61 -0
  101. package/hooks/jetbrains-copilot/precompact.mjs +54 -0
  102. package/hooks/jetbrains-copilot/pretooluse.mjs +27 -0
  103. package/hooks/jetbrains-copilot/sessionstart.mjs +119 -0
  104. package/hooks/kiro/posttooluse.mjs +6 -7
  105. package/hooks/kiro/pretooluse.mjs +3 -2
  106. package/hooks/posttooluse.mjs +8 -8
  107. package/hooks/precompact.mjs +3 -4
  108. package/hooks/pretooluse.mjs +5 -4
  109. package/hooks/routing-block.mjs +35 -33
  110. package/hooks/session-attribution.bundle.mjs +1 -0
  111. package/hooks/session-db.bundle.mjs +27 -8
  112. package/hooks/session-extract.bundle.mjs +2 -1
  113. package/hooks/session-helpers.mjs +44 -3
  114. package/hooks/session-loaders.mjs +37 -0
  115. package/hooks/sessionstart.mjs +5 -5
  116. package/hooks/userpromptsubmit.mjs +26 -9
  117. package/hooks/vscode-copilot/posttooluse.mjs +8 -8
  118. package/hooks/vscode-copilot/precompact.mjs +2 -2
  119. package/hooks/vscode-copilot/pretooluse.mjs +3 -2
  120. package/hooks/vscode-copilot/sessionstart.mjs +2 -2
  121. package/insight/server.mjs +237 -25
  122. package/insight/src/lib/api.ts +2 -1
  123. package/insight/src/routes/index.tsx +16 -3
  124. package/insight/src/routes/search.tsx +1 -1
  125. package/openclaw.plugin.json +1 -1
  126. package/package.json +11 -2
  127. package/server.bundle.mjs +94 -80
  128. package/skills/ctx-insight/SKILL.md +1 -1
@@ -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;
@@ -17,16 +17,19 @@
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 { createHash } from "node:crypto";
21
- import { readFileSync, writeFileSync, mkdirSync, copyFileSync, accessSync, constants, } from "node:fs";
22
- import { resolve, join, dirname } from "node:path";
20
+ import { readFileSync, writeFileSync, mkdirSync, } from "node:fs";
21
+ import { resolve, dirname } from "node:path";
23
22
  import { fileURLToPath } from "node:url";
24
23
  import { homedir } from "node:os";
25
- import { HOOK_TYPES as KIRO_HOOK_TYPES, buildHookCommand as buildKiroHookCommand, isContextModeHook as isKiroContextModeHook, } from "./hooks.js";
24
+ import { BaseAdapter } from "../base.js";
25
+ import { HOOK_TYPES as KIRO_HOOK_TYPES, PRE_TOOL_USE_MATCHER_PATTERN as KIRO_PRE_TOOL_USE_MATCHER_PATTERN, buildHookCommand as buildKiroHookCommand, isContextModeHook as isKiroContextModeHook, } from "./hooks.js";
26
26
  // ─────────────────────────────────────────────────────────
27
27
  // Adapter implementation
28
28
  // ─────────────────────────────────────────────────────────
29
- export class KiroAdapter {
29
+ export class KiroAdapter extends BaseAdapter {
30
+ constructor() {
31
+ super([".kiro"]);
32
+ }
30
33
  name = "Kiro";
31
34
  paradigm = "json-stdio";
32
35
  capabilities = {
@@ -95,31 +98,12 @@ export class KiroAdapter {
95
98
  getSettingsPath() {
96
99
  return resolve(homedir(), ".kiro", "settings", "mcp.json");
97
100
  }
98
- getSessionDir() {
99
- const dir = join(homedir(), ".kiro", "context-mode", "sessions");
100
- mkdirSync(dir, { recursive: true });
101
- return dir;
102
- }
103
- getSessionDBPath(projectDir) {
104
- const hash = createHash("sha256")
105
- .update(projectDir)
106
- .digest("hex")
107
- .slice(0, 16);
108
- return join(this.getSessionDir(), `${hash}.db`);
109
- }
110
- getSessionEventsPath(projectDir) {
111
- const hash = createHash("sha256")
112
- .update(projectDir)
113
- .digest("hex")
114
- .slice(0, 16);
115
- return join(this.getSessionDir(), `${hash}-events.md`);
116
- }
117
101
  generateHookConfig(pluginRoot) {
118
102
  // Kiro CLI hook config format: { preToolUse: [{ matcher, command }] }
119
103
  // Note: This generates the entries for agent config files
120
104
  return {
121
105
  [KIRO_HOOK_TYPES.PRE_TOOL_USE]: [{
122
- matcher: "*",
106
+ matcher: KIRO_PRE_TOOL_USE_MATCHER_PATTERN,
123
107
  hooks: [{ type: "command", command: buildKiroHookCommand(KIRO_HOOK_TYPES.PRE_TOOL_USE, pluginRoot) }],
124
108
  }],
125
109
  [KIRO_HOOK_TYPES.POST_TOOL_USE]: [{
@@ -241,7 +225,7 @@ export class KiroAdapter {
241
225
  const preToolUseEntries = (hooks[KIRO_HOOK_TYPES.PRE_TOOL_USE] ?? []);
242
226
  if (!preToolUseEntries.some(e => isKiroContextModeHook(e, KIRO_HOOK_TYPES.PRE_TOOL_USE))) {
243
227
  preToolUseEntries.push({
244
- matcher: "*",
228
+ matcher: KIRO_PRE_TOOL_USE_MATCHER_PATTERN,
245
229
  command: buildKiroHookCommand(KIRO_HOOK_TYPES.PRE_TOOL_USE, pluginRoot),
246
230
  });
247
231
  hooks[KIRO_HOOK_TYPES.PRE_TOOL_USE] = preToolUseEntries;
@@ -265,18 +249,6 @@ export class KiroAdapter {
265
249
  }
266
250
  return changes;
267
251
  }
268
- backupSettings() {
269
- const settingsPath = this.getSettingsPath();
270
- try {
271
- accessSync(settingsPath, constants.R_OK);
272
- const backupPath = settingsPath + ".bak";
273
- copyFileSync(settingsPath, backupPath);
274
- return backupPath;
275
- }
276
- catch {
277
- return null;
278
- }
279
- }
280
252
  setHookPermissions(_pluginRoot) {
281
253
  return [];
282
254
  }
@@ -15,8 +15,10 @@
15
15
  * - Config: openclaw.json plugins.entries, ~/.openclaw/extensions/
16
16
  * - Session dir: ~/.openclaw/context-mode/sessions/
17
17
  */
18
+ import { BaseAdapter } from "../base.js";
18
19
  import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
19
- export declare class OpenClawAdapter implements HookAdapter {
20
+ export declare class OpenClawAdapter extends BaseAdapter implements HookAdapter {
21
+ constructor();
20
22
  readonly name = "OpenClaw";
21
23
  readonly paradigm: HookParadigm;
22
24
  readonly capabilities: PlatformCapabilities;
@@ -29,9 +31,6 @@ export declare class OpenClawAdapter implements HookAdapter {
29
31
  formatPreCompactResponse(response: PreCompactResponse): unknown;
30
32
  formatSessionStartResponse(response: SessionStartResponse): unknown;
31
33
  getSettingsPath(): string;
32
- getSessionDir(): string;
33
- getSessionDBPath(projectDir: string): string;
34
- getSessionEventsPath(projectDir: string): string;
35
34
  generateHookConfig(_pluginRoot: string): HookRegistration;
36
35
  readSettings(): Record<string, unknown> | null;
37
36
  writeSettings(settings: Record<string, unknown>): void;
@@ -15,10 +15,10 @@
15
15
  * - Config: openclaw.json plugins.entries, ~/.openclaw/extensions/
16
16
  * - Session dir: ~/.openclaw/context-mode/sessions/
17
17
  */
18
- import { createHash } from "node:crypto";
19
- import { readFileSync, writeFileSync, mkdirSync, copyFileSync, accessSync, constants, } from "node:fs";
18
+ import { readFileSync, writeFileSync, copyFileSync, accessSync, constants, } from "node:fs";
20
19
  import { resolve, join } from "node:path";
21
20
  import { homedir } from "node:os";
21
+ import { BaseAdapter } from "../base.js";
22
22
  // ─────────────────────────────────────────────────────────
23
23
  // Hook constants (re-exported from hooks.ts)
24
24
  // ─────────────────────────────────────────────────────────
@@ -26,7 +26,10 @@ import { HOOK_EVENTS as OPENCLAW_HOOK_EVENTS } from "./hooks.js";
26
26
  // ─────────────────────────────────────────────────────────
27
27
  // Adapter implementation
28
28
  // ─────────────────────────────────────────────────────────
29
- export class OpenClawAdapter {
29
+ export class OpenClawAdapter extends BaseAdapter {
30
+ constructor() {
31
+ super([".openclaw"]);
32
+ }
30
33
  name = "OpenClaw";
31
34
  paradigm = "ts-plugin";
32
35
  capabilities = {
@@ -140,25 +143,6 @@ export class OpenClawAdapter {
140
143
  // OpenClaw uses openclaw.json in the project root or ~/.openclaw/openclaw.json
141
144
  return resolve("openclaw.json");
142
145
  }
143
- getSessionDir() {
144
- const dir = join(homedir(), ".openclaw", "context-mode", "sessions");
145
- mkdirSync(dir, { recursive: true });
146
- return dir;
147
- }
148
- getSessionDBPath(projectDir) {
149
- const hash = createHash("sha256")
150
- .update(projectDir)
151
- .digest("hex")
152
- .slice(0, 16);
153
- return join(this.getSessionDir(), `${hash}.db`);
154
- }
155
- getSessionEventsPath(projectDir) {
156
- const hash = createHash("sha256")
157
- .update(projectDir)
158
- .digest("hex")
159
- .slice(0, 16);
160
- return join(this.getSessionDir(), `${hash}-events.md`);
161
- }
162
146
  generateHookConfig(_pluginRoot) {
163
147
  // OpenClaw uses TS plugin paradigm — hooks are registered via
164
148
  // api.registerHook() in the plugin entry point, not via config files.
@@ -15,9 +15,10 @@
15
15
  * - Config: opencode.json plugin array, .opencode/plugins/*.ts
16
16
  * - Session dir: ~/.config/opencode/context-mode/sessions/
17
17
  */
18
+ import { BaseAdapter } from "../base.js";
18
19
  import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration, PlatformId } from "../types.js";
19
20
  export type AdapterPlatformType = Extract<PlatformId, "opencode" | "kilo">;
20
- export declare class OpenCodeAdapter implements HookAdapter {
21
+ export declare class OpenCodeAdapter extends BaseAdapter implements HookAdapter {
21
22
  get name(): string;
22
23
  readonly paradigm: HookParadigm;
23
24
  private settingsPath?;
@@ -35,8 +36,6 @@ export declare class OpenCodeAdapter implements HookAdapter {
35
36
  getSettingsPath(): string;
36
37
  private paths;
37
38
  getSessionDir(): string;
38
- getSessionDBPath(projectDir: string): string;
39
- getSessionEventsPath(projectDir: string): string;
40
39
  generateHookConfig(_pluginRoot: string): HookRegistration;
41
40
  readSettings(): Record<string, unknown> | null;
42
41
  writeSettings(settings: Record<string, unknown>): void;