context-mode 1.0.56 → 1.0.58

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.
@@ -6,14 +6,14 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Claude Code plugins by Mert Koseoğlu",
9
- "version": "1.0.56"
9
+ "version": "1.0.58"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "context-mode",
14
14
  "source": "./",
15
15
  "description": "Claude Code MCP plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
16
- "version": "1.0.56",
16
+ "version": "1.0.58",
17
17
  "author": {
18
18
  "name": "Mert Koseoğlu"
19
19
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-mode",
3
- "version": "1.0.56",
3
+ "version": "1.0.58",
4
4
  "description": "MCP server that saves 98% of your context window with session continuity. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and automatic state restore across compactions.",
5
5
  "author": {
6
6
  "name": "Mert Koseoğlu",
@@ -3,7 +3,7 @@
3
3
  "name": "Context Mode",
4
4
  "kind": "tool",
5
5
  "description": "OpenClaw plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
6
- "version": "1.0.56",
6
+ "version": "1.0.58",
7
7
  "sandbox": {
8
8
  "mode": "permissive",
9
9
  "filesystem_access": "full",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-mode",
3
- "version": "1.0.56",
3
+ "version": "1.0.58",
4
4
  "description": "OpenClaw plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
5
5
  "author": {
6
6
  "name": "Mert Koseoğlu",
package/README.md CHANGED
@@ -188,7 +188,7 @@ Full hook config including PreCompact: [`configs/vscode-copilot/hooks.json`](con
188
188
  </details>
189
189
 
190
190
  <details>
191
- <summary><strong>Cursor</strong> — hooks without SessionStart</summary>
191
+ <summary><strong>Cursor</strong> — hooks with stop support</summary>
192
192
 
193
193
  **Prerequisites:** Node.js 18+, Cursor with agent mode.
194
194
 
@@ -228,12 +228,17 @@ Full hook config including PreCompact: [`configs/vscode-copilot/hooks.json`](con
228
228
  {
229
229
  "command": "context-mode hook cursor posttooluse"
230
230
  }
231
+ ],
232
+ "stop": [
233
+ {
234
+ "command": "context-mode hook cursor stop"
235
+ }
231
236
  ]
232
237
  }
233
238
  }
234
239
  ```
235
240
 
236
- The `preToolUse` matcher is optional — without it, the hook fires on all tools.
241
+ The `preToolUse` matcher is optional — without it, the hook fires on all tools. The `stop` hook fires when the agent turn ends and can send a followup message to continue the loop. `afterAgentResponse` is also available (fire-and-forget, receives full response text).
237
242
 
238
243
  4. Copy the routing rules file. Cursor lacks a SessionStart hook, so the model needs a rules file for routing awareness:
239
244
 
@@ -246,7 +251,7 @@ Full hook config including PreCompact: [`configs/vscode-copilot/hooks.json`](con
246
251
 
247
252
  **Verify:** Open Cursor Settings > MCP and confirm "context-mode" shows as connected. In agent chat, type `ctx stats`.
248
253
 
249
- **Routing:** Hooks enforce routing programmatically via `preToolUse`/`postToolUse`. The `.cursor/rules/context-mode.mdc` file provides routing instructions at session start since Cursor's `sessionStart` hook is currently rejected by their validator ([forum report](https://forum.cursor.com/t/unknown-hook-type-sessionstart/149566)). Project `.cursor/hooks.json` overrides `~/.cursor/hooks.json`.
254
+ **Routing:** Hooks enforce routing programmatically via `preToolUse`/`postToolUse`/`stop`. The `.cursor/rules/context-mode.mdc` file provides routing instructions at session start since Cursor's `sessionStart` hook is currently rejected by their validator ([forum report](https://forum.cursor.com/t/unknown-hook-type-sessionstart/149566)). Project `.cursor/hooks.json` overrides `~/.cursor/hooks.json`.
250
255
 
251
256
  Full configs: [`configs/cursor/hooks.json`](configs/cursor/hooks.json) | [`configs/cursor/mcp.json`](configs/cursor/mcp.json) | [`configs/cursor/context-mode.mdc`](configs/cursor/context-mode.mdc)
252
257
 
@@ -388,7 +393,7 @@ Full documentation: [`docs/adapters/openclaw.md`](docs/adapters/openclaw.md)
388
393
  </details>
389
394
 
390
395
  <details>
391
- <summary><strong>Codex CLI</strong> — MCP-only, no hooks</summary>
396
+ <summary><strong>Codex CLI</strong> — hooks + MCP</summary>
392
397
 
393
398
  **Prerequisites:** Node.js 18+, Codex CLI installed.
394
399
 
@@ -407,7 +412,20 @@ Full documentation: [`docs/adapters/openclaw.md`](docs/adapters/openclaw.md)
407
412
  command = "context-mode"
408
413
  ```
409
414
 
410
- 3. Copy routing instructions (Codex CLI has no hook support):
415
+ 3. *(Optional)* Add hooks for session tracking. Create `~/.codex/hooks.json`:
416
+
417
+ ```json
418
+ {
419
+ "hooks": {
420
+ "PostToolUse": [{ "hooks": [{ "type": "command", "command": "context-mode hook codex posttooluse" }] }],
421
+ "SessionStart": [{ "hooks": [{ "type": "command", "command": "context-mode hook codex sessionstart" }] }]
422
+ }
423
+ }
424
+ ```
425
+
426
+ Hooks enable session continuity and event tracking. Without hooks, only MCP tools are available.
427
+
428
+ 4. Copy routing instructions (recommended even with hooks for full routing awareness):
411
429
 
412
430
  ```bash
413
431
  cp node_modules/context-mode/configs/codex/AGENTS.md ./AGENTS.md
@@ -415,11 +433,11 @@ Full documentation: [`docs/adapters/openclaw.md`](docs/adapters/openclaw.md)
415
433
 
416
434
  For global use: `cp node_modules/context-mode/configs/codex/AGENTS.md ~/.codex/AGENTS.md`. Global applies to all projects. If both exist, Codex CLI merges them.
417
435
 
418
- 4. Restart Codex CLI.
436
+ 5. Restart Codex CLI.
419
437
 
420
438
  **Verify:** Start a session and type `ctx stats`. Context-mode tools should appear and respond.
421
439
 
422
- **Routing:** Manual. The `AGENTS.md` file is the only enforcement method (~60% compliance). There is no programmatic interception the model can run raw `curl`, read large files, or bypass sandbox tools at any time. Hook support PRs [#2904](https://github.com/openai/codex/pull/2904) and [#9796](https://github.com/openai/codex/pull/9796) were closed without merge.
440
+ **Routing:** With hooks, SessionStart injects routing instructions and PostToolUse tracks events. Without hooks, the `AGENTS.md` file is the only enforcement method (~60% compliance). Codex CLI's hook system uses the same JSON stdin/stdout wire protocol as Claude Code but does not support arg or output modification.
423
441
 
424
442
  </details>
425
443
 
@@ -581,19 +599,21 @@ Full configs: [`configs/kiro/mcp.json`](configs/kiro/mcp.json) | [`configs/kiro/
581
599
  npm run build
582
600
  ```
583
601
 
584
- 2. Add to `~/.pi/settings/mcp.json` (or `.pi/settings/mcp.json` for project-level):
602
+ 2. Add to `~/.pi/agent/mcp.json` (or `.pi/mcp.json` for project-level):
585
603
 
586
604
  ```json
587
605
  {
588
606
  "mcpServers": {
589
607
  "context-mode": {
590
608
  "command": "node",
591
- "args": ["~/.pi/extensions/context-mode/node_modules/context-mode/start.mjs"]
609
+ "args": ["/home/youruser/.pi/extensions/context-mode/node_modules/context-mode/start.mjs"]
592
610
  }
593
611
  }
594
612
  }
595
613
  ```
596
614
 
615
+ > **Note:** JSON does not expand `~`. Replace `/home/youruser` with your actual home directory (run `echo $HOME` to find it).
616
+
597
617
  3. Restart Pi.
598
618
 
599
619
  **Verify:** In a Pi session, type `ctx stats`. Context-mode tools should appear and respond.
@@ -1,14 +1,19 @@
1
1
  /**
2
- * adapters/codex — Codex CLI platform adapter.
2
+ * adapters/codex — Codex CLI (codex-rs) platform adapter.
3
3
  *
4
- * Implements HookAdapter for Codex CLI's MCP-only paradigm.
4
+ * Implements HookAdapter for Codex CLI's JSON stdin/stdout hook paradigm.
5
5
  *
6
6
  * Codex CLI hook specifics:
7
- * - NO hook support (PRs #2904, #9796 were closed without merge)
8
- * - Only "hook": notify config for agent-turn-complete (very limited)
9
- * - Config: ~/.codex/config.toml (TOML format, not JSON)
7
+ * - I/O: JSON on stdin, JSON on stdout (same wire protocol as Claude Code)
8
+ * - 5 hook events: PreToolUse, PostToolUse, SessionStart, PreCompact, Stop
9
+ * - Arg modification: NOT supported (no updatedInput field)
10
+ * - Output modification: NOT supported (no updatedMCPToolOutput field)
11
+ * - Blocking: `hookSpecificOutput.permissionDecision: "deny"` in response
12
+ * - Context injection: `hookSpecificOutput.additionalContext` in response
13
+ * - Session ID: session_id field from hook input
14
+ * - Project dir: cwd field from hook input
15
+ * - Config: ~/.codex/config.toml (TOML format)
10
16
  * - MCP: full support via [mcp_servers] in config.toml
11
- * - All capabilities are false — MCP is the only integration path
12
17
  * - Session dir: ~/.codex/context-mode/sessions/
13
18
  */
14
19
  import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
@@ -16,19 +21,19 @@ export declare class CodexAdapter implements HookAdapter {
16
21
  readonly name = "Codex CLI";
17
22
  readonly paradigm: HookParadigm;
18
23
  readonly capabilities: PlatformCapabilities;
19
- parsePreToolUseInput(_raw: unknown): PreToolUseEvent;
20
- parsePostToolUseInput(_raw: unknown): PostToolUseEvent;
21
- parsePreCompactInput(_raw: unknown): PreCompactEvent;
22
- parseSessionStartInput(_raw: unknown): SessionStartEvent;
23
- formatPreToolUseResponse(_response: PreToolUseResponse): unknown;
24
- formatPostToolUseResponse(_response: PostToolUseResponse): unknown;
25
- formatPreCompactResponse(_response: PreCompactResponse): unknown;
26
- formatSessionStartResponse(_response: SessionStartResponse): unknown;
24
+ parsePreToolUseInput(raw: unknown): PreToolUseEvent;
25
+ parsePostToolUseInput(raw: unknown): PostToolUseEvent;
26
+ parsePreCompactInput(raw: unknown): PreCompactEvent;
27
+ parseSessionStartInput(raw: unknown): SessionStartEvent;
28
+ formatPreToolUseResponse(response: PreToolUseResponse): unknown;
29
+ formatPostToolUseResponse(response: PostToolUseResponse): unknown;
30
+ formatPreCompactResponse(response: PreCompactResponse): unknown;
31
+ formatSessionStartResponse(response: SessionStartResponse): unknown;
27
32
  getSettingsPath(): string;
28
33
  getSessionDir(): string;
29
34
  getSessionDBPath(projectDir: string): string;
30
35
  getSessionEventsPath(projectDir: string): string;
31
- generateHookConfig(_pluginRoot: string): HookRegistration;
36
+ generateHookConfig(pluginRoot: string): HookRegistration;
32
37
  readSettings(): Record<string, unknown> | null;
33
38
  writeSettings(_settings: Record<string, unknown>): void;
34
39
  validateHooks(_pluginRoot: string): DiagnosticResult[];
@@ -39,4 +44,9 @@ export declare class CodexAdapter implements HookAdapter {
39
44
  setHookPermissions(_pluginRoot: string): string[];
40
45
  updatePluginRegistry(_pluginRoot: string, _version: string): void;
41
46
  getRoutingInstructions(): string;
47
+ /**
48
+ * Extract session ID from Codex CLI hook input.
49
+ * Priority: session_id field > fallback to ppid.
50
+ */
51
+ private extractSessionId;
42
52
  }
@@ -1,14 +1,19 @@
1
1
  /**
2
- * adapters/codex — Codex CLI platform adapter.
2
+ * adapters/codex — Codex CLI (codex-rs) platform adapter.
3
3
  *
4
- * Implements HookAdapter for Codex CLI's MCP-only paradigm.
4
+ * Implements HookAdapter for Codex CLI's JSON stdin/stdout hook paradigm.
5
5
  *
6
6
  * Codex CLI hook specifics:
7
- * - NO hook support (PRs #2904, #9796 were closed without merge)
8
- * - Only "hook": notify config for agent-turn-complete (very limited)
9
- * - Config: ~/.codex/config.toml (TOML format, not JSON)
7
+ * - I/O: JSON on stdin, JSON on stdout (same wire protocol as Claude Code)
8
+ * - 5 hook events: PreToolUse, PostToolUse, SessionStart, PreCompact, Stop
9
+ * - Arg modification: NOT supported (no updatedInput field)
10
+ * - Output modification: NOT supported (no updatedMCPToolOutput field)
11
+ * - Blocking: `hookSpecificOutput.permissionDecision: "deny"` in response
12
+ * - Context injection: `hookSpecificOutput.additionalContext` in response
13
+ * - Session ID: session_id field from hook input
14
+ * - Project dir: cwd field from hook input
15
+ * - Config: ~/.codex/config.toml (TOML format)
10
16
  * - MCP: full support via [mcp_servers] in config.toml
11
- * - All capabilities are false — MCP is the only integration path
12
17
  * - Session dir: ~/.codex/context-mode/sessions/
13
18
  */
14
19
  import { createHash } from "node:crypto";
@@ -21,44 +26,121 @@ import { homedir } from "node:os";
21
26
  // ─────────────────────────────────────────────────────────
22
27
  export class CodexAdapter {
23
28
  name = "Codex CLI";
24
- paradigm = "mcp-only";
29
+ paradigm = "json-stdio";
25
30
  capabilities = {
26
- preToolUse: false,
27
- postToolUse: false,
31
+ preToolUse: true,
32
+ postToolUse: true,
28
33
  preCompact: false,
29
- sessionStart: false,
34
+ sessionStart: true,
30
35
  canModifyArgs: false,
31
36
  canModifyOutput: false,
32
- canInjectSessionContext: false,
37
+ canInjectSessionContext: true,
33
38
  };
34
39
  // ── Input parsing ──────────────────────────────────────
35
- // Codex CLI does not support hooks. These methods exist to satisfy the
36
- // interface contract but will throw if called.
37
- parsePreToolUseInput(_raw) {
38
- throw new Error("Codex CLI does not support hooks");
40
+ parsePreToolUseInput(raw) {
41
+ const input = raw;
42
+ return {
43
+ toolName: input.tool_name ?? "",
44
+ toolInput: input.tool_input ?? {},
45
+ sessionId: this.extractSessionId(input),
46
+ projectDir: input.cwd,
47
+ raw,
48
+ };
39
49
  }
40
- parsePostToolUseInput(_raw) {
41
- throw new Error("Codex CLI does not support hooks");
50
+ parsePostToolUseInput(raw) {
51
+ const input = raw;
52
+ return {
53
+ toolName: input.tool_name ?? "",
54
+ toolInput: input.tool_input ?? {},
55
+ toolOutput: input.tool_response,
56
+ sessionId: this.extractSessionId(input),
57
+ projectDir: input.cwd,
58
+ raw,
59
+ };
42
60
  }
43
- parsePreCompactInput(_raw) {
44
- throw new Error("Codex CLI does not support hooks");
61
+ parsePreCompactInput(raw) {
62
+ const input = raw;
63
+ return {
64
+ sessionId: this.extractSessionId(input),
65
+ projectDir: input.cwd,
66
+ raw,
67
+ };
45
68
  }
46
- parseSessionStartInput(_raw) {
47
- throw new Error("Codex CLI does not support hooks");
69
+ parseSessionStartInput(raw) {
70
+ const input = raw;
71
+ const rawSource = input.source ?? "startup";
72
+ let source;
73
+ switch (rawSource) {
74
+ case "compact":
75
+ source = "compact";
76
+ break;
77
+ case "resume":
78
+ source = "resume";
79
+ break;
80
+ case "clear":
81
+ source = "clear";
82
+ break;
83
+ default:
84
+ source = "startup";
85
+ }
86
+ return {
87
+ sessionId: this.extractSessionId(input),
88
+ source,
89
+ projectDir: input.cwd,
90
+ raw,
91
+ };
48
92
  }
49
93
  // ── Response formatting ────────────────────────────────
50
- // Codex CLI does not support hooks. Return undefined for all responses.
51
- formatPreToolUseResponse(_response) {
52
- return undefined;
94
+ // Codex CLI uses hookSpecificOutput wrapper for all hook responses.
95
+ // Unlike Claude Code, Codex does NOT support updatedInput or updatedMCPToolOutput.
96
+ formatPreToolUseResponse(response) {
97
+ if (response.decision === "deny") {
98
+ return {
99
+ hookSpecificOutput: {
100
+ permissionDecision: "deny",
101
+ permissionDecisionReason: response.reason ?? "Blocked by context-mode hook",
102
+ },
103
+ };
104
+ }
105
+ if (response.decision === "context" && response.additionalContext) {
106
+ return {
107
+ hookSpecificOutput: {
108
+ additionalContext: response.additionalContext,
109
+ },
110
+ };
111
+ }
112
+ // "allow" — return empty object for passthrough
113
+ return {};
53
114
  }
54
- formatPostToolUseResponse(_response) {
55
- return undefined;
115
+ formatPostToolUseResponse(response) {
116
+ if (response.additionalContext) {
117
+ return {
118
+ hookSpecificOutput: {
119
+ additionalContext: response.additionalContext,
120
+ },
121
+ };
122
+ }
123
+ return {};
56
124
  }
57
- formatPreCompactResponse(_response) {
58
- return undefined;
125
+ formatPreCompactResponse(response) {
126
+ if (response.context) {
127
+ return {
128
+ hookSpecificOutput: {
129
+ additionalContext: response.context,
130
+ },
131
+ };
132
+ }
133
+ return {};
59
134
  }
60
- formatSessionStartResponse(_response) {
61
- return undefined;
135
+ formatSessionStartResponse(response) {
136
+ if (response.context) {
137
+ return {
138
+ hookSpecificOutput: {
139
+ additionalContext: response.context,
140
+ },
141
+ };
142
+ }
143
+ return {};
62
144
  }
63
145
  // ── Configuration ──────────────────────────────────────
64
146
  getSettingsPath() {
@@ -83,9 +165,42 @@ export class CodexAdapter {
83
165
  .slice(0, 16);
84
166
  return join(this.getSessionDir(), `${hash}-events.md`);
85
167
  }
86
- generateHookConfig(_pluginRoot) {
87
- // Codex CLI does not support hooks — return empty registration
88
- return {};
168
+ generateHookConfig(pluginRoot) {
169
+ return {
170
+ PreToolUse: [
171
+ {
172
+ matcher: "",
173
+ hooks: [
174
+ {
175
+ type: "command",
176
+ command: `node ${pluginRoot}/hooks/pretooluse.mjs`,
177
+ },
178
+ ],
179
+ },
180
+ ],
181
+ PostToolUse: [
182
+ {
183
+ matcher: "",
184
+ hooks: [
185
+ {
186
+ type: "command",
187
+ command: `node ${pluginRoot}/hooks/posttooluse.mjs`,
188
+ },
189
+ ],
190
+ },
191
+ ],
192
+ SessionStart: [
193
+ {
194
+ matcher: "",
195
+ hooks: [
196
+ {
197
+ type: "command",
198
+ command: `node ${pluginRoot}/hooks/sessionstart.mjs`,
199
+ },
200
+ ],
201
+ },
202
+ ],
203
+ };
89
204
  }
90
205
  readSettings() {
91
206
  // Codex CLI uses TOML format. Full TOML parsing is complex;
@@ -110,9 +225,8 @@ export class CodexAdapter {
110
225
  return [
111
226
  {
112
227
  check: "Hook support",
113
- status: "warn",
114
- message: "Codex CLI does not support hooks (PRs #2904, #9796 closed without merge). " +
115
- "Only MCP integration is available.",
228
+ status: "pass",
229
+ message: "Codex CLI supports hooks (PreToolUse, PostToolUse, SessionStart) via JSON stdin/stdout.",
116
230
  },
117
231
  ];
118
232
  }
@@ -158,7 +272,7 @@ export class CodexAdapter {
158
272
  }
159
273
  // ── Upgrade ────────────────────────────────────────────
160
274
  configureAllHooks(_pluginRoot) {
161
- // Codex CLI does not support hooks nothing to configure
275
+ // Codex CLI hook configuration is done via hooks.json, not config.toml
162
276
  return [];
163
277
  }
164
278
  backupSettings() {
@@ -174,7 +288,7 @@ export class CodexAdapter {
174
288
  }
175
289
  }
176
290
  setHookPermissions(_pluginRoot) {
177
- // No hook scripts for Codex CLI
291
+ // Hook permissions are set during plugin install
178
292
  return [];
179
293
  }
180
294
  updatePluginRegistry(_pluginRoot, _version) {
@@ -190,4 +304,14 @@ export class CodexAdapter {
190
304
  return "# context-mode\n\nUse context-mode MCP tools (execute, execute_file, batch_execute, fetch_and_index, search) instead of bash/cat/curl for data-heavy operations.";
191
305
  }
192
306
  }
307
+ // ── Internal helpers ───────────────────────────────────
308
+ /**
309
+ * Extract session ID from Codex CLI hook input.
310
+ * Priority: session_id field > fallback to ppid.
311
+ */
312
+ extractSessionId(input) {
313
+ if (input.session_id)
314
+ return input.session_id;
315
+ return `pid-${process.ppid}`;
316
+ }
193
317
  }
@@ -10,6 +10,8 @@ export declare const HOOK_TYPES: {
10
10
  readonly PRE_TOOL_USE: "preToolUse";
11
11
  readonly POST_TOOL_USE: "postToolUse";
12
12
  readonly SESSION_START: "sessionStart";
13
+ readonly STOP: "stop";
14
+ readonly AFTER_AGENT_RESPONSE: "afterAgentResponse";
13
15
  };
14
16
  export type HookType = (typeof HOOK_TYPES)[keyof typeof HOOK_TYPES];
15
17
  /** Map of hook types to their script file names. */
@@ -10,12 +10,16 @@ export const HOOK_TYPES = {
10
10
  PRE_TOOL_USE: "preToolUse",
11
11
  POST_TOOL_USE: "postToolUse",
12
12
  SESSION_START: "sessionStart",
13
+ STOP: "stop",
14
+ AFTER_AGENT_RESPONSE: "afterAgentResponse",
13
15
  };
14
16
  /** Map of hook types to their script file names. */
15
17
  export const HOOK_SCRIPTS = {
16
18
  [HOOK_TYPES.PRE_TOOL_USE]: "pretooluse.mjs",
17
19
  [HOOK_TYPES.POST_TOOL_USE]: "posttooluse.mjs",
18
20
  [HOOK_TYPES.SESSION_START]: "sessionstart.mjs",
21
+ [HOOK_TYPES.STOP]: "stop.mjs",
22
+ [HOOK_TYPES.AFTER_AGENT_RESPONSE]: "afteragentresponse.mjs",
19
23
  };
20
24
  /** Canonical Cursor-native matchers for tools context-mode routes proactively. */
21
25
  export const PRE_TOOL_USE_MATCHERS = [
@@ -5,6 +5,13 @@
5
5
  * `.cursor/hooks.json` / `~/.cursor/hooks.json`.
6
6
  */
7
7
  import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, SessionStartResponse, HookRegistration } from "../types.js";
8
+ interface StopEvent {
9
+ sessionId: string;
10
+ status: string;
11
+ loopCount: number;
12
+ generationId?: string;
13
+ transcriptPath?: string;
14
+ }
8
15
  export declare class CursorAdapter implements HookAdapter {
9
16
  readonly name = "Cursor";
10
17
  readonly paradigm: HookParadigm;
@@ -15,6 +22,13 @@ export declare class CursorAdapter implements HookAdapter {
15
22
  formatPreToolUseResponse(response: PreToolUseResponse): unknown;
16
23
  formatPostToolUseResponse(response: PostToolUseResponse): unknown;
17
24
  formatSessionStartResponse(response: SessionStartResponse): unknown;
25
+ parseStopInput(raw: unknown): StopEvent;
26
+ formatStopResponse(response: {
27
+ followupMessage?: string;
28
+ }): Record<string, unknown>;
29
+ parseAfterAgentResponseInput(raw: unknown): {
30
+ text: string;
31
+ };
18
32
  getSettingsPath(): string;
19
33
  getSessionDir(): string;
20
34
  getSessionDBPath(projectDir: string): string;
@@ -36,3 +50,4 @@ export declare class CursorAdapter implements HookAdapter {
36
50
  private hasClaudeCompatibilityHooks;
37
51
  private upsertHookEntry;
38
52
  }
53
+ export {};
@@ -102,6 +102,26 @@ export class CursorAdapter {
102
102
  // the payload is effectively a no-op.
103
103
  return { additional_context: response.context ?? "" };
104
104
  }
105
+ parseStopInput(raw) {
106
+ const input = raw;
107
+ return {
108
+ sessionId: input.conversation_id ?? `pid-${process.ppid}`,
109
+ status: input.status ?? "completed",
110
+ loopCount: input.loop_count ?? 0,
111
+ generationId: input.generation_id,
112
+ transcriptPath: input.transcript_path ?? undefined,
113
+ };
114
+ }
115
+ formatStopResponse(response) {
116
+ if (response.followupMessage) {
117
+ return { followup_message: response.followupMessage };
118
+ }
119
+ return {};
120
+ }
121
+ parseAfterAgentResponseInput(raw) {
122
+ const input = raw;
123
+ return { text: input.text ?? "" };
124
+ }
105
125
  getSettingsPath() {
106
126
  return resolve(".cursor", "hooks.json");
107
127
  }
@@ -151,6 +171,22 @@ export class CursorAdapter {
151
171
  failClosed: false,
152
172
  },
153
173
  ],
174
+ [CURSOR_HOOK_NAMES.STOP]: [
175
+ {
176
+ type: "command",
177
+ command: buildHookCommand(CURSOR_HOOK_NAMES.STOP),
178
+ loop_limit: null,
179
+ failClosed: false,
180
+ },
181
+ ],
182
+ [CURSOR_HOOK_NAMES.AFTER_AGENT_RESPONSE]: [
183
+ {
184
+ type: "command",
185
+ command: buildHookCommand(CURSOR_HOOK_NAMES.AFTER_AGENT_RESPONSE),
186
+ loop_limit: null,
187
+ failClosed: false,
188
+ },
189
+ ],
154
190
  };
155
191
  return hooks;
156
192
  }
@@ -301,6 +337,18 @@ export class CursorAdapter {
301
337
  loop_limit: null,
302
338
  failClosed: false,
303
339
  }, changes);
340
+ this.upsertHookEntry(hooks, CURSOR_HOOK_NAMES.STOP, {
341
+ type: "command",
342
+ command: buildHookCommand(CURSOR_HOOK_NAMES.STOP),
343
+ loop_limit: null,
344
+ failClosed: false,
345
+ }, changes);
346
+ this.upsertHookEntry(hooks, CURSOR_HOOK_NAMES.AFTER_AGENT_RESPONSE, {
347
+ type: "command",
348
+ command: buildHookCommand(CURSOR_HOOK_NAMES.AFTER_AGENT_RESPONSE),
349
+ loop_limit: null,
350
+ failClosed: false,
351
+ }, changes);
304
352
  settings.version = 1;
305
353
  settings.hooks = hooks;
306
354
  this.writeSettings(settings);
@@ -47,6 +47,10 @@ export declare class OpenCodeAdapter implements HookAdapter {
47
47
  backupSettings(): string | null;
48
48
  setHookPermissions(_pluginRoot: string): string[];
49
49
  updatePluginRegistry(_pluginRoot: string, _version: string): void;
50
+ /**
51
+ * Check whether a settings object has the context-mode plugin registered.
52
+ */
53
+ private hasContextModePlugin;
50
54
  /**
51
55
  * Extract session ID from OpenCode hook input.
52
56
  * OpenCode uses camelCase sessionID.