context-mode 1.0.57 → 1.0.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/README.md +36 -14
- package/build/adapters/codex/index.d.ts +25 -15
- package/build/adapters/codex/index.js +162 -38
- package/build/adapters/cursor/hooks.d.ts +2 -0
- package/build/adapters/cursor/hooks.js +4 -0
- package/build/adapters/cursor/index.d.ts +15 -0
- package/build/adapters/cursor/index.js +48 -0
- package/build/adapters/opencode/index.d.ts +4 -0
- package/build/adapters/opencode/index.js +61 -33
- package/build/cli.js +44 -20
- package/build/db-base.d.ts +7 -6
- package/build/db-base.js +65 -1
- package/build/opencode-plugin.d.ts +1 -1
- package/build/opencode-plugin.js +6 -18
- package/build/store.d.ts +2 -0
- package/build/store.js +38 -5
- package/cli.bundle.mjs +93 -93
- package/configs/codex/hooks.json +25 -0
- package/configs/cursor/hooks.json +5 -0
- package/hooks/session-db.bundle.mjs +2 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +73 -73
- package/skills/context-mode-ops/SKILL.md +3 -1
- package/skills/context-mode-ops/marketing.md +124 -0
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Claude Code plugins by Mert Koseoğlu",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.59"
|
|
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.
|
|
16
|
+
"version": "1.0.59",
|
|
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.
|
|
3
|
+
"version": "1.0.59",
|
|
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.
|
|
6
|
+
"version": "1.0.59",
|
|
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.
|
|
3
|
+
"version": "1.0.59",
|
|
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
|
|
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> —
|
|
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,21 @@ Full documentation: [`docs/adapters/openclaw.md`](docs/adapters/openclaw.md)
|
|
|
407
412
|
command = "context-mode"
|
|
408
413
|
```
|
|
409
414
|
|
|
410
|
-
3.
|
|
415
|
+
3. Add hooks for routing enforcement and session tracking. Create `~/.codex/hooks.json`:
|
|
416
|
+
|
|
417
|
+
```json
|
|
418
|
+
{
|
|
419
|
+
"hooks": {
|
|
420
|
+
"PreToolUse": [{ "hooks": [{ "type": "command", "command": "context-mode hook codex pretooluse" }] }],
|
|
421
|
+
"PostToolUse": [{ "hooks": [{ "type": "command", "command": "context-mode hook codex posttooluse" }] }],
|
|
422
|
+
"SessionStart": [{ "hooks": [{ "type": "command", "command": "context-mode hook codex sessionstart" }] }]
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
`PreToolUse` enforces sandbox routing (blocks dangerous commands, redirects to MCP tools). `PostToolUse` captures session events. `SessionStart` restores state after compaction.
|
|
428
|
+
|
|
429
|
+
4. Copy routing instructions (recommended even with hooks for full routing awareness):
|
|
411
430
|
|
|
412
431
|
```bash
|
|
413
432
|
cp node_modules/context-mode/configs/codex/AGENTS.md ./AGENTS.md
|
|
@@ -415,11 +434,11 @@ Full documentation: [`docs/adapters/openclaw.md`](docs/adapters/openclaw.md)
|
|
|
415
434
|
|
|
416
435
|
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
436
|
|
|
418
|
-
|
|
437
|
+
5. Restart Codex CLI.
|
|
419
438
|
|
|
420
439
|
**Verify:** Start a session and type `ctx stats`. Context-mode tools should appear and respond.
|
|
421
440
|
|
|
422
|
-
**Routing:**
|
|
441
|
+
**Routing:** Hooks enforce routing programmatically via PreToolUse. PostToolUse tracks session events. SessionStart restores state. The optional AGENTS.md file provides routing instructions for model awareness. 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
442
|
|
|
424
443
|
</details>
|
|
425
444
|
|
|
@@ -581,19 +600,21 @@ Full configs: [`configs/kiro/mcp.json`](configs/kiro/mcp.json) | [`configs/kiro/
|
|
|
581
600
|
npm run build
|
|
582
601
|
```
|
|
583
602
|
|
|
584
|
-
2. Add to `~/.pi/
|
|
603
|
+
2. Add to `~/.pi/agent/mcp.json` (or `.pi/mcp.json` for project-level):
|
|
585
604
|
|
|
586
605
|
```json
|
|
587
606
|
{
|
|
588
607
|
"mcpServers": {
|
|
589
608
|
"context-mode": {
|
|
590
609
|
"command": "node",
|
|
591
|
-
"args": ["
|
|
610
|
+
"args": ["/home/youruser/.pi/extensions/context-mode/node_modules/context-mode/start.mjs"]
|
|
592
611
|
}
|
|
593
612
|
}
|
|
594
613
|
}
|
|
595
614
|
```
|
|
596
615
|
|
|
616
|
+
> **Note:** JSON does not expand `~`. Replace `/home/youruser` with your actual home directory (run `echo $HOME` to find it).
|
|
617
|
+
|
|
597
618
|
3. Restart Pi.
|
|
598
619
|
|
|
599
620
|
**Verify:** In a Pi session, type `ctx stats`. Context-mode tools should appear and respond.
|
|
@@ -718,13 +739,14 @@ Session continuity requires 4 hooks working together:
|
|
|
718
739
|
|
|
719
740
|
| Hook | Role | Claude Code | Gemini CLI | VS Code Copilot | Cursor | OpenCode | KiloCode | OpenClaw | Codex CLI | Antigravity | Kiro | Zed | Pi |
|
|
720
741
|
|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
|
721
|
-
| **
|
|
742
|
+
| **PreToolUse** | Enforces sandbox routing before tool execution | Yes | -- | -- | Yes | -- | -- | -- | Yes | -- | Yes | -- | ✓ (via tool_call event) |
|
|
743
|
+
| **PostToolUse** | Captures events after each tool call | Yes | Yes | Yes | Yes | Plugin | Plugin | Plugin | Yes | -- | Yes | -- | ✓ (via tool_result event) |
|
|
722
744
|
| **UserPromptSubmit** | Captures user decisions and corrections | Yes | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
|
|
723
745
|
| **PreCompact** | Builds snapshot before compaction | Yes | Yes | Yes | -- | Plugin | Plugin | Plugin | -- | -- | -- | -- | ✓ (via session_before_compact) |
|
|
724
|
-
| **SessionStart** | Restores state after compaction or resume | Yes | Yes | Yes | -- | -- | -- | Plugin |
|
|
725
|
-
| | **Session completeness** | **Full** | **High** | **High** | **Partial** | **High** | **High** | **High** |
|
|
746
|
+
| **SessionStart** | Restores state after compaction or resume | Yes | Yes | Yes | -- | -- | -- | Plugin | Yes | -- | -- | -- | ✓ (via session_start event) |
|
|
747
|
+
| | **Session completeness** | **Full** | **High** | **High** | **Partial** | **High** | **High** | **High** | **Partial** | **--** | **Partial** | **--** | **High** |
|
|
726
748
|
|
|
727
|
-
> **Note:** Full session continuity (capture + snapshot + restore) works on **Claude Code**, **Gemini CLI**, and **VS Code Copilot**. **OpenCode** provides **high** session continuity: it captures tool events and injects compaction snapshots via the plugin, but SessionStart is not yet available ([#14808](https://github.com/sst/opencode/issues/14808)), so startup/resume restore is not supported. **KiloCode** shares the same plugin architecture as OpenCode via the OpenCodeAdapter, so its continuity level depends on KiloCode's SessionStart support. **Cursor** captures tool events via `preToolUse`/`postToolUse`, but `sessionStart` is currently rejected by Cursor's validator ([forum report](https://forum.cursor.com/t/unknown-hook-type-sessionstart/149566)), so session restore after compaction is not available yet. **OpenClaw** uses native gateway plugin hooks (`api.on()`) for full session continuity. **Pi Coding Agent** provides high session continuity via extension hooks (`tool_call`, `tool_result`, `session_start`, `session_before_compact`). **Codex CLI
|
|
749
|
+
> **Note:** Full session continuity (capture + snapshot + restore) works on **Claude Code**, **Gemini CLI**, and **VS Code Copilot**. **OpenCode** provides **high** session continuity: it captures tool events and injects compaction snapshots via the plugin, but SessionStart is not yet available ([#14808](https://github.com/sst/opencode/issues/14808)), so startup/resume restore is not supported. **KiloCode** shares the same plugin architecture as OpenCode via the OpenCodeAdapter, so its continuity level depends on KiloCode's SessionStart support. **Cursor** captures tool events via `preToolUse`/`postToolUse`, but `sessionStart` is currently rejected by Cursor's validator ([forum report](https://forum.cursor.com/t/unknown-hook-type-sessionstart/149566)), so session restore after compaction is not available yet. **OpenClaw** uses native gateway plugin hooks (`api.on()`) for full session continuity. **Pi Coding Agent** provides high session continuity via extension hooks (`tool_call`, `tool_result`, `session_start`, `session_before_compact`). **Codex CLI** provides hook-based session tracking via PreToolUse/PostToolUse/SessionStart, using the same JSON stdin/stdout protocol as Claude Code. **Antigravity**, **Kiro**, and **Zed** have no hook support in the current release, so session tracking is not available.
|
|
728
750
|
|
|
729
751
|
<details>
|
|
730
752
|
<summary><strong>What gets captured</strong></summary>
|
|
@@ -807,7 +829,7 @@ Detailed event data is also indexed into FTS5 for on-demand retrieval via `searc
|
|
|
807
829
|
|
|
808
830
|
**OpenClaw / Pi Agent** — High coverage. All tool lifecycle hooks (`after_tool_call`, `before_compaction`, `session_start`) fire via the native gateway plugin. User decisions aren't captured but file edits, git ops, errors, and tasks are fully tracked. Falls back to DB snapshot reconstruction if compaction hooks fail on older gateway versions. See [`docs/adapters/openclaw.md`](docs/adapters/openclaw.md).
|
|
809
831
|
|
|
810
|
-
**Codex CLI** —
|
|
832
|
+
**Codex CLI** — Hook-based session tracking. PreToolUse enforces routing, PostToolUse captures events, SessionStart restores state after compaction. Same wire protocol as Claude Code. PreCompact and UserPromptSubmit are not yet available, so compaction snapshots rely on DB reconstruction.
|
|
811
833
|
|
|
812
834
|
**Antigravity** — No session support. Same as Codex CLI — no hooks, no event capture. Requires manually copying `GEMINI.md` to your project root. Auto-detected via MCP protocol handshake (`clientInfo.name`).
|
|
813
835
|
|
|
@@ -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
|
|
4
|
+
* Implements HookAdapter for Codex CLI's JSON stdin/stdout hook paradigm.
|
|
5
5
|
*
|
|
6
6
|
* Codex CLI hook specifics:
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
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(
|
|
20
|
-
parsePostToolUseInput(
|
|
21
|
-
parsePreCompactInput(
|
|
22
|
-
parseSessionStartInput(
|
|
23
|
-
formatPreToolUseResponse(
|
|
24
|
-
formatPostToolUseResponse(
|
|
25
|
-
formatPreCompactResponse(
|
|
26
|
-
formatSessionStartResponse(
|
|
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(
|
|
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
|
|
4
|
+
* Implements HookAdapter for Codex CLI's JSON stdin/stdout hook paradigm.
|
|
5
5
|
*
|
|
6
6
|
* Codex CLI hook specifics:
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
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 = "
|
|
29
|
+
paradigm = "json-stdio";
|
|
25
30
|
capabilities = {
|
|
26
|
-
preToolUse:
|
|
27
|
-
postToolUse:
|
|
31
|
+
preToolUse: true,
|
|
32
|
+
postToolUse: true,
|
|
28
33
|
preCompact: false,
|
|
29
|
-
sessionStart:
|
|
34
|
+
sessionStart: true,
|
|
30
35
|
canModifyArgs: false,
|
|
31
36
|
canModifyOutput: false,
|
|
32
|
-
canInjectSessionContext:
|
|
37
|
+
canInjectSessionContext: true,
|
|
33
38
|
};
|
|
34
39
|
// ── Input parsing ──────────────────────────────────────
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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(
|
|
41
|
-
|
|
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(
|
|
44
|
-
|
|
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(
|
|
47
|
-
|
|
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
|
|
51
|
-
|
|
52
|
-
|
|
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(
|
|
55
|
-
|
|
115
|
+
formatPostToolUseResponse(response) {
|
|
116
|
+
if (response.additionalContext) {
|
|
117
|
+
return {
|
|
118
|
+
hookSpecificOutput: {
|
|
119
|
+
additionalContext: response.additionalContext,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return {};
|
|
56
124
|
}
|
|
57
|
-
formatPreCompactResponse(
|
|
58
|
-
|
|
125
|
+
formatPreCompactResponse(response) {
|
|
126
|
+
if (response.context) {
|
|
127
|
+
return {
|
|
128
|
+
hookSpecificOutput: {
|
|
129
|
+
additionalContext: response.context,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return {};
|
|
59
134
|
}
|
|
60
|
-
formatSessionStartResponse(
|
|
61
|
-
|
|
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(
|
|
87
|
-
|
|
88
|
-
|
|
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: "
|
|
114
|
-
message: "Codex CLI
|
|
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
|
|
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
|
-
//
|
|
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.
|