context-mode 1.0.57 → 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.
- 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 +29 -9
- 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/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.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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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,20 @@ Full documentation: [`docs/adapters/openclaw.md`](docs/adapters/openclaw.md)
|
|
|
407
412
|
command = "context-mode"
|
|
408
413
|
```
|
|
409
414
|
|
|
410
|
-
3.
|
|
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
|
-
|
|
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:**
|
|
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/
|
|
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": ["
|
|
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
|
|
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.
|