context-mode 1.0.101 → 1.0.104
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 +66 -5
- package/bin/statusline.mjs +321 -0
- package/build/adapters/antigravity/index.d.ts +6 -0
- package/build/adapters/antigravity/index.js +10 -0
- package/build/adapters/base.d.ts +23 -0
- package/build/adapters/base.js +29 -0
- package/build/adapters/codex/index.d.ts +10 -0
- package/build/adapters/codex/index.js +22 -4
- package/build/adapters/cursor/index.d.ts +7 -0
- package/build/adapters/cursor/index.js +11 -0
- package/build/adapters/detect.d.ts +12 -1
- package/build/adapters/detect.js +69 -7
- package/build/adapters/gemini-cli/index.d.ts +8 -1
- package/build/adapters/gemini-cli/index.js +19 -7
- package/build/adapters/jetbrains-copilot/index.d.ts +7 -0
- package/build/adapters/jetbrains-copilot/index.js +12 -0
- package/build/adapters/kiro/index.d.ts +8 -0
- package/build/adapters/kiro/index.js +12 -0
- package/build/adapters/openclaw/index.d.ts +17 -0
- package/build/adapters/openclaw/index.js +29 -4
- package/build/adapters/opencode/index.d.ts +8 -0
- package/build/adapters/opencode/index.js +18 -6
- package/build/adapters/qwen-code/index.d.ts +1 -0
- package/build/adapters/qwen-code/index.js +3 -0
- package/build/adapters/types.d.ts +33 -0
- package/build/adapters/vscode-copilot/index.d.ts +6 -0
- package/build/adapters/vscode-copilot/index.js +10 -0
- package/build/adapters/zed/index.d.ts +1 -0
- package/build/adapters/zed/index.js +3 -0
- package/build/cli.d.ts +15 -0
- package/build/cli.js +62 -16
- package/build/concurrency/runPool.d.ts +36 -0
- package/build/concurrency/runPool.js +51 -0
- package/build/executor.d.ts +11 -1
- package/build/executor.js +59 -16
- package/build/fetch-cache.d.ts +13 -0
- package/build/fetch-cache.js +15 -0
- package/build/lifecycle.d.ts +6 -2
- package/build/lifecycle.js +29 -2
- package/build/opencode-plugin.d.ts +6 -0
- package/build/opencode-plugin.js +60 -1
- package/build/routing-block.d.ts +8 -0
- package/build/routing-block.js +86 -0
- package/build/runtime.d.ts +1 -0
- package/build/runtime.js +54 -3
- package/build/search/auto-memory.d.ts +23 -10
- package/build/search/auto-memory.js +64 -26
- package/build/search/unified.d.ts +3 -0
- package/build/search/unified.js +2 -2
- package/build/server.d.ts +42 -0
- package/build/server.js +693 -164
- package/build/session/analytics.d.ts +49 -1
- package/build/session/analytics.js +278 -16
- package/build/session/db.d.ts +39 -8
- package/build/session/db.js +170 -19
- package/build/session/extract.js +124 -2
- package/build/tool-naming.d.ts +4 -0
- package/build/tool-naming.js +24 -0
- package/cli.bundle.mjs +201 -159
- package/configs/antigravity/GEMINI.md +11 -0
- package/configs/claude-code/CLAUDE.md +11 -0
- package/configs/codex/AGENTS.md +11 -0
- package/configs/cursor/context-mode.mdc +11 -0
- package/configs/gemini-cli/GEMINI.md +11 -0
- package/configs/jetbrains-copilot/copilot-instructions.md +3 -0
- package/configs/kilo/AGENTS.md +11 -0
- package/configs/kiro/KIRO.md +11 -0
- package/configs/openclaw/AGENTS.md +11 -0
- package/configs/opencode/AGENTS.md +11 -0
- package/configs/pi/AGENTS.md +11 -0
- package/configs/qwen-code/QWEN.md +11 -0
- package/configs/vscode-copilot/copilot-instructions.md +3 -0
- package/configs/zed/AGENTS.md +11 -0
- package/hooks/auto-injection.mjs +36 -10
- package/hooks/cache-heal-utils.mjs +231 -0
- package/hooks/codex/sessionstart.mjs +7 -4
- package/hooks/core/routing.mjs +5 -0
- package/hooks/cursor/sessionstart.mjs +7 -4
- package/hooks/formatters/claude-code.mjs +20 -0
- package/hooks/gemini-cli/sessionstart.mjs +7 -2
- package/hooks/jetbrains-copilot/sessionstart.mjs +7 -2
- package/hooks/normalize-hooks.mjs +184 -0
- package/hooks/session-db.bundle.mjs +33 -14
- package/hooks/session-extract.bundle.mjs +2 -2
- package/hooks/session-helpers.mjs +68 -20
- package/hooks/session-loaders.mjs +8 -2
- package/hooks/sessionstart.mjs +8 -2
- package/hooks/vscode-copilot/sessionstart.mjs +7 -2
- package/insight/src/routes/index.tsx +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -1
- package/server.bundle.mjs +164 -125
- package/skills/ctx-insight/SKILL.md +1 -1
- package/start.mjs +63 -3
|
@@ -40,6 +40,17 @@ Use `mcp__context-mode__ctx_execute(language: "shell", code: "grep ...")` in san
|
|
|
40
40
|
4. **WEB**: `mcp__context-mode__ctx_fetch_and_index(url, source)` then `mcp__context-mode__ctx_search(queries)` — raw HTML never enters context.
|
|
41
41
|
5. **INDEX**: `mcp__context-mode__ctx_index(content, source)` — store in FTS5 for later search.
|
|
42
42
|
|
|
43
|
+
## Parallel I/O batches
|
|
44
|
+
|
|
45
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
46
|
+
|
|
47
|
+
- `mcp__context-mode__ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
48
|
+
- `mcp__context-mode__ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
49
|
+
|
|
50
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
51
|
+
|
|
52
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
53
|
+
|
|
43
54
|
## Output
|
|
44
55
|
|
|
45
56
|
Terse like caveman. Technical substance exact. Only fluff die.
|
|
@@ -40,6 +40,17 @@ Use `ctx_execute(language: "shell", code: "grep ...")` in sandbox.
|
|
|
40
40
|
4. **WEB**: `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` — raw HTML never enters context.
|
|
41
41
|
5. **INDEX**: `ctx_index(content, source)` — store in FTS5 for later search.
|
|
42
42
|
|
|
43
|
+
## Parallel I/O batches
|
|
44
|
+
|
|
45
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
46
|
+
|
|
47
|
+
- `ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
48
|
+
- `ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
49
|
+
|
|
50
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
51
|
+
|
|
52
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
53
|
+
|
|
43
54
|
## Subagent routing
|
|
44
55
|
|
|
45
56
|
Routing block auto-injected into subagent prompts. Bash-type subagents upgraded to general-purpose. No manual instruction needed.
|
package/configs/codex/AGENTS.md
CHANGED
|
@@ -41,6 +41,17 @@ Use `ctx_execute(language: "shell", code: "grep ...")` in sandbox.
|
|
|
41
41
|
4. **WEB**: `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` — raw HTML never enters context.
|
|
42
42
|
5. **INDEX**: `ctx_index(content, source)` — store in FTS5 for later search.
|
|
43
43
|
|
|
44
|
+
## Parallel I/O batches
|
|
45
|
+
|
|
46
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
47
|
+
|
|
48
|
+
- `ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
49
|
+
- `ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
50
|
+
|
|
51
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
52
|
+
|
|
53
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
54
|
+
|
|
44
55
|
## Output
|
|
45
56
|
|
|
46
57
|
Terse like caveman. Technical substance exact. Only fluff die.
|
|
@@ -20,6 +20,17 @@ Analyze/count/filter/compare/search/parse/transform data: **write code** via `ct
|
|
|
20
20
|
4. **WEB**: `ctx_fetch_and_index(url)` then `ctx_search(queries)` — never dump raw HTML.
|
|
21
21
|
5. **INDEX**: `ctx_index(content, source)` — store in FTS5 for later search.
|
|
22
22
|
|
|
23
|
+
## Parallel I/O batches
|
|
24
|
+
|
|
25
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
26
|
+
|
|
27
|
+
- `ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
28
|
+
- `ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
29
|
+
|
|
30
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
31
|
+
|
|
32
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
33
|
+
|
|
23
34
|
## Forbidden Actions
|
|
24
35
|
|
|
25
36
|
- DO NOT use Bash for >20 lines output — use `ctx_execute` or `ctx_batch_execute`.
|
|
@@ -40,6 +40,17 @@ Use `mcp__context-mode__ctx_execute(language: "shell", code: "grep ...")` in san
|
|
|
40
40
|
4. **WEB**: `mcp__context-mode__ctx_fetch_and_index(url, source)` then `mcp__context-mode__ctx_search(queries)` — raw HTML never enters context.
|
|
41
41
|
5. **INDEX**: `mcp__context-mode__ctx_index(content, source)` — store in FTS5 for later search.
|
|
42
42
|
|
|
43
|
+
## Parallel I/O batches
|
|
44
|
+
|
|
45
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
46
|
+
|
|
47
|
+
- `mcp__context-mode__ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
48
|
+
- `mcp__context-mode__ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
49
|
+
|
|
50
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
51
|
+
|
|
52
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
53
|
+
|
|
43
54
|
## Output
|
|
44
55
|
|
|
45
56
|
Terse like caveman. Technical substance exact. Only fluff die.
|
|
@@ -40,6 +40,9 @@ Use `ctx_execute(language: "shell", code: "grep ...")` in sandbox.
|
|
|
40
40
|
4. **WEB**: `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` — raw HTML never enters context.
|
|
41
41
|
5. **INDEX**: `ctx_index(content, source)` — store in FTS5 for later search.
|
|
42
42
|
|
|
43
|
+
### Parallel I/O batches
|
|
44
|
+
Pass `concurrency: 4-8` to `ctx_batch_execute` and `ctx_fetch_and_index` for network/API batches. Keep `concurrency: 1` for CPU-bound work (test, build, lint). GitHub gh: cap at 4.
|
|
45
|
+
|
|
43
46
|
## Output
|
|
44
47
|
|
|
45
48
|
Terse like caveman. Technical substance exact. Only fluff die.
|
package/configs/kilo/AGENTS.md
CHANGED
|
@@ -40,6 +40,17 @@ Use `context-mode_ctx_execute(language: "shell", code: "grep ...")` in sandbox.
|
|
|
40
40
|
4. **WEB**: `context-mode_ctx_fetch_and_index(url, source)` then `context-mode_ctx_search(queries)` — raw HTML never enters context.
|
|
41
41
|
5. **INDEX**: `context-mode_ctx_index(content, source)` — store in FTS5 for later search.
|
|
42
42
|
|
|
43
|
+
## Parallel I/O batches
|
|
44
|
+
|
|
45
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
46
|
+
|
|
47
|
+
- `context-mode_ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
48
|
+
- `context-mode_ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
49
|
+
|
|
50
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
51
|
+
|
|
52
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
53
|
+
|
|
43
54
|
## Output
|
|
44
55
|
|
|
45
56
|
Terse like caveman. Technical substance exact. Only fluff die.
|
package/configs/kiro/KIRO.md
CHANGED
|
@@ -40,6 +40,17 @@ Use `@context-mode/ctx_execute(language: "shell", code: "grep ...")` in sandbox.
|
|
|
40
40
|
4. **WEB**: `@context-mode/ctx_fetch_and_index(url, source)` then `@context-mode/ctx_search(queries)` — raw HTML never enters context.
|
|
41
41
|
5. **INDEX**: `@context-mode/ctx_index(content, source)` — store in FTS5 for later search.
|
|
42
42
|
|
|
43
|
+
## Parallel I/O batches
|
|
44
|
+
|
|
45
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
46
|
+
|
|
47
|
+
- `@context-mode/ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
48
|
+
- `@context-mode/ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
49
|
+
|
|
50
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
51
|
+
|
|
52
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
53
|
+
|
|
43
54
|
## Output
|
|
44
55
|
|
|
45
56
|
Terse like caveman. Technical substance exact. Only fluff die.
|
|
@@ -40,6 +40,17 @@ Use `context-mode__ctx_execute(language: "shell", code: "grep ...")` in sandbox.
|
|
|
40
40
|
4. **WEB**: `context-mode__ctx_fetch_and_index(url, source)` then `context-mode__ctx_search(queries)` — raw HTML never enters context.
|
|
41
41
|
5. **INDEX**: `context-mode__ctx_index(content, source)` — store in FTS5 for later search.
|
|
42
42
|
|
|
43
|
+
## Parallel I/O batches
|
|
44
|
+
|
|
45
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
46
|
+
|
|
47
|
+
- `context-mode__ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
48
|
+
- `context-mode__ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
49
|
+
|
|
50
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
51
|
+
|
|
52
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
53
|
+
|
|
43
54
|
## Output
|
|
44
55
|
|
|
45
56
|
Terse like caveman. Technical substance exact. Only fluff die.
|
|
@@ -40,6 +40,17 @@ Use `context-mode_ctx_execute(language: "shell", code: "grep ...")` in sandbox.
|
|
|
40
40
|
4. **WEB**: `context-mode_ctx_fetch_and_index(url, source)` then `context-mode_ctx_search(queries)` — raw HTML never enters context.
|
|
41
41
|
5. **INDEX**: `context-mode_ctx_index(content, source)` — store in FTS5 for later search.
|
|
42
42
|
|
|
43
|
+
## Parallel I/O batches
|
|
44
|
+
|
|
45
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
46
|
+
|
|
47
|
+
- `context-mode_ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
48
|
+
- `context-mode_ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
49
|
+
|
|
50
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
51
|
+
|
|
52
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
53
|
+
|
|
43
54
|
## Output
|
|
44
55
|
|
|
45
56
|
Terse like caveman. Technical substance exact. Only fluff die.
|
package/configs/pi/AGENTS.md
CHANGED
|
@@ -41,6 +41,17 @@ Use `ctx_execute(language: "shell", code: "grep ...")` in sandbox.
|
|
|
41
41
|
4. **WEB**: `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` — raw HTML never enters context.
|
|
42
42
|
5. **INDEX**: `ctx_index(content, source)` — store in FTS5 for later search.
|
|
43
43
|
|
|
44
|
+
## Parallel I/O batches
|
|
45
|
+
|
|
46
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
47
|
+
|
|
48
|
+
- `ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
49
|
+
- `ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
50
|
+
|
|
51
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
52
|
+
|
|
53
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
54
|
+
|
|
44
55
|
## Output
|
|
45
56
|
|
|
46
57
|
Terse like caveman. Technical substance exact. Only fluff die.
|
|
@@ -40,6 +40,17 @@ Use `mcp__context-mode__ctx_execute(language: "shell", code: "grep ...")` in san
|
|
|
40
40
|
4. **WEB**: `mcp__context-mode__ctx_fetch_and_index(url, source)` then `mcp__context-mode__ctx_search(queries)` — raw HTML never enters context.
|
|
41
41
|
5. **INDEX**: `mcp__context-mode__ctx_index(content, source)` — store in FTS5 for later search.
|
|
42
42
|
|
|
43
|
+
## Parallel I/O batches
|
|
44
|
+
|
|
45
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
46
|
+
|
|
47
|
+
- `mcp__context-mode__ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
48
|
+
- `mcp__context-mode__ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
49
|
+
|
|
50
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
51
|
+
|
|
52
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
53
|
+
|
|
43
54
|
## Subagent routing
|
|
44
55
|
|
|
45
56
|
Routing block auto-injected into subagent prompts. Bash-type subagents upgraded to general-purpose. No manual instruction needed.
|
|
@@ -40,6 +40,9 @@ Use `ctx_execute(language: "shell", code: "grep ...")` in sandbox.
|
|
|
40
40
|
4. **WEB**: `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` — raw HTML never enters context.
|
|
41
41
|
5. **INDEX**: `ctx_index(content, source)` — store in FTS5 for later search.
|
|
42
42
|
|
|
43
|
+
### Parallel I/O batches
|
|
44
|
+
Pass `concurrency: 4-8` to `ctx_batch_execute` and `ctx_fetch_and_index` for network/API batches. Keep `concurrency: 1` for CPU-bound work (test, build, lint). GitHub gh: cap at 4.
|
|
45
|
+
|
|
43
46
|
## Output
|
|
44
47
|
|
|
45
48
|
Terse like caveman. Technical substance exact. Only fluff die.
|
package/configs/zed/AGENTS.md
CHANGED
|
@@ -40,6 +40,17 @@ Use `mcp:context-mode:ctx_execute(language: "shell", code: "grep ...")` in sandb
|
|
|
40
40
|
4. **WEB**: `mcp:context-mode:ctx_fetch_and_index(url, source)` then `mcp:context-mode:ctx_search(queries)` — raw HTML never enters context.
|
|
41
41
|
5. **INDEX**: `mcp:context-mode:ctx_index(content, source)` — store in FTS5 for later search.
|
|
42
42
|
|
|
43
|
+
## Parallel I/O batches
|
|
44
|
+
|
|
45
|
+
For multi-URL fetches or multi-API calls, **always** include `concurrency: N` (1-8):
|
|
46
|
+
|
|
47
|
+
- `mcp:context-mode:ctx_batch_execute(commands: [3+ network commands], concurrency: 5)` — gh, curl, dig, docker inspect, multi-region cloud queries
|
|
48
|
+
- `mcp:context-mode:ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)` — multi-URL batch fetch
|
|
49
|
+
|
|
50
|
+
**Use concurrency 4-8** for I/O-bound work (network calls, API queries). **Keep concurrency 1** for CPU-bound (npm test, build, lint) or commands sharing state (ports, lock files, same-repo writes).
|
|
51
|
+
|
|
52
|
+
GitHub API rate-limit: cap at 4 for `gh` calls.
|
|
53
|
+
|
|
43
54
|
## Output
|
|
44
55
|
|
|
45
56
|
Terse like caveman. Technical substance exact. Only fluff die.
|
package/hooks/auto-injection.mjs
CHANGED
|
@@ -28,19 +28,47 @@ export function estimateTokens(text) {
|
|
|
28
28
|
* @returns {string} XML block or empty string
|
|
29
29
|
*/
|
|
30
30
|
export function buildAutoInjection(events) {
|
|
31
|
+
// Single O(N) pass instead of 4× O(N) Array.filter() loops. UserPromptSubmit
|
|
32
|
+
// fires this on every prompt; with N up to 100 events the prior implementation
|
|
33
|
+
// walked the array 4 times per prompt — wasteful on macOS, painful on Windows
|
|
34
|
+
// where V8 cold paths cost more.
|
|
35
|
+
let role;
|
|
36
|
+
const decisionsAll = [];
|
|
37
|
+
const skillsSeen = new Set();
|
|
38
|
+
const skillsOrdered = [];
|
|
39
|
+
let intent;
|
|
40
|
+
for (const e of events) {
|
|
41
|
+
switch (e.category) {
|
|
42
|
+
case "role":
|
|
43
|
+
role = e;
|
|
44
|
+
break;
|
|
45
|
+
case "decision":
|
|
46
|
+
decisionsAll.push(e);
|
|
47
|
+
break;
|
|
48
|
+
case "skill":
|
|
49
|
+
if (!skillsSeen.has(e.data)) {
|
|
50
|
+
skillsSeen.add(e.data);
|
|
51
|
+
skillsOrdered.push(e.data);
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
case "intent":
|
|
55
|
+
intent = e;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
31
60
|
const parts = [];
|
|
32
61
|
let budget = 500; // hard cap in tokens
|
|
33
62
|
|
|
34
63
|
// P1: Role (always first, never truncated from output)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const text = `<behavioral_directive>\n${roleEvent.data.slice(0, 400)}\n</behavioral_directive>`;
|
|
64
|
+
if (role) {
|
|
65
|
+
const text = `<behavioral_directive>\n${role.data.slice(0, 400)}\n</behavioral_directive>`;
|
|
38
66
|
parts.push(text);
|
|
39
67
|
budget -= estimateTokens(text);
|
|
40
68
|
}
|
|
41
69
|
|
|
42
70
|
// P2: Decisions (latest 5)
|
|
43
|
-
const decisions =
|
|
71
|
+
const decisions = decisionsAll.slice(-5);
|
|
44
72
|
if (decisions.length > 0) {
|
|
45
73
|
const lines = decisions.map(d => `- ${d.data.slice(0, 100)}`).join("\n");
|
|
46
74
|
const text = `<rules>\nFollow these decisions:\n${lines}\n</rules>`;
|
|
@@ -58,17 +86,15 @@ export function buildAutoInjection(events) {
|
|
|
58
86
|
}
|
|
59
87
|
|
|
60
88
|
// P3: Skills (unique names, latest 10)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const text = `<active_skills>\nRe-invoke if relevant: ${skills.slice(-10).join(", ")}\nTo reload: call the Skill tool with the skill name.\n</active_skills>`;
|
|
89
|
+
if (skillsOrdered.length > 0 && budget > 50) {
|
|
90
|
+
const text = `<active_skills>\nRe-invoke if relevant: ${skillsOrdered.slice(-10).join(", ")}\nTo reload: call the Skill tool with the skill name.\n</active_skills>`;
|
|
64
91
|
parts.push(text);
|
|
65
92
|
budget -= estimateTokens(text);
|
|
66
93
|
}
|
|
67
94
|
|
|
68
95
|
// P4: Intent (latest)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
parts.push(`<session_mode>${intentEvent.data}</session_mode>`);
|
|
96
|
+
if (intent && budget > 20) {
|
|
97
|
+
parts.push(`<session_mode>${intent.data}</session_mode>`);
|
|
72
98
|
}
|
|
73
99
|
|
|
74
100
|
if (parts.length === 0) return "";
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// cache-heal-utils.mjs — fixes Brew-node-upgrade stale path bug
|
|
2
|
+
//
|
|
3
|
+
// Problem: start.mjs writes process.execPath into ~/.claude/settings.json
|
|
4
|
+
// when registering the cache-heal hook. On Brew, process.execPath returns
|
|
5
|
+
// the *versioned* Cellar snapshot:
|
|
6
|
+
//
|
|
7
|
+
// /opt/homebrew/Cellar/node/25.9.0_2/bin/node
|
|
8
|
+
//
|
|
9
|
+
// When Brew upgrades Node, that path disappears and Claude fails to spawn
|
|
10
|
+
// the hook ("session start" error). The stable symlink is:
|
|
11
|
+
//
|
|
12
|
+
// /opt/homebrew/bin/node
|
|
13
|
+
//
|
|
14
|
+
// Fix is two layered:
|
|
15
|
+
// A) New installs on Unix: write hook script with `#!/usr/bin/env node`
|
|
16
|
+
// shebang + chmod +x, register hook command as the bare script path.
|
|
17
|
+
// `env` resolves node from PATH at runtime — survives any Node upgrade.
|
|
18
|
+
// Windows keeps the explicit-execPath form (no shebang support).
|
|
19
|
+
// B) Self-heal: every MCP boot, scan ~/.claude/settings.json for an
|
|
20
|
+
// existing cache-heal hook command whose leading node path no longer
|
|
21
|
+
// exists. If stale, rewrite using pattern (A).
|
|
22
|
+
//
|
|
23
|
+
// This module is pure (no global state) and side-effect free except for
|
|
24
|
+
// the explicit selfHealCacheHealHook() entry point that touches disk.
|
|
25
|
+
|
|
26
|
+
import {
|
|
27
|
+
existsSync,
|
|
28
|
+
readFileSync,
|
|
29
|
+
writeFileSync,
|
|
30
|
+
chmodSync,
|
|
31
|
+
statSync,
|
|
32
|
+
} from "node:fs";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Convert any path string to forward slashes (matches normalize-hooks style,
|
|
36
|
+
* keeps round-trips on Windows safe).
|
|
37
|
+
*/
|
|
38
|
+
function fwd(p) {
|
|
39
|
+
return String(p).replace(/\\/g, "/");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Extract the leading executable path from a hook command string IF it
|
|
44
|
+
* looks like a node binary. Returns null when the command is shebang-style
|
|
45
|
+
* (bare script path) or when the leading executable isn't node.
|
|
46
|
+
*
|
|
47
|
+
* Accepted shapes:
|
|
48
|
+
* '"/abs/path/to/node" "/abs/path/script.mjs"'
|
|
49
|
+
* '/abs/path/to/node "/abs/path/script.mjs"' (unquoted node)
|
|
50
|
+
*
|
|
51
|
+
* Returns null for:
|
|
52
|
+
* '"/abs/path/script.mjs"' (shebang form)
|
|
53
|
+
* '"/usr/bin/python3" "/abs/path/script.py"' (not node)
|
|
54
|
+
*/
|
|
55
|
+
export function extractNodePath(cmd) {
|
|
56
|
+
if (!cmd || typeof cmd !== "string") return null;
|
|
57
|
+
const trimmed = cmd.trim();
|
|
58
|
+
if (!trimmed) return null;
|
|
59
|
+
|
|
60
|
+
// Match: optional quote, capture path until matching quote or whitespace.
|
|
61
|
+
let leading;
|
|
62
|
+
if (trimmed.startsWith('"')) {
|
|
63
|
+
const end = trimmed.indexOf('"', 1);
|
|
64
|
+
if (end === -1) return null;
|
|
65
|
+
leading = trimmed.slice(1, end);
|
|
66
|
+
} else {
|
|
67
|
+
const end = trimmed.search(/\s/);
|
|
68
|
+
leading = end === -1 ? trimmed : trimmed.slice(0, end);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!leading) return null;
|
|
72
|
+
|
|
73
|
+
// Only treat as a node path if the basename is a node binary.
|
|
74
|
+
// Match: "node", "node.exe" (case-insensitive on Windows-style names).
|
|
75
|
+
const base = leading.split(/[\\/]/).pop() ?? "";
|
|
76
|
+
if (!/^node(\.exe)?$/i.test(base)) return null;
|
|
77
|
+
|
|
78
|
+
return leading;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* True when the hook command's leading node path no longer exists on disk.
|
|
83
|
+
* Returns false for shebang-style commands (no node prefix to validate).
|
|
84
|
+
*/
|
|
85
|
+
export function isStaleNodePath(cmd) {
|
|
86
|
+
const nodePath = extractNodePath(cmd);
|
|
87
|
+
if (!nodePath) return false;
|
|
88
|
+
try {
|
|
89
|
+
return !existsSync(nodePath);
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Build a cross-platform hook command for the cache-heal script.
|
|
97
|
+
*
|
|
98
|
+
* On Unix (anything except win32):
|
|
99
|
+
* - Returns just the script path (double-quoted), e.g. '"/path/to/script.mjs"'
|
|
100
|
+
* - Caller MUST ensure the script has `#!/usr/bin/env node` shebang and
|
|
101
|
+
* chmod 0o755.
|
|
102
|
+
* - `env` resolves node from PATH at runtime → survives Brew/asdf/nvm
|
|
103
|
+
* upgrades.
|
|
104
|
+
*
|
|
105
|
+
* On Windows:
|
|
106
|
+
* - Returns '"<nodePath>" "<scriptPath>"' (forward slashes, both quoted).
|
|
107
|
+
* - Windows has no shebang support; we must invoke node explicitly.
|
|
108
|
+
*/
|
|
109
|
+
export function buildHookCommand({ scriptPath, platform, nodePath }) {
|
|
110
|
+
if (!scriptPath || typeof scriptPath !== "string") {
|
|
111
|
+
throw new TypeError("buildHookCommand: scriptPath is required");
|
|
112
|
+
}
|
|
113
|
+
const safeScript = fwd(scriptPath);
|
|
114
|
+
if (platform === "win32") {
|
|
115
|
+
if (!nodePath || typeof nodePath !== "string") {
|
|
116
|
+
throw new TypeError(
|
|
117
|
+
"buildHookCommand: nodePath is required on win32",
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
const safeNode = fwd(nodePath);
|
|
121
|
+
return `"${safeNode}" "${safeScript}"`;
|
|
122
|
+
}
|
|
123
|
+
return `"${safeScript}"`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Self-heal step for ~/.claude/settings.json.
|
|
128
|
+
*
|
|
129
|
+
* - Looks at SessionStart hooks for any registered cache-heal hook.
|
|
130
|
+
* - If its command has a stale node path (Brew upgrade scenario),
|
|
131
|
+
* rewrites the command using buildHookCommand() — Unix gets shebang
|
|
132
|
+
* form, Windows gets explicit nodePath form.
|
|
133
|
+
* - No-op when:
|
|
134
|
+
* * settings.json doesn't exist
|
|
135
|
+
* * no cache-heal hook is registered
|
|
136
|
+
* * the hook command is already valid (path exists or shebang form)
|
|
137
|
+
* - On Unix, also re-asserts the script's shebang + chmod +x so a healed
|
|
138
|
+
* command actually works.
|
|
139
|
+
*
|
|
140
|
+
* Returns: one of "noop" | "healed" | "missing-settings" — useful for
|
|
141
|
+
* tests and telemetry.
|
|
142
|
+
*
|
|
143
|
+
* Best-effort — all I/O is wrapped; never throws.
|
|
144
|
+
*/
|
|
145
|
+
export function selfHealCacheHealHook({
|
|
146
|
+
settingsPath,
|
|
147
|
+
scriptPath,
|
|
148
|
+
platform,
|
|
149
|
+
nodePath,
|
|
150
|
+
}) {
|
|
151
|
+
if (!settingsPath || !existsSync(settingsPath)) return "missing-settings";
|
|
152
|
+
|
|
153
|
+
let raw;
|
|
154
|
+
try {
|
|
155
|
+
raw = readFileSync(settingsPath, "utf-8");
|
|
156
|
+
} catch {
|
|
157
|
+
return "noop";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let parsed;
|
|
161
|
+
try {
|
|
162
|
+
parsed = JSON.parse(raw);
|
|
163
|
+
} catch {
|
|
164
|
+
return "noop";
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const hooks = parsed?.hooks;
|
|
168
|
+
if (!hooks || typeof hooks !== "object") return "noop";
|
|
169
|
+
const sessionStart = Array.isArray(hooks.SessionStart)
|
|
170
|
+
? hooks.SessionStart
|
|
171
|
+
: null;
|
|
172
|
+
if (!sessionStart) return "noop";
|
|
173
|
+
|
|
174
|
+
let healed = false;
|
|
175
|
+
for (const matcher of sessionStart) {
|
|
176
|
+
const inner = matcher?.hooks;
|
|
177
|
+
if (!Array.isArray(inner)) continue;
|
|
178
|
+
for (const h of inner) {
|
|
179
|
+
if (typeof h?.command !== "string") continue;
|
|
180
|
+
if (!h.command.includes("context-mode-cache-heal")) continue;
|
|
181
|
+
if (!isStaleNodePath(h.command)) continue;
|
|
182
|
+
|
|
183
|
+
// Stale → rewrite.
|
|
184
|
+
h.command = buildHookCommand({ scriptPath, platform, nodePath });
|
|
185
|
+
healed = true;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!healed) return "noop";
|
|
190
|
+
|
|
191
|
+
// Unix: re-assert shebang + chmod so the bare-script command works.
|
|
192
|
+
if (platform !== "win32" && scriptPath && existsSync(scriptPath)) {
|
|
193
|
+
try {
|
|
194
|
+
ensureShebangAndExecBit(scriptPath);
|
|
195
|
+
} catch {
|
|
196
|
+
/* best effort */
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
writeFileSync(
|
|
202
|
+
settingsPath,
|
|
203
|
+
JSON.stringify(parsed, null, 2) + "\n",
|
|
204
|
+
"utf-8",
|
|
205
|
+
);
|
|
206
|
+
} catch {
|
|
207
|
+
return "noop";
|
|
208
|
+
}
|
|
209
|
+
return "healed";
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Ensure a script starts with `#!/usr/bin/env node` and has 0o755 mode.
|
|
214
|
+
* Idempotent — leaves correctly-shebanged scripts unchanged.
|
|
215
|
+
*/
|
|
216
|
+
export function ensureShebangAndExecBit(scriptPath) {
|
|
217
|
+
if (!scriptPath || !existsSync(scriptPath)) return;
|
|
218
|
+
try {
|
|
219
|
+
const content = readFileSync(scriptPath, "utf-8");
|
|
220
|
+
if (!content.startsWith("#!")) {
|
|
221
|
+
writeFileSync(scriptPath, `#!/usr/bin/env node\n${content}`, "utf-8");
|
|
222
|
+
}
|
|
223
|
+
// statSync().mode lower 9 bits = perms.
|
|
224
|
+
const mode = statSync(scriptPath).mode & 0o777;
|
|
225
|
+
if (mode !== 0o755) {
|
|
226
|
+
chmodSync(scriptPath, 0o755);
|
|
227
|
+
}
|
|
228
|
+
} catch {
|
|
229
|
+
/* best effort */
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
writeSessionEventsFile,
|
|
15
15
|
buildSessionDirective,
|
|
16
16
|
getSessionEvents,
|
|
17
|
-
getLatestSessionEvents,
|
|
18
17
|
} from "../session-directive.mjs";
|
|
19
18
|
import {
|
|
20
19
|
readStdin,
|
|
@@ -57,9 +56,13 @@ try {
|
|
|
57
56
|
try { unlinkSync(getCleanupFlagPath(OPTS)); } catch { /* no flag */ }
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
// Filter events to the session being resumed/compacted. Falling back to
|
|
60
|
+
// getLatestSessionEvents(db) for resume leaks events from any other
|
|
61
|
+
// session whose session_meta.started_at is more recent — observed
|
|
62
|
+
// cross-session bleed when a different session started after this one
|
|
63
|
+
// and before the resume.
|
|
64
|
+
const sessionId = getSessionId(input, OPTS);
|
|
65
|
+
const events = sessionId ? getSessionEvents(db, sessionId) : [];
|
|
63
66
|
if (events.length > 0) {
|
|
64
67
|
const eventMeta = writeSessionEventsFile(events, getSessionEventsPath(OPTS));
|
|
65
68
|
additionalContext += buildSessionDirective(source, eventMeta, toolNamer);
|
package/hooks/core/routing.mjs
CHANGED
|
@@ -153,6 +153,11 @@ const TOOL_ALIASES = {
|
|
|
153
153
|
"container.exec": "Bash",
|
|
154
154
|
"local_shell": "Bash",
|
|
155
155
|
"grep_files": "Grep",
|
|
156
|
+
// OpenClaw native tools
|
|
157
|
+
"exec": "Bash",
|
|
158
|
+
"read": "Read",
|
|
159
|
+
"grep": "Grep",
|
|
160
|
+
"search": "Grep",
|
|
156
161
|
// Cursor
|
|
157
162
|
"mcp_web_fetch": "WebFetch",
|
|
158
163
|
"mcp_fetch_tool": "WebFetch",
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
writeSessionEventsFile,
|
|
15
15
|
buildSessionDirective,
|
|
16
16
|
getSessionEvents,
|
|
17
|
-
getLatestSessionEvents,
|
|
18
17
|
} from "../session-directive.mjs";
|
|
19
18
|
import {
|
|
20
19
|
readStdin,
|
|
@@ -61,9 +60,13 @@ try {
|
|
|
61
60
|
try { unlinkSync(getCleanupFlagPath(OPTS)); } catch { /* no flag */ }
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
// Filter events to the session being resumed/compacted. Falling back to
|
|
64
|
+
// getLatestSessionEvents(db) for resume leaks events from any other
|
|
65
|
+
// session whose session_meta.started_at is more recent — observed
|
|
66
|
+
// cross-session bleed when a different session started after this one
|
|
67
|
+
// and before the resume.
|
|
68
|
+
const sessionId = getSessionId(input, OPTS);
|
|
69
|
+
const events = sessionId ? getSessionEvents(db, sessionId) : [];
|
|
67
70
|
if (events.length > 0) {
|
|
68
71
|
const eventMeta = writeSessionEventsFile(events, getSessionEventsPath(OPTS));
|
|
69
72
|
additionalContext += buildSessionDirective(source, eventMeta, toolNamer);
|
|
@@ -14,11 +14,29 @@
|
|
|
14
14
|
* @param {object | null} decision - Normalized decision from routePreToolUse
|
|
15
15
|
* @returns {object | null} Claude Code hook response, or null for passthrough
|
|
16
16
|
*/
|
|
17
|
+
|
|
18
|
+
// In `claude --print` (headless) the CLI has no TTY to surface an "ask" prompt,
|
|
19
|
+
// so the agent stalls forever. Launchers running headless set CLAUDE_CODE_HEADLESS=1;
|
|
20
|
+
// when set, we mirror gemini-cli.mjs and passthrough on ask instead of blocking.
|
|
21
|
+
//
|
|
22
|
+
// We also passthrough on `deny` and `modify` in headless mode — context-mode's
|
|
23
|
+
// purpose is to nudge the agent toward `ctx_*` tools to save context. In a TTY
|
|
24
|
+
// session that nudge is useful: the agent reconsiders or asks the user. In
|
|
25
|
+
// headless `--print` mode the agent has no UI to reconsider; a `deny` aborts
|
|
26
|
+
// the run with no path forward, and `modify` silently swaps a curl for an
|
|
27
|
+
// `echo "use ctx_execute"` line that produces zero stdout — which is exactly
|
|
28
|
+
// what blocked the homelab daily explorer agent (Loki/Prom curl turned into
|
|
29
|
+
// empty echoes, all data-fetch steps reported BLOCKED). In headless launchers,
|
|
30
|
+
// the operator has already accepted the context-budget tradeoff by running
|
|
31
|
+
// raw tools; let those tools through.
|
|
32
|
+
const isHeadless = () => process.env.CLAUDE_CODE_HEADLESS === "1";
|
|
33
|
+
|
|
17
34
|
export function formatDecision(decision) {
|
|
18
35
|
if (!decision) return null;
|
|
19
36
|
|
|
20
37
|
switch (decision.action) {
|
|
21
38
|
case "deny":
|
|
39
|
+
if (isHeadless()) return null;
|
|
22
40
|
return {
|
|
23
41
|
hookSpecificOutput: {
|
|
24
42
|
hookEventName: "PreToolUse",
|
|
@@ -28,6 +46,7 @@ export function formatDecision(decision) {
|
|
|
28
46
|
};
|
|
29
47
|
|
|
30
48
|
case "ask":
|
|
49
|
+
if (isHeadless()) return null;
|
|
31
50
|
return {
|
|
32
51
|
hookSpecificOutput: {
|
|
33
52
|
hookEventName: "PreToolUse",
|
|
@@ -36,6 +55,7 @@ export function formatDecision(decision) {
|
|
|
36
55
|
};
|
|
37
56
|
|
|
38
57
|
case "modify":
|
|
58
|
+
if (isHeadless()) return null;
|
|
39
59
|
return {
|
|
40
60
|
hookSpecificOutput: {
|
|
41
61
|
hookEventName: "PreToolUse",
|