context-mode 1.0.53 → 1.0.54
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 +86 -29
- package/build/adapters/claude-code/hooks.d.ts +18 -0
- package/build/adapters/claude-code/hooks.js +23 -0
- package/build/adapters/claude-code/index.js +34 -2
- package/build/adapters/client-map.js +1 -0
- package/build/adapters/detect.d.ts +1 -0
- package/build/adapters/detect.js +18 -2
- package/build/adapters/opencode/index.d.ts +5 -2
- package/build/adapters/opencode/index.js +24 -9
- package/build/adapters/types.d.ts +1 -1
- package/build/cli.js +12 -28
- package/build/executor.js +3 -3
- package/build/openclaw-plugin.js +41 -33
- package/build/opencode-plugin.js +5 -2
- package/build/runtime.js +29 -11
- package/build/server.d.ts +2 -0
- package/build/server.js +35 -44
- package/build/store.d.ts +4 -3
- package/build/store.js +101 -34
- package/cli.bundle.mjs +188 -134
- package/configs/codex/AGENTS.md +19 -0
- package/configs/kilo/AGENTS.md +58 -0
- package/configs/kilo/kilo.json +10 -0
- package/hooks/core/tool-naming.mjs +1 -0
- package/hooks/pretooluse.mjs +25 -20
- package/hooks/sessionstart.mjs +25 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +155 -101
|
@@ -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.54"
|
|
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.54",
|
|
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.54",
|
|
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.54",
|
|
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.54",
|
|
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
|
@@ -5,14 +5,6 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/context-mode) [](https://www.npmjs.com/package/context-mode) [](https://github.com/mksglu/context-mode) [](https://github.com/mksglu/context-mode/stargazers) [](https://github.com/mksglu/context-mode/network/members) [](https://github.com/mksglu/context-mode/commits) [](LICENSE)
|
|
6
6
|
[](https://discord.gg/DCN9jUgN5v)
|
|
7
7
|
|
|
8
|
-
## Privacy & Architecture
|
|
9
|
-
|
|
10
|
-
Context Mode is not a CLI output filter or a cloud analytics dashboard. It operates at the MCP protocol layer — raw data stays in a sandboxed subprocess and never enters your context window. Web pages, API responses, file analysis, Playwright snapshots, log files — everything is processed in complete isolation.
|
|
11
|
-
|
|
12
|
-
**Nothing leaves your machine.** No telemetry, no cloud sync, no usage tracking, no account required. Your code, your prompts, your session data — all local. The SQLite databases live in your home directory and die when you're done.
|
|
13
|
-
|
|
14
|
-
This is a deliberate architectural choice, not a missing feature. Context optimization should happen at the source, not in a dashboard behind a per-seat subscription. Privacy-first is our philosophy — and every design decision follows from it. [License →](#license)
|
|
15
|
-
|
|
16
8
|
## The Problem
|
|
17
9
|
|
|
18
10
|
Every MCP tool call dumps raw data into your context window. A Playwright snapshot costs 56 KB. Twenty GitHub issues cost 59 KB. One access log — 45 KB. After 30 minutes, 40% of your context is gone. And when the agent compacts the conversation to free space, it forgets which files it was editing, what tasks are in progress, and what you last asked for.
|
|
@@ -302,6 +294,46 @@ Full config: [`configs/opencode/opencode.json`](configs/opencode/opencode.json)
|
|
|
302
294
|
|
|
303
295
|
</details>
|
|
304
296
|
|
|
297
|
+
<details>
|
|
298
|
+
<summary><strong>KiloCode</strong> — TypeScript plugin with hooks</summary>
|
|
299
|
+
|
|
300
|
+
**Prerequisites:** Node.js 18+, KiloCode installed.
|
|
301
|
+
|
|
302
|
+
**Install:**
|
|
303
|
+
|
|
304
|
+
1. Install context-mode globally:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
npm install -g context-mode
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
2. Add to `kilo.json` in your project root (or `~/.config/kilo/kilo.json` for global):
|
|
311
|
+
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"$schema": "https://app.kilo.ai/config.json",
|
|
315
|
+
"mcp": {
|
|
316
|
+
"context-mode": {
|
|
317
|
+
"type": "local",
|
|
318
|
+
"command": ["context-mode"]
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
"plugin": ["context-mode"]
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
The `mcp` entry registers the 6 sandbox tools. The `plugin` entry enables hooks — KiloCode calls the plugin's TypeScript functions directly before and after each tool execution, blocking dangerous commands and enforcing sandbox routing.
|
|
326
|
+
|
|
327
|
+
3. Restart KiloCode.
|
|
328
|
+
|
|
329
|
+
**Verify:** In the KiloCode session, type `ctx stats`. Context-mode tools should appear and respond.
|
|
330
|
+
|
|
331
|
+
**Routing:** Automatic. The plugin intercepts tool calls at runtime via `tool.execute.before` and `tool.execute.after`. No routing file is written to your project. The `experimental.session.compacting` hook builds resume snapshots when the conversation compacts.
|
|
332
|
+
|
|
333
|
+
> **Note:** KiloCode shares the same plugin architecture as OpenCode, using the OpenCodeAdapter with platform-specific configuration paths (`kilo.json` instead of `opencode.json`, `~/.config/kilo/` instead of `~/.config/opencode/`). SessionStart hook availability depends on KiloCode's implementation.
|
|
334
|
+
|
|
335
|
+
</details>
|
|
336
|
+
|
|
305
337
|
<details>
|
|
306
338
|
<summary><strong>OpenClaw / Pi Agent</strong> — native gateway plugin</summary>
|
|
307
339
|
|
|
@@ -601,7 +633,7 @@ npm install -g context-mode
|
|
|
601
633
|
| `ctx_execute_file` | Process files in sandbox. Raw content never leaves. | 45 KB → 155 B |
|
|
602
634
|
| `ctx_index` | Chunk markdown into FTS5 with BM25 ranking. | 60 KB → 40 B |
|
|
603
635
|
| `ctx_search` | Query indexed content with multiple queries in one call. | On-demand retrieval |
|
|
604
|
-
| `ctx_fetch_and_index` | Fetch URL,
|
|
636
|
+
| `ctx_fetch_and_index` | Fetch URL, chunk and index. 24h TTL cache — repeat calls skip network. `force: true` to bypass. | 60 KB → 40 B |
|
|
605
637
|
| `ctx_stats` | Show context savings, call counts, and session statistics. | — |
|
|
606
638
|
| `ctx_doctor` | Diagnose installation: runtimes, hooks, FTS5, versions. | — |
|
|
607
639
|
| `ctx_upgrade` | Upgrade to latest version from GitHub, rebuild, reconfigure hooks. | — |
|
|
@@ -643,6 +675,19 @@ Levenshtein distance corrects typos before re-searching. "kuberntes" becomes "ku
|
|
|
643
675
|
|
|
644
676
|
Search results use intelligent extraction instead of truncation. Instead of returning the first N characters (which might miss the important part), Context Mode finds where your query terms appear in the content and returns windows around those matches.
|
|
645
677
|
|
|
678
|
+
### TTL Cache
|
|
679
|
+
|
|
680
|
+
Indexed content persists in a per-project SQLite database at `~/.context-mode/content/`. When `ctx_fetch_and_index` is called for a URL that was already indexed within the last 24 hours, the fetch is skipped entirely. The model searches the existing index directly.
|
|
681
|
+
|
|
682
|
+
- **Fresh (<24h):** Returns a cache hint (0.3KB) instead of re-fetching (48KB+). Model proceeds to `ctx_search`.
|
|
683
|
+
- **Stale (>24h):** Re-fetches silently. No user action needed.
|
|
684
|
+
- **`force: true`:** Bypasses cache and re-fetches regardless of TTL.
|
|
685
|
+
- **14-day cleanup:** Content databases and sources older than 14 days are removed on startup.
|
|
686
|
+
|
|
687
|
+
This means `--continue` sessions preserve indexed docs across restarts. No re-fetching, no wasted context tokens.
|
|
688
|
+
|
|
689
|
+
`ctx_stats` reports cache performance separately: hits, data avoided, network requests saved, and total context savings including cache.
|
|
690
|
+
|
|
646
691
|
### Progressive Throttling
|
|
647
692
|
|
|
648
693
|
- **Calls 1-3:** Normal results (2 per query)
|
|
@@ -657,15 +702,15 @@ Context Mode captures every meaningful event during your session and persists th
|
|
|
657
702
|
|
|
658
703
|
Session continuity requires 4 hooks working together:
|
|
659
704
|
|
|
660
|
-
| Hook | Role | Claude Code | Gemini CLI | VS Code Copilot | Cursor | OpenCode | OpenClaw | Codex CLI | Antigravity | Kiro | Zed | Pi |
|
|
661
|
-
|
|
662
|
-
| **PostToolUse** | Captures events after each tool call | Yes | Yes | Yes | Yes | Plugin | Plugin | -- | -- | Yes | -- | ✓ (via tool_result event) |
|
|
663
|
-
| **UserPromptSubmit** | Captures user decisions and corrections | Yes | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
|
|
664
|
-
| **PreCompact** | Builds snapshot before compaction | Yes | Yes | Yes | -- | Plugin | Plugin | -- | -- | -- | -- | ✓ (via session_before_compact) |
|
|
665
|
-
| **SessionStart** | Restores state after compaction or resume | Yes | Yes | Yes | -- | -- | Plugin | -- | -- | -- | -- | ✓ (via session_start event) |
|
|
666
|
-
| | **Session completeness** | **Full** | **High** | **High** | **Partial** | **High** | **High** | **--** | **--** | **Partial** | **--** | **High** |
|
|
705
|
+
| Hook | Role | Claude Code | Gemini CLI | VS Code Copilot | Cursor | OpenCode | KiloCode | OpenClaw | Codex CLI | Antigravity | Kiro | Zed | Pi |
|
|
706
|
+
|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
|
707
|
+
| **PostToolUse** | Captures events after each tool call | Yes | Yes | Yes | Yes | Plugin | Plugin | Plugin | -- | -- | Yes | -- | ✓ (via tool_result event) |
|
|
708
|
+
| **UserPromptSubmit** | Captures user decisions and corrections | Yes | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
|
|
709
|
+
| **PreCompact** | Builds snapshot before compaction | Yes | Yes | Yes | -- | Plugin | Plugin | Plugin | -- | -- | -- | -- | ✓ (via session_before_compact) |
|
|
710
|
+
| **SessionStart** | Restores state after compaction or resume | Yes | Yes | Yes | -- | -- | -- | Plugin | -- | -- | -- | -- | ✓ (via session_start event) |
|
|
711
|
+
| | **Session completeness** | **Full** | **High** | **High** | **Partial** | **High** | **High** | **High** | **--** | **--** | **Partial** | **--** | **High** |
|
|
667
712
|
|
|
668
|
-
> **Note:** Full session continuity (capture + snapshot + restore) works on **Claude Code**, **Gemini CLI**, **VS Code Copilot**, and **OpenCode**. **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. **OpenCode** uses the `experimental.session.compacting` plugin hook for compaction recovery, but SessionStart is not yet available ([#14808](https://github.com/sst/opencode/issues/14808)), so startup/resume is not supported. **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**, **Antigravity**, **Kiro**, and **Zed** have no hook support in the current release, so session tracking is not available.
|
|
713
|
+
> **Note:** Full session continuity (capture + snapshot + restore) works on **Claude Code**, **Gemini CLI**, **VS Code Copilot**, and **OpenCode**. **KiloCode** shares the same plugin architecture as OpenCode via the OpenCodeAdapter. **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. **OpenCode** uses the `experimental.session.compacting` plugin hook for compaction recovery, but SessionStart is not yet available ([#14808](https://github.com/sst/opencode/issues/14808)), so startup/resume is not supported. **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**, **Antigravity**, **Kiro**, and **Zed** have no hook support in the current release, so session tracking is not available.
|
|
669
714
|
|
|
670
715
|
<details>
|
|
671
716
|
<summary><strong>What gets captured</strong></summary>
|
|
@@ -744,6 +789,8 @@ Detailed event data is also indexed into FTS5 for on-demand retrieval via `searc
|
|
|
744
789
|
|
|
745
790
|
**OpenCode** — Partial. The TypeScript plugin captures PostToolUse events via `tool.execute.after`, but SessionStart is not yet available ([#14808](https://github.com/sst/opencode/issues/14808)). Events are stored but not automatically restored after compaction.
|
|
746
791
|
|
|
792
|
+
**KiloCode** — Partial. Shares the same plugin architecture as OpenCode via the OpenCodeAdapter. The TypeScript plugin captures PostToolUse events via `tool.execute.after`, but SessionStart availability depends on KiloCode's implementation. Events are stored but may not be automatically restored after compaction.
|
|
793
|
+
|
|
747
794
|
**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).
|
|
748
795
|
|
|
749
796
|
**Codex CLI** — No session support. No hooks means no event capture. Each compaction or new session starts fresh. Requires manually copying `AGENTS.md` to your project root.
|
|
@@ -760,21 +807,23 @@ Detailed event data is also indexed into FTS5 for on-demand retrieval via `searc
|
|
|
760
807
|
|
|
761
808
|
## Platform Compatibility
|
|
762
809
|
|
|
763
|
-
| Feature | Claude Code | Gemini CLI | VS Code Copilot | Cursor | OpenCode | OpenClaw | Codex CLI | Antigravity | Kiro | Zed | Pi |
|
|
764
|
-
|
|
765
|
-
| MCP Server | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
|
|
766
|
-
| PreToolUse Hook | Yes | Yes | Yes | Yes | Plugin | Plugin | -- | -- | Yes | -- | Yes (extension) |
|
|
767
|
-
| PostToolUse Hook | Yes | Yes | Yes | Yes | Plugin | Plugin | -- | -- | Yes | -- | Yes (extension) |
|
|
768
|
-
| SessionStart Hook | Yes | Yes | Yes | -- | -- | Plugin | -- | -- | -- | -- | Yes (extension) |
|
|
769
|
-
| PreCompact Hook | Yes | Yes | Yes | -- | Plugin | Plugin | -- | -- | -- | -- | Yes (extension) |
|
|
770
|
-
| Can Modify Args | Yes | Yes | Yes | Yes | Plugin | Plugin | -- | -- | -- | -- | Yes (extension) |
|
|
771
|
-
| Can Block Tools | Yes | Yes | Yes | Yes | Plugin | Plugin | -- | -- | Yes | -- | Yes (extension) |
|
|
772
|
-
| Utility Commands (ctx) | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes (/ctx-stats, /ctx-doctor) |
|
|
773
|
-
| Slash Commands | Yes | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
|
|
774
|
-
| Plugin Marketplace | Yes | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
|
|
810
|
+
| Feature | Claude Code | Gemini CLI | VS Code Copilot | Cursor | OpenCode | KiloCode | OpenClaw | Codex CLI | Antigravity | Kiro | Zed | Pi |
|
|
811
|
+
|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
|
812
|
+
| MCP Server | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
|
|
813
|
+
| PreToolUse Hook | Yes | Yes | Yes | Yes | Plugin | Plugin | Plugin | -- | -- | Yes | -- | Yes (extension) |
|
|
814
|
+
| PostToolUse Hook | Yes | Yes | Yes | Yes | Plugin | Plugin | Plugin | -- | -- | Yes | -- | Yes (extension) |
|
|
815
|
+
| SessionStart Hook | Yes | Yes | Yes | -- | -- | -- | Plugin | -- | -- | -- | -- | Yes (extension) |
|
|
816
|
+
| PreCompact Hook | Yes | Yes | Yes | -- | Plugin | Plugin | Plugin | -- | -- | -- | -- | Yes (extension) |
|
|
817
|
+
| Can Modify Args | Yes | Yes | Yes | Yes | Plugin | Plugin | Plugin | -- | -- | -- | -- | Yes (extension) |
|
|
818
|
+
| Can Block Tools | Yes | Yes | Yes | Yes | Plugin | Plugin | Plugin | -- | -- | Yes | -- | Yes (extension) |
|
|
819
|
+
| Utility Commands (ctx) | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes (/ctx-stats, /ctx-doctor) |
|
|
820
|
+
| Slash Commands | Yes | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
|
|
821
|
+
| Plugin Marketplace | Yes | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
|
|
775
822
|
|
|
776
823
|
> **OpenCode** uses a TypeScript plugin paradigm — hooks run as in-process functions via `tool.execute.before`, `tool.execute.after`, and `experimental.session.compacting`, providing the same routing enforcement and session continuity as shell-based hooks. SessionStart is not yet available ([#14808](https://github.com/sst/opencode/issues/14808)), but compaction recovery works via the plugin's compacting hook.
|
|
777
824
|
>
|
|
825
|
+
> **KiloCode** shares the same TypeScript plugin architecture as OpenCode via the OpenCodeAdapter, with platform-specific configuration paths (`kilo.json` instead of `opencode.json`, `~/.config/kilo/` instead of `~/.config/opencode/`). Hook capabilities depend on KiloCode's implementation of the plugin interface.
|
|
826
|
+
>
|
|
778
827
|
> **OpenClaw** runs context-mode as a native gateway plugin targeting Pi Agent sessions. Hooks register via `api.on()` (tool/lifecycle) and `api.registerHook()` (commands). All tool interception and compaction hooks are supported. See [`docs/adapters/openclaw.md`](docs/adapters/openclaw.md).
|
|
779
828
|
>
|
|
780
829
|
> **Codex CLI**, **Antigravity**, and **Zed** do not support hooks. They rely solely on manually-copied routing instruction files (`AGENTS.md` / `GEMINI.md`) for enforcement (~60% compliance). See each platform's install section for copy instructions. Antigravity and Zed are auto-detected via MCP protocol handshake — no manual platform configuration needed.
|
|
@@ -887,6 +936,14 @@ event count. When context compacts, the model continues from your last prompt
|
|
|
887
936
|
with tasks, files, and decisions intact — no re-prompting needed.
|
|
888
937
|
```
|
|
889
938
|
|
|
939
|
+
## Privacy & Architecture
|
|
940
|
+
|
|
941
|
+
Context Mode is not a CLI output filter or a cloud analytics dashboard. It operates at the MCP protocol layer — raw data stays in a sandboxed subprocess and never enters your context window. Web pages, API responses, file analysis, Playwright snapshots, log files — everything is processed in complete isolation.
|
|
942
|
+
|
|
943
|
+
**Nothing leaves your machine.** No telemetry, no cloud sync, no usage tracking, no account required. Your code, your prompts, your session data — all local. The SQLite databases live in your home directory and die when you're done.
|
|
944
|
+
|
|
945
|
+
This is a deliberate architectural choice, not a missing feature. Context optimization should happen at the source, not in a dashboard behind a per-seat subscription. Privacy-first is our philosophy — and every design decision follows from it. [License →](#license)
|
|
946
|
+
|
|
890
947
|
## Security
|
|
891
948
|
|
|
892
949
|
Context Mode enforces the same permission rules you already use — but extends them to the MCP sandbox. If you block `sudo`, it's also blocked inside `ctx_execute`, `ctx_execute_file`, and `ctx_batch_execute`.
|
|
@@ -53,3 +53,21 @@ export declare function isContextModeHook(entry: {
|
|
|
53
53
|
* Falls back to CLI dispatcher if pluginRoot is not provided.
|
|
54
54
|
*/
|
|
55
55
|
export declare function buildHookCommand(hookType: HookType, pluginRoot?: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* Extract the hook script file path from a command string.
|
|
58
|
+
* Returns the path if the command uses the `node "/path/to/hook.mjs"` format,
|
|
59
|
+
* or null if it uses the CLI dispatcher format (which is path-independent).
|
|
60
|
+
*
|
|
61
|
+
* Handles both quoted and unquoted paths, and both forward/back slashes.
|
|
62
|
+
*/
|
|
63
|
+
export declare function extractHookScriptPath(command: string): string | null;
|
|
64
|
+
/**
|
|
65
|
+
* Check if a hook entry is a context-mode hook (any hook type).
|
|
66
|
+
* Broader than `isContextModeHook` — matches any context-mode script name
|
|
67
|
+
* without requiring a specific hookType.
|
|
68
|
+
*/
|
|
69
|
+
export declare function isAnyContextModeHook(entry: {
|
|
70
|
+
hooks?: Array<{
|
|
71
|
+
command?: string;
|
|
72
|
+
}>;
|
|
73
|
+
}): boolean;
|
|
@@ -93,3 +93,26 @@ export function buildHookCommand(hookType, pluginRoot) {
|
|
|
93
93
|
}
|
|
94
94
|
return `context-mode hook claude-code ${hookType.toLowerCase()}`;
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Extract the hook script file path from a command string.
|
|
98
|
+
* Returns the path if the command uses the `node "/path/to/hook.mjs"` format,
|
|
99
|
+
* or null if it uses the CLI dispatcher format (which is path-independent).
|
|
100
|
+
*
|
|
101
|
+
* Handles both quoted and unquoted paths, and both forward/back slashes.
|
|
102
|
+
*/
|
|
103
|
+
export function extractHookScriptPath(command) {
|
|
104
|
+
// Match: node "/path/to/hooks/scriptname.mjs" or node /path/to/hooks/scriptname.mjs
|
|
105
|
+
const match = command.match(/node\s+"?([^"]+\.mjs)"?/);
|
|
106
|
+
return match?.[1] ?? null;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Check if a hook entry is a context-mode hook (any hook type).
|
|
110
|
+
* Broader than `isContextModeHook` — matches any context-mode script name
|
|
111
|
+
* without requiring a specific hookType.
|
|
112
|
+
*/
|
|
113
|
+
export function isAnyContextModeHook(entry) {
|
|
114
|
+
const scriptNames = Object.values(HOOK_SCRIPTS);
|
|
115
|
+
return (entry.hooks?.some((h) => h.command != null &&
|
|
116
|
+
(scriptNames.some((s) => h.command.includes(s)) ||
|
|
117
|
+
h.command.includes("context-mode hook"))) ?? false);
|
|
118
|
+
}
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
* - Session dir: ~/.claude/context-mode/sessions/
|
|
15
15
|
*/
|
|
16
16
|
import { createHash } from "node:crypto";
|
|
17
|
-
import { readFileSync, writeFileSync, mkdirSync, copyFileSync, accessSync, readdirSync, chmodSync, constants, } from "node:fs";
|
|
17
|
+
import { readFileSync, writeFileSync, mkdirSync, copyFileSync, accessSync, existsSync, readdirSync, chmodSync, constants, } from "node:fs";
|
|
18
18
|
import { resolve, join } from "node:path";
|
|
19
19
|
import { homedir } from "node:os";
|
|
20
|
-
import { HOOK_TYPES, HOOK_SCRIPTS, PRE_TOOL_USE_MATCHER_PATTERN, isContextModeHook, buildHookCommand, } from "./hooks.js";
|
|
20
|
+
import { HOOK_TYPES, HOOK_SCRIPTS, PRE_TOOL_USE_MATCHER_PATTERN, isContextModeHook, isAnyContextModeHook, extractHookScriptPath, buildHookCommand, } from "./hooks.js";
|
|
21
21
|
// ─────────────────────────────────────────────────────────
|
|
22
22
|
// Adapter implementation
|
|
23
23
|
// ─────────────────────────────────────────────────────────
|
|
@@ -383,6 +383,38 @@ export class ClaudeCodeAdapter {
|
|
|
383
383
|
const settings = this.readSettings() ?? {};
|
|
384
384
|
const hooks = (settings.hooks ?? {});
|
|
385
385
|
const changes = [];
|
|
386
|
+
// Remove stale context-mode hook entries across ALL hook types (fixes #187).
|
|
387
|
+
// After a marketplace auto-update or version change, settings.json may contain
|
|
388
|
+
// hardcoded paths pointing to deleted version directories (e.g., .../0.9.17/hooks/...).
|
|
389
|
+
// Clean these before registering fresh entries to prevent SessionStart errors.
|
|
390
|
+
for (const hookType of Object.keys(hooks)) {
|
|
391
|
+
const entries = hooks[hookType];
|
|
392
|
+
if (!Array.isArray(entries))
|
|
393
|
+
continue;
|
|
394
|
+
const filtered = entries.filter((entry) => {
|
|
395
|
+
const typedEntry = entry;
|
|
396
|
+
if (!isAnyContextModeHook(typedEntry))
|
|
397
|
+
return true; // preserve non-context-mode hooks
|
|
398
|
+
// Keep CLI dispatcher entries (path-independent, never stale)
|
|
399
|
+
const commands = typedEntry.hooks ?? [];
|
|
400
|
+
const hasOnlyDispatcherCommands = commands.every((h) => !h.command || !extractHookScriptPath(h.command));
|
|
401
|
+
if (hasOnlyDispatcherCommands)
|
|
402
|
+
return true;
|
|
403
|
+
// For node path commands, check if the referenced script file exists
|
|
404
|
+
return commands.every((h) => {
|
|
405
|
+
const scriptPath = h.command ? extractHookScriptPath(h.command) : null;
|
|
406
|
+
if (!scriptPath)
|
|
407
|
+
return true; // not a path-based command
|
|
408
|
+
return existsSync(scriptPath);
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
const removed = entries.length - filtered.length;
|
|
412
|
+
if (removed > 0) {
|
|
413
|
+
hooks[hookType] = filtered;
|
|
414
|
+
changes.push(`Removed ${removed} stale ${hookType} hook(s)`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
// Register fresh hooks for required hook types
|
|
386
418
|
const hookTypes = [
|
|
387
419
|
HOOK_TYPES.PRE_TOOL_USE,
|
|
388
420
|
HOOK_TYPES.SESSION_START,
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* Verified env vars per platform (from source code audit):
|
|
10
10
|
* - Claude Code: CLAUDE_PROJECT_DIR, CLAUDE_SESSION_ID | ~/.claude/
|
|
11
11
|
* - Gemini CLI: GEMINI_PROJECT_DIR (hooks), GEMINI_CLI (MCP) | ~/.gemini/
|
|
12
|
+
* - KiloCode: KILO, KILO_PID | ~/.config/kilo/
|
|
12
13
|
* - OpenCode: OPENCODE, OPENCODE_PID | ~/.config/opencode/
|
|
13
14
|
* - OpenClaw: OPENCLAW_HOME, OPENCLAW_CLI | ~/.openclaw/
|
|
14
15
|
* - Codex CLI: CODEX_CI, CODEX_THREAD_ID | ~/.codex/
|
package/build/adapters/detect.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* Verified env vars per platform (from source code audit):
|
|
10
10
|
* - Claude Code: CLAUDE_PROJECT_DIR, CLAUDE_SESSION_ID | ~/.claude/
|
|
11
11
|
* - Gemini CLI: GEMINI_PROJECT_DIR (hooks), GEMINI_CLI (MCP) | ~/.gemini/
|
|
12
|
+
* - KiloCode: KILO, KILO_PID | ~/.config/kilo/
|
|
12
13
|
* - OpenCode: OPENCODE, OPENCODE_PID | ~/.config/opencode/
|
|
13
14
|
* - OpenClaw: OPENCLAW_HOME, OPENCLAW_CLI | ~/.openclaw/
|
|
14
15
|
* - Codex CLI: CODEX_CI, CODEX_THREAD_ID | ~/.codex/
|
|
@@ -41,7 +42,7 @@ export function detectPlatform(clientInfo) {
|
|
|
41
42
|
const platformOverride = process.env.CONTEXT_MODE_PLATFORM;
|
|
42
43
|
if (platformOverride) {
|
|
43
44
|
const validPlatforms = [
|
|
44
|
-
"claude-code", "gemini-cli", "opencode", "codex",
|
|
45
|
+
"claude-code", "gemini-cli", "kilo", "opencode", "codex",
|
|
45
46
|
"vscode-copilot", "cursor", "antigravity", "kiro", "pi", "zed",
|
|
46
47
|
];
|
|
47
48
|
if (validPlatforms.includes(platformOverride)) {
|
|
@@ -74,6 +75,13 @@ export function detectPlatform(clientInfo) {
|
|
|
74
75
|
reason: "OPENCLAW_HOME or OPENCLAW_CLI env var set",
|
|
75
76
|
};
|
|
76
77
|
}
|
|
78
|
+
if (process.env.KILO || process.env.KILO_PID) {
|
|
79
|
+
return {
|
|
80
|
+
platform: "kilo",
|
|
81
|
+
confidence: "high",
|
|
82
|
+
reason: "KILO or KILO_PID env var set",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
77
85
|
if (process.env.OPENCODE || process.env.OPENCODE_PID) {
|
|
78
86
|
return {
|
|
79
87
|
platform: "opencode",
|
|
@@ -153,6 +161,13 @@ export function detectPlatform(clientInfo) {
|
|
|
153
161
|
reason: "~/.openclaw/ directory exists",
|
|
154
162
|
};
|
|
155
163
|
}
|
|
164
|
+
if (existsSync(resolve(home, ".config", "kilo"))) {
|
|
165
|
+
return {
|
|
166
|
+
platform: "kilo",
|
|
167
|
+
confidence: "medium",
|
|
168
|
+
reason: "~/.config/kilo/ directory exists",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
156
171
|
if (existsSync(resolve(home, ".config", "opencode"))) {
|
|
157
172
|
return {
|
|
158
173
|
platform: "opencode",
|
|
@@ -189,9 +204,10 @@ export async function getAdapter(platform) {
|
|
|
189
204
|
const { GeminiCLIAdapter } = await import("./gemini-cli/index.js");
|
|
190
205
|
return new GeminiCLIAdapter();
|
|
191
206
|
}
|
|
207
|
+
case "kilo":
|
|
192
208
|
case "opencode": {
|
|
193
209
|
const { OpenCodeAdapter } = await import("./opencode/index.js");
|
|
194
|
-
return new OpenCodeAdapter();
|
|
210
|
+
return new OpenCodeAdapter(target);
|
|
195
211
|
}
|
|
196
212
|
case "openclaw": {
|
|
197
213
|
const { OpenClawAdapter } = await import("./openclaw/index.js");
|
|
@@ -15,12 +15,15 @@
|
|
|
15
15
|
* - Config: opencode.json plugin array, .opencode/plugins/*.ts
|
|
16
16
|
* - Session dir: ~/.config/opencode/context-mode/sessions/
|
|
17
17
|
*/
|
|
18
|
-
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration, RoutingInstructionsConfig } from "../types.js";
|
|
18
|
+
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration, RoutingInstructionsConfig, PlatformId } from "../types.js";
|
|
19
|
+
export type AdapterPlatformType = Extract<PlatformId, "opencode" | "kilo">;
|
|
19
20
|
export declare class OpenCodeAdapter implements HookAdapter {
|
|
20
|
-
|
|
21
|
+
get name(): string;
|
|
21
22
|
readonly paradigm: HookParadigm;
|
|
22
23
|
private settingsPath?;
|
|
23
24
|
readonly capabilities: PlatformCapabilities;
|
|
25
|
+
private platform;
|
|
26
|
+
constructor(platform?: AdapterPlatformType);
|
|
24
27
|
parsePreToolUseInput(raw: unknown): PreToolUseEvent;
|
|
25
28
|
parsePostToolUseInput(raw: unknown): PostToolUseEvent;
|
|
26
29
|
parsePreCompactInput(raw: unknown): PreCompactEvent;
|
|
@@ -23,11 +23,10 @@ import { homedir } from "node:os";
|
|
|
23
23
|
// Hook constants (re-exported from hooks.ts)
|
|
24
24
|
// ─────────────────────────────────────────────────────────
|
|
25
25
|
import { HOOK_TYPES as OPENCODE_HOOK_NAMES } from "./hooks.js";
|
|
26
|
-
// ─────────────────────────────────────────────────────────
|
|
27
|
-
// Adapter implementation
|
|
28
|
-
// ─────────────────────────────────────────────────────────
|
|
29
26
|
export class OpenCodeAdapter {
|
|
30
|
-
name
|
|
27
|
+
get name() {
|
|
28
|
+
return this.platform === "kilo" ? "KiloCode" : "OpenCode";
|
|
29
|
+
}
|
|
31
30
|
paradigm = "ts-plugin";
|
|
32
31
|
settingsPath;
|
|
33
32
|
capabilities = {
|
|
@@ -39,6 +38,10 @@ export class OpenCodeAdapter {
|
|
|
39
38
|
canModifyOutput: true, // with TUI bug caveat for bash (#13575)
|
|
40
39
|
canInjectSessionContext: false,
|
|
41
40
|
};
|
|
41
|
+
platform;
|
|
42
|
+
constructor(platform = "opencode") {
|
|
43
|
+
this.platform = platform;
|
|
44
|
+
}
|
|
42
45
|
// ── Input parsing ──────────────────────────────────────
|
|
43
46
|
parsePreToolUseInput(raw) {
|
|
44
47
|
const input = raw;
|
|
@@ -134,9 +137,17 @@ export class OpenCodeAdapter {
|
|
|
134
137
|
}
|
|
135
138
|
// ── Configuration ──────────────────────────────────────
|
|
136
139
|
getSettingsPath() {
|
|
137
|
-
|
|
140
|
+
// OpenCode uses opencode.json in the project root or .opencode/opencode.json
|
|
141
|
+
return this.settingsPath ?? resolve(`${this.platform}.json`);
|
|
138
142
|
}
|
|
139
143
|
paths() {
|
|
144
|
+
if (this.platform === "kilo") {
|
|
145
|
+
return [
|
|
146
|
+
resolve("kilo.json"),
|
|
147
|
+
resolve(".kilocode", "kilo.json"),
|
|
148
|
+
join(homedir(), ".config", "kilo", "kilo.json"),
|
|
149
|
+
];
|
|
150
|
+
}
|
|
140
151
|
return [
|
|
141
152
|
resolve("opencode.json"),
|
|
142
153
|
resolve(".opencode", "opencode.json"),
|
|
@@ -144,7 +155,7 @@ export class OpenCodeAdapter {
|
|
|
144
155
|
];
|
|
145
156
|
}
|
|
146
157
|
getSessionDir() {
|
|
147
|
-
const dir = join(homedir(), ".config",
|
|
158
|
+
const dir = join(homedir(), ".config", this.platform, "context-mode", "sessions");
|
|
148
159
|
mkdirSync(dir, { recursive: true });
|
|
149
160
|
return dir;
|
|
150
161
|
}
|
|
@@ -203,6 +214,9 @@ export class OpenCodeAdapter {
|
|
|
203
214
|
};
|
|
204
215
|
}
|
|
205
216
|
readSettings() {
|
|
217
|
+
// Try project-local paths first, then global config
|
|
218
|
+
// const paths = this.getConfigFilePaths();
|
|
219
|
+
// for (const configPath of paths) {
|
|
206
220
|
this.settingsPath = undefined;
|
|
207
221
|
for (const configPath of this.paths()) {
|
|
208
222
|
try {
|
|
@@ -217,6 +231,7 @@ export class OpenCodeAdapter {
|
|
|
217
231
|
return null;
|
|
218
232
|
}
|
|
219
233
|
writeSettings(settings) {
|
|
234
|
+
// Write to opencode.json/kilo.json in current directory
|
|
220
235
|
writeFileSync(this.getSettingsPath(), JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
221
236
|
}
|
|
222
237
|
// ── Diagnostics (doctor) ─────────────────────────────────
|
|
@@ -293,7 +308,7 @@ export class OpenCodeAdapter {
|
|
|
293
308
|
getInstalledVersion() {
|
|
294
309
|
// Check ~/.cache/opencode/node_modules/ for context-mode
|
|
295
310
|
try {
|
|
296
|
-
const pkgPath = resolve(homedir(), ".cache",
|
|
311
|
+
const pkgPath = resolve(homedir(), ".cache", this.platform, "node_modules", "context-mode", "package.json");
|
|
297
312
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
298
313
|
if (typeof pkg.version === "string")
|
|
299
314
|
return pkg.version;
|
|
@@ -347,14 +362,14 @@ export class OpenCodeAdapter {
|
|
|
347
362
|
getRoutingInstructionsConfig() {
|
|
348
363
|
return {
|
|
349
364
|
fileName: "AGENTS.md",
|
|
350
|
-
globalPath: resolve(homedir(), ".config",
|
|
365
|
+
globalPath: resolve(homedir(), ".config", this.platform, "AGENTS.md"),
|
|
351
366
|
projectRelativePath: "AGENTS.md",
|
|
352
367
|
};
|
|
353
368
|
}
|
|
354
369
|
writeRoutingInstructions(projectDir, pluginRoot) {
|
|
355
370
|
const config = this.getRoutingInstructionsConfig();
|
|
356
371
|
const targetPath = resolve(projectDir, config.projectRelativePath);
|
|
357
|
-
const sourcePath = resolve(pluginRoot, "configs",
|
|
372
|
+
const sourcePath = resolve(pluginRoot, "configs", this.platform, config.fileName);
|
|
358
373
|
try {
|
|
359
374
|
const content = readFileSync(sourcePath, "utf-8");
|
|
360
375
|
try {
|
|
@@ -206,7 +206,7 @@ export interface DiagnosticResult {
|
|
|
206
206
|
fix?: string;
|
|
207
207
|
}
|
|
208
208
|
/** Supported platform identifiers. */
|
|
209
|
-
export type PlatformId = "claude-code" | "gemini-cli" | "opencode" | "openclaw" | "codex" | "vscode-copilot" | "cursor" | "antigravity" | "kiro" | "pi" | "zed" | "unknown";
|
|
209
|
+
export type PlatformId = "claude-code" | "gemini-cli" | "opencode" | "kilo" | "openclaw" | "codex" | "vscode-copilot" | "cursor" | "antigravity" | "kiro" | "pi" | "zed" | "unknown";
|
|
210
210
|
/** Detection signal used to identify which platform is running. */
|
|
211
211
|
export interface DetectionSignal {
|
|
212
212
|
/** Platform identifier. */
|
package/build/cli.js
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import * as p from "@clack/prompts";
|
|
15
15
|
import color from "picocolors";
|
|
16
|
-
import {
|
|
17
|
-
import { readFileSync, writeFileSync, cpSync, accessSync, existsSync,
|
|
16
|
+
import { execFileSync } from "node:child_process";
|
|
17
|
+
import { readFileSync, writeFileSync, cpSync, accessSync, existsSync, rmSync, closeSync, openSync, chmodSync, constants } from "node:fs";
|
|
18
18
|
import { request as httpsRequest } from "node:https";
|
|
19
19
|
import { resolve, dirname, join } from "node:path";
|
|
20
20
|
import { tmpdir, devNull } from "node:os";
|
|
@@ -351,7 +351,7 @@ async function upgrade() {
|
|
|
351
351
|
const tmpDir = join(tmpdir(), `context-mode-upgrade-${Date.now()}`);
|
|
352
352
|
s.start("Cloning mksglu/context-mode");
|
|
353
353
|
try {
|
|
354
|
-
|
|
354
|
+
execFileSync("git", ["clone", "--depth", "1", "https://github.com/mksglu/context-mode.git", tmpDir], { stdio: "pipe", timeout: 30000 });
|
|
355
355
|
s.stop("Downloaded");
|
|
356
356
|
const srcDir = tmpDir;
|
|
357
357
|
const newPkg = JSON.parse(readFileSync(resolve(srcDir, "package.json"), "utf-8"));
|
|
@@ -364,12 +364,12 @@ async function upgrade() {
|
|
|
364
364
|
}
|
|
365
365
|
// Step 2: Install dependencies + build
|
|
366
366
|
s.start("Installing dependencies & building");
|
|
367
|
-
|
|
367
|
+
execFileSync("npm", ["install", "--no-audit", "--no-fund"], {
|
|
368
368
|
cwd: srcDir,
|
|
369
369
|
stdio: "pipe",
|
|
370
370
|
timeout: 120000,
|
|
371
371
|
});
|
|
372
|
-
|
|
372
|
+
execFileSync("npm", ["run", "build"], {
|
|
373
373
|
cwd: srcDir,
|
|
374
374
|
stdio: "pipe",
|
|
375
375
|
timeout: 60000,
|
|
@@ -377,24 +377,8 @@ async function upgrade() {
|
|
|
377
377
|
s.stop("Built successfully");
|
|
378
378
|
// Step 3: Update in-place
|
|
379
379
|
s.start("Updating files in-place");
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
const cacheParent = cacheParentMatch[1];
|
|
383
|
-
const myDir = pluginRoot.replace(cacheParent, "").replace(/[\\/]/g, "");
|
|
384
|
-
try {
|
|
385
|
-
const oldDirs = readdirSync(cacheParent).filter(d => d !== myDir);
|
|
386
|
-
for (const d of oldDirs) {
|
|
387
|
-
try {
|
|
388
|
-
rmSync(resolve(cacheParent, d), { recursive: true, force: true });
|
|
389
|
-
}
|
|
390
|
-
catch { /* skip */ }
|
|
391
|
-
}
|
|
392
|
-
if (oldDirs.length > 0) {
|
|
393
|
-
p.log.info(color.dim(` Cleaned ${oldDirs.length} stale cache dir(s)`));
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
catch { /* parent may not exist */ }
|
|
397
|
-
}
|
|
380
|
+
// Old version dirs are cleaned lazily by sessionstart.mjs (age-gated >1h)
|
|
381
|
+
// to avoid breaking active sessions that still reference them (#181).
|
|
398
382
|
const items = [
|
|
399
383
|
"build", "src", "hooks", "skills", "scripts", ".claude-plugin",
|
|
400
384
|
"start.mjs", "server.bundle.mjs", "cli.bundle.mjs", "package.json",
|
|
@@ -422,7 +406,7 @@ async function upgrade() {
|
|
|
422
406
|
p.log.info(color.dim(" Registry synced to " + pluginRoot));
|
|
423
407
|
// Install production deps
|
|
424
408
|
s.start("Installing production dependencies");
|
|
425
|
-
|
|
409
|
+
execFileSync("npm", ["install", "--production", "--no-audit", "--no-fund"], {
|
|
426
410
|
cwd: pluginRoot,
|
|
427
411
|
stdio: "pipe",
|
|
428
412
|
timeout: 60000,
|
|
@@ -431,7 +415,7 @@ async function upgrade() {
|
|
|
431
415
|
// Rebuild native addons for current Node.js ABI (fixes #131)
|
|
432
416
|
s.start("Rebuilding native addons");
|
|
433
417
|
try {
|
|
434
|
-
|
|
418
|
+
execFileSync("npm", ["rebuild", "better-sqlite3"], {
|
|
435
419
|
cwd: pluginRoot,
|
|
436
420
|
stdio: "pipe",
|
|
437
421
|
timeout: 60000,
|
|
@@ -449,7 +433,7 @@ async function upgrade() {
|
|
|
449
433
|
// Update global npm
|
|
450
434
|
s.start("Updating npm global package");
|
|
451
435
|
try {
|
|
452
|
-
|
|
436
|
+
execFileSync("npm", ["install", "-g", pluginRoot, "--no-audit", "--no-fund"], {
|
|
453
437
|
stdio: "pipe",
|
|
454
438
|
timeout: 30000,
|
|
455
439
|
});
|
|
@@ -507,7 +491,7 @@ async function upgrade() {
|
|
|
507
491
|
const binPath = resolve(pluginRoot, bin);
|
|
508
492
|
try {
|
|
509
493
|
accessSync(binPath, constants.F_OK);
|
|
510
|
-
|
|
494
|
+
chmodSync(binPath, 0o755);
|
|
511
495
|
permSet.push(binPath);
|
|
512
496
|
}
|
|
513
497
|
catch { /* not found — skip */ }
|
|
@@ -535,7 +519,7 @@ async function upgrade() {
|
|
|
535
519
|
const cliBundlePath = resolve(pluginRoot, "cli.bundle.mjs");
|
|
536
520
|
const cliBuildPath = resolve(pluginRoot, "build", "cli.js");
|
|
537
521
|
const cliPath = existsSync(cliBundlePath) ? cliBundlePath : cliBuildPath;
|
|
538
|
-
|
|
522
|
+
execFileSync("node", [cliPath, "doctor"], {
|
|
539
523
|
stdio: "inherit",
|
|
540
524
|
timeout: 30000,
|
|
541
525
|
cwd: pluginRoot,
|