@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,378 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * context-mode status line — Claude Code statusLine integration.
4
+ *
5
+ * Reads stats DIRECTLY from SessionDB (`session_events` + `session_resume`),
6
+ * mirroring the `ctx_stats` MCP handler at src/server.ts:2807-2891 so the
7
+ * statusline and ctx_stats never drift. The legacy per-PID sidecar JSON
8
+ * (`stats-pid-*.json`) is no longer the source of truth — sidecars were
9
+ * eventually-consistent (500ms+30s throttles) and PID-scoped (multiple
10
+ * Claude sessions colliding on the same shell ppid).
11
+ *
12
+ * Discipline (Datadog / Stripe / Vercel pattern):
13
+ * - "context-mode" full brand label, never abbreviated
14
+ * - ONE chromatic accent (status dot ●), everything else monochrome
15
+ * - Bold for KPI numbers ($, %), dim for context
16
+ * - No counts (calls / tokens / events) — only $ and % pass the
17
+ * value-per-pixel test
18
+ *
19
+ * Wire it up in ~/.claude/settings.json:
20
+ * {
21
+ * "statusLine": {
22
+ * "type": "command",
23
+ * "command": "context-mode statusline"
24
+ * }
25
+ * }
26
+ */
27
+
28
+ import { existsSync, readFileSync } from "node:fs";
29
+ import { dirname, resolve } from "node:path";
30
+ import { fileURLToPath, pathToFileURL } from "node:url";
31
+ import { execFileSync } from "node:child_process";
32
+ import {
33
+ ensureWritableStorageDir,
34
+ resolveDefaultSessionDir,
35
+ resolveSessionStorageDir,
36
+ } from "../hooks/session-db.bundle.mjs";
37
+
38
+ // ── Analytics import — resolved relative to this script ─────────────────
39
+ // statusline.mjs ships in `bin/`; the compiled analytics module lives in
40
+ // `build/session/analytics.js`. Import lazily so a missing build doesn't
41
+ // crash the renderer — degrade to the substantiated headline instead.
42
+ //
43
+ // The dynamic import target MUST be a `file://` URL on Windows. Node's
44
+ // ESM loader rejects absolute drive-letter paths (`C:\...`) with
45
+ // ERR_UNSUPPORTED_ESM_URL_SCHEME — which the catch below silently
46
+ // swallows, leaving `_analytics = null` and rendering the empty-state
47
+ // headline forever. Convert to a file URL so Windows accepts it.
48
+ const __filename = fileURLToPath(import.meta.url);
49
+ const __dirname = dirname(__filename);
50
+ const ANALYTICS_PATH = resolve(__dirname, "..", "build", "session", "analytics.js");
51
+ const ANALYTICS_URL = pathToFileURL(ANALYTICS_PATH).href;
52
+
53
+ let _analytics = null;
54
+ async function loadAnalytics() {
55
+ if (_analytics) return _analytics;
56
+ try {
57
+ _analytics = await import(ANALYTICS_URL);
58
+ } catch {
59
+ _analytics = null;
60
+ }
61
+ return _analytics;
62
+ }
63
+
64
+ // Test seams — keep production behaviour identical when env vars unset.
65
+ // CTX_TEST_PLATFORM — override process.platform for cross-OS resolver tests
66
+ // CTX_TEST_PROC_DIR — override /proc base dir for Linux PID-walk tests
67
+ const TEST_PLATFORM = process.env.CTX_TEST_PLATFORM;
68
+ const PROC_DIR = process.env.CTX_TEST_PROC_DIR || "/proc";
69
+ function platform() {
70
+ return TEST_PLATFORM || process.platform;
71
+ }
72
+
73
+ // Single-shot stderr warning latch — keep noise out of Claude Code's
74
+ // statusline output even when our parent runs us repeatedly per session.
75
+ const __warnedKeys = new Set();
76
+ function warnOnce(key, msg) {
77
+ if (__warnedKeys.has(key)) return;
78
+ __warnedKeys.add(key);
79
+ try { process.stderr.write(`context-mode statusline: ${msg}\n`); } catch { /* ignore */ }
80
+ }
81
+
82
+ // ── ANSI palette (single chromatic accent on the status dot) ────────────
83
+ const NO_COLOR = process.env.NO_COLOR || !process.stdout.isTTY;
84
+ const ansi = (code, text) => (NO_COLOR ? text : `\x1b[${code}m${text}\x1b[0m`);
85
+ const brand = (t) => ansi("1;36", t); // bold cyan — brand presence
86
+ const bold = (t) => ansi("1", t); // bold default fg — KPI numbers
87
+ const dim = (t) => ansi("2", t); // dim default fg — context
88
+ const green = (t) => ansi("32", t); // healthy dot
89
+ const yellow = (t) => ansi("33", t); // degraded dot
90
+ const red = (t) => ansi("31", t); // stale dot
91
+ const SEP = dim("·");
92
+
93
+ // ── Stdin drain ─────────────────────────────────────────────────────────
94
+ function readStdinJson() {
95
+ try {
96
+ const raw = readFileSync(0, "utf-8");
97
+ if (!raw.trim()) return {};
98
+ return JSON.parse(raw);
99
+ } catch (err) {
100
+ // The payload is load-bearing — it carries session_id, which resolves the
101
+ // per-session KPI. Empty stdin (normal first render) returned above and
102
+ // stays silent; a non-empty payload that fails to parse is a real anomaly
103
+ // worth one latched stderr line (never pollutes the statusline's stdout).
104
+ warnOnce("stdin-parse", `failed to parse statusline stdin JSON: ${err?.message ?? err}`);
105
+ return {};
106
+ }
107
+ }
108
+
109
+ function resolveSessionDir() {
110
+ return ensureWritableStorageDir(
111
+ resolveSessionStorageDir(() => resolveDefaultSessionDir({
112
+ configDir: ".claude",
113
+ configDirEnv: "CLAUDE_CONFIG_DIR",
114
+ legacySessionDirEnv: "CONTEXT_MODE_SESSION_DIR",
115
+ onLegacySessionDir: () => {
116
+ warnOnce(
117
+ "legacy-session-dir",
118
+ "CONTEXT_MODE_SESSION_DIR is deprecated; set CONTEXT_MODE_DIR to the parent context-mode root.",
119
+ );
120
+ },
121
+ })),
122
+ );
123
+ }
124
+
125
+ /**
126
+ * Walk up the parent process chain to find the Claude Code PID.
127
+ *
128
+ * Claude Code spawns the status line through a shell, so process.ppid is
129
+ * the intermediate shell, not Claude Code itself. We walk up until we find
130
+ * a process whose name matches /claude/i.
131
+ *
132
+ * Per-OS resolver:
133
+ * - linux: read PPid + Name from /proc/<pid>/status
134
+ * - darwin: ps -o ppid=,comm= -p <pid> (BSD ps; works without /proc)
135
+ * - win32: degraded — process.ppid only, with a one-shot stderr warning
136
+ *
137
+ * Without this walk, multiple concurrent Claude sessions all see the same
138
+ * shell ppid and collide on per-PID stats lookup.
139
+ */
140
+ function findClaudePid() {
141
+ const plat = platform();
142
+ if (plat === "linux") return findClaudePidLinux();
143
+ if (plat === "darwin") return findClaudePidDarwin();
144
+ if (plat === "win32") {
145
+ warnOnce(
146
+ "win",
147
+ "Windows process-tree walk unsupported; multiple concurrent Claude sessions may collide. Set CLAUDE_SESSION_ID for deterministic resolution.",
148
+ );
149
+ return process.ppid;
150
+ }
151
+ return process.ppid;
152
+ }
153
+
154
+ function findClaudePidLinux() {
155
+ let pid = process.ppid;
156
+ for (let i = 0; i < 8 && pid && pid > 1; i++) {
157
+ try {
158
+ const status = readFileSync(`${PROC_DIR}/${pid}/status`, "utf-8");
159
+ const nameMatch = status.match(/^Name:\s+(.+)$/m);
160
+ const ppidMatch = status.match(/^PPid:\s+(\d+)/m);
161
+ const name = nameMatch?.[1]?.trim() ?? "";
162
+ if (/claude/i.test(name)) return pid;
163
+ pid = ppidMatch ? Number(ppidMatch[1]) : 0;
164
+ } catch {
165
+ return process.ppid;
166
+ }
167
+ }
168
+ return process.ppid;
169
+ }
170
+
171
+ function findClaudePidDarwin() {
172
+ let pid = process.ppid;
173
+ for (let i = 0; i < 8 && pid && pid > 1; i++) {
174
+ try {
175
+ const out = execFileSync(
176
+ "ps",
177
+ ["-o", "ppid=,comm=", "-p", String(pid)],
178
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] },
179
+ ).trim();
180
+ if (!out) return process.ppid;
181
+ const m = out.match(/^\s*(\d+)\s+(.+)$/);
182
+ if (!m) return process.ppid;
183
+ const parentPid = Number(m[1]);
184
+ const comm = m[2].trim();
185
+ const base = comm.split("/").pop() || comm;
186
+ if (/claude/i.test(base)) return pid;
187
+ pid = parentPid;
188
+ } catch {
189
+ return process.ppid;
190
+ }
191
+ }
192
+ return process.ppid;
193
+ }
194
+
195
+ function resolveSessionId(payload) {
196
+ // PRIMARY: the session_id Claude Code delivers in the statusLine stdin
197
+ // payload. This is the SAME id the recording hooks key session_events by,
198
+ // so it's the only source that reliably matches stored per-session data.
199
+ //
200
+ // Claude Code does NOT export a CLAUDE_SESSION_ID env var — session_id is
201
+ // delivered only in the stdin JSON (statusline.md "Available data"). And the
202
+ // /proc PID walk yields `pid-<n>`, which never matches a UUID-keyed session.
203
+ // So without reading the payload, the per-session KPI is unreachable and the
204
+ // bar falls back to the global lifetime aggregate — identical in every
205
+ // session and seemingly "frozen".
206
+ const fromPayload = payload?.session_id;
207
+ if (typeof fromPayload === "string" && fromPayload) return fromPayload;
208
+ // Fallback when the payload carries no session_id (and how test fixtures
209
+ // pin a deterministic id). NOT an override — payload wins when present.
210
+ if (process.env.CLAUDE_SESSION_ID) return process.env.CLAUDE_SESSION_ID;
211
+ // Last resort: walk the process tree (only matches pid-keyed events).
212
+ return `pid-${findClaudePid()}`;
213
+ }
214
+
215
+ // ── Formatters ───────────────────────────────────────────────────────────
216
+ function fmtUsd(n) {
217
+ const safe = Number.isFinite(n) && n >= 0 ? n : 0;
218
+ if (safe >= 100) return `$${safe.toFixed(0)}`;
219
+ return `$${safe.toFixed(2)}`;
220
+ }
221
+
222
+ // ── Status dot — the ONE accent ──────────────────────────────────────────
223
+ function statusDot(pct) {
224
+ if (pct >= 50) return green("●");
225
+ if (pct >= 1) return yellow("●");
226
+ return green("●");
227
+ }
228
+
229
+ // ── Main render ──────────────────────────────────────────────────────────
230
+ async function main() {
231
+ const payload = readStdinJson(); // canonical source of session_id
232
+ const sessionsDir = resolveSessionDir();
233
+ const sessionId = resolveSessionId(payload);
234
+
235
+ const analytics = await loadAnalytics();
236
+
237
+ // BRAND-NEW / build missing — substantiated headline only
238
+ if (!analytics) {
239
+ process.stdout.write(
240
+ `${brand("context-mode")} ${green("●")} ${dim("saves ~98% of context window")}`,
241
+ );
242
+ return;
243
+ }
244
+
245
+ const {
246
+ getRealBytesStats,
247
+ getMultiAdapterLifetimeStats,
248
+ kb,
249
+ } = analytics;
250
+
251
+ // Sessions dir doesn't exist yet — first ever launch
252
+ if (!existsSync(sessionsDir)) {
253
+ process.stdout.write(
254
+ `${brand("context-mode")} ${green("●")} ${dim("saves ~98% of context window")}`,
255
+ );
256
+ return;
257
+ }
258
+
259
+ // Lifetime real-bytes across this adapter's sessions dir.
260
+ // Mirrors src/server.ts:2860 — the same call ctx_stats uses.
261
+ let lifetime;
262
+ try {
263
+ lifetime = getRealBytesStats({ sessionsDir });
264
+ } catch {
265
+ lifetime = null;
266
+ }
267
+
268
+ // Per-conversation real-bytes for the session $ KPI.
269
+ // Statusline doesn't know the worktree hash, so scan every db in the
270
+ // dir and let getRealBytesStats filter by sessionId.
271
+ let conversation;
272
+ try {
273
+ conversation = getRealBytesStats({ sessionsDir, sessionId });
274
+ } catch {
275
+ conversation = null;
276
+ }
277
+
278
+ // Cross-adapter lifetime — drives the "across N tools" headline when
279
+ // 2+ real adapters are present. Mirrors src/server.ts:2840.
280
+ let multi;
281
+ try {
282
+ multi = getMultiAdapterLifetimeStats();
283
+ } catch {
284
+ multi = null;
285
+ }
286
+
287
+ // v1.0.118: drop the $ math — ctx_stats's narrative renderer is the source
288
+ // of truth and uses byte-based metrics. Statusline mirrors the same
289
+ // formulas so the two displays never diverge again.
290
+ //
291
+ // Lifetime bytes — multi-adapter aggregate when present, else local-DB
292
+ // real bytes. Mirrors src/session/analytics.ts:1684 narrative renderer.
293
+ const lifetimeBytes = (multi?.totalBytes && multi.totalBytes > 0)
294
+ ? multi.totalBytes
295
+ : (lifetime?.totalSavedTokens ?? 0) * 4;
296
+
297
+ // This-chat bytes — real bytes accounting (data + bytes-avoided + snapshot).
298
+ const sessionBytes = conversation
299
+ ? ((conversation.eventDataBytes ?? 0)
300
+ + (conversation.bytesAvoided ?? 0)
301
+ + (conversation.snapshotBytes ?? 0))
302
+ : 0;
303
+
304
+ // Per-day average — same lifetime-day computation ctx_stats opener uses.
305
+ const sinceMs = lifetime?.firstEventMs ?? multi?.perAdapter?.[0]?.firstMs ?? 0;
306
+ const lifetimeDays = sinceMs > 0
307
+ ? Math.max(1, Math.round((Date.now() - sinceMs) / 86_400_000))
308
+ : 0;
309
+ const perDayBytes = lifetimeDays > 0 ? lifetimeBytes / lifetimeDays : 0;
310
+
311
+ // Reduction % — same as before (bytes-avoided + snapshot vs returned).
312
+ const totalReturned = lifetime?.bytesReturned ?? 0;
313
+ const totalKept =
314
+ (lifetime?.bytesAvoided ?? 0)
315
+ + (lifetime?.snapshotBytes ?? 0)
316
+ + (lifetime?.eventDataBytes ?? 0);
317
+ const totalProcessed = totalKept + totalReturned;
318
+ const pct = totalProcessed > 0
319
+ ? Math.round((totalKept / totalProcessed) * 100)
320
+ : 0;
321
+
322
+ const dot = statusDot(pct);
323
+
324
+ // Cross-tool count — used in the headline when 2+ real adapters detected.
325
+ const realAdapters = (multi?.perAdapter ?? []).filter((a) => a?.isReal);
326
+ const showMultiAdapter = realAdapters.length >= 2;
327
+
328
+ // BRAND-NEW: no data at all → marketing headline.
329
+ if (lifetimeBytes === 0 && sessionBytes === 0) {
330
+ process.stdout.write(
331
+ `${brand("context-mode")} ${green("●")} ${dim("saves ~98% of context window")}`,
332
+ );
333
+ return;
334
+ }
335
+
336
+ // FRESH session, no this-chat data yet — lead with lifetime number.
337
+ if (sessionBytes === 0 && lifetimeBytes > 0) {
338
+ const blocks = [`${bold(kb(lifetimeBytes))} ${dim("kept out")}`];
339
+ if (perDayBytes > 0) {
340
+ blocks.push(`${bold(kb(perDayBytes) + "/day")}`);
341
+ }
342
+ if (showMultiAdapter) {
343
+ blocks.push(`${dim(`across ${realAdapters.length} tools`)}`);
344
+ }
345
+ blocks.push(dim("preserved across compact, restart & upgrade"));
346
+ process.stdout.write(
347
+ `${brand("context-mode")} ${dot} ${blocks.join(` ${SEP} `)}`,
348
+ );
349
+ return;
350
+ }
351
+
352
+ // ACTIVE: this-chat · lifetime · [N tools] · % efficient
353
+ const valueBlocks = [
354
+ `${bold(kb(sessionBytes))} ${dim("this chat")}`,
355
+ ];
356
+ if (lifetimeBytes > 0) {
357
+ valueBlocks.push(`${bold(kb(lifetimeBytes))} ${dim("lifetime")}`);
358
+ }
359
+ if (showMultiAdapter) {
360
+ valueBlocks.push(`${dim(`across ${realAdapters.length} tools`)}`);
361
+ }
362
+ if (pct > 0) {
363
+ valueBlocks.push(`${bold(`${pct}%`)} ${dim("kept out")}`);
364
+ }
365
+
366
+ const head = `${brand("context-mode")} ${dot} `;
367
+ const tail = valueBlocks.join(` ${SEP} `);
368
+ process.stdout.write(head + tail);
369
+ }
370
+
371
+ main().catch(() => {
372
+ // Last-resort fallback — a thrown error must never produce a blank statusline.
373
+ try {
374
+ process.stdout.write(
375
+ `${brand("context-mode")} ${green("●")} ${dim("saves ~98% of context window")}`,
376
+ );
377
+ } catch { /* ignore */ }
378
+ });
@@ -0,0 +1,51 @@
1
+ /**
2
+ * adapters/antigravity — Google Antigravity platform adapter.
3
+ *
4
+ * Implements HookAdapter for Antigravity's MCP-only paradigm.
5
+ *
6
+ * Antigravity hook specifics:
7
+ * - NO hook support (MCP-only, same as Codex CLI)
8
+ * - Config: ~/.gemini/antigravity/mcp_config.json (JSON format)
9
+ * - MCP: full support via mcpServers in mcp_config.json
10
+ * - All capabilities are false — MCP is the only integration path
11
+ * - Session dir: ~/.gemini/context-mode/sessions/
12
+ * - Routing file: GEMINI.md (shared with Gemini CLI filename, different content)
13
+ *
14
+ * Sources:
15
+ * - Config path: https://github.com/google-gemini/gemini-cli/issues/16058
16
+ * - MCP support: https://antigravity.google/docs/mcp
17
+ * - Tool list: System prompt leak (21 verified tools)
18
+ */
19
+ import { BaseAdapter } from "../base.js";
20
+ import type { HookAdapter, HookParadigm, PlatformCapabilities, DiagnosticResult, PreToolUseEvent, PostToolUseEvent, PreCompactEvent, SessionStartEvent, PreToolUseResponse, PostToolUseResponse, PreCompactResponse, SessionStartResponse, HookRegistration } from "../types.js";
21
+ export declare class AntigravityAdapter extends BaseAdapter implements HookAdapter {
22
+ constructor();
23
+ readonly name: string;
24
+ readonly paradigm: HookParadigm;
25
+ readonly capabilities: PlatformCapabilities;
26
+ parsePreToolUseInput(_raw: unknown): PreToolUseEvent;
27
+ parsePostToolUseInput(_raw: unknown): PostToolUseEvent;
28
+ parsePreCompactInput(_raw: unknown): PreCompactEvent;
29
+ parseSessionStartInput(_raw: unknown): SessionStartEvent;
30
+ formatPreToolUseResponse(_response: PreToolUseResponse): unknown;
31
+ formatPostToolUseResponse(_response: PostToolUseResponse): unknown;
32
+ formatPreCompactResponse(_response: PreCompactResponse): unknown;
33
+ formatSessionStartResponse(_response: SessionStartResponse): unknown;
34
+ getSettingsPath(): string;
35
+ /**
36
+ * Antigravity nests under ~/.gemini/antigravity/. Always absolute.
37
+ * `_projectDir` accepted for interface symmetry but unused — home-rooted.
38
+ */
39
+ getConfigDir(_projectDir?: string): string;
40
+ getInstructionFiles(): string[];
41
+ generateHookConfig(_pluginRoot: string): HookRegistration;
42
+ readSettings(): Record<string, unknown> | null;
43
+ writeSettings(settings: Record<string, unknown>): void;
44
+ validateHooks(_pluginRoot: string): DiagnosticResult[];
45
+ checkPluginRegistration(): DiagnosticResult;
46
+ getInstalledVersion(): string;
47
+ configureAllHooks(_pluginRoot: string): string[];
48
+ setHookPermissions(_pluginRoot: string): string[];
49
+ updatePluginRegistry(_pluginRoot: string, _version: string): void;
50
+ getRoutingInstructions(): string;
51
+ }
@@ -0,0 +1,169 @@
1
+ /**
2
+ * adapters/antigravity — Google Antigravity platform adapter.
3
+ *
4
+ * Implements HookAdapter for Antigravity's MCP-only paradigm.
5
+ *
6
+ * Antigravity hook specifics:
7
+ * - NO hook support (MCP-only, same as Codex CLI)
8
+ * - Config: ~/.gemini/antigravity/mcp_config.json (JSON format)
9
+ * - MCP: full support via mcpServers in mcp_config.json
10
+ * - All capabilities are false — MCP is the only integration path
11
+ * - Session dir: ~/.gemini/context-mode/sessions/
12
+ * - Routing file: GEMINI.md (shared with Gemini CLI filename, different content)
13
+ *
14
+ * Sources:
15
+ * - Config path: https://github.com/google-gemini/gemini-cli/issues/16058
16
+ * - MCP support: https://antigravity.google/docs/mcp
17
+ * - Tool list: System prompt leak (21 verified tools)
18
+ */
19
+ import { readFileSync, writeFileSync, mkdirSync, } from "node:fs";
20
+ import { resolve, dirname } from "node:path";
21
+ import { fileURLToPath } from "node:url";
22
+ import { homedir } from "node:os";
23
+ import { BaseAdapter } from "../base.js";
24
+ // ─────────────────────────────────────────────────────────
25
+ // Adapter implementation
26
+ // ─────────────────────────────────────────────────────────
27
+ export class AntigravityAdapter extends BaseAdapter {
28
+ constructor() {
29
+ super([".gemini"]);
30
+ }
31
+ name = "Antigravity";
32
+ paradigm = "mcp-only";
33
+ capabilities = {
34
+ preToolUse: false,
35
+ postToolUse: false,
36
+ preCompact: false,
37
+ sessionStart: false,
38
+ canModifyArgs: false,
39
+ canModifyOutput: false,
40
+ canInjectSessionContext: false,
41
+ };
42
+ // ── Input parsing ──────────────────────────────────────
43
+ // Antigravity does not support hooks. These methods exist to satisfy the
44
+ // interface contract but will throw if called.
45
+ parsePreToolUseInput(_raw) {
46
+ throw new Error("Antigravity does not support hooks");
47
+ }
48
+ parsePostToolUseInput(_raw) {
49
+ throw new Error("Antigravity does not support hooks");
50
+ }
51
+ parsePreCompactInput(_raw) {
52
+ throw new Error("Antigravity does not support hooks");
53
+ }
54
+ parseSessionStartInput(_raw) {
55
+ throw new Error("Antigravity does not support hooks");
56
+ }
57
+ // ── Response formatting ────────────────────────────────
58
+ // Antigravity does not support hooks. Return undefined for all responses.
59
+ formatPreToolUseResponse(_response) {
60
+ return undefined;
61
+ }
62
+ formatPostToolUseResponse(_response) {
63
+ return undefined;
64
+ }
65
+ formatPreCompactResponse(_response) {
66
+ return undefined;
67
+ }
68
+ formatSessionStartResponse(_response) {
69
+ return undefined;
70
+ }
71
+ // ── Configuration ──────────────────────────────────────
72
+ getSettingsPath() {
73
+ return resolve(homedir(), ".gemini", "antigravity", "mcp_config.json");
74
+ }
75
+ /**
76
+ * Antigravity nests under ~/.gemini/antigravity/. Always absolute.
77
+ * `_projectDir` accepted for interface symmetry but unused — home-rooted.
78
+ */
79
+ getConfigDir(_projectDir) {
80
+ return resolve(homedir(), ".gemini", "antigravity");
81
+ }
82
+ getInstructionFiles() {
83
+ return ["GEMINI.md"];
84
+ }
85
+ generateHookConfig(_pluginRoot) {
86
+ return {};
87
+ }
88
+ readSettings() {
89
+ try {
90
+ const raw = readFileSync(this.getSettingsPath(), "utf-8");
91
+ return JSON.parse(raw);
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ }
97
+ writeSettings(settings) {
98
+ const settingsPath = this.getSettingsPath();
99
+ mkdirSync(dirname(settingsPath), { recursive: true });
100
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
101
+ }
102
+ // ── Diagnostics (doctor) ─────────────────────────────────
103
+ validateHooks(_pluginRoot) {
104
+ return [
105
+ {
106
+ check: "Hook support",
107
+ status: "warn",
108
+ message: "Antigravity does not support hooks. " +
109
+ "Only MCP integration is available.",
110
+ },
111
+ ];
112
+ }
113
+ checkPluginRegistration() {
114
+ try {
115
+ const raw = readFileSync(this.getSettingsPath(), "utf-8");
116
+ const config = JSON.parse(raw);
117
+ const mcpServers = config?.mcpServers ?? {};
118
+ if ("context-mode" in mcpServers) {
119
+ return {
120
+ check: "MCP registration",
121
+ status: "pass",
122
+ message: "context-mode found in mcpServers config",
123
+ };
124
+ }
125
+ return {
126
+ check: "MCP registration",
127
+ status: "fail",
128
+ message: "context-mode not found in mcpServers",
129
+ fix: "Add context-mode to mcpServers in ~/.gemini/antigravity/mcp_config.json",
130
+ };
131
+ }
132
+ catch {
133
+ return {
134
+ check: "MCP registration",
135
+ status: "warn",
136
+ message: "Could not read ~/.gemini/antigravity/mcp_config.json",
137
+ };
138
+ }
139
+ }
140
+ getInstalledVersion() {
141
+ try {
142
+ const pkgPath = resolve(homedir(), ".gemini", "extensions", "context-mode", "package.json");
143
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
144
+ return pkg.version ?? "unknown";
145
+ }
146
+ catch {
147
+ return "not installed";
148
+ }
149
+ }
150
+ // ── Upgrade ────────────────────────────────────────────
151
+ configureAllHooks(_pluginRoot) {
152
+ return [];
153
+ }
154
+ setHookPermissions(_pluginRoot) {
155
+ return [];
156
+ }
157
+ updatePluginRegistry(_pluginRoot, _version) {
158
+ // Antigravity plugin registry is managed via mcp_config.json
159
+ }
160
+ getRoutingInstructions() {
161
+ const instructionsPath = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "configs", "antigravity", "GEMINI.md");
162
+ try {
163
+ return readFileSync(instructionsPath, "utf-8");
164
+ }
165
+ catch {
166
+ return "# context-mode\n\nUse context-mode MCP tools (execute, execute_file, batch_execute, fetch_and_index, search) instead of run_command/view_file for data-heavy operations.";
167
+ }
168
+ }
169
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * adapters/antigravity-cli — Google Antigravity CLI (`agy`) adapter.
3
+ *
4
+ * Integration: MCP tools plus agy's Claude-compatible hook surface. `agy`
5
+ * reads its global MCP profile from `~/.gemini/config/mcp_config.json`
6
+ * (distinct from the Antigravity IDE's `~/.gemini/antigravity/mcp_config.json`)
7
+ * and hooks from `~/.gemini/config/hooks.json`, or from an installed agy
8
+ * plugin's root `hooks.json`.
9
+ *
10
+ * context-mode wires only the surfaces that have a verified mapping:
11
+ * - PreToolUse for bounded routing enforcement on Bash/Read/Grep/WebFetch
12
+ * - PostToolUse capture for executed tool calls
13
+ * - best-effort Stop capture for session-end continuity when agy emits it
14
+ *
15
+ * PreInvocation/PostInvocation are intentionally not registered here: there is
16
+ * no verified payload/response contract or shared context-mode pipeline target
17
+ * for those agy events yet.
18
+ */
19
+ import { AntigravityAdapter } from "../antigravity/index.js";
20
+ import type { DiagnosticResult, HookParadigm, PlatformCapabilities, PostToolUseEvent, PostToolUseResponse, PreToolUseEvent, PreToolUseResponse } from "../types.js";
21
+ export declare function antigravityCliMcpConfigPath(): string;
22
+ export declare function antigravityCliConfigDir(): string;
23
+ /** agy reads user hooks from ~/.gemini/config/hooks.json (sibling of mcp_config.json). */
24
+ export declare function antigravityCliHooksPath(): string;
25
+ /**
26
+ * `agy plugin install <bundle>` registers MCP + hook + skill into agy's plugin
27
+ * profile under ~/.gemini/config/plugins/<name>/ (verified on agy 1.0.6, re-verified 1.0.10) — the
28
+ * canonical install. The global mcp_config.json / hooks.json paths above are the
29
+ * manual (no-plugin) fallback. doctor must recognize BOTH.
30
+ */
31
+ export declare function antigravityCliPluginDir(): string;
32
+ export declare class AntigravityCliAdapter extends AntigravityAdapter {
33
+ readonly name = "Antigravity CLI";
34
+ readonly paradigm: HookParadigm;
35
+ readonly capabilities: PlatformCapabilities;
36
+ getSettingsPath(): string;
37
+ getConfigDir(_projectDir?: string): string;
38
+ parsePreToolUseInput(raw: unknown): PreToolUseEvent;
39
+ parsePostToolUseInput(raw: unknown): PostToolUseEvent;
40
+ formatPreToolUseResponse(response: PreToolUseResponse): unknown;
41
+ formatPostToolUseResponse(_response: PostToolUseResponse): unknown;
42
+ checkPluginRegistration(): DiagnosticResult;
43
+ getInstalledVersion(): string;
44
+ /**
45
+ * Write/merge the agy hooks into ~/.gemini/config/hooks.json (manual,
46
+ * non-plugin path). Idempotent — unrelated hook entries are preserved.
47
+ */
48
+ configureAllHooks(_pluginRoot: string): string[];
49
+ /** Report agy hook status across plugin and manual profiles. */
50
+ validateHooks(_pluginRoot: string): DiagnosticResult[];
51
+ }