@mxalbert/context-mode 2.0.0
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 +33 -0
- package/.claude-plugin/plugin.json +31 -0
- package/.codex-plugin/hooks.json +65 -0
- package/.codex-plugin/mcp.json +13 -0
- package/.codex-plugin/plugin.json +31 -0
- package/.openclaw-plugin/index.ts +12 -0
- package/.openclaw-plugin/openclaw.plugin.json +38 -0
- package/.openclaw-plugin/package.json +28 -0
- package/LICENSE +94 -0
- package/README.md +1619 -0
- package/bin/statusline.mjs +378 -0
- package/build/adapters/antigravity/index.d.ts +51 -0
- package/build/adapters/antigravity/index.js +169 -0
- package/build/adapters/antigravity-cli/index.d.ts +51 -0
- package/build/adapters/antigravity-cli/index.js +342 -0
- package/build/adapters/base.d.ts +92 -0
- package/build/adapters/base.js +135 -0
- package/build/adapters/claude-code/config.d.ts +8 -0
- package/build/adapters/claude-code/config.js +8 -0
- package/build/adapters/claude-code/hooks.d.ts +106 -0
- package/build/adapters/claude-code/hooks.js +183 -0
- package/build/adapters/claude-code/index.d.ts +80 -0
- package/build/adapters/claude-code/index.js +569 -0
- package/build/adapters/claude-code-base.d.ts +49 -0
- package/build/adapters/claude-code-base.js +113 -0
- package/build/adapters/client-map.d.ts +10 -0
- package/build/adapters/client-map.js +42 -0
- package/build/adapters/codex/config.d.ts +8 -0
- package/build/adapters/codex/config.js +8 -0
- package/build/adapters/codex/hooks.d.ts +55 -0
- package/build/adapters/codex/hooks.js +64 -0
- package/build/adapters/codex/index.d.ts +87 -0
- package/build/adapters/codex/index.js +995 -0
- package/build/adapters/codex/paths.d.ts +1 -0
- package/build/adapters/codex/paths.js +12 -0
- package/build/adapters/codex/usage.d.ts +107 -0
- package/build/adapters/codex/usage.js +227 -0
- package/build/adapters/copilot-base.d.ts +94 -0
- package/build/adapters/copilot-base.js +297 -0
- package/build/adapters/copilot-cli/hooks.d.ts +33 -0
- package/build/adapters/copilot-cli/hooks.js +64 -0
- package/build/adapters/copilot-cli/index.d.ts +48 -0
- package/build/adapters/copilot-cli/index.js +341 -0
- package/build/adapters/cursor/config.d.ts +4 -0
- package/build/adapters/cursor/config.js +4 -0
- package/build/adapters/cursor/hooks.d.ts +55 -0
- package/build/adapters/cursor/hooks.js +82 -0
- package/build/adapters/cursor/index.d.ts +64 -0
- package/build/adapters/cursor/index.js +517 -0
- package/build/adapters/detect.d.ts +136 -0
- package/build/adapters/detect.js +623 -0
- package/build/adapters/gemini-cli/config.d.ts +8 -0
- package/build/adapters/gemini-cli/config.js +8 -0
- package/build/adapters/gemini-cli/hooks.d.ts +83 -0
- package/build/adapters/gemini-cli/hooks.js +115 -0
- package/build/adapters/gemini-cli/index.d.ts +80 -0
- package/build/adapters/gemini-cli/index.js +483 -0
- package/build/adapters/jetbrains-copilot/config.d.ts +8 -0
- package/build/adapters/jetbrains-copilot/config.js +8 -0
- package/build/adapters/jetbrains-copilot/hooks.d.ts +59 -0
- package/build/adapters/jetbrains-copilot/hooks.js +87 -0
- package/build/adapters/jetbrains-copilot/index.d.ts +31 -0
- package/build/adapters/jetbrains-copilot/index.js +131 -0
- package/build/adapters/kimi/config.d.ts +8 -0
- package/build/adapters/kimi/config.js +8 -0
- package/build/adapters/kimi/hooks.d.ts +28 -0
- package/build/adapters/kimi/hooks.js +34 -0
- package/build/adapters/kimi/index.d.ts +66 -0
- package/build/adapters/kimi/index.js +537 -0
- package/build/adapters/kimi/paths.d.ts +21 -0
- package/build/adapters/kimi/paths.js +52 -0
- package/build/adapters/kimi/usage.d.ts +82 -0
- package/build/adapters/kimi/usage.js +217 -0
- package/build/adapters/kiro/hooks.d.ts +61 -0
- package/build/adapters/kiro/hooks.js +94 -0
- package/build/adapters/kiro/index.d.ts +61 -0
- package/build/adapters/kiro/index.js +301 -0
- package/build/adapters/omp/index.d.ts +65 -0
- package/build/adapters/omp/index.js +182 -0
- package/build/adapters/omp/plugin.d.ts +81 -0
- package/build/adapters/omp/plugin.js +331 -0
- package/build/adapters/omp/usage.d.ts +49 -0
- package/build/adapters/omp/usage.js +110 -0
- package/build/adapters/openclaw/config.d.ts +8 -0
- package/build/adapters/openclaw/config.js +8 -0
- package/build/adapters/openclaw/hooks.d.ts +50 -0
- package/build/adapters/openclaw/hooks.js +61 -0
- package/build/adapters/openclaw/index.d.ts +74 -0
- package/build/adapters/openclaw/index.js +439 -0
- package/build/adapters/openclaw/mcp-tools.d.ts +54 -0
- package/build/adapters/openclaw/mcp-tools.js +207 -0
- package/build/adapters/openclaw/plugin.d.ts +141 -0
- package/build/adapters/openclaw/plugin.js +818 -0
- package/build/adapters/openclaw/session-db.d.ts +55 -0
- package/build/adapters/openclaw/session-db.js +88 -0
- package/build/adapters/openclaw/usage.d.ts +34 -0
- package/build/adapters/openclaw/usage.js +52 -0
- package/build/adapters/openclaw/workspace-router.d.ts +29 -0
- package/build/adapters/openclaw/workspace-router.js +64 -0
- package/build/adapters/opencode/config.d.ts +8 -0
- package/build/adapters/opencode/config.js +8 -0
- package/build/adapters/opencode/hooks.d.ts +38 -0
- package/build/adapters/opencode/hooks.js +50 -0
- package/build/adapters/opencode/index.d.ts +144 -0
- package/build/adapters/opencode/index.js +638 -0
- package/build/adapters/opencode/plugin.d.ts +249 -0
- package/build/adapters/opencode/plugin.js +1536 -0
- package/build/adapters/opencode/v2.d.ts +117 -0
- package/build/adapters/opencode/v2.js +224 -0
- package/build/adapters/opencode/zod3tov4.d.ts +1 -0
- package/build/adapters/opencode/zod3tov4.js +132 -0
- package/build/adapters/pi/extension.d.ts +81 -0
- package/build/adapters/pi/extension.js +861 -0
- package/build/adapters/pi/index.d.ts +57 -0
- package/build/adapters/pi/index.js +173 -0
- package/build/adapters/pi/mcp-bridge.d.ts +268 -0
- package/build/adapters/pi/mcp-bridge.js +894 -0
- package/build/adapters/qwen-code/hooks.d.ts +26 -0
- package/build/adapters/qwen-code/hooks.js +29 -0
- package/build/adapters/qwen-code/index.d.ts +40 -0
- package/build/adapters/qwen-code/index.js +361 -0
- package/build/adapters/qwen-code/usage.d.ts +90 -0
- package/build/adapters/qwen-code/usage.js +222 -0
- package/build/adapters/types.d.ts +360 -0
- package/build/adapters/types.js +118 -0
- package/build/adapters/vscode-copilot/config.d.ts +8 -0
- package/build/adapters/vscode-copilot/config.js +8 -0
- package/build/adapters/vscode-copilot/hooks.d.ts +71 -0
- package/build/adapters/vscode-copilot/hooks.js +98 -0
- package/build/adapters/vscode-copilot/index.d.ts +32 -0
- package/build/adapters/vscode-copilot/index.js +222 -0
- package/build/adapters/zed/index.d.ts +40 -0
- package/build/adapters/zed/index.js +163 -0
- package/build/cli.d.ts +34 -0
- package/build/cli.js +1828 -0
- package/build/db-base.d.ts +250 -0
- package/build/db-base.js +756 -0
- package/build/executor.d.ts +72 -0
- package/build/executor.js +678 -0
- package/build/exit-classify.d.ts +19 -0
- package/build/exit-classify.js +12 -0
- package/build/fetch/blocks.d.ts +145 -0
- package/build/fetch/blocks.js +244 -0
- package/build/fetch/extract.d.ts +68 -0
- package/build/fetch/extract.js +123 -0
- package/build/fetch/page-store.d.ts +66 -0
- package/build/fetch/page-store.js +174 -0
- package/build/fetch-cache.d.ts +13 -0
- package/build/fetch-cache.js +15 -0
- package/build/lifecycle.d.ts +124 -0
- package/build/lifecycle.js +278 -0
- package/build/package-identity.d.ts +26 -0
- package/build/package-identity.js +28 -0
- package/build/runPool.d.ts +36 -0
- package/build/runPool.js +51 -0
- package/build/runtime.d.ts +71 -0
- package/build/runtime.js +659 -0
- package/build/search/auto-memory.d.ts +47 -0
- package/build/search/auto-memory.js +170 -0
- package/build/search/ctx-search-schema.d.ts +90 -0
- package/build/search/ctx-search-schema.js +135 -0
- package/build/search/flood-guard.d.ts +57 -0
- package/build/search/flood-guard.js +80 -0
- package/build/search/unified.d.ts +56 -0
- package/build/search/unified.js +104 -0
- package/build/security.d.ts +206 -0
- package/build/security.js +780 -0
- package/build/server.d.ts +240 -0
- package/build/server.js +5034 -0
- package/build/session/analytics.d.ts +773 -0
- package/build/session/analytics.js +2420 -0
- package/build/session/db.d.ts +468 -0
- package/build/session/db.js +1330 -0
- package/build/session/error-classifier.d.ts +87 -0
- package/build/session/error-classifier.js +303 -0
- package/build/session/event-emit.d.ts +48 -0
- package/build/session/event-emit.js +101 -0
- package/build/session/extract.d.ts +333 -0
- package/build/session/extract.js +2688 -0
- package/build/session/model-prices.json +429 -0
- package/build/session/persist-tool-calls.d.ts +54 -0
- package/build/session/persist-tool-calls.js +105 -0
- package/build/session/pricing.d.ts +64 -0
- package/build/session/pricing.js +151 -0
- package/build/session/project-attribution.d.ts +73 -0
- package/build/session/project-attribution.js +245 -0
- package/build/session/purge.d.ts +138 -0
- package/build/session/purge.js +240 -0
- package/build/session/retrieval-marker.d.ts +39 -0
- package/build/session/retrieval-marker.js +65 -0
- package/build/session/snapshot.d.ts +46 -0
- package/build/session/snapshot.js +532 -0
- package/build/store-directory.d.ts +56 -0
- package/build/store-directory.js +254 -0
- package/build/store.d.ts +147 -0
- package/build/store.js +1714 -0
- package/build/truncate.d.ts +57 -0
- package/build/truncate.js +142 -0
- package/build/types.d.ts +117 -0
- package/build/types.js +20 -0
- package/build/util/claude-config.d.ts +32 -0
- package/build/util/claude-config.js +84 -0
- package/build/util/hook-config.d.ts +27 -0
- package/build/util/hook-config.js +76 -0
- package/build/util/jsonc.d.ts +14 -0
- package/build/util/jsonc.js +104 -0
- package/build/util/plugin-cache-integrity.d.ts +51 -0
- package/build/util/plugin-cache-integrity.js +146 -0
- package/build/util/project-dir.d.ts +149 -0
- package/build/util/project-dir.js +340 -0
- package/build/util/sibling-mcp.d.ts +79 -0
- package/build/util/sibling-mcp.js +181 -0
- package/cli.bundle.mjs +1495 -0
- package/configs/antigravity/GEMINI.md +68 -0
- package/configs/antigravity/mcp_config.json +7 -0
- package/configs/antigravity-cli/hooks/hooks.json +37 -0
- package/configs/antigravity-cli/hooks.json +37 -0
- package/configs/antigravity-cli/mcp_config.json +10 -0
- package/configs/antigravity-cli/plugin.json +14 -0
- package/configs/antigravity-cli/rules/context-mode.md +77 -0
- package/configs/antigravity-cli/skills/context-mode/SKILL.md +77 -0
- package/configs/claude-code/CLAUDE.md +91 -0
- package/configs/codex/AGENTS.md +99 -0
- package/configs/codex/config.toml +8 -0
- package/configs/codex/hooks.json +47 -0
- package/configs/copilot-cli/.github/plugin/plugin.json +23 -0
- package/configs/copilot-cli/.mcp.json +12 -0
- package/configs/copilot-cli/README.md +47 -0
- package/configs/copilot-cli/hooks.json +41 -0
- package/configs/copilot-cli/skills/context-mode/SKILL.md +38 -0
- package/configs/cursor/context-mode.mdc +76 -0
- package/configs/cursor/hooks.json +21 -0
- package/configs/cursor/mcp.json +7 -0
- package/configs/gemini-cli/GEMINI.md +88 -0
- package/configs/gemini-cli/mcp.json +7 -0
- package/configs/gemini-cli/settings.json +60 -0
- package/configs/jetbrains-copilot/copilot-instructions.md +80 -0
- package/configs/jetbrains-copilot/hooks.json +16 -0
- package/configs/jetbrains-copilot/mcp.json +7 -0
- package/configs/kilo/AGENTS.md +84 -0
- package/configs/kilo/kilo.json +6 -0
- package/configs/kimi/hooks.json +54 -0
- package/configs/kiro/KIRO.md +84 -0
- package/configs/kiro/agent.json +18 -0
- package/configs/kiro/mcp.json +7 -0
- package/configs/omp/SYSTEM.md +85 -0
- package/configs/omp/mcp.json +7 -0
- package/configs/openclaw/AGENTS.md +87 -0
- package/configs/openclaw/openclaw.json +13 -0
- package/configs/opencode/AGENTS.md +84 -0
- package/configs/opencode/opencode.json +6 -0
- package/configs/pi/AGENTS.md +3 -0
- package/configs/qwen-code/QWEN.md +91 -0
- package/configs/vscode-copilot/copilot-instructions.md +80 -0
- package/configs/vscode-copilot/hooks.json +16 -0
- package/configs/vscode-copilot/mcp.json +7 -0
- package/configs/zed/AGENTS.md +68 -0
- package/hooks/antigravity-cli/payload.mjs +98 -0
- package/hooks/antigravity-cli/posttooluse.mjs +138 -0
- package/hooks/antigravity-cli/pretooluse.mjs +78 -0
- package/hooks/antigravity-cli/stop.mjs +58 -0
- package/hooks/auto-injection.mjs +102 -0
- package/hooks/cache-heal-utils.mjs +379 -0
- package/hooks/codex/platform.mjs +1 -0
- package/hooks/codex/posttooluse.mjs +66 -0
- package/hooks/codex/precompact.mjs +70 -0
- package/hooks/codex/pretooluse.mjs +42 -0
- package/hooks/codex/sessionstart.mjs +121 -0
- package/hooks/codex/stop.mjs +138 -0
- package/hooks/codex/userpromptsubmit.mjs +75 -0
- package/hooks/copilot-cli/posttooluse.mjs +79 -0
- package/hooks/copilot-cli/precompact.mjs +66 -0
- package/hooks/copilot-cli/pretooluse.mjs +41 -0
- package/hooks/copilot-cli/sessionstart.mjs +121 -0
- package/hooks/copilot-cli/stop.mjs +59 -0
- package/hooks/copilot-cli/userpromptsubmit.mjs +77 -0
- package/hooks/core/codex-caps.mjs +112 -0
- package/hooks/core/formatters.mjs +356 -0
- package/hooks/core/mcp-ready.mjs +109 -0
- package/hooks/core/platform-detect.mjs +49 -0
- package/hooks/core/routing.mjs +1050 -0
- package/hooks/core/stdin.mjs +90 -0
- package/hooks/core/tool-naming.mjs +57 -0
- package/hooks/cursor/afteragentresponse.mjs +74 -0
- package/hooks/cursor/hooks.json +31 -0
- package/hooks/cursor/posttooluse.mjs +72 -0
- package/hooks/cursor/pretooluse.mjs +26 -0
- package/hooks/cursor/sessionstart.mjs +97 -0
- package/hooks/cursor/stop.mjs +48 -0
- package/hooks/ensure-deps.mjs +254 -0
- package/hooks/formatters/claude-code.mjs +113 -0
- package/hooks/formatters/cursor.mjs +37 -0
- package/hooks/formatters/gemini-cli.mjs +55 -0
- package/hooks/formatters/vscode-copilot.mjs +55 -0
- package/hooks/gemini-cli/aftermodel.mjs +70 -0
- package/hooks/gemini-cli/aftertool.mjs +61 -0
- package/hooks/gemini-cli/beforeagent.mjs +99 -0
- package/hooks/gemini-cli/beforetool.mjs +27 -0
- package/hooks/gemini-cli/precompress.mjs +55 -0
- package/hooks/gemini-cli/sessionstart.mjs +137 -0
- package/hooks/heal-partial-install.mjs +712 -0
- package/hooks/hooks.json +143 -0
- package/hooks/jetbrains-copilot/posttooluse.mjs +61 -0
- package/hooks/jetbrains-copilot/precompact.mjs +55 -0
- package/hooks/jetbrains-copilot/pretooluse.mjs +27 -0
- package/hooks/jetbrains-copilot/sessionstart.mjs +124 -0
- package/hooks/kimi/platform.mjs +1 -0
- package/hooks/kimi/posttooluse.mjs +72 -0
- package/hooks/kimi/precompact.mjs +80 -0
- package/hooks/kimi/pretooluse.mjs +42 -0
- package/hooks/kimi/sessionend.mjs +61 -0
- package/hooks/kimi/sessionstart.mjs +113 -0
- package/hooks/kimi/stop.mjs +132 -0
- package/hooks/kimi/userpromptsubmit.mjs +90 -0
- package/hooks/kiro/agentspawn.mjs +97 -0
- package/hooks/kiro/posttooluse.mjs +51 -0
- package/hooks/kiro/pretooluse.mjs +64 -0
- package/hooks/kiro/userpromptsubmit.mjs +88 -0
- package/hooks/normalize-hooks.mjs +323 -0
- package/hooks/platform-bridge.mjs +340 -0
- package/hooks/posttooluse.mjs +225 -0
- package/hooks/precompact.mjs +100 -0
- package/hooks/pretooluse.mjs +227 -0
- package/hooks/qwen-code/platform.mjs +1 -0
- package/hooks/qwen-code/stop.mjs +168 -0
- package/hooks/routing-block.mjs +105 -0
- package/hooks/run-hook.mjs +95 -0
- package/hooks/security.bundle.mjs +2 -0
- package/hooks/session-attribution.bundle.mjs +1 -0
- package/hooks/session-db.bundle.mjs +145 -0
- package/hooks/session-directive.mjs +520 -0
- package/hooks/session-extract.bundle.mjs +3 -0
- package/hooks/session-helpers.mjs +428 -0
- package/hooks/session-loaders.mjs +448 -0
- package/hooks/session-snapshot.bundle.mjs +32 -0
- package/hooks/sessionstart.mjs +464 -0
- package/hooks/stop.mjs +82 -0
- package/hooks/suppress-stderr.mjs +25 -0
- package/hooks/userpromptsubmit.mjs +108 -0
- package/hooks/vscode-copilot/posttooluse.mjs +61 -0
- package/hooks/vscode-copilot/precompact.mjs +55 -0
- package/hooks/vscode-copilot/pretooluse.mjs +27 -0
- package/hooks/vscode-copilot/sessionstart.mjs +129 -0
- package/openclaw.plugin.json +38 -0
- package/package.json +132 -0
- package/scripts/heal-better-sqlite3.mjs +430 -0
- package/scripts/heal-installed-plugins.mjs +635 -0
- package/scripts/plugin-cache-integrity.mjs +248 -0
- package/scripts/postinstall.mjs +397 -0
- package/server.bundle.mjs +1421 -0
- package/server.js +5 -0
- package/skills/.ignore +7 -0
- package/skills/context-mode/SKILL.md +300 -0
- package/skills/context-mode/references/anti-patterns.md +283 -0
- package/skills/context-mode/references/patterns-javascript.md +298 -0
- package/skills/context-mode/references/patterns-python.md +304 -0
- package/skills/context-mode/references/patterns-shell.md +277 -0
- package/skills/ctx-doctor/SKILL.md +22 -0
- package/skills/ctx-index/SKILL.md +46 -0
- package/skills/ctx-insight/SKILL.md +24 -0
- package/skills/ctx-purge/SKILL.md +49 -0
- package/skills/ctx-search/SKILL.md +35 -0
- package/skills/ctx-stats/SKILL.md +26 -0
- package/skills/ctx-upgrade/SKILL.md +31 -0
- package/start.mjs +616 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters/types — Platform adapter interface for multi-platform hook support.
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract that each platform adapter must implement.
|
|
5
|
+
* Three paradigms exist across supported platforms:
|
|
6
|
+
* A) JSON stdin/stdout — Claude Code, Gemini/Qwen family CLIs, Copilot/Codex/Kimi,
|
|
7
|
+
* Cursor, Kiro, Antigravity CLI (`agy`)
|
|
8
|
+
* B) TS Plugin Functions — OpenCode, KiloCode, OpenClaw
|
|
9
|
+
* C) MCP-only (no hooks) — Antigravity IDE, Zed, Pi/OMP MCP-only paths
|
|
10
|
+
*
|
|
11
|
+
* The MCP server layer is 100% portable and needs no adapter.
|
|
12
|
+
* Only the hook layer requires platform-specific adapters.
|
|
13
|
+
*/
|
|
14
|
+
// ─────────────────────────────────────────────────────────
|
|
15
|
+
// Hook paradigm
|
|
16
|
+
// ─────────────────────────────────────────────────────────
|
|
17
|
+
import { resolveHookRuntime } from "../runtime.js";
|
|
18
|
+
// ─────────────────────────────────────────────────────────
|
|
19
|
+
// Platform detection
|
|
20
|
+
// ─────────────────────────────────────────────────────────
|
|
21
|
+
// ─────────────────────────────────────────────────────────
|
|
22
|
+
// Cross-platform command helpers (#369, #372)
|
|
23
|
+
// ─────────────────────────────────────────────────────────
|
|
24
|
+
/**
|
|
25
|
+
* Build a cross-platform `node <script>` command string.
|
|
26
|
+
*
|
|
27
|
+
* Fixes two Windows bugs:
|
|
28
|
+
* #369 — Bare `node` fails on Windows Git Bash (MSYS) because PATH
|
|
29
|
+
* resolution is unreliable. Uses `process.execPath` instead.
|
|
30
|
+
* #372 — MSYS rewrites absolute paths on non-C: drives (e.g.
|
|
31
|
+
* `C:\Users\...` → `D:\c\Users\...`). Forward slashes +
|
|
32
|
+
* double-quoting prevents the translation.
|
|
33
|
+
*
|
|
34
|
+
* Safe on macOS/Linux — quoting and forward slashes are no-ops there.
|
|
35
|
+
*/
|
|
36
|
+
export function buildNodeCommand(scriptPath, opts) {
|
|
37
|
+
let nodePath = process.execPath.replace(/\\/g, "/");
|
|
38
|
+
if (isInProcessPluginPlatform(opts?.platform)) {
|
|
39
|
+
const base = nodePath.split("/").pop().replace(/\.exe$/i, "");
|
|
40
|
+
if (!JS_RUNTIMES.has(base)) {
|
|
41
|
+
nodePath = opts?.jsRuntime?.replace(/\\/g, "/") ?? "node";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const safePath = scriptPath.replace(/\\/g, "/");
|
|
45
|
+
return `"${nodePath}" "${safePath}"`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build a cross-platform hook spawn command using the resolved JS runtime
|
|
49
|
+
* (issue #738). Identical wire-format to {@link buildNodeCommand} — two
|
|
50
|
+
* double-quoted, forward-slashed tokens separated by whitespace — so it
|
|
51
|
+
* round-trips through {@link parseNodeCommand} unchanged.
|
|
52
|
+
*
|
|
53
|
+
* The only difference is the runtime path: when a Bun ≥1.0 install is
|
|
54
|
+
* detected at process start, that path is used in place of `process.execPath`.
|
|
55
|
+
* Hooks run end-to-end in pure JS (no native modules) so swapping the
|
|
56
|
+
* runtime is a no-op for output but cuts ~40-60ms of Node cold-start per
|
|
57
|
+
* tool call.
|
|
58
|
+
*
|
|
59
|
+
* Why a SEPARATE helper instead of repurposing {@link buildNodeCommand}:
|
|
60
|
+
* `buildNodeCommand` is also called by openclaw plugin (doctor / upgrade
|
|
61
|
+
* command suggestions in `src/adapters/openclaw/plugin.ts`). Those CLI
|
|
62
|
+
* targets MUST stay on Node because they load better-sqlite3, which has
|
|
63
|
+
* no Bun-compatible prebuild yet (#543). Keeping the two helpers separate
|
|
64
|
+
* makes the audit trivial: anything emitting a hook spawn command uses
|
|
65
|
+
* `buildHookRuntimeCommand`; anything emitting a user-visible CLI command
|
|
66
|
+
* stays on `buildNodeCommand`.
|
|
67
|
+
*
|
|
68
|
+
* `opts.platform` is forwarded to {@link isInProcessPluginPlatform} so the
|
|
69
|
+
* existing opencode/kilo in-process JS-runtime substitution still works
|
|
70
|
+
* (those platforms inject their own runtime via `opts.jsRuntime`).
|
|
71
|
+
*/
|
|
72
|
+
export function buildHookRuntimeCommand(scriptPath, opts) {
|
|
73
|
+
// In-process plugin platforms (opencode/kilo) inject their own runtime —
|
|
74
|
+
// delegate to buildNodeCommand which already handles that special case.
|
|
75
|
+
if (isInProcessPluginPlatform(opts?.platform)) {
|
|
76
|
+
return buildNodeCommand(scriptPath, opts);
|
|
77
|
+
}
|
|
78
|
+
const runtime = resolveHookRuntime();
|
|
79
|
+
const runtimePath = runtime.path.replace(/\\/g, "/");
|
|
80
|
+
const safePath = scriptPath.replace(/\\/g, "/");
|
|
81
|
+
return `"${runtimePath}" "${safePath}"`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Strict inverse of `buildNodeCommand`.
|
|
85
|
+
*
|
|
86
|
+
* Returns `{ nodePath, scriptPath }` ONLY when `cmd` could have been
|
|
87
|
+
* produced by `buildNodeCommand` — i.e. exactly two double-quoted args
|
|
88
|
+
* separated by whitespace. Anything else (bare `node …`, single quotes,
|
|
89
|
+
* unquoted ambiguous input, CLI dispatcher entries) returns `null`.
|
|
90
|
+
*
|
|
91
|
+
* Why strict: the legacy `\S+\.mjs` fallback in
|
|
92
|
+
* `src/util/hook-config.ts:24` and the two-step regex in
|
|
93
|
+
* `src/adapters/claude-code/hooks.ts:178` silently grabbed the path tail
|
|
94
|
+
* after the last whitespace whenever the host wire-format dropped quotes,
|
|
95
|
+
* producing the #548 doubled-path FAIL when `pluginRoot` contained
|
|
96
|
+
* spaces (e.g. `C:\Users\High Ground Services\…`). A canonical inverse
|
|
97
|
+
* lets every emit (`buildNodeCommand`) round-trip through every parse
|
|
98
|
+
* (`parseNodeCommand`) without inventing fallbacks. Adapter #16 inherits
|
|
99
|
+
* the contract by importing one module.
|
|
100
|
+
*/
|
|
101
|
+
export function parseNodeCommand(cmd) {
|
|
102
|
+
if (typeof cmd !== "string" || cmd.length === 0)
|
|
103
|
+
return null;
|
|
104
|
+
// Match `"<nodePath>" "<scriptPath>"` with arbitrary whitespace
|
|
105
|
+
// separator. Both segments must be non-empty and contain no embedded
|
|
106
|
+
// double quotes — buildNodeCommand never emits embedded quotes.
|
|
107
|
+
const m = cmd.match(/^"([^"]+)"\s+"([^"]+)"\s*$/);
|
|
108
|
+
if (!m)
|
|
109
|
+
return null;
|
|
110
|
+
return { nodePath: m[1], scriptPath: m[2] };
|
|
111
|
+
}
|
|
112
|
+
/** Known JS runtime binary names (base filename without extension). */
|
|
113
|
+
export const JS_RUNTIMES = new Set(["node", "bun", "deno"]);
|
|
114
|
+
/** Platforms where context-mode runs as an in-process TS plugin (not MCP stdio). */
|
|
115
|
+
export const IN_PROCESS_PLUGIN_PLATFORMS = new Set(["opencode", "kilo"]);
|
|
116
|
+
export function isInProcessPluginPlatform(p) {
|
|
117
|
+
return !!p && IN_PROCESS_PLUGIN_PLATFORMS.has(p);
|
|
118
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters/vscode-copilot/config — Thin re-exports from VSCodeCopilotAdapter.
|
|
3
|
+
*
|
|
4
|
+
* This module exists for backward compatibility. All logic lives in the
|
|
5
|
+
* adapter class (index.ts). New code should use getAdapter() from detect.ts.
|
|
6
|
+
*/
|
|
7
|
+
export { VSCodeCopilotAdapter } from "./index.js";
|
|
8
|
+
export { HOOK_TYPES, HOOK_SCRIPTS, REQUIRED_HOOKS, OPTIONAL_HOOKS } from "./hooks.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters/vscode-copilot/config — Thin re-exports from VSCodeCopilotAdapter.
|
|
3
|
+
*
|
|
4
|
+
* This module exists for backward compatibility. All logic lives in the
|
|
5
|
+
* adapter class (index.ts). New code should use getAdapter() from detect.ts.
|
|
6
|
+
*/
|
|
7
|
+
export { VSCodeCopilotAdapter } from "./index.js";
|
|
8
|
+
export { HOOK_TYPES, HOOK_SCRIPTS, REQUIRED_HOOKS, OPTIONAL_HOOKS } from "./hooks.js";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters/vscode-copilot/hooks — VS Code Copilot hook definitions and matchers.
|
|
3
|
+
*
|
|
4
|
+
* Defines the hook types, matchers, and registration format specific to
|
|
5
|
+
* VS Code Copilot's hook system. This module is used by:
|
|
6
|
+
* - CLI setup/upgrade commands (to configure hooks)
|
|
7
|
+
* - Doctor command (to validate hook configuration)
|
|
8
|
+
* - Hook config generation
|
|
9
|
+
*
|
|
10
|
+
* VS Code Copilot hook system reference:
|
|
11
|
+
* - Hooks are registered in .github/hooks/*.json
|
|
12
|
+
* - Hook names: PreToolUse, PostToolUse, PreCompact, SessionStart (PascalCase)
|
|
13
|
+
* - CRITICAL: matchers are parsed but IGNORED (all hooks fire on all tools)
|
|
14
|
+
* - Input: JSON on stdin
|
|
15
|
+
* - Output: JSON on stdout (or empty for passthrough)
|
|
16
|
+
* - Preview status — API may change
|
|
17
|
+
*/
|
|
18
|
+
/** VS Code Copilot hook types. */
|
|
19
|
+
export declare const HOOK_TYPES: {
|
|
20
|
+
readonly PRE_TOOL_USE: "PreToolUse";
|
|
21
|
+
readonly POST_TOOL_USE: "PostToolUse";
|
|
22
|
+
readonly PRE_COMPACT: "PreCompact";
|
|
23
|
+
readonly SESSION_START: "SessionStart";
|
|
24
|
+
};
|
|
25
|
+
export type HookType = (typeof HOOK_TYPES)[keyof typeof HOOK_TYPES];
|
|
26
|
+
/** Map of hook types to their script file names. */
|
|
27
|
+
export declare const HOOK_SCRIPTS: Record<string, string>;
|
|
28
|
+
/** Required hooks that must be configured for context-mode to function. */
|
|
29
|
+
export declare const REQUIRED_HOOKS: HookType[];
|
|
30
|
+
/** Optional hooks that enhance functionality but aren't critical. */
|
|
31
|
+
export declare const OPTIONAL_HOOKS: HookType[];
|
|
32
|
+
/**
|
|
33
|
+
* Check if a hook entry points to a context-mode hook script.
|
|
34
|
+
* Matches both legacy format (node .../pretooluse.mjs) and
|
|
35
|
+
* CLI dispatcher format (context-mode hook vscode-copilot pretooluse).
|
|
36
|
+
*/
|
|
37
|
+
export declare function isContextModeHook(entry: {
|
|
38
|
+
hooks?: Array<{
|
|
39
|
+
command?: string;
|
|
40
|
+
}>;
|
|
41
|
+
}, hookType: HookType): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Build the hook command string for a given hook type.
|
|
44
|
+
*
|
|
45
|
+
* Always emits the CLI dispatcher form
|
|
46
|
+
* (`context-mode hook vscode-copilot <event>`) — the `pluginRoot` argument
|
|
47
|
+
* is accepted for API compatibility but intentionally ignored.
|
|
48
|
+
*
|
|
49
|
+
* Why the dispatcher form is mandatory here (Issue #613 — Tier C contract):
|
|
50
|
+
* `.github/hooks/context-mode.json` is a **workspace-committed** file
|
|
51
|
+
* (upstream: refs/platforms/vscode-copilot/assets/prompts/skills/
|
|
52
|
+
* agent-customization/references/hooks.md line 7 — "Workspace
|
|
53
|
+
* (team-shared)"). It lands in every teammate's `git status`. Embedding
|
|
54
|
+
* `process.execPath` or any absolute pluginRoot path here:
|
|
55
|
+
* - Leaks PII (username, `C:/Users/<user>/...` paths).
|
|
56
|
+
* - Breaks cross-machine portability (fnm/nvm/volta/brew shims are
|
|
57
|
+
* per-shell-session ephemeral; the path goes stale immediately on
|
|
58
|
+
* Windows + fnm).
|
|
59
|
+
*
|
|
60
|
+
* Commit `f5c9d02` (2026-03-06) added an absolute-path branch when a
|
|
61
|
+
* pluginRoot was passed. It solved a real PATH-availability bug on
|
|
62
|
+
* Brew/nvm setups by going too far — the CLI then always passes
|
|
63
|
+
* pluginRoot, so the portable form became unreachable in production
|
|
64
|
+
* and every `/ctx-upgrade` baked a non-portable command into the
|
|
65
|
+
* committed config. This reverts to the pre-`f5c9d02` shape.
|
|
66
|
+
*
|
|
67
|
+
* For users without a global install, the recovery path is the same as
|
|
68
|
+
* every other CLI-dispatcher adapter (cursor, codex):
|
|
69
|
+
* `npm install -g @mxalbert/context-mode`
|
|
70
|
+
*/
|
|
71
|
+
export declare function buildHookCommand(hookType: HookType, _pluginRoot?: string): string;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters/vscode-copilot/hooks — VS Code Copilot hook definitions and matchers.
|
|
3
|
+
*
|
|
4
|
+
* Defines the hook types, matchers, and registration format specific to
|
|
5
|
+
* VS Code Copilot's hook system. This module is used by:
|
|
6
|
+
* - CLI setup/upgrade commands (to configure hooks)
|
|
7
|
+
* - Doctor command (to validate hook configuration)
|
|
8
|
+
* - Hook config generation
|
|
9
|
+
*
|
|
10
|
+
* VS Code Copilot hook system reference:
|
|
11
|
+
* - Hooks are registered in .github/hooks/*.json
|
|
12
|
+
* - Hook names: PreToolUse, PostToolUse, PreCompact, SessionStart (PascalCase)
|
|
13
|
+
* - CRITICAL: matchers are parsed but IGNORED (all hooks fire on all tools)
|
|
14
|
+
* - Input: JSON on stdin
|
|
15
|
+
* - Output: JSON on stdout (or empty for passthrough)
|
|
16
|
+
* - Preview status — API may change
|
|
17
|
+
*/
|
|
18
|
+
// ─────────────────────────────────────────────────────────
|
|
19
|
+
// Hook type constants
|
|
20
|
+
// ─────────────────────────────────────────────────────────
|
|
21
|
+
/** VS Code Copilot hook types. */
|
|
22
|
+
export const HOOK_TYPES = {
|
|
23
|
+
PRE_TOOL_USE: "PreToolUse",
|
|
24
|
+
POST_TOOL_USE: "PostToolUse",
|
|
25
|
+
PRE_COMPACT: "PreCompact",
|
|
26
|
+
SESSION_START: "SessionStart",
|
|
27
|
+
};
|
|
28
|
+
// ─────────────────────────────────────────────────────────
|
|
29
|
+
// Hook script file names
|
|
30
|
+
// ─────────────────────────────────────────────────────────
|
|
31
|
+
/** Map of hook types to their script file names. */
|
|
32
|
+
export const HOOK_SCRIPTS = {
|
|
33
|
+
[HOOK_TYPES.PRE_TOOL_USE]: "pretooluse.mjs",
|
|
34
|
+
[HOOK_TYPES.POST_TOOL_USE]: "posttooluse.mjs",
|
|
35
|
+
[HOOK_TYPES.PRE_COMPACT]: "precompact.mjs",
|
|
36
|
+
[HOOK_TYPES.SESSION_START]: "sessionstart.mjs",
|
|
37
|
+
};
|
|
38
|
+
// ─────────────────────────────────────────────────────────
|
|
39
|
+
// Hook validation
|
|
40
|
+
// ─────────────────────────────────────────────────────────
|
|
41
|
+
/** Required hooks that must be configured for context-mode to function. */
|
|
42
|
+
export const REQUIRED_HOOKS = [
|
|
43
|
+
HOOK_TYPES.PRE_TOOL_USE,
|
|
44
|
+
HOOK_TYPES.SESSION_START,
|
|
45
|
+
];
|
|
46
|
+
/** Optional hooks that enhance functionality but aren't critical. */
|
|
47
|
+
export const OPTIONAL_HOOKS = [
|
|
48
|
+
HOOK_TYPES.POST_TOOL_USE,
|
|
49
|
+
HOOK_TYPES.PRE_COMPACT,
|
|
50
|
+
];
|
|
51
|
+
/**
|
|
52
|
+
* Check if a hook entry points to a context-mode hook script.
|
|
53
|
+
* Matches both legacy format (node .../pretooluse.mjs) and
|
|
54
|
+
* CLI dispatcher format (context-mode hook vscode-copilot pretooluse).
|
|
55
|
+
*/
|
|
56
|
+
export function isContextModeHook(entry, hookType) {
|
|
57
|
+
const scriptName = HOOK_SCRIPTS[hookType];
|
|
58
|
+
if (!scriptName)
|
|
59
|
+
return false;
|
|
60
|
+
const cliCommand = buildHookCommand(hookType);
|
|
61
|
+
return (entry.hooks?.some((h) => h.command?.includes(scriptName) || h.command?.includes(cliCommand)) ?? false);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Build the hook command string for a given hook type.
|
|
65
|
+
*
|
|
66
|
+
* Always emits the CLI dispatcher form
|
|
67
|
+
* (`context-mode hook vscode-copilot <event>`) — the `pluginRoot` argument
|
|
68
|
+
* is accepted for API compatibility but intentionally ignored.
|
|
69
|
+
*
|
|
70
|
+
* Why the dispatcher form is mandatory here (Issue #613 — Tier C contract):
|
|
71
|
+
* `.github/hooks/context-mode.json` is a **workspace-committed** file
|
|
72
|
+
* (upstream: refs/platforms/vscode-copilot/assets/prompts/skills/
|
|
73
|
+
* agent-customization/references/hooks.md line 7 — "Workspace
|
|
74
|
+
* (team-shared)"). It lands in every teammate's `git status`. Embedding
|
|
75
|
+
* `process.execPath` or any absolute pluginRoot path here:
|
|
76
|
+
* - Leaks PII (username, `C:/Users/<user>/...` paths).
|
|
77
|
+
* - Breaks cross-machine portability (fnm/nvm/volta/brew shims are
|
|
78
|
+
* per-shell-session ephemeral; the path goes stale immediately on
|
|
79
|
+
* Windows + fnm).
|
|
80
|
+
*
|
|
81
|
+
* Commit `f5c9d02` (2026-03-06) added an absolute-path branch when a
|
|
82
|
+
* pluginRoot was passed. It solved a real PATH-availability bug on
|
|
83
|
+
* Brew/nvm setups by going too far — the CLI then always passes
|
|
84
|
+
* pluginRoot, so the portable form became unreachable in production
|
|
85
|
+
* and every `/ctx-upgrade` baked a non-portable command into the
|
|
86
|
+
* committed config. This reverts to the pre-`f5c9d02` shape.
|
|
87
|
+
*
|
|
88
|
+
* For users without a global install, the recovery path is the same as
|
|
89
|
+
* every other CLI-dispatcher adapter (cursor, codex):
|
|
90
|
+
* `npm install -g @mxalbert/context-mode`
|
|
91
|
+
*/
|
|
92
|
+
export function buildHookCommand(hookType, _pluginRoot) {
|
|
93
|
+
const scriptName = HOOK_SCRIPTS[hookType];
|
|
94
|
+
if (!scriptName) {
|
|
95
|
+
throw new Error(`No script defined for hook type: ${hookType}`);
|
|
96
|
+
}
|
|
97
|
+
return `context-mode hook vscode-copilot ${hookType.toLowerCase()}`;
|
|
98
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters/vscode-copilot — VS Code Copilot platform adapter.
|
|
3
|
+
*
|
|
4
|
+
* Extends CopilotBaseAdapter with VS Code-specific logic:
|
|
5
|
+
* - extractSessionId: VSCODE_PID fallback
|
|
6
|
+
* - getProjectDir: CLAUDE_PROJECT_DIR
|
|
7
|
+
* - getSessionDir: .github/ detection with ~/.vscode/ fallback
|
|
8
|
+
* - checkPluginRegistration: reads .vscode/mcp.json
|
|
9
|
+
* - getInstalledVersion: scans VS Code extensions dir
|
|
10
|
+
* - validateHooks: preview status + matcher warnings
|
|
11
|
+
*/
|
|
12
|
+
import { CopilotBaseAdapter } from "../copilot-base.js";
|
|
13
|
+
import type { CopilotHookInput, CopilotHookModule } from "../copilot-base.js";
|
|
14
|
+
import type { DiagnosticResult } from "../types.js";
|
|
15
|
+
export declare class VSCodeCopilotAdapter extends CopilotBaseAdapter {
|
|
16
|
+
constructor();
|
|
17
|
+
readonly name = "VS Code Copilot";
|
|
18
|
+
protected readonly hookModule: CopilotHookModule;
|
|
19
|
+
protected readonly hookSubdir = "vscode-copilot";
|
|
20
|
+
protected extractSessionId(input: CopilotHookInput): string;
|
|
21
|
+
protected getProjectDir(): string;
|
|
22
|
+
getSessionDir(): string;
|
|
23
|
+
/**
|
|
24
|
+
* VS Code Copilot honors .github/copilot-instructions.md per project.
|
|
25
|
+
* Always returned absolute, resolved against `projectDir` (or `cwd`).
|
|
26
|
+
*/
|
|
27
|
+
getConfigDir(projectDir?: string): string;
|
|
28
|
+
getInstructionFiles(): string[];
|
|
29
|
+
validateHooks(pluginRoot: string): DiagnosticResult[];
|
|
30
|
+
checkPluginRegistration(): DiagnosticResult;
|
|
31
|
+
getInstalledVersion(): string;
|
|
32
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters/vscode-copilot — VS Code Copilot platform adapter.
|
|
3
|
+
*
|
|
4
|
+
* Extends CopilotBaseAdapter with VS Code-specific logic:
|
|
5
|
+
* - extractSessionId: VSCODE_PID fallback
|
|
6
|
+
* - getProjectDir: CLAUDE_PROJECT_DIR
|
|
7
|
+
* - getSessionDir: .github/ detection with ~/.vscode/ fallback
|
|
8
|
+
* - checkPluginRegistration: reads .vscode/mcp.json
|
|
9
|
+
* - getInstalledVersion: scans VS Code extensions dir
|
|
10
|
+
* - validateHooks: preview status + matcher warnings
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync, mkdirSync, accessSync, existsSync, constants, } from "node:fs";
|
|
13
|
+
import { resolve, join } from "node:path";
|
|
14
|
+
import { homedir } from "node:os";
|
|
15
|
+
import { CopilotBaseAdapter } from "../copilot-base.js";
|
|
16
|
+
import { resolveContextModeDataRoot } from "../base.js";
|
|
17
|
+
// ─────────────────────────────────────────────────────────
|
|
18
|
+
// Hook constants (re-exported from hooks.ts)
|
|
19
|
+
// ─────────────────────────────────────────────────────────
|
|
20
|
+
import { HOOK_TYPES as VSCODE_HOOK_NAMES, HOOK_SCRIPTS as VSCODE_HOOK_SCRIPTS, buildHookCommand as buildVSCodeHookCommand, } from "./hooks.js";
|
|
21
|
+
// ─────────────────────────────────────────────────────────
|
|
22
|
+
// Adapter implementation
|
|
23
|
+
// ─────────────────────────────────────────────────────────
|
|
24
|
+
export class VSCodeCopilotAdapter extends CopilotBaseAdapter {
|
|
25
|
+
constructor() {
|
|
26
|
+
// sessionDirSegments unused — vscode-copilot overrides getSessionDir()
|
|
27
|
+
// with .github directory detection fallback logic
|
|
28
|
+
super([".vscode"]);
|
|
29
|
+
}
|
|
30
|
+
name = "VS Code Copilot";
|
|
31
|
+
hookModule = {
|
|
32
|
+
HOOK_TYPES: VSCODE_HOOK_NAMES,
|
|
33
|
+
HOOK_SCRIPTS: VSCODE_HOOK_SCRIPTS,
|
|
34
|
+
buildHookCommand: buildVSCodeHookCommand,
|
|
35
|
+
};
|
|
36
|
+
hookSubdir = "vscode-copilot";
|
|
37
|
+
// ── Platform-specific overrides ────────────────────────
|
|
38
|
+
extractSessionId(input) {
|
|
39
|
+
if (input.sessionId)
|
|
40
|
+
return input.sessionId;
|
|
41
|
+
if (process.env.VSCODE_PID)
|
|
42
|
+
return `vscode-${process.env.VSCODE_PID}`;
|
|
43
|
+
return `pid-${process.ppid}`;
|
|
44
|
+
}
|
|
45
|
+
getProjectDir() {
|
|
46
|
+
// Cascade order (locked by tests/adapters/vscode-copilot.test.ts):
|
|
47
|
+
// 1. CLAUDE_PROJECT_DIR — top priority for users running VS Code under
|
|
48
|
+
// Claude Code CLI.
|
|
49
|
+
// 2. VSCODE_CWD — exported by VS Code's bootstrap into every child it
|
|
50
|
+
// spawns (refs/platforms/vscode-copilot/src/util/vs/base/common/
|
|
51
|
+
// process.ts:31). The MCP child inherits it. Was previously missing
|
|
52
|
+
// from this cascade — every direct VS Code Copilot session silently
|
|
53
|
+
// lost its workspace folder. PR #689 5-agent EM audit (Phase A
|
|
54
|
+
// claim verification) confirmed the gap; this is the minimal fix.
|
|
55
|
+
// 3. process.cwd() — last resort.
|
|
56
|
+
return (process.env.CLAUDE_PROJECT_DIR
|
|
57
|
+
|| process.env.VSCODE_CWD
|
|
58
|
+
|| process.cwd());
|
|
59
|
+
}
|
|
60
|
+
getSessionDir() {
|
|
61
|
+
// Issue #649: CONTEXT_MODE_DATA_DIR wins over both the .github project
|
|
62
|
+
// dir and the ~/.vscode fallback so dev-container/CI users can pin
|
|
63
|
+
// storage to a writable volume regardless of whether a .github tree
|
|
64
|
+
// happens to exist in cwd.
|
|
65
|
+
const override = resolveContextModeDataRoot();
|
|
66
|
+
if (override) {
|
|
67
|
+
const overrideDir = join(override, "context-mode", "sessions");
|
|
68
|
+
mkdirSync(overrideDir, { recursive: true });
|
|
69
|
+
return overrideDir;
|
|
70
|
+
}
|
|
71
|
+
// Prefer .github/context-mode/sessions/ if .github exists,
|
|
72
|
+
// otherwise fall back to ~/.vscode/context-mode/sessions/
|
|
73
|
+
const githubDir = resolve(".github", "context-mode", "sessions");
|
|
74
|
+
const fallbackDir = join(homedir(), ".vscode", "context-mode", "sessions");
|
|
75
|
+
const dir = existsSync(resolve(".github")) ? githubDir : fallbackDir;
|
|
76
|
+
mkdirSync(dir, { recursive: true });
|
|
77
|
+
return dir;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* VS Code Copilot honors .github/copilot-instructions.md per project.
|
|
81
|
+
* Always returned absolute, resolved against `projectDir` (or `cwd`).
|
|
82
|
+
*/
|
|
83
|
+
getConfigDir(projectDir) {
|
|
84
|
+
return resolve(projectDir ?? process.cwd(), ".github");
|
|
85
|
+
}
|
|
86
|
+
getInstructionFiles() {
|
|
87
|
+
return ["copilot-instructions.md"];
|
|
88
|
+
}
|
|
89
|
+
// ── Diagnostics (doctor) ─────────────────────────────────
|
|
90
|
+
validateHooks(pluginRoot) {
|
|
91
|
+
const results = [];
|
|
92
|
+
// Check .github/hooks/ directory for hook JSON files
|
|
93
|
+
const hooksDir = resolve(".github", "hooks");
|
|
94
|
+
try {
|
|
95
|
+
accessSync(hooksDir, constants.R_OK);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
results.push({
|
|
99
|
+
check: "Hooks directory",
|
|
100
|
+
status: "fail",
|
|
101
|
+
message: ".github/hooks/ directory not found",
|
|
102
|
+
fix: "context-mode upgrade",
|
|
103
|
+
});
|
|
104
|
+
return results;
|
|
105
|
+
}
|
|
106
|
+
// Check for context-mode hook config
|
|
107
|
+
const hookConfigPath = resolve(hooksDir, "context-mode.json");
|
|
108
|
+
try {
|
|
109
|
+
const raw = readFileSync(hookConfigPath, "utf-8");
|
|
110
|
+
const config = JSON.parse(raw);
|
|
111
|
+
const hooks = config.hooks;
|
|
112
|
+
// Check PreToolUse
|
|
113
|
+
if (hooks?.[VSCODE_HOOK_NAMES.PRE_TOOL_USE]) {
|
|
114
|
+
results.push({
|
|
115
|
+
check: "PreToolUse hook",
|
|
116
|
+
status: "pass",
|
|
117
|
+
message: "PreToolUse hook configured in context-mode.json",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
results.push({
|
|
122
|
+
check: "PreToolUse hook",
|
|
123
|
+
status: "fail",
|
|
124
|
+
message: "PreToolUse not found in context-mode.json",
|
|
125
|
+
fix: "context-mode upgrade",
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
// Check SessionStart
|
|
129
|
+
if (hooks?.[VSCODE_HOOK_NAMES.SESSION_START]) {
|
|
130
|
+
results.push({
|
|
131
|
+
check: "SessionStart hook",
|
|
132
|
+
status: "pass",
|
|
133
|
+
message: "SessionStart hook configured in context-mode.json",
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
results.push({
|
|
138
|
+
check: "SessionStart hook",
|
|
139
|
+
status: "fail",
|
|
140
|
+
message: "SessionStart not found in context-mode.json",
|
|
141
|
+
fix: "context-mode upgrade",
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
results.push({
|
|
147
|
+
check: "Hook configuration",
|
|
148
|
+
status: "fail",
|
|
149
|
+
message: "Could not read .github/hooks/context-mode.json",
|
|
150
|
+
fix: "context-mode upgrade",
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// Warn about preview status
|
|
154
|
+
results.push({
|
|
155
|
+
check: "API stability",
|
|
156
|
+
status: "warn",
|
|
157
|
+
message: "VS Code Copilot hooks are in preview — API may change without notice",
|
|
158
|
+
});
|
|
159
|
+
// Warn about matcher behavior
|
|
160
|
+
results.push({
|
|
161
|
+
check: "Matcher support",
|
|
162
|
+
status: "warn",
|
|
163
|
+
message: "Matchers are parsed but IGNORED — all hooks fire on all tools",
|
|
164
|
+
});
|
|
165
|
+
return results;
|
|
166
|
+
}
|
|
167
|
+
checkPluginRegistration() {
|
|
168
|
+
// Check MCP config in .vscode/mcp.json
|
|
169
|
+
try {
|
|
170
|
+
const mcpConfigPath = resolve(".vscode", "mcp.json");
|
|
171
|
+
const raw = readFileSync(mcpConfigPath, "utf-8");
|
|
172
|
+
const config = JSON.parse(raw);
|
|
173
|
+
const servers = config.servers;
|
|
174
|
+
if (servers) {
|
|
175
|
+
const hasPlugin = Object.keys(servers).some((k) => k.includes("context-mode"));
|
|
176
|
+
if (hasPlugin) {
|
|
177
|
+
return {
|
|
178
|
+
check: "MCP registration",
|
|
179
|
+
status: "pass",
|
|
180
|
+
message: "context-mode found in .vscode/mcp.json",
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
check: "MCP registration",
|
|
186
|
+
status: "fail",
|
|
187
|
+
message: "context-mode not found in .vscode/mcp.json",
|
|
188
|
+
fix: "Add context-mode server to .vscode/mcp.json",
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return {
|
|
193
|
+
check: "MCP registration",
|
|
194
|
+
status: "warn",
|
|
195
|
+
message: "Could not read .vscode/mcp.json",
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
getInstalledVersion() {
|
|
200
|
+
// Check VS Code extensions for context-mode
|
|
201
|
+
const extensionDirs = [
|
|
202
|
+
join(homedir(), ".vscode", "extensions"),
|
|
203
|
+
join(homedir(), ".vscode-insiders", "extensions"),
|
|
204
|
+
];
|
|
205
|
+
for (const extDir of extensionDirs) {
|
|
206
|
+
try {
|
|
207
|
+
const entries = readFileSync(join(extDir, "extensions.json"), "utf-8");
|
|
208
|
+
const exts = JSON.parse(entries);
|
|
209
|
+
const contextMode = exts.find((e) => typeof e.identifier === "object" &&
|
|
210
|
+
e.identifier !== null &&
|
|
211
|
+
e.identifier.id?.toString().includes("context-mode"));
|
|
212
|
+
if (contextMode && typeof contextMode.version === "string") {
|
|
213
|
+
return contextMode.version;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return "not installed";
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters/zed — Zed editor platform adapter.
|
|
3
|
+
*
|
|
4
|
+
* Implements HookAdapter for Zed's MCP-only paradigm.
|
|
5
|
+
*
|
|
6
|
+
* Zed hook specifics:
|
|
7
|
+
* - NO hook support — Zed is an editor, not a CLI with hook pipelines
|
|
8
|
+
* - Config: ~/.config/zed/settings.json (JSON format)
|
|
9
|
+
* - MCP: full support via context_servers section in settings.json
|
|
10
|
+
* - All capabilities are false — MCP is the only integration path
|
|
11
|
+
* - Session dir: ~/.config/zed/context-mode/sessions/
|
|
12
|
+
*/
|
|
13
|
+
import { BaseAdapter } from "../base.js";
|
|
14
|
+
import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
|
|
15
|
+
export declare class ZedAdapter extends BaseAdapter implements HookAdapter {
|
|
16
|
+
constructor();
|
|
17
|
+
readonly name = "Zed";
|
|
18
|
+
readonly paradigm: HookParadigm;
|
|
19
|
+
readonly capabilities: PlatformCapabilities;
|
|
20
|
+
parsePreToolUseInput(_raw: unknown): PreToolUseEvent;
|
|
21
|
+
parsePostToolUseInput(_raw: unknown): PostToolUseEvent;
|
|
22
|
+
parsePreCompactInput(_raw: unknown): PreCompactEvent;
|
|
23
|
+
parseSessionStartInput(_raw: unknown): SessionStartEvent;
|
|
24
|
+
formatPreToolUseResponse(_response: PreToolUseResponse): unknown;
|
|
25
|
+
formatPostToolUseResponse(_response: PostToolUseResponse): unknown;
|
|
26
|
+
formatPreCompactResponse(_response: PreCompactResponse): unknown;
|
|
27
|
+
formatSessionStartResponse(_response: SessionStartResponse): unknown;
|
|
28
|
+
getSettingsPath(): string;
|
|
29
|
+
getInstructionFiles(): string[];
|
|
30
|
+
generateHookConfig(_pluginRoot: string): HookRegistration;
|
|
31
|
+
readSettings(): Record<string, unknown> | null;
|
|
32
|
+
writeSettings(settings: Record<string, unknown>): void;
|
|
33
|
+
validateHooks(_pluginRoot: string): DiagnosticResult[];
|
|
34
|
+
checkPluginRegistration(): DiagnosticResult;
|
|
35
|
+
getInstalledVersion(): string;
|
|
36
|
+
configureAllHooks(_pluginRoot: string): string[];
|
|
37
|
+
setHookPermissions(_pluginRoot: string): string[];
|
|
38
|
+
updatePluginRegistry(_pluginRoot: string, _version: string): void;
|
|
39
|
+
getRoutingInstructions(): string;
|
|
40
|
+
}
|