@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.
Files changed (365) hide show
  1. package/.claude-plugin/marketplace.json +33 -0
  2. package/.claude-plugin/plugin.json +31 -0
  3. package/.codex-plugin/hooks.json +65 -0
  4. package/.codex-plugin/mcp.json +13 -0
  5. package/.codex-plugin/plugin.json +31 -0
  6. package/.openclaw-plugin/index.ts +12 -0
  7. package/.openclaw-plugin/openclaw.plugin.json +38 -0
  8. package/.openclaw-plugin/package.json +28 -0
  9. package/LICENSE +94 -0
  10. package/README.md +1619 -0
  11. package/bin/statusline.mjs +378 -0
  12. package/build/adapters/antigravity/index.d.ts +51 -0
  13. package/build/adapters/antigravity/index.js +169 -0
  14. package/build/adapters/antigravity-cli/index.d.ts +51 -0
  15. package/build/adapters/antigravity-cli/index.js +342 -0
  16. package/build/adapters/base.d.ts +92 -0
  17. package/build/adapters/base.js +135 -0
  18. package/build/adapters/claude-code/config.d.ts +8 -0
  19. package/build/adapters/claude-code/config.js +8 -0
  20. package/build/adapters/claude-code/hooks.d.ts +106 -0
  21. package/build/adapters/claude-code/hooks.js +183 -0
  22. package/build/adapters/claude-code/index.d.ts +80 -0
  23. package/build/adapters/claude-code/index.js +569 -0
  24. package/build/adapters/claude-code-base.d.ts +49 -0
  25. package/build/adapters/claude-code-base.js +113 -0
  26. package/build/adapters/client-map.d.ts +10 -0
  27. package/build/adapters/client-map.js +42 -0
  28. package/build/adapters/codex/config.d.ts +8 -0
  29. package/build/adapters/codex/config.js +8 -0
  30. package/build/adapters/codex/hooks.d.ts +55 -0
  31. package/build/adapters/codex/hooks.js +64 -0
  32. package/build/adapters/codex/index.d.ts +87 -0
  33. package/build/adapters/codex/index.js +995 -0
  34. package/build/adapters/codex/paths.d.ts +1 -0
  35. package/build/adapters/codex/paths.js +12 -0
  36. package/build/adapters/codex/usage.d.ts +107 -0
  37. package/build/adapters/codex/usage.js +227 -0
  38. package/build/adapters/copilot-base.d.ts +94 -0
  39. package/build/adapters/copilot-base.js +297 -0
  40. package/build/adapters/copilot-cli/hooks.d.ts +33 -0
  41. package/build/adapters/copilot-cli/hooks.js +64 -0
  42. package/build/adapters/copilot-cli/index.d.ts +48 -0
  43. package/build/adapters/copilot-cli/index.js +341 -0
  44. package/build/adapters/cursor/config.d.ts +4 -0
  45. package/build/adapters/cursor/config.js +4 -0
  46. package/build/adapters/cursor/hooks.d.ts +55 -0
  47. package/build/adapters/cursor/hooks.js +82 -0
  48. package/build/adapters/cursor/index.d.ts +64 -0
  49. package/build/adapters/cursor/index.js +517 -0
  50. package/build/adapters/detect.d.ts +136 -0
  51. package/build/adapters/detect.js +623 -0
  52. package/build/adapters/gemini-cli/config.d.ts +8 -0
  53. package/build/adapters/gemini-cli/config.js +8 -0
  54. package/build/adapters/gemini-cli/hooks.d.ts +83 -0
  55. package/build/adapters/gemini-cli/hooks.js +115 -0
  56. package/build/adapters/gemini-cli/index.d.ts +80 -0
  57. package/build/adapters/gemini-cli/index.js +483 -0
  58. package/build/adapters/jetbrains-copilot/config.d.ts +8 -0
  59. package/build/adapters/jetbrains-copilot/config.js +8 -0
  60. package/build/adapters/jetbrains-copilot/hooks.d.ts +59 -0
  61. package/build/adapters/jetbrains-copilot/hooks.js +87 -0
  62. package/build/adapters/jetbrains-copilot/index.d.ts +31 -0
  63. package/build/adapters/jetbrains-copilot/index.js +131 -0
  64. package/build/adapters/kimi/config.d.ts +8 -0
  65. package/build/adapters/kimi/config.js +8 -0
  66. package/build/adapters/kimi/hooks.d.ts +28 -0
  67. package/build/adapters/kimi/hooks.js +34 -0
  68. package/build/adapters/kimi/index.d.ts +66 -0
  69. package/build/adapters/kimi/index.js +537 -0
  70. package/build/adapters/kimi/paths.d.ts +21 -0
  71. package/build/adapters/kimi/paths.js +52 -0
  72. package/build/adapters/kimi/usage.d.ts +82 -0
  73. package/build/adapters/kimi/usage.js +217 -0
  74. package/build/adapters/kiro/hooks.d.ts +61 -0
  75. package/build/adapters/kiro/hooks.js +94 -0
  76. package/build/adapters/kiro/index.d.ts +61 -0
  77. package/build/adapters/kiro/index.js +301 -0
  78. package/build/adapters/omp/index.d.ts +65 -0
  79. package/build/adapters/omp/index.js +182 -0
  80. package/build/adapters/omp/plugin.d.ts +81 -0
  81. package/build/adapters/omp/plugin.js +331 -0
  82. package/build/adapters/omp/usage.d.ts +49 -0
  83. package/build/adapters/omp/usage.js +110 -0
  84. package/build/adapters/openclaw/config.d.ts +8 -0
  85. package/build/adapters/openclaw/config.js +8 -0
  86. package/build/adapters/openclaw/hooks.d.ts +50 -0
  87. package/build/adapters/openclaw/hooks.js +61 -0
  88. package/build/adapters/openclaw/index.d.ts +74 -0
  89. package/build/adapters/openclaw/index.js +439 -0
  90. package/build/adapters/openclaw/mcp-tools.d.ts +54 -0
  91. package/build/adapters/openclaw/mcp-tools.js +207 -0
  92. package/build/adapters/openclaw/plugin.d.ts +141 -0
  93. package/build/adapters/openclaw/plugin.js +818 -0
  94. package/build/adapters/openclaw/session-db.d.ts +55 -0
  95. package/build/adapters/openclaw/session-db.js +88 -0
  96. package/build/adapters/openclaw/usage.d.ts +34 -0
  97. package/build/adapters/openclaw/usage.js +52 -0
  98. package/build/adapters/openclaw/workspace-router.d.ts +29 -0
  99. package/build/adapters/openclaw/workspace-router.js +64 -0
  100. package/build/adapters/opencode/config.d.ts +8 -0
  101. package/build/adapters/opencode/config.js +8 -0
  102. package/build/adapters/opencode/hooks.d.ts +38 -0
  103. package/build/adapters/opencode/hooks.js +50 -0
  104. package/build/adapters/opencode/index.d.ts +144 -0
  105. package/build/adapters/opencode/index.js +638 -0
  106. package/build/adapters/opencode/plugin.d.ts +249 -0
  107. package/build/adapters/opencode/plugin.js +1536 -0
  108. package/build/adapters/opencode/v2.d.ts +117 -0
  109. package/build/adapters/opencode/v2.js +224 -0
  110. package/build/adapters/opencode/zod3tov4.d.ts +1 -0
  111. package/build/adapters/opencode/zod3tov4.js +132 -0
  112. package/build/adapters/pi/extension.d.ts +81 -0
  113. package/build/adapters/pi/extension.js +861 -0
  114. package/build/adapters/pi/index.d.ts +57 -0
  115. package/build/adapters/pi/index.js +173 -0
  116. package/build/adapters/pi/mcp-bridge.d.ts +268 -0
  117. package/build/adapters/pi/mcp-bridge.js +894 -0
  118. package/build/adapters/qwen-code/hooks.d.ts +26 -0
  119. package/build/adapters/qwen-code/hooks.js +29 -0
  120. package/build/adapters/qwen-code/index.d.ts +40 -0
  121. package/build/adapters/qwen-code/index.js +361 -0
  122. package/build/adapters/qwen-code/usage.d.ts +90 -0
  123. package/build/adapters/qwen-code/usage.js +222 -0
  124. package/build/adapters/types.d.ts +360 -0
  125. package/build/adapters/types.js +118 -0
  126. package/build/adapters/vscode-copilot/config.d.ts +8 -0
  127. package/build/adapters/vscode-copilot/config.js +8 -0
  128. package/build/adapters/vscode-copilot/hooks.d.ts +71 -0
  129. package/build/adapters/vscode-copilot/hooks.js +98 -0
  130. package/build/adapters/vscode-copilot/index.d.ts +32 -0
  131. package/build/adapters/vscode-copilot/index.js +222 -0
  132. package/build/adapters/zed/index.d.ts +40 -0
  133. package/build/adapters/zed/index.js +163 -0
  134. package/build/cli.d.ts +34 -0
  135. package/build/cli.js +1828 -0
  136. package/build/db-base.d.ts +250 -0
  137. package/build/db-base.js +756 -0
  138. package/build/executor.d.ts +72 -0
  139. package/build/executor.js +678 -0
  140. package/build/exit-classify.d.ts +19 -0
  141. package/build/exit-classify.js +12 -0
  142. package/build/fetch/blocks.d.ts +145 -0
  143. package/build/fetch/blocks.js +244 -0
  144. package/build/fetch/extract.d.ts +68 -0
  145. package/build/fetch/extract.js +123 -0
  146. package/build/fetch/page-store.d.ts +66 -0
  147. package/build/fetch/page-store.js +174 -0
  148. package/build/fetch-cache.d.ts +13 -0
  149. package/build/fetch-cache.js +15 -0
  150. package/build/lifecycle.d.ts +124 -0
  151. package/build/lifecycle.js +278 -0
  152. package/build/package-identity.d.ts +26 -0
  153. package/build/package-identity.js +28 -0
  154. package/build/runPool.d.ts +36 -0
  155. package/build/runPool.js +51 -0
  156. package/build/runtime.d.ts +71 -0
  157. package/build/runtime.js +659 -0
  158. package/build/search/auto-memory.d.ts +47 -0
  159. package/build/search/auto-memory.js +170 -0
  160. package/build/search/ctx-search-schema.d.ts +90 -0
  161. package/build/search/ctx-search-schema.js +135 -0
  162. package/build/search/flood-guard.d.ts +57 -0
  163. package/build/search/flood-guard.js +80 -0
  164. package/build/search/unified.d.ts +56 -0
  165. package/build/search/unified.js +104 -0
  166. package/build/security.d.ts +206 -0
  167. package/build/security.js +780 -0
  168. package/build/server.d.ts +240 -0
  169. package/build/server.js +5034 -0
  170. package/build/session/analytics.d.ts +773 -0
  171. package/build/session/analytics.js +2420 -0
  172. package/build/session/db.d.ts +468 -0
  173. package/build/session/db.js +1330 -0
  174. package/build/session/error-classifier.d.ts +87 -0
  175. package/build/session/error-classifier.js +303 -0
  176. package/build/session/event-emit.d.ts +48 -0
  177. package/build/session/event-emit.js +101 -0
  178. package/build/session/extract.d.ts +333 -0
  179. package/build/session/extract.js +2688 -0
  180. package/build/session/model-prices.json +429 -0
  181. package/build/session/persist-tool-calls.d.ts +54 -0
  182. package/build/session/persist-tool-calls.js +105 -0
  183. package/build/session/pricing.d.ts +64 -0
  184. package/build/session/pricing.js +151 -0
  185. package/build/session/project-attribution.d.ts +73 -0
  186. package/build/session/project-attribution.js +245 -0
  187. package/build/session/purge.d.ts +138 -0
  188. package/build/session/purge.js +240 -0
  189. package/build/session/retrieval-marker.d.ts +39 -0
  190. package/build/session/retrieval-marker.js +65 -0
  191. package/build/session/snapshot.d.ts +46 -0
  192. package/build/session/snapshot.js +532 -0
  193. package/build/store-directory.d.ts +56 -0
  194. package/build/store-directory.js +254 -0
  195. package/build/store.d.ts +147 -0
  196. package/build/store.js +1714 -0
  197. package/build/truncate.d.ts +57 -0
  198. package/build/truncate.js +142 -0
  199. package/build/types.d.ts +117 -0
  200. package/build/types.js +20 -0
  201. package/build/util/claude-config.d.ts +32 -0
  202. package/build/util/claude-config.js +84 -0
  203. package/build/util/hook-config.d.ts +27 -0
  204. package/build/util/hook-config.js +76 -0
  205. package/build/util/jsonc.d.ts +14 -0
  206. package/build/util/jsonc.js +104 -0
  207. package/build/util/plugin-cache-integrity.d.ts +51 -0
  208. package/build/util/plugin-cache-integrity.js +146 -0
  209. package/build/util/project-dir.d.ts +149 -0
  210. package/build/util/project-dir.js +340 -0
  211. package/build/util/sibling-mcp.d.ts +79 -0
  212. package/build/util/sibling-mcp.js +181 -0
  213. package/cli.bundle.mjs +1495 -0
  214. package/configs/antigravity/GEMINI.md +68 -0
  215. package/configs/antigravity/mcp_config.json +7 -0
  216. package/configs/antigravity-cli/hooks/hooks.json +37 -0
  217. package/configs/antigravity-cli/hooks.json +37 -0
  218. package/configs/antigravity-cli/mcp_config.json +10 -0
  219. package/configs/antigravity-cli/plugin.json +14 -0
  220. package/configs/antigravity-cli/rules/context-mode.md +77 -0
  221. package/configs/antigravity-cli/skills/context-mode/SKILL.md +77 -0
  222. package/configs/claude-code/CLAUDE.md +91 -0
  223. package/configs/codex/AGENTS.md +99 -0
  224. package/configs/codex/config.toml +8 -0
  225. package/configs/codex/hooks.json +47 -0
  226. package/configs/copilot-cli/.github/plugin/plugin.json +23 -0
  227. package/configs/copilot-cli/.mcp.json +12 -0
  228. package/configs/copilot-cli/README.md +47 -0
  229. package/configs/copilot-cli/hooks.json +41 -0
  230. package/configs/copilot-cli/skills/context-mode/SKILL.md +38 -0
  231. package/configs/cursor/context-mode.mdc +76 -0
  232. package/configs/cursor/hooks.json +21 -0
  233. package/configs/cursor/mcp.json +7 -0
  234. package/configs/gemini-cli/GEMINI.md +88 -0
  235. package/configs/gemini-cli/mcp.json +7 -0
  236. package/configs/gemini-cli/settings.json +60 -0
  237. package/configs/jetbrains-copilot/copilot-instructions.md +80 -0
  238. package/configs/jetbrains-copilot/hooks.json +16 -0
  239. package/configs/jetbrains-copilot/mcp.json +7 -0
  240. package/configs/kilo/AGENTS.md +84 -0
  241. package/configs/kilo/kilo.json +6 -0
  242. package/configs/kimi/hooks.json +54 -0
  243. package/configs/kiro/KIRO.md +84 -0
  244. package/configs/kiro/agent.json +18 -0
  245. package/configs/kiro/mcp.json +7 -0
  246. package/configs/omp/SYSTEM.md +85 -0
  247. package/configs/omp/mcp.json +7 -0
  248. package/configs/openclaw/AGENTS.md +87 -0
  249. package/configs/openclaw/openclaw.json +13 -0
  250. package/configs/opencode/AGENTS.md +84 -0
  251. package/configs/opencode/opencode.json +6 -0
  252. package/configs/pi/AGENTS.md +3 -0
  253. package/configs/qwen-code/QWEN.md +91 -0
  254. package/configs/vscode-copilot/copilot-instructions.md +80 -0
  255. package/configs/vscode-copilot/hooks.json +16 -0
  256. package/configs/vscode-copilot/mcp.json +7 -0
  257. package/configs/zed/AGENTS.md +68 -0
  258. package/hooks/antigravity-cli/payload.mjs +98 -0
  259. package/hooks/antigravity-cli/posttooluse.mjs +138 -0
  260. package/hooks/antigravity-cli/pretooluse.mjs +78 -0
  261. package/hooks/antigravity-cli/stop.mjs +58 -0
  262. package/hooks/auto-injection.mjs +102 -0
  263. package/hooks/cache-heal-utils.mjs +379 -0
  264. package/hooks/codex/platform.mjs +1 -0
  265. package/hooks/codex/posttooluse.mjs +66 -0
  266. package/hooks/codex/precompact.mjs +70 -0
  267. package/hooks/codex/pretooluse.mjs +42 -0
  268. package/hooks/codex/sessionstart.mjs +121 -0
  269. package/hooks/codex/stop.mjs +138 -0
  270. package/hooks/codex/userpromptsubmit.mjs +75 -0
  271. package/hooks/copilot-cli/posttooluse.mjs +79 -0
  272. package/hooks/copilot-cli/precompact.mjs +66 -0
  273. package/hooks/copilot-cli/pretooluse.mjs +41 -0
  274. package/hooks/copilot-cli/sessionstart.mjs +121 -0
  275. package/hooks/copilot-cli/stop.mjs +59 -0
  276. package/hooks/copilot-cli/userpromptsubmit.mjs +77 -0
  277. package/hooks/core/codex-caps.mjs +112 -0
  278. package/hooks/core/formatters.mjs +356 -0
  279. package/hooks/core/mcp-ready.mjs +109 -0
  280. package/hooks/core/platform-detect.mjs +49 -0
  281. package/hooks/core/routing.mjs +1050 -0
  282. package/hooks/core/stdin.mjs +90 -0
  283. package/hooks/core/tool-naming.mjs +57 -0
  284. package/hooks/cursor/afteragentresponse.mjs +74 -0
  285. package/hooks/cursor/hooks.json +31 -0
  286. package/hooks/cursor/posttooluse.mjs +72 -0
  287. package/hooks/cursor/pretooluse.mjs +26 -0
  288. package/hooks/cursor/sessionstart.mjs +97 -0
  289. package/hooks/cursor/stop.mjs +48 -0
  290. package/hooks/ensure-deps.mjs +254 -0
  291. package/hooks/formatters/claude-code.mjs +113 -0
  292. package/hooks/formatters/cursor.mjs +37 -0
  293. package/hooks/formatters/gemini-cli.mjs +55 -0
  294. package/hooks/formatters/vscode-copilot.mjs +55 -0
  295. package/hooks/gemini-cli/aftermodel.mjs +70 -0
  296. package/hooks/gemini-cli/aftertool.mjs +61 -0
  297. package/hooks/gemini-cli/beforeagent.mjs +99 -0
  298. package/hooks/gemini-cli/beforetool.mjs +27 -0
  299. package/hooks/gemini-cli/precompress.mjs +55 -0
  300. package/hooks/gemini-cli/sessionstart.mjs +137 -0
  301. package/hooks/heal-partial-install.mjs +712 -0
  302. package/hooks/hooks.json +143 -0
  303. package/hooks/jetbrains-copilot/posttooluse.mjs +61 -0
  304. package/hooks/jetbrains-copilot/precompact.mjs +55 -0
  305. package/hooks/jetbrains-copilot/pretooluse.mjs +27 -0
  306. package/hooks/jetbrains-copilot/sessionstart.mjs +124 -0
  307. package/hooks/kimi/platform.mjs +1 -0
  308. package/hooks/kimi/posttooluse.mjs +72 -0
  309. package/hooks/kimi/precompact.mjs +80 -0
  310. package/hooks/kimi/pretooluse.mjs +42 -0
  311. package/hooks/kimi/sessionend.mjs +61 -0
  312. package/hooks/kimi/sessionstart.mjs +113 -0
  313. package/hooks/kimi/stop.mjs +132 -0
  314. package/hooks/kimi/userpromptsubmit.mjs +90 -0
  315. package/hooks/kiro/agentspawn.mjs +97 -0
  316. package/hooks/kiro/posttooluse.mjs +51 -0
  317. package/hooks/kiro/pretooluse.mjs +64 -0
  318. package/hooks/kiro/userpromptsubmit.mjs +88 -0
  319. package/hooks/normalize-hooks.mjs +323 -0
  320. package/hooks/platform-bridge.mjs +340 -0
  321. package/hooks/posttooluse.mjs +225 -0
  322. package/hooks/precompact.mjs +100 -0
  323. package/hooks/pretooluse.mjs +227 -0
  324. package/hooks/qwen-code/platform.mjs +1 -0
  325. package/hooks/qwen-code/stop.mjs +168 -0
  326. package/hooks/routing-block.mjs +105 -0
  327. package/hooks/run-hook.mjs +95 -0
  328. package/hooks/security.bundle.mjs +2 -0
  329. package/hooks/session-attribution.bundle.mjs +1 -0
  330. package/hooks/session-db.bundle.mjs +145 -0
  331. package/hooks/session-directive.mjs +520 -0
  332. package/hooks/session-extract.bundle.mjs +3 -0
  333. package/hooks/session-helpers.mjs +428 -0
  334. package/hooks/session-loaders.mjs +448 -0
  335. package/hooks/session-snapshot.bundle.mjs +32 -0
  336. package/hooks/sessionstart.mjs +464 -0
  337. package/hooks/stop.mjs +82 -0
  338. package/hooks/suppress-stderr.mjs +25 -0
  339. package/hooks/userpromptsubmit.mjs +108 -0
  340. package/hooks/vscode-copilot/posttooluse.mjs +61 -0
  341. package/hooks/vscode-copilot/precompact.mjs +55 -0
  342. package/hooks/vscode-copilot/pretooluse.mjs +27 -0
  343. package/hooks/vscode-copilot/sessionstart.mjs +129 -0
  344. package/openclaw.plugin.json +38 -0
  345. package/package.json +132 -0
  346. package/scripts/heal-better-sqlite3.mjs +430 -0
  347. package/scripts/heal-installed-plugins.mjs +635 -0
  348. package/scripts/plugin-cache-integrity.mjs +248 -0
  349. package/scripts/postinstall.mjs +397 -0
  350. package/server.bundle.mjs +1421 -0
  351. package/server.js +5 -0
  352. package/skills/.ignore +7 -0
  353. package/skills/context-mode/SKILL.md +300 -0
  354. package/skills/context-mode/references/anti-patterns.md +283 -0
  355. package/skills/context-mode/references/patterns-javascript.md +298 -0
  356. package/skills/context-mode/references/patterns-python.md +304 -0
  357. package/skills/context-mode/references/patterns-shell.md +277 -0
  358. package/skills/ctx-doctor/SKILL.md +22 -0
  359. package/skills/ctx-index/SKILL.md +46 -0
  360. package/skills/ctx-insight/SKILL.md +24 -0
  361. package/skills/ctx-purge/SKILL.md +49 -0
  362. package/skills/ctx-search/SKILL.md +35 -0
  363. package/skills/ctx-stats/SKILL.md +26 -0
  364. package/skills/ctx-upgrade/SKILL.md +31 -0
  365. package/start.mjs +616 -0
@@ -0,0 +1,57 @@
1
+ /**
2
+ * adapters/pi — Pi coding agent platform adapter.
3
+ *
4
+ * Implements HookAdapter for Pi's MCP-only paradigm at the adapter layer.
5
+ *
6
+ * Pi hook specifics:
7
+ * - NO JSON-stdio hooks. Pi exposes a JS-callback runtime API
8
+ * (`pi.on("session_start", fn)`, `pi.on("tool_call", fn)`, …) which is
9
+ * wired DIRECTLY by `src/adapters/pi/extension.ts`. The HookAdapter
10
+ * contract here intentionally reports `mcp-only` and all-false
11
+ * capabilities so harness paths that walk the JSON-stdio matrix do not
12
+ * try to register stdio hooks for Pi.
13
+ * - Config root: ~/.pi/
14
+ * - Settings: ~/.pi/settings.json (kept lightweight — Pi does not
15
+ * prescribe a canonical settings file, but several internal tools
16
+ * write one; using settings.json keeps parity with Claude Code).
17
+ * - Session dir: ~/.pi/context-mode/sessions/ (parallel to ~/.claude/,
18
+ * ~/.omp/) — this is the data-isolation contract from issue #473.
19
+ * - Instruction file: AGENTS.md (per configs/pi/AGENTS.md).
20
+ *
21
+ * Why a dedicated adapter is mandatory:
22
+ * Before this adapter existed, `getAdapter("pi")` fell through to the
23
+ * `default` arm of the switch in `src/adapters/detect.ts` and returned a
24
+ * ClaudeCodeAdapter. Pi sessions therefore wrote DBs and event logs into
25
+ * `~/.claude/context-mode/sessions/`, contaminating Claude Code state and
26
+ * silently leaking Pi user data into the wrong storage root (issue #473
27
+ * follow-up). The OMP adapter fixed the same class of bug for OMP; this
28
+ * adapter closes the gap for Pi.
29
+ */
30
+ import { BaseAdapter } from "../base.js";
31
+ import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
32
+ export declare class PiAdapter extends BaseAdapter implements HookAdapter {
33
+ constructor();
34
+ readonly name = "Pi";
35
+ readonly paradigm: HookParadigm;
36
+ readonly capabilities: PlatformCapabilities;
37
+ parsePreToolUseInput(_raw: unknown): PreToolUseEvent;
38
+ parsePostToolUseInput(_raw: unknown): PostToolUseEvent;
39
+ parsePreCompactInput(_raw: unknown): PreCompactEvent;
40
+ parseSessionStartInput(_raw: unknown): SessionStartEvent;
41
+ formatPreToolUseResponse(_response: PreToolUseResponse): unknown;
42
+ formatPostToolUseResponse(_response: PostToolUseResponse): unknown;
43
+ formatPreCompactResponse(_response: PreCompactResponse): unknown;
44
+ formatSessionStartResponse(_response: SessionStartResponse): unknown;
45
+ getSettingsPath(): string;
46
+ getInstructionFiles(): string[];
47
+ generateHookConfig(_pluginRoot: string): HookRegistration;
48
+ readSettings(): Record<string, unknown> | null;
49
+ writeSettings(settings: Record<string, unknown>): void;
50
+ validateHooks(_pluginRoot: string): DiagnosticResult[];
51
+ checkPluginRegistration(): DiagnosticResult;
52
+ getInstalledVersion(): string;
53
+ configureAllHooks(_pluginRoot: string): string[];
54
+ setHookPermissions(_pluginRoot: string): string[];
55
+ updatePluginRegistry(_pluginRoot: string, _version: string): void;
56
+ getRoutingInstructions(): string;
57
+ }
@@ -0,0 +1,173 @@
1
+ /**
2
+ * adapters/pi — Pi coding agent platform adapter.
3
+ *
4
+ * Implements HookAdapter for Pi's MCP-only paradigm at the adapter layer.
5
+ *
6
+ * Pi hook specifics:
7
+ * - NO JSON-stdio hooks. Pi exposes a JS-callback runtime API
8
+ * (`pi.on("session_start", fn)`, `pi.on("tool_call", fn)`, …) which is
9
+ * wired DIRECTLY by `src/adapters/pi/extension.ts`. The HookAdapter
10
+ * contract here intentionally reports `mcp-only` and all-false
11
+ * capabilities so harness paths that walk the JSON-stdio matrix do not
12
+ * try to register stdio hooks for Pi.
13
+ * - Config root: ~/.pi/
14
+ * - Settings: ~/.pi/settings.json (kept lightweight — Pi does not
15
+ * prescribe a canonical settings file, but several internal tools
16
+ * write one; using settings.json keeps parity with Claude Code).
17
+ * - Session dir: ~/.pi/context-mode/sessions/ (parallel to ~/.claude/,
18
+ * ~/.omp/) — this is the data-isolation contract from issue #473.
19
+ * - Instruction file: AGENTS.md (per configs/pi/AGENTS.md).
20
+ *
21
+ * Why a dedicated adapter is mandatory:
22
+ * Before this adapter existed, `getAdapter("pi")` fell through to the
23
+ * `default` arm of the switch in `src/adapters/detect.ts` and returned a
24
+ * ClaudeCodeAdapter. Pi sessions therefore wrote DBs and event logs into
25
+ * `~/.claude/context-mode/sessions/`, contaminating Claude Code state and
26
+ * silently leaking Pi user data into the wrong storage root (issue #473
27
+ * follow-up). The OMP adapter fixed the same class of bug for OMP; this
28
+ * adapter closes the gap for Pi.
29
+ */
30
+ import { readFileSync, writeFileSync, mkdirSync, } from "node:fs";
31
+ import { resolve, dirname } from "node:path";
32
+ import { homedir } from "node:os";
33
+ import { BaseAdapter } from "../base.js";
34
+ // ─────────────────────────────────────────────────────────
35
+ // Adapter implementation
36
+ // ─────────────────────────────────────────────────────────
37
+ export class PiAdapter extends BaseAdapter {
38
+ constructor() {
39
+ super([".pi"]);
40
+ }
41
+ name = "Pi";
42
+ paradigm = "mcp-only";
43
+ capabilities = {
44
+ preToolUse: false,
45
+ postToolUse: false,
46
+ preCompact: false,
47
+ sessionStart: false,
48
+ canModifyArgs: false,
49
+ canModifyOutput: false,
50
+ canInjectSessionContext: false,
51
+ };
52
+ // ── Input parsing ──────────────────────────────────────
53
+ // Pi does not feed the adapter via JSON-stdio. These methods exist to
54
+ // satisfy the HookAdapter contract and throw if the harness mistakenly
55
+ // routes a JSON-stdio event through the adapter.
56
+ parsePreToolUseInput(_raw) {
57
+ throw new Error("Pi does not support JSON-stdio hooks (wired via extension.ts)");
58
+ }
59
+ parsePostToolUseInput(_raw) {
60
+ throw new Error("Pi does not support JSON-stdio hooks (wired via extension.ts)");
61
+ }
62
+ parsePreCompactInput(_raw) {
63
+ throw new Error("Pi does not support JSON-stdio hooks (wired via extension.ts)");
64
+ }
65
+ parseSessionStartInput(_raw) {
66
+ throw new Error("Pi does not support JSON-stdio hooks (wired via extension.ts)");
67
+ }
68
+ // ── Response formatting ────────────────────────────────
69
+ // No JSON-stdio path — return undefined to satisfy the contract.
70
+ formatPreToolUseResponse(_response) {
71
+ return undefined;
72
+ }
73
+ formatPostToolUseResponse(_response) {
74
+ return undefined;
75
+ }
76
+ formatPreCompactResponse(_response) {
77
+ return undefined;
78
+ }
79
+ formatSessionStartResponse(_response) {
80
+ return undefined;
81
+ }
82
+ // ── Configuration ──────────────────────────────────────
83
+ getSettingsPath() {
84
+ return resolve(homedir(), ".pi", "settings.json");
85
+ }
86
+ getInstructionFiles() {
87
+ return ["AGENTS.md"];
88
+ }
89
+ generateHookConfig(_pluginRoot) {
90
+ return {};
91
+ }
92
+ readSettings() {
93
+ try {
94
+ const raw = readFileSync(this.getSettingsPath(), "utf-8");
95
+ return JSON.parse(raw);
96
+ }
97
+ catch {
98
+ return null;
99
+ }
100
+ }
101
+ writeSettings(settings) {
102
+ const settingsPath = this.getSettingsPath();
103
+ mkdirSync(dirname(settingsPath), { recursive: true });
104
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
105
+ }
106
+ // ── Diagnostics (doctor) ─────────────────────────────────
107
+ validateHooks(_pluginRoot) {
108
+ return [
109
+ {
110
+ check: "Hook support",
111
+ status: "pass",
112
+ message: "Pi hooks are wired via the context-mode Pi extension " +
113
+ "(~/.pi/extensions/context-mode/), not via JSON-stdio.",
114
+ },
115
+ ];
116
+ }
117
+ checkPluginRegistration() {
118
+ // Pi registers extensions by directory presence; the version-sync
119
+ // script writes ~/.pi/extensions/context-mode/package.json. We treat
120
+ // that file as the registration signal.
121
+ const pkgPath = resolve(homedir(), ".pi", "extensions", "context-mode", "package.json");
122
+ try {
123
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
124
+ if (pkg?.name === "context-mode") {
125
+ return {
126
+ check: "Pi extension registration",
127
+ status: "pass",
128
+ message: `context-mode extension installed at ${pkgPath}`,
129
+ };
130
+ }
131
+ return {
132
+ check: "Pi extension registration",
133
+ status: "warn",
134
+ message: `Unexpected package at ${pkgPath}`,
135
+ };
136
+ }
137
+ catch {
138
+ return {
139
+ check: "Pi extension registration",
140
+ status: "fail",
141
+ message: `context-mode not found at ${pkgPath}`,
142
+ fix: "Run: context-mode upgrade",
143
+ };
144
+ }
145
+ }
146
+ getInstalledVersion() {
147
+ try {
148
+ const pkgPath = resolve(homedir(), ".pi", "extensions", "context-mode", "package.json");
149
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
150
+ return pkg.version ?? "unknown";
151
+ }
152
+ catch {
153
+ return "not installed";
154
+ }
155
+ }
156
+ // ── Upgrade ────────────────────────────────────────────
157
+ // Pi does NOT use settings.json hook entries. The extension is the
158
+ // integration point — there is nothing for the harness to register
159
+ // beyond copying the extension into ~/.pi/extensions/context-mode/.
160
+ configureAllHooks(_pluginRoot) {
161
+ return [];
162
+ }
163
+ setHookPermissions(_pluginRoot) {
164
+ return [];
165
+ }
166
+ updatePluginRegistry(_pluginRoot, _version) {
167
+ // Pi extension version is managed by scripts/version-sync.mjs writing
168
+ // to ~/.pi/extensions/context-mode/package.json. No-op here.
169
+ }
170
+ getRoutingInstructions() {
171
+ return "# context-mode\n\nUse context-mode MCP tools (ctx_execute, ctx_execute_file, ctx_batch_execute, ctx_fetch_and_index, ctx_search) instead of inline shell/HTTP calls for data-heavy operations.";
172
+ }
173
+ }
@@ -0,0 +1,268 @@
1
+ /**
2
+ * MCP-stdio bridge for the Pi Coding Agent extension.
3
+ *
4
+ * Pi 0.73.x has no native MCP support — its README is explicit:
5
+ * > "No MCP. Build CLI tools with READMEs (see Skills), or build an
6
+ * > extension that adds MCP support."
7
+ *
8
+ * Without this bridge, the routing block tells the LLM to call
9
+ * `ctx_execute`, `ctx_search`, etc. — but those tools never enter Pi's
10
+ * tool list, so the LLM cannot reach them. context-mode then becomes a
11
+ * pure cost on Pi (~2.5K tokens of system-prompt overhead with 0
12
+ * actual ctx_* calls). Reported in mksglu/context-mode#426.
13
+ *
14
+ * The bridge spawns `server.bundle.mjs` as a long-lived child via stdio
15
+ * JSON-RPC, performs the MCP handshake, calls `tools/list` once, and
16
+ * registers each returned tool through `pi.registerTool({ … })`. Each
17
+ * tool's `execute()` forwards into the child via `tools/call` — same
18
+ * code path Claude Code, Gemini CLI, and the other adapters use, so
19
+ * Pi behavior matches the rest of the platform suite.
20
+ *
21
+ * No external dependencies — pure node:child_process + JSON line frames.
22
+ */
23
+ export interface ResolveDeps {
24
+ detect?: () => {
25
+ javascript: string | null;
26
+ };
27
+ which?: (cmd: string) => string | null;
28
+ execPath?: string;
29
+ }
30
+ /**
31
+ * Resolve a JS runtime safe to spawn the MCP server with.
32
+ *
33
+ * Returns `null` when no real runtime is reachable (caller must skip
34
+ * the bridge gracefully — see bootstrapMCPTools). Pi-named binaries are
35
+ * explicitly rejected at every step to prevent the #516 fork bomb.
36
+ */
37
+ export declare function resolveJsRuntimeForBridge(deps?: ResolveDeps): string | null;
38
+ export interface MCPTool {
39
+ name: string;
40
+ description?: string;
41
+ inputSchema?: Record<string, unknown>;
42
+ }
43
+ export interface MCPCallResult {
44
+ content?: Array<{
45
+ type?: string;
46
+ text?: string;
47
+ }>;
48
+ isError?: boolean;
49
+ }
50
+ export declare class PiTextComponent {
51
+ private text;
52
+ constructor(text?: string);
53
+ setText(text: string): void;
54
+ invalidate(): void;
55
+ render(width: number): string[];
56
+ }
57
+ export declare function truncateAnsiLine(line: string, maxWidth: number): string;
58
+ interface PiRenderTheme {
59
+ bold(text: string): string;
60
+ fg(color: string, text: string): string;
61
+ }
62
+ interface PiRenderContext {
63
+ lastComponent?: unknown;
64
+ }
65
+ /**
66
+ * Minimal stdio JSON-RPC client targeting the context-mode MCP server.
67
+ *
68
+ * Implementation notes:
69
+ * - One outstanding ID per request; results matched by `id` from the
70
+ * returned envelope. Notifications (no id) are sent fire-and-forget.
71
+ * - Buffer is split on `\n` because the MCP server writes one
72
+ * newline-delimited JSON message per `console.log` / `stdout.write`
73
+ * invocation — this is the standard MCP stdio transport framing.
74
+ * - On child exit / error, every in-flight request is rejected so
75
+ * callers do not hang forever.
76
+ */
77
+ export declare class MCPStdioClient {
78
+ private readonly serverScript;
79
+ private readonly env;
80
+ private readonly runtimeOverride;
81
+ /**
82
+ * TUI-safe sink for the child's forwarded stderr (#868). Defaults to a
83
+ * no-op so direct callers (skippedBridge, tests) never leak to the
84
+ * terminal; bootstrapMCPTools wires this to the Pi host's file logger.
85
+ */
86
+ private readonly diag;
87
+ private child;
88
+ private requestId;
89
+ private readonly pending;
90
+ private buffer;
91
+ private initialized;
92
+ private exited;
93
+ /**
94
+ * In-flight respawn promise — set while {@link respawn} runs so
95
+ * concurrent callers awaiting `request()` after an idle exit observe
96
+ * the SAME respawn, not N parallel ones. Without this guard, two
97
+ * simultaneous `callTool` calls would each see `this.exited === true`,
98
+ * each fire their own `respawn()`, and the loser leaks an orphaned
99
+ * child process the GC cannot reach (no `.kill()` reference).
100
+ */
101
+ private respawnPromise;
102
+ /**
103
+ * Live env passed to the spawned child — exposed (read-only intent)
104
+ * so tests can pin the fork-bomb-prevention env counter (#516)
105
+ * without needing to attach a process-tree probe.
106
+ */
107
+ _spawnEnv: NodeJS.ProcessEnv | null;
108
+ constructor(serverScript: string, env?: NodeJS.ProcessEnv, runtimeOverride?: string | null,
109
+ /**
110
+ * TUI-safe sink for the child's forwarded stderr (#868). Defaults to a
111
+ * no-op so direct callers (skippedBridge, tests) never leak to the
112
+ * terminal; bootstrapMCPTools wires this to the Pi host's file logger.
113
+ */
114
+ diag?: BridgeDiag);
115
+ /** Spawn the MCP child. Idempotent. */
116
+ start(): void;
117
+ private onExit;
118
+ private onData;
119
+ request<T = unknown>(method: string, params: unknown, timeoutMs?: number): Promise<T>;
120
+ private writeFrame;
121
+ notify(method: string, params: unknown): void;
122
+ initialize(): Promise<void>;
123
+ listTools(): Promise<MCPTool[]>;
124
+ callTool(name: string, args: unknown): Promise<MCPCallResult>;
125
+ /**
126
+ * Respawn the MCP child after an exit (clean shutdown or crash).
127
+ * Resets state so a fresh `start()` + `initialize()` cycle runs, then
128
+ * the caller's pending request flows through the new child.
129
+ *
130
+ * Single-flight — concurrent callers share one in-flight respawn via
131
+ * {@link respawnPromise}. Internal — only entered via {@link request}.
132
+ *
133
+ * Sequencing pinned (do not reorder without updating the regression
134
+ * test in tests/adapters/pi-mcp-bridge.test.ts):
135
+ * 1. `this.child = null` — drop stale handle
136
+ * 2. `this.buffer = ""` — discard leftover bytes from old child
137
+ * 3. `this.exited = false` — must precede `start()` + `initialize()`,
138
+ * because `request("initialize", …)`
139
+ * inside `initialize()` re-checks this
140
+ * flag and would otherwise re-enter
141
+ * respawn in an infinite loop
142
+ * 4. `this.initialized = false`
143
+ * 5. `this.start()`
144
+ * 6. `await this.initialize()` — flows through `request()` recursively
145
+ */
146
+ private respawn;
147
+ shutdown(): void;
148
+ }
149
+ /**
150
+ * Subset of the Pi ExtensionAPI we touch. Typed structurally so we don't
151
+ * pull `@earendil-works/pi-coding-agent` as a build dependency — keeps
152
+ * the bundle size unchanged and matches the existing pi-extension.ts
153
+ * style (which also types `pi` as `any`).
154
+ */
155
+ export interface PiToolRegistration {
156
+ name: string;
157
+ label: string;
158
+ description: string;
159
+ parameters: unknown;
160
+ renderCall?: (args: unknown, theme: PiRenderTheme, context: PiRenderContext) => unknown;
161
+ renderResult?: (result: MCPCallResult, options: {
162
+ expanded: boolean;
163
+ isPartial: boolean;
164
+ }, theme: PiRenderTheme, context: PiRenderContext) => unknown;
165
+ execute: (toolCallId: string, params: Record<string, unknown>) => Promise<{
166
+ content: Array<{
167
+ type: "text";
168
+ text: string;
169
+ }>;
170
+ details: Record<string, unknown>;
171
+ isError?: boolean;
172
+ }>;
173
+ }
174
+ export interface PiLikeAPI {
175
+ registerTool: (tool: PiToolRegistration) => void;
176
+ /**
177
+ * Pi's rotating file logger (`~/.omp/logs/`). Pi runs a raw-mode TUI that
178
+ * owns the terminal, so an in-process extension MUST NOT write to
179
+ * process.stdout/stderr — any console write is rendered straight into the
180
+ * editor input box and blocks typing (#868, confirmed against
181
+ * oh-my-pi tui/terminal.ts raw-mode + docs/skills/authoring-extensions.md:
182
+ * "nothing is written to the console, which would corrupt the TUI"). All
183
+ * bridge diagnostics route here instead. Optional: absent in tests / minimal
184
+ * hosts, in which case diagnostics are dropped — we NEVER fall back to the
185
+ * terminal.
186
+ */
187
+ logger?: {
188
+ debug?: (message: string, context?: Record<string, unknown>) => void;
189
+ info?: (message: string, context?: Record<string, unknown>) => void;
190
+ warn?: (message: string, context?: Record<string, unknown>) => void;
191
+ error?: (message: string, context?: Record<string, unknown>) => void;
192
+ };
193
+ }
194
+ /** TUI-safe diagnostics sink: routes to Pi's file logger, never the terminal. */
195
+ export type BridgeDiag = (line: string, level?: "warn" | "debug") => void;
196
+ /**
197
+ * Build a {@link BridgeDiag} bound to a Pi host's file logger (#868). Writing to
198
+ * process.stderr from inside Pi's raw-mode TUI corrupts the editor, so every
199
+ * bridge diagnostic — the forwarded MCP child stderr included — goes to
200
+ * `pi.logger` instead. When no logger is reachable (tests, non-Pi hosts) the
201
+ * line is dropped; we never touch the terminal as a fallback.
202
+ */
203
+ export declare function makeBridgeDiag(pi: PiLikeAPI | null | undefined): BridgeDiag;
204
+ /**
205
+ * Split a chunk of forwarded child output into lines without a regex (the repo
206
+ * forbids regex in source). Trailing `\r` is stripped so CRLF traces stay clean
207
+ * in the log; the final partial line (no trailing newline) is preserved.
208
+ */
209
+ export declare function splitDiagLines(text: string): string[];
210
+ /**
211
+ * #868: is this the FOREGROUND interactive Pi session (vs a subagent / print /
212
+ * RPC session)? Pi passes an ExtensionContext as the 2nd arg to
213
+ * `before_agent_start`; `ctx.hasUI === true` only for the interactive session
214
+ * with a real UI attached (refs oh-my-pi runner.ts:330-331), while subagents
215
+ * are provably `hasUI: false` (refs executor.ts:2052). Fail-safe: treat anything
216
+ * that is NOT an explicit `hasUI === false` as foreground, so an
217
+ * ambiguous/absent ctx keeps the session's bridge ALIVE rather than risking the
218
+ * #868 idle-drop. Mis-classifying an abandoned non-interactive child as
219
+ * foreground only costs one lingering child until parent-death/ session_shutdown
220
+ * reaps it; the opposite error re-drops the user's tools mid-session.
221
+ */
222
+ export declare function isForegroundSession(ctx: unknown): boolean;
223
+ /**
224
+ * #868: derive the bridge child's spawn env for a session kind. The FOREGROUND
225
+ * interactive session's child must never be idle-reaped — a multi-minute human
226
+ * pause should not drop its ctx_* tools — so we disable the #854 reaper for it
227
+ * via `CONTEXT_MODE_BRIDGE_IDLE_MS=0` (lifecycle.ts honors 0 → reaper not armed).
228
+ * Sub-context / non-interactive children keep the default reaper so abandoned
229
+ * children still can't accumulate (#854). The foreground child is still reaped
230
+ * on actual parent death by the ppid/​signal watchdog (#311/#388) — only the
231
+ * idle-time path is disabled. Pure; does not mutate the input env.
232
+ */
233
+ export declare function foregroundBridgeEnv(baseEnv: NodeJS.ProcessEnv, foreground: boolean): NodeJS.ProcessEnv;
234
+ /** Result of bootstrapping the bridge. */
235
+ export interface BridgeHandle {
236
+ /** Names of tools registered with Pi (for diagnostics / tests). */
237
+ tools: string[];
238
+ /** Idempotent shutdown — terminates the MCP child. */
239
+ shutdown: () => void;
240
+ /** Underlying client, exposed for tests / advanced callers. */
241
+ client: MCPStdioClient;
242
+ }
243
+ /**
244
+ * Spawn the MCP server and register each of its tools with Pi via
245
+ * `pi.registerTool()`. The same JSON Schema returned by `tools/list` is
246
+ * passed straight through as `parameters` — TypeBox emits JSON-Schema
247
+ * compatible objects, so any Pi runtime that validates JSON Schema
248
+ * accepts this shape (verified against pi 0.73.x).
249
+ *
250
+ * Errors during MCP `tools/call` are translated to a `throw` from the
251
+ * `execute()` callback — Pi's contract is "throw to mark the tool call
252
+ * failed", which lets the LLM see and adapt.
253
+ */
254
+ export interface BootstrapOptions {
255
+ env?: NodeJS.ProcessEnv;
256
+ /** DI hook for tests: override the runtime resolver entirely. */
257
+ _resolveJsRuntime?: () => string | null;
258
+ /**
259
+ * #868: true for the foreground interactive Pi session → spawn the child with
260
+ * the #854 idle reaper DISABLED so a human pause never drops its tools.
261
+ * Defaults to false (keep the reaper) for any non-foreground / unspecified
262
+ * caller; the pi extension resolves this from `ctx.hasUI` via
263
+ * {@link isForegroundSession}.
264
+ */
265
+ foreground?: boolean;
266
+ }
267
+ export declare function bootstrapMCPTools(pi: PiLikeAPI, serverScript: string, options?: BootstrapOptions): Promise<BridgeHandle>;
268
+ export {};