@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,26 @@
1
+ /**
2
+ * adapters/qwen-code/hooks — Qwen Code hook definitions.
3
+ *
4
+ * Qwen Code is a Gemini CLI fork (packages/core/src/tools/tool-names.ts —
5
+ * shares native names like `run_shell_command`, `read_file`). The hook wire
6
+ * protocol is JSON stdin / stdout, identical to Claude Code and Gemini CLI.
7
+ *
8
+ * Config: ~/.qwen/settings.json under "hooks" key.
9
+ */
10
+ /**
11
+ * Negative-lookahead matcher for external MCP tool namespaces on Qwen Code (#529).
12
+ *
13
+ * Qwen Code MCP wire shape: `mcp__<server>__<tool>` (shared with Gemini CLI
14
+ * upstream). Own context-mode MCP surfaces as both
15
+ * `mcp__plugin_context-mode_context-mode__ctx_*` (Claude shim path when users
16
+ * install via the Claude marketplace) and `mcp__context-mode__ctx_*` (Qwen
17
+ * canonical — see hooks/core/tool-naming.mjs). The negative lookahead
18
+ * `(?!.*context-mode)` excludes both variants from the external-MCP routing
19
+ * branch so context-mode's own tools (already wired by the explicit entries
20
+ * above this catch-all) are not double-routed.
21
+ *
22
+ * Without this matcher, large payloads from slack / telegram / gdrive / notion
23
+ * MCPs bypass the routing nudge and flood the model's context window —
24
+ * PostToolUse runs too late to keep the raw data out.
25
+ */
26
+ export declare const EXTERNAL_MCP_MATCHER_PATTERN = "mcp__(?!.*context-mode)";
@@ -0,0 +1,29 @@
1
+ /**
2
+ * adapters/qwen-code/hooks — Qwen Code hook definitions.
3
+ *
4
+ * Qwen Code is a Gemini CLI fork (packages/core/src/tools/tool-names.ts —
5
+ * shares native names like `run_shell_command`, `read_file`). The hook wire
6
+ * protocol is JSON stdin / stdout, identical to Claude Code and Gemini CLI.
7
+ *
8
+ * Config: ~/.qwen/settings.json under "hooks" key.
9
+ */
10
+ // ─────────────────────────────────────────────────────────
11
+ // External MCP routing matcher (#529)
12
+ // ─────────────────────────────────────────────────────────
13
+ /**
14
+ * Negative-lookahead matcher for external MCP tool namespaces on Qwen Code (#529).
15
+ *
16
+ * Qwen Code MCP wire shape: `mcp__<server>__<tool>` (shared with Gemini CLI
17
+ * upstream). Own context-mode MCP surfaces as both
18
+ * `mcp__plugin_context-mode_context-mode__ctx_*` (Claude shim path when users
19
+ * install via the Claude marketplace) and `mcp__context-mode__ctx_*` (Qwen
20
+ * canonical — see hooks/core/tool-naming.mjs). The negative lookahead
21
+ * `(?!.*context-mode)` excludes both variants from the external-MCP routing
22
+ * branch so context-mode's own tools (already wired by the explicit entries
23
+ * above this catch-all) are not double-routed.
24
+ *
25
+ * Without this matcher, large payloads from slack / telegram / gdrive / notion
26
+ * MCPs bypass the routing nudge and flood the model's context window —
27
+ * PostToolUse runs too late to keep the raw data out.
28
+ */
29
+ export const EXTERNAL_MCP_MATCHER_PATTERN = "mcp__(?!.*context-mode)";
@@ -0,0 +1,40 @@
1
+ /**
2
+ * adapters/qwen-code — Qwen Code platform adapter.
3
+ *
4
+ * Extends ClaudeCodeBaseAdapter (shared wire-protocol parse/format methods)
5
+ * with Qwen Code-specific configuration, diagnostics, and session ID logic.
6
+ *
7
+ * Differences from Claude Code:
8
+ * - Config dir: ~/.qwen/ (not ~/.claude/)
9
+ * - Env vars: QWEN_PROJECT_DIR, QWEN_SESSION_ID (not CLAUDE_*)
10
+ * - Session ID priority: session_id field first (Claude: transcript_path first)
11
+ * - No plugin registry (Qwen uses settings.json directly)
12
+ * - MCP clientInfo: qwen-cli-mcp-client-* (pattern)
13
+ * - 12 hook events (superset of Claude's 5, but context-mode uses the shared 5)
14
+ */
15
+ import { ClaudeCodeBaseAdapter, type ClaudeCodeWireInput } from "../claude-code-base.js";
16
+ import { type HookAdapter, type HookParadigm, type PlatformCapabilities, type DiagnosticResult, type HookRegistration } from "../types.js";
17
+ export declare class QwenCodeAdapter extends ClaudeCodeBaseAdapter implements HookAdapter {
18
+ constructor();
19
+ readonly name = "Qwen Code";
20
+ readonly paradigm: HookParadigm;
21
+ protected readonly projectDirEnvVar = "QWEN_PROJECT_DIR";
22
+ readonly capabilities: PlatformCapabilities;
23
+ getSettingsPath(): string;
24
+ getInstructionFiles(): string[];
25
+ generateHookConfig(pluginRoot: string): HookRegistration;
26
+ readSettings(): Record<string, unknown> | null;
27
+ writeSettings(settings: Record<string, unknown>): void;
28
+ validateHooks(_pluginRoot: string): DiagnosticResult[];
29
+ checkPluginRegistration(): DiagnosticResult;
30
+ getInstalledVersion(): string;
31
+ configureAllHooks(pluginRoot: string): string[];
32
+ setHookPermissions(_pluginRoot: string): string[];
33
+ updatePluginRegistry(_pluginRoot: string, _version: string): void;
34
+ getRoutingInstructionsConfig(): {
35
+ instructionsPath: string;
36
+ targetPath: string;
37
+ platformName: string;
38
+ };
39
+ protected extractSessionId(input: ClaudeCodeWireInput): string;
40
+ }
@@ -0,0 +1,361 @@
1
+ /**
2
+ * adapters/qwen-code — Qwen Code platform adapter.
3
+ *
4
+ * Extends ClaudeCodeBaseAdapter (shared wire-protocol parse/format methods)
5
+ * with Qwen Code-specific configuration, diagnostics, and session ID logic.
6
+ *
7
+ * Differences from Claude Code:
8
+ * - Config dir: ~/.qwen/ (not ~/.claude/)
9
+ * - Env vars: QWEN_PROJECT_DIR, QWEN_SESSION_ID (not CLAUDE_*)
10
+ * - Session ID priority: session_id field first (Claude: transcript_path first)
11
+ * - No plugin registry (Qwen uses settings.json directly)
12
+ * - MCP clientInfo: qwen-cli-mcp-client-* (pattern)
13
+ * - 12 hook events (superset of Claude's 5, but context-mode uses the shared 5)
14
+ */
15
+ import { readFileSync, writeFileSync, existsSync, } from "node:fs";
16
+ import { resolve, join } from "node:path";
17
+ import { homedir } from "node:os";
18
+ import { ClaudeCodeBaseAdapter } from "../claude-code-base.js";
19
+ import { EXTERNAL_MCP_MATCHER_PATTERN } from "./hooks.js";
20
+ import { buildHookRuntimeCommand, } from "../types.js";
21
+ // ─────────────────────────────────────────────────────────
22
+ // Adapter implementation
23
+ // ─────────────────────────────────────────────────────────
24
+ export class QwenCodeAdapter extends ClaudeCodeBaseAdapter {
25
+ constructor() {
26
+ super([".qwen"]);
27
+ }
28
+ name = "Qwen Code";
29
+ paradigm = "json-stdio";
30
+ projectDirEnvVar = "QWEN_PROJECT_DIR";
31
+ capabilities = {
32
+ preToolUse: true,
33
+ postToolUse: true,
34
+ preCompact: true,
35
+ sessionStart: true,
36
+ canModifyArgs: true,
37
+ canModifyOutput: true,
38
+ canInjectSessionContext: true,
39
+ };
40
+ // ── Configuration (differs from Claude Code) ───────────
41
+ getSettingsPath() {
42
+ return resolve(homedir(), ".qwen", "settings.json");
43
+ }
44
+ getInstructionFiles() {
45
+ return ["QWEN.md"];
46
+ }
47
+ generateHookConfig(pluginRoot) {
48
+ // Qwen Code passes native tool names in hook stdin (verified from
49
+ // packages/core/src/tools/tool-names.ts). Claude-style names (Bash, Read)
50
+ // are only accepted in permission configs, NOT in hook tool_name payloads.
51
+ const preToolUseMatcher = [
52
+ // Qwen-native names (canonical tool_name in hook stdin)
53
+ "run_shell_command", "read_file", "read_many_files", "grep_search",
54
+ "web_fetch", "agent",
55
+ // MCP tools (same naming convention as Claude Code)
56
+ "mcp__plugin_context-mode_context-mode__ctx_execute",
57
+ "mcp__plugin_context-mode_context-mode__ctx_execute_file",
58
+ "mcp__plugin_context-mode_context-mode__ctx_batch_execute",
59
+ // External MCP catch-all (#529). Negative-lookahead excludes context-mode's
60
+ // own server segments so the explicit entries above are not double-routed.
61
+ EXTERNAL_MCP_MATCHER_PATTERN,
62
+ ].join("|");
63
+ return {
64
+ PreToolUse: [
65
+ {
66
+ matcher: preToolUseMatcher,
67
+ hooks: [
68
+ { type: "command", command: buildHookRuntimeCommand(`${pluginRoot}/hooks/pretooluse.mjs`) },
69
+ ],
70
+ },
71
+ ],
72
+ PostToolUse: [
73
+ {
74
+ matcher: "run_shell_command|read_file|write_file|edit|glob|grep_search|todo_write|agent|ask_user_question|mcp__",
75
+ hooks: [
76
+ { type: "command", command: buildHookRuntimeCommand(`${pluginRoot}/hooks/posttooluse.mjs`) },
77
+ ],
78
+ },
79
+ ],
80
+ SessionStart: [
81
+ {
82
+ matcher: "",
83
+ hooks: [
84
+ { type: "command", command: buildHookRuntimeCommand(`${pluginRoot}/hooks/sessionstart.mjs`) },
85
+ ],
86
+ },
87
+ ],
88
+ PreCompact: [
89
+ {
90
+ matcher: "",
91
+ hooks: [
92
+ { type: "command", command: buildHookRuntimeCommand(`${pluginRoot}/hooks/precompact.mjs`) },
93
+ ],
94
+ },
95
+ ],
96
+ UserPromptSubmit: [
97
+ {
98
+ matcher: "",
99
+ hooks: [
100
+ { type: "command", command: buildHookRuntimeCommand(`${pluginRoot}/hooks/userpromptsubmit.mjs`) },
101
+ ],
102
+ },
103
+ ],
104
+ // Stop fires at end-of-turn. The qwen-specific stop hook records a
105
+ // turn_end marker AND captures per-turn token cost by tailing the session
106
+ // chats JSONL (~/.qwen/tmp/<hash>/chats/<sessionId>.jsonl) — usage is not
107
+ // reachable through hook stdin (usage.ts matrix §4). Points at the
108
+ // qwen-code/ hook dir (not the shared root) so it sets the qwen platform.
109
+ Stop: [
110
+ {
111
+ matcher: "",
112
+ hooks: [
113
+ { type: "command", command: buildHookRuntimeCommand(`${pluginRoot}/hooks/qwen-code/stop.mjs`) },
114
+ ],
115
+ },
116
+ ],
117
+ };
118
+ }
119
+ // ── Settings read/write ────────────────────────────────
120
+ readSettings() {
121
+ try {
122
+ const raw = readFileSync(this.getSettingsPath(), "utf-8");
123
+ return JSON.parse(raw);
124
+ }
125
+ catch {
126
+ return null;
127
+ }
128
+ }
129
+ writeSettings(settings) {
130
+ // Issue #511: use top-level static import (line 18) — never inline
131
+ // `require("node:fs")` in ESM-bundled sources. esbuild rewrites them to
132
+ // a `__require` shim that throws `Dynamic require of "node:fs" is not
133
+ // supported` under Node ESM/Bun (this adapter is pulled into both
134
+ // server.bundle.mjs and cli.bundle.mjs via adapter detect).
135
+ writeFileSync(this.getSettingsPath(), JSON.stringify(settings, null, 2));
136
+ }
137
+ // ── Diagnostics (doctor) ───────────────────────────────
138
+ validateHooks(_pluginRoot) {
139
+ const results = [];
140
+ const settings = this.readSettings();
141
+ const hooks = (settings?.hooks ?? {});
142
+ for (const hookName of ["PreToolUse", "PostToolUse", "SessionStart", "PreCompact", "UserPromptSubmit", "Stop"]) {
143
+ const configured = Array.isArray(hooks[hookName]) && hooks[hookName].length > 0;
144
+ results.push({
145
+ check: `${hookName} hook`,
146
+ status: configured ? "pass" : "fail",
147
+ message: configured
148
+ ? `${hookName} hook configured in ~/.qwen/settings.json`
149
+ : `${hookName} hook not found in ~/.qwen/settings.json`,
150
+ ...(configured ? {} : { fix: `Add ${hookName} hook to ~/.qwen/settings.json` }),
151
+ });
152
+ }
153
+ return results;
154
+ }
155
+ checkPluginRegistration() {
156
+ // Qwen Code has no plugin registry — check for MCP config instead
157
+ try {
158
+ const settings = this.readSettings();
159
+ if (settings?.mcpServers && typeof settings.mcpServers === "object") {
160
+ const servers = settings.mcpServers;
161
+ if (Object.keys(servers).some(k => k.includes("context-mode"))) {
162
+ return {
163
+ check: "Plugin registration",
164
+ status: "pass",
165
+ message: "context-mode found in mcpServers",
166
+ };
167
+ }
168
+ return {
169
+ check: "Plugin registration",
170
+ status: "fail",
171
+ message: "mcpServers exists but context-mode not found",
172
+ fix: "Add context-mode to mcpServers in ~/.qwen/settings.json",
173
+ };
174
+ }
175
+ return {
176
+ check: "Plugin registration",
177
+ status: "warn",
178
+ message: "No mcpServers in ~/.qwen/settings.json",
179
+ };
180
+ }
181
+ catch {
182
+ return {
183
+ check: "Plugin registration",
184
+ status: "warn",
185
+ message: "Could not read ~/.qwen/settings.json",
186
+ };
187
+ }
188
+ }
189
+ getInstalledVersion() {
190
+ const settings = this.readSettings();
191
+ if (!settings)
192
+ return "not installed";
193
+ const hooks = settings.hooks;
194
+ if (!hooks)
195
+ return "not installed";
196
+ // Check if any hook type has context-mode scripts configured
197
+ const contextModeScripts = [
198
+ "pretooluse.mjs",
199
+ "posttooluse.mjs",
200
+ "precompact.mjs",
201
+ "sessionstart.mjs",
202
+ "userpromptsubmit.mjs",
203
+ ];
204
+ for (const [, entries] of Object.entries(hooks)) {
205
+ if (!Array.isArray(entries))
206
+ continue;
207
+ for (const entry of entries) {
208
+ const e = entry;
209
+ if (e.hooks?.some((h) => h.command && contextModeScripts.some((s) => h.command.includes(s)))) {
210
+ return "installed (hooks configured)";
211
+ }
212
+ }
213
+ }
214
+ return "not installed";
215
+ }
216
+ configureAllHooks(pluginRoot) {
217
+ const settings = this.readSettings() ?? {};
218
+ const hooks = (settings.hooks ?? {});
219
+ const changes = [];
220
+ // ── Phase 1: Clean stale context-mode hooks ──────────
221
+ // After an upgrade, settings.json may contain hardcoded paths
222
+ // pointing to deleted version directories. Remove those.
223
+ for (const hookType of Object.keys(hooks)) {
224
+ const entries = hooks[hookType];
225
+ if (!Array.isArray(entries))
226
+ continue;
227
+ const filtered = entries.filter((entry) => {
228
+ const e = entry;
229
+ const commands = e.hooks ?? [];
230
+ // Preserve entries that are not context-mode hooks
231
+ const isContextMode = commands.some((h) => h.command && /context-mode|pretooluse|posttooluse|precompact|sessionstart|userpromptsubmit/i.test(h.command));
232
+ if (!isContextMode)
233
+ return true;
234
+ // For context-mode hooks, check if referenced script files exist
235
+ return commands.every((h) => {
236
+ if (!h.command)
237
+ return true;
238
+ // Extract path from both new ("nodePath" "scriptPath.mjs") and legacy (node .../script.mjs) formats
239
+ const newFmt = h.command.match(/"[^"]+"\s+"([^"]+\.mjs)"/);
240
+ const legacyFmt = h.command.match(/node\s+"?([^"]+\.mjs)"?/);
241
+ const scriptMatch = newFmt || legacyFmt;
242
+ if (!scriptMatch)
243
+ return true; // CLI dispatcher format, always valid
244
+ return existsSync(scriptMatch[1]);
245
+ });
246
+ });
247
+ const removed = entries.length - filtered.length;
248
+ if (removed > 0) {
249
+ hooks[hookType] = filtered;
250
+ changes.push(`Removed ${removed} stale ${hookType} hook(s)`);
251
+ }
252
+ }
253
+ // ── Phase 2: Register fresh hooks ────────────────────
254
+ // All 5 hooks must be wired (z6 — capabilities declare 5 events but
255
+ // configureAllHooks previously only wrote 2). Qwen Code's hook stdin shape
256
+ // is wire-identical to Claude Code, so we reuse top-level hook scripts.
257
+ const hookTypes = [
258
+ {
259
+ name: "PreToolUse",
260
+ script: "pretooluse.mjs",
261
+ matcher: [
262
+ "run_shell_command", "read_file", "read_many_files", "grep_search",
263
+ "web_fetch", "agent",
264
+ "mcp__plugin_context-mode_context-mode__ctx_execute",
265
+ "mcp__plugin_context-mode_context-mode__ctx_execute_file",
266
+ "mcp__plugin_context-mode_context-mode__ctx_batch_execute",
267
+ // External MCP catch-all (#529) — keep in sync with generateHookConfig above.
268
+ EXTERNAL_MCP_MATCHER_PATTERN,
269
+ ].join("|"),
270
+ },
271
+ {
272
+ name: "PostToolUse",
273
+ script: "posttooluse.mjs",
274
+ matcher: "run_shell_command|read_file|write_file|edit|glob|grep_search|todo_write|agent|ask_user_question|mcp__",
275
+ },
276
+ {
277
+ name: "SessionStart",
278
+ script: "sessionstart.mjs",
279
+ matcher: "",
280
+ },
281
+ {
282
+ name: "PreCompact",
283
+ script: "precompact.mjs",
284
+ matcher: "",
285
+ },
286
+ {
287
+ name: "UserPromptSubmit",
288
+ script: "userpromptsubmit.mjs",
289
+ matcher: "",
290
+ },
291
+ {
292
+ // Stop captures per-turn token cost by tailing the session chats JSONL
293
+ // (usage is unreachable through hook stdin). Routes to the qwen-code/
294
+ // hook dir so it sets the qwen platform — keep in sync with
295
+ // generateHookConfig above.
296
+ name: "Stop",
297
+ script: "qwen-code/stop.mjs",
298
+ matcher: "",
299
+ },
300
+ ];
301
+ for (const { name, script, matcher } of hookTypes) {
302
+ const entry = {
303
+ matcher,
304
+ hooks: [{ type: "command", command: buildHookRuntimeCommand(`${pluginRoot}/hooks/${script}`) }],
305
+ };
306
+ const existing = hooks[name];
307
+ if (existing && Array.isArray(existing)) {
308
+ // Replace existing context-mode entry or append
309
+ const idx = existing.findIndex((e) => {
310
+ const typed = e;
311
+ return typed.hooks?.some((h) => h.command?.includes(script)) ?? false;
312
+ });
313
+ if (idx >= 0) {
314
+ existing[idx] = entry;
315
+ changes.push(`Updated ${name} hook`);
316
+ }
317
+ else {
318
+ existing.push(entry);
319
+ changes.push(`Added ${name} hook`);
320
+ }
321
+ hooks[name] = existing;
322
+ }
323
+ else {
324
+ hooks[name] = [entry];
325
+ changes.push(`Created ${name} hooks`);
326
+ }
327
+ }
328
+ settings.hooks = hooks;
329
+ this.writeSettings(settings);
330
+ return changes;
331
+ }
332
+ setHookPermissions(_pluginRoot) {
333
+ return [];
334
+ }
335
+ updatePluginRegistry(_pluginRoot, _version) {
336
+ // No plugin registry in Qwen Code
337
+ }
338
+ getRoutingInstructionsConfig() {
339
+ const instructionsPath = resolve(join(homedir(), ".qwen", "QWEN.md"));
340
+ return {
341
+ instructionsPath,
342
+ targetPath: "QWEN.md",
343
+ platformName: "Qwen Code",
344
+ };
345
+ }
346
+ // ── Session ID extraction (differs from Claude Code) ───
347
+ // Qwen Code prioritizes session_id field, then QWEN_SESSION_ID env var.
348
+ // Claude Code prioritizes transcript_path UUID first.
349
+ extractSessionId(input) {
350
+ if (input.session_id)
351
+ return input.session_id;
352
+ if (input.transcript_path) {
353
+ const match = input.transcript_path.match(/([a-f0-9-]{36})\.jsonl$/);
354
+ if (match)
355
+ return match[1];
356
+ }
357
+ if (process.env.QWEN_SESSION_ID)
358
+ return process.env.QWEN_SESSION_ID;
359
+ return `pid-${process.ppid}`;
360
+ }
361
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * adapters/qwen-code/usage — per-turn token capture from the session JSONL.
3
+ *
4
+ * Qwen Code is a Gemini-CLI fork and normalizes EVERY backend (Gemini-native,
5
+ * OpenAI-compat/DashScope, Anthropic) to the same canonical token shape:
6
+ * `GenerateContentResponseUsageMetadata` { promptTokenCount, candidatesTokenCount,
7
+ * cachedContentTokenCount, thoughtsTokenCount, totalTokenCount }
8
+ * (matrix §1: turn.ts:96,417 + converter.ts:1145-1148). That metadata is
9
+ * persisted, per API call, into the session record file as a `ChatRecord`
10
+ * carrying `.usageMetadata` + `.model`
11
+ * (refs: packages/core/src/services/chatRecordingService.ts:259,261,919 file at
12
+ * ~/.qwen/tmp/<project_id>/chats/<sessionId>.jsonl — :451 location comment,
13
+ * :600,628-629 path build).
14
+ *
15
+ * CRITICAL (matrix §4): qwen-code's hook payloads carry tool I/O ONLY — token
16
+ * usage is unreachable through the hook stream (grep of hookEventHandler.ts /
17
+ * hookSystem.ts / toolHookTriggers.ts for token|usageMetadata|usage → zero
18
+ * matches). The ONLY live capture path is a tail of the session JSONL. This
19
+ * module is therefore the JSONL-tail counterpart to claude-code's
20
+ * `extractTranscriptUsageSince` (src/session/extract.ts) — same cursor-gated,
21
+ * char-algorithmic, NO-regex parse, same `buildAgentUsageEvent` emission path.
22
+ *
23
+ * Per matrix §3 each ChatRecord.usageMetadata is INCREMENTAL per API call
24
+ * (cumulative session totals are derived downstream via += in
25
+ * uiTelemetry.ts:237-241), so summing the NEW records since the cursor yields
26
+ * the exact billed delta with no double-count.
27
+ *
28
+ * No native USD — cost_usd is derived from the pricing catalog inside
29
+ * buildAgentUsageEvent (native_cost_usd omitted). Pure, null-safe, NO regex.
30
+ */
31
+ import { type AgentUsageCounts, type SessionEvent } from "../../session/extract.js";
32
+ /**
33
+ * Parse ONE qwen `ChatRecord` into the `buildAgentUsageEvent` input shape, or
34
+ * null when the record carries no usage / sums to zero.
35
+ *
36
+ * Mapping → builder shape (AgentUsageCounts):
37
+ * promptTokenCount → input_tokens
38
+ * candidatesTokenCount → output_tokens
39
+ * thoughtsTokenCount → ADDED into output_tokens (Gemini-lineage bills
40
+ * reasoning/thoughts as output — same fold as
41
+ * parseGeminiUsage in src/session/extract.ts)
42
+ * cachedContentTokenCount → cache_read_tokens (when present)
43
+ * model_id → ChatRecord.model
44
+ *
45
+ * No native cost — native_cost_usd omitted (catalog-derived). NO regex.
46
+ */
47
+ export declare function parseQwenUsage(record: unknown): AgentUsageCounts | null;
48
+ /**
49
+ * Cursor-aware tail of the qwen session JSONL. Emits one priced `agent_usage`
50
+ * event PER distinct model across the records NEW since `cursor`, so re-reading
51
+ * the (append-only, ever-growing) JSONL each Stop never double-counts.
52
+ *
53
+ * - cursor null/empty → process ALL records.
54
+ * - cursor found → process records STRICTLY AFTER it.
55
+ * - cursor set but NOT found → compaction/rotation dropped it: bounded
56
+ * fallback processes ONLY THE LAST record (never re-emit full history).
57
+ *
58
+ * `cursor` returns the id of the LAST id-bearing record seen (whether or not it
59
+ * carried usage), so the next call resumes exactly past it. When no record
60
+ * carries an id, the input cursor is returned unchanged.
61
+ *
62
+ * One linear walk, JSON.parse per line, NO regex — mirrors
63
+ * extractTranscriptUsageSince's structure exactly.
64
+ */
65
+ export declare function extractQwenUsageSince(jsonlText: string, cursor: string | null): {
66
+ events: SessionEvent[];
67
+ cursor: string | null;
68
+ };
69
+ /**
70
+ * Hash a project root into qwen-code's `<project_id>` directory segment.
71
+ *
72
+ * EXACT port of qwen's `getProjectHash`
73
+ * (refs/platforms/qwen-code/packages/core/src/utils/paths.ts:262 —
74
+ * `crypto.createHash('sha256').update(normalizedPath).digest('hex')`). On
75
+ * Windows qwen lowercases the path first (case-insensitive FS); we mirror that
76
+ * so a hook running on win32 resolves the same tmp dir qwen itself wrote.
77
+ * Pure, deterministic, NO regex.
78
+ */
79
+ export declare function qwenProjectHash(projectRoot: string): string;
80
+ /**
81
+ * Build the canonical session JSONL path qwen-code writes its ChatRecords to:
82
+ * <qwenHome>/tmp/<sha256(projectRoot)>/chats/<sessionId>.jsonl
83
+ * (refs chatRecordingService.ts:451 location + storage.ts:316-320
84
+ * getProjectTempDir → getGlobalTempDir(<qwenHome>/tmp) + getProjectHash).
85
+ *
86
+ * `qwenHome` is normally `<homedir>/.qwen`. Pure path join — does NOT touch the
87
+ * FS, so it is fully unit-testable; existence probing + the glob fallback live
88
+ * in the Stop hook (which cannot import this TS at runtime). NO regex.
89
+ */
90
+ export declare function qwenChatJsonlPath(qwenHome: string, projectRoot: string, sessionId: string): string;