context-mode 1.0.169 → 2.0.0-next.5

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 (379) hide show
  1. package/.claude-plugin/marketplace.json +4 -22
  2. package/.claude-plugin/plugin.json +9 -24
  3. package/SHA256SUMS +31 -0
  4. package/claude-code/skills/ctx-doctor/SKILL.md +6 -0
  5. package/claude-code/skills/ctx-stats/SKILL.md +6 -0
  6. package/claude-code/skills/ctx-upgrade/SKILL.md +6 -0
  7. package/cli.mjs +6744 -0
  8. package/copilot/plugin.json +14 -0
  9. package/fixtures/hook-roundtrip.json +22 -0
  10. package/gemini-extension.json +14 -0
  11. package/hook.mjs +202 -0
  12. package/hooks/claude-code.json +50 -0
  13. package/hooks/codex.json +50 -0
  14. package/hooks/copilot-cli.json +33 -0
  15. package/hooks/hooks.json +16 -111
  16. package/hooks/kiro.json +69 -0
  17. package/hooks/qwen.json +50 -0
  18. package/hooks/vscode.json +40 -0
  19. package/hooks/zcode.json +53 -0
  20. package/opencode/plugin.js +22456 -0
  21. package/package.json +29 -114
  22. package/pi/index.js +50841 -0
  23. package/pi/skills/ctx-doctor/SKILL.md +6 -0
  24. package/pi/skills/ctx-stats/SKILL.md +6 -0
  25. package/pi/skills/ctx-upgrade/SKILL.md +6 -0
  26. package/qwen-extension.json +15 -0
  27. package/run.mjs +5633 -0
  28. package/search.mjs +5633 -0
  29. package/server.mjs +48198 -0
  30. package/skills/ctx-doctor/SKILL.md +3 -19
  31. package/skills/ctx-stats/SKILL.md +3 -23
  32. package/skills/ctx-upgrade/SKILL.md +3 -28
  33. package/.codex-plugin/hooks.json +0 -65
  34. package/.codex-plugin/mcp.json +0 -13
  35. package/.codex-plugin/plugin.json +0 -31
  36. package/.openclaw-plugin/index.ts +0 -12
  37. package/.openclaw-plugin/openclaw.plugin.json +0 -38
  38. package/.openclaw-plugin/package.json +0 -28
  39. package/LICENSE +0 -94
  40. package/README.md +0 -1619
  41. package/bin/statusline.mjs +0 -378
  42. package/build/adapters/antigravity/index.d.ts +0 -51
  43. package/build/adapters/antigravity/index.js +0 -169
  44. package/build/adapters/antigravity-cli/index.d.ts +0 -51
  45. package/build/adapters/antigravity-cli/index.js +0 -342
  46. package/build/adapters/base.d.ts +0 -92
  47. package/build/adapters/base.js +0 -135
  48. package/build/adapters/claude-code/config.d.ts +0 -8
  49. package/build/adapters/claude-code/config.js +0 -8
  50. package/build/adapters/claude-code/hooks.d.ts +0 -106
  51. package/build/adapters/claude-code/hooks.js +0 -183
  52. package/build/adapters/claude-code/index.d.ts +0 -80
  53. package/build/adapters/claude-code/index.js +0 -569
  54. package/build/adapters/claude-code-base.d.ts +0 -49
  55. package/build/adapters/claude-code-base.js +0 -113
  56. package/build/adapters/client-map.d.ts +0 -10
  57. package/build/adapters/client-map.js +0 -42
  58. package/build/adapters/codex/config.d.ts +0 -8
  59. package/build/adapters/codex/config.js +0 -8
  60. package/build/adapters/codex/hooks.d.ts +0 -55
  61. package/build/adapters/codex/hooks.js +0 -64
  62. package/build/adapters/codex/index.d.ts +0 -87
  63. package/build/adapters/codex/index.js +0 -992
  64. package/build/adapters/codex/paths.d.ts +0 -1
  65. package/build/adapters/codex/paths.js +0 -12
  66. package/build/adapters/codex/usage.d.ts +0 -107
  67. package/build/adapters/codex/usage.js +0 -227
  68. package/build/adapters/copilot-base.d.ts +0 -94
  69. package/build/adapters/copilot-base.js +0 -297
  70. package/build/adapters/copilot-cli/hooks.d.ts +0 -33
  71. package/build/adapters/copilot-cli/hooks.js +0 -64
  72. package/build/adapters/copilot-cli/index.d.ts +0 -48
  73. package/build/adapters/copilot-cli/index.js +0 -341
  74. package/build/adapters/cursor/config.d.ts +0 -4
  75. package/build/adapters/cursor/config.js +0 -4
  76. package/build/adapters/cursor/hooks.d.ts +0 -55
  77. package/build/adapters/cursor/hooks.js +0 -82
  78. package/build/adapters/cursor/index.d.ts +0 -64
  79. package/build/adapters/cursor/index.js +0 -517
  80. package/build/adapters/detect.d.ts +0 -136
  81. package/build/adapters/detect.js +0 -623
  82. package/build/adapters/gemini-cli/config.d.ts +0 -8
  83. package/build/adapters/gemini-cli/config.js +0 -8
  84. package/build/adapters/gemini-cli/hooks.d.ts +0 -83
  85. package/build/adapters/gemini-cli/hooks.js +0 -115
  86. package/build/adapters/gemini-cli/index.d.ts +0 -80
  87. package/build/adapters/gemini-cli/index.js +0 -483
  88. package/build/adapters/jetbrains-copilot/config.d.ts +0 -8
  89. package/build/adapters/jetbrains-copilot/config.js +0 -8
  90. package/build/adapters/jetbrains-copilot/hooks.d.ts +0 -59
  91. package/build/adapters/jetbrains-copilot/hooks.js +0 -87
  92. package/build/adapters/jetbrains-copilot/index.d.ts +0 -31
  93. package/build/adapters/jetbrains-copilot/index.js +0 -131
  94. package/build/adapters/kimi/config.d.ts +0 -8
  95. package/build/adapters/kimi/config.js +0 -8
  96. package/build/adapters/kimi/hooks.d.ts +0 -28
  97. package/build/adapters/kimi/hooks.js +0 -34
  98. package/build/adapters/kimi/index.d.ts +0 -66
  99. package/build/adapters/kimi/index.js +0 -537
  100. package/build/adapters/kimi/paths.d.ts +0 -21
  101. package/build/adapters/kimi/paths.js +0 -52
  102. package/build/adapters/kimi/usage.d.ts +0 -82
  103. package/build/adapters/kimi/usage.js +0 -217
  104. package/build/adapters/kiro/hooks.d.ts +0 -61
  105. package/build/adapters/kiro/hooks.js +0 -94
  106. package/build/adapters/kiro/index.d.ts +0 -61
  107. package/build/adapters/kiro/index.js +0 -301
  108. package/build/adapters/omp/index.d.ts +0 -65
  109. package/build/adapters/omp/index.js +0 -182
  110. package/build/adapters/omp/plugin.d.ts +0 -81
  111. package/build/adapters/omp/plugin.js +0 -331
  112. package/build/adapters/omp/usage.d.ts +0 -49
  113. package/build/adapters/omp/usage.js +0 -110
  114. package/build/adapters/openclaw/config.d.ts +0 -8
  115. package/build/adapters/openclaw/config.js +0 -8
  116. package/build/adapters/openclaw/hooks.d.ts +0 -50
  117. package/build/adapters/openclaw/hooks.js +0 -61
  118. package/build/adapters/openclaw/index.d.ts +0 -74
  119. package/build/adapters/openclaw/index.js +0 -439
  120. package/build/adapters/openclaw/mcp-tools.d.ts +0 -54
  121. package/build/adapters/openclaw/mcp-tools.js +0 -207
  122. package/build/adapters/openclaw/plugin.d.ts +0 -141
  123. package/build/adapters/openclaw/plugin.js +0 -818
  124. package/build/adapters/openclaw/session-db.d.ts +0 -55
  125. package/build/adapters/openclaw/session-db.js +0 -88
  126. package/build/adapters/openclaw/usage.d.ts +0 -34
  127. package/build/adapters/openclaw/usage.js +0 -52
  128. package/build/adapters/openclaw/workspace-router.d.ts +0 -29
  129. package/build/adapters/openclaw/workspace-router.js +0 -64
  130. package/build/adapters/opencode/config.d.ts +0 -8
  131. package/build/adapters/opencode/config.js +0 -8
  132. package/build/adapters/opencode/hooks.d.ts +0 -38
  133. package/build/adapters/opencode/hooks.js +0 -50
  134. package/build/adapters/opencode/index.d.ts +0 -67
  135. package/build/adapters/opencode/index.js +0 -463
  136. package/build/adapters/opencode/plugin.d.ts +0 -184
  137. package/build/adapters/opencode/plugin.js +0 -558
  138. package/build/adapters/opencode/zod3tov4.d.ts +0 -1
  139. package/build/adapters/opencode/zod3tov4.js +0 -132
  140. package/build/adapters/pi/extension.d.ts +0 -81
  141. package/build/adapters/pi/extension.js +0 -861
  142. package/build/adapters/pi/index.d.ts +0 -57
  143. package/build/adapters/pi/index.js +0 -173
  144. package/build/adapters/pi/mcp-bridge.d.ts +0 -268
  145. package/build/adapters/pi/mcp-bridge.js +0 -894
  146. package/build/adapters/qwen-code/hooks.d.ts +0 -26
  147. package/build/adapters/qwen-code/hooks.js +0 -29
  148. package/build/adapters/qwen-code/index.d.ts +0 -40
  149. package/build/adapters/qwen-code/index.js +0 -361
  150. package/build/adapters/qwen-code/usage.d.ts +0 -90
  151. package/build/adapters/qwen-code/usage.js +0 -222
  152. package/build/adapters/types.d.ts +0 -360
  153. package/build/adapters/types.js +0 -118
  154. package/build/adapters/vscode-copilot/config.d.ts +0 -8
  155. package/build/adapters/vscode-copilot/config.js +0 -8
  156. package/build/adapters/vscode-copilot/hooks.d.ts +0 -71
  157. package/build/adapters/vscode-copilot/hooks.js +0 -98
  158. package/build/adapters/vscode-copilot/index.d.ts +0 -32
  159. package/build/adapters/vscode-copilot/index.js +0 -222
  160. package/build/adapters/zed/index.d.ts +0 -40
  161. package/build/adapters/zed/index.js +0 -163
  162. package/build/cli.d.ts +0 -34
  163. package/build/cli.js +0 -1827
  164. package/build/db-base.d.ts +0 -179
  165. package/build/db-base.js +0 -569
  166. package/build/executor.d.ts +0 -72
  167. package/build/executor.js +0 -678
  168. package/build/exit-classify.d.ts +0 -19
  169. package/build/exit-classify.js +0 -12
  170. package/build/fetch-cache.d.ts +0 -13
  171. package/build/fetch-cache.js +0 -15
  172. package/build/lifecycle.d.ts +0 -124
  173. package/build/lifecycle.js +0 -278
  174. package/build/runPool.d.ts +0 -36
  175. package/build/runPool.js +0 -51
  176. package/build/runtime.d.ts +0 -71
  177. package/build/runtime.js +0 -659
  178. package/build/search/auto-memory.d.ts +0 -47
  179. package/build/search/auto-memory.js +0 -170
  180. package/build/search/ctx-search-schema.d.ts +0 -90
  181. package/build/search/ctx-search-schema.js +0 -135
  182. package/build/search/flood-guard.d.ts +0 -57
  183. package/build/search/flood-guard.js +0 -80
  184. package/build/search/unified.d.ts +0 -56
  185. package/build/search/unified.js +0 -104
  186. package/build/security.d.ts +0 -206
  187. package/build/security.js +0 -780
  188. package/build/server.d.ts +0 -184
  189. package/build/server.js +0 -4563
  190. package/build/session/analytics.d.ts +0 -773
  191. package/build/session/analytics.js +0 -2420
  192. package/build/session/db.d.ts +0 -468
  193. package/build/session/db.js +0 -1308
  194. package/build/session/error-classifier.d.ts +0 -87
  195. package/build/session/error-classifier.js +0 -303
  196. package/build/session/event-emit.d.ts +0 -48
  197. package/build/session/event-emit.js +0 -101
  198. package/build/session/extract.d.ts +0 -333
  199. package/build/session/extract.js +0 -2688
  200. package/build/session/model-prices.json +0 -429
  201. package/build/session/persist-tool-calls.d.ts +0 -54
  202. package/build/session/persist-tool-calls.js +0 -105
  203. package/build/session/pricing.d.ts +0 -64
  204. package/build/session/pricing.js +0 -151
  205. package/build/session/project-attribution.d.ts +0 -73
  206. package/build/session/project-attribution.js +0 -245
  207. package/build/session/purge.d.ts +0 -138
  208. package/build/session/purge.js +0 -240
  209. package/build/session/retrieval-marker.d.ts +0 -39
  210. package/build/session/retrieval-marker.js +0 -65
  211. package/build/session/snapshot.d.ts +0 -46
  212. package/build/session/snapshot.js +0 -532
  213. package/build/store-directory.d.ts +0 -56
  214. package/build/store-directory.js +0 -254
  215. package/build/store.d.ts +0 -147
  216. package/build/store.js +0 -1714
  217. package/build/truncate.d.ts +0 -57
  218. package/build/truncate.js +0 -142
  219. package/build/types.d.ts +0 -117
  220. package/build/types.js +0 -20
  221. package/build/util/claude-config.d.ts +0 -32
  222. package/build/util/claude-config.js +0 -84
  223. package/build/util/hook-config.d.ts +0 -27
  224. package/build/util/hook-config.js +0 -76
  225. package/build/util/jsonc.d.ts +0 -14
  226. package/build/util/jsonc.js +0 -104
  227. package/build/util/plugin-cache-integrity.d.ts +0 -51
  228. package/build/util/plugin-cache-integrity.js +0 -146
  229. package/build/util/project-dir.d.ts +0 -149
  230. package/build/util/project-dir.js +0 -340
  231. package/build/util/sibling-mcp.d.ts +0 -79
  232. package/build/util/sibling-mcp.js +0 -181
  233. package/cli.bundle.mjs +0 -1236
  234. package/configs/antigravity/GEMINI.md +0 -68
  235. package/configs/antigravity/mcp_config.json +0 -7
  236. package/configs/antigravity-cli/hooks/hooks.json +0 -37
  237. package/configs/antigravity-cli/hooks.json +0 -37
  238. package/configs/antigravity-cli/mcp_config.json +0 -10
  239. package/configs/antigravity-cli/plugin.json +0 -14
  240. package/configs/antigravity-cli/rules/context-mode.md +0 -77
  241. package/configs/antigravity-cli/skills/context-mode/SKILL.md +0 -77
  242. package/configs/claude-code/CLAUDE.md +0 -91
  243. package/configs/codex/AGENTS.md +0 -99
  244. package/configs/codex/config.toml +0 -8
  245. package/configs/codex/hooks.json +0 -47
  246. package/configs/copilot-cli/.github/plugin/plugin.json +0 -23
  247. package/configs/copilot-cli/.mcp.json +0 -12
  248. package/configs/copilot-cli/README.md +0 -47
  249. package/configs/copilot-cli/hooks.json +0 -41
  250. package/configs/copilot-cli/skills/context-mode/SKILL.md +0 -38
  251. package/configs/cursor/context-mode.mdc +0 -76
  252. package/configs/cursor/hooks.json +0 -21
  253. package/configs/cursor/mcp.json +0 -7
  254. package/configs/gemini-cli/GEMINI.md +0 -88
  255. package/configs/gemini-cli/mcp.json +0 -7
  256. package/configs/gemini-cli/settings.json +0 -60
  257. package/configs/jetbrains-copilot/copilot-instructions.md +0 -80
  258. package/configs/jetbrains-copilot/hooks.json +0 -16
  259. package/configs/jetbrains-copilot/mcp.json +0 -7
  260. package/configs/kilo/AGENTS.md +0 -84
  261. package/configs/kilo/kilo.json +0 -6
  262. package/configs/kimi/hooks.json +0 -54
  263. package/configs/kiro/KIRO.md +0 -84
  264. package/configs/kiro/agent.json +0 -18
  265. package/configs/kiro/mcp.json +0 -7
  266. package/configs/omp/SYSTEM.md +0 -85
  267. package/configs/omp/mcp.json +0 -7
  268. package/configs/openclaw/AGENTS.md +0 -87
  269. package/configs/openclaw/openclaw.json +0 -13
  270. package/configs/opencode/AGENTS.md +0 -84
  271. package/configs/opencode/opencode.json +0 -6
  272. package/configs/pi/AGENTS.md +0 -3
  273. package/configs/qwen-code/QWEN.md +0 -91
  274. package/configs/vscode-copilot/copilot-instructions.md +0 -80
  275. package/configs/vscode-copilot/hooks.json +0 -16
  276. package/configs/vscode-copilot/mcp.json +0 -7
  277. package/configs/zed/AGENTS.md +0 -68
  278. package/hooks/antigravity-cli/payload.mjs +0 -98
  279. package/hooks/antigravity-cli/posttooluse.mjs +0 -138
  280. package/hooks/antigravity-cli/pretooluse.mjs +0 -78
  281. package/hooks/antigravity-cli/stop.mjs +0 -58
  282. package/hooks/auto-injection.mjs +0 -102
  283. package/hooks/cache-heal-utils.mjs +0 -379
  284. package/hooks/codex/platform.mjs +0 -1
  285. package/hooks/codex/posttooluse.mjs +0 -66
  286. package/hooks/codex/precompact.mjs +0 -70
  287. package/hooks/codex/pretooluse.mjs +0 -42
  288. package/hooks/codex/sessionstart.mjs +0 -121
  289. package/hooks/codex/stop.mjs +0 -138
  290. package/hooks/codex/userpromptsubmit.mjs +0 -75
  291. package/hooks/copilot-cli/posttooluse.mjs +0 -79
  292. package/hooks/copilot-cli/precompact.mjs +0 -66
  293. package/hooks/copilot-cli/pretooluse.mjs +0 -41
  294. package/hooks/copilot-cli/sessionstart.mjs +0 -121
  295. package/hooks/copilot-cli/stop.mjs +0 -59
  296. package/hooks/copilot-cli/userpromptsubmit.mjs +0 -77
  297. package/hooks/core/codex-caps.mjs +0 -112
  298. package/hooks/core/formatters.mjs +0 -356
  299. package/hooks/core/mcp-ready.mjs +0 -109
  300. package/hooks/core/platform-detect.mjs +0 -49
  301. package/hooks/core/routing.mjs +0 -1017
  302. package/hooks/core/stdin.mjs +0 -90
  303. package/hooks/core/tool-naming.mjs +0 -57
  304. package/hooks/cursor/afteragentresponse.mjs +0 -74
  305. package/hooks/cursor/hooks.json +0 -31
  306. package/hooks/cursor/posttooluse.mjs +0 -72
  307. package/hooks/cursor/pretooluse.mjs +0 -26
  308. package/hooks/cursor/sessionstart.mjs +0 -97
  309. package/hooks/cursor/stop.mjs +0 -48
  310. package/hooks/ensure-deps.mjs +0 -254
  311. package/hooks/formatters/claude-code.mjs +0 -113
  312. package/hooks/formatters/cursor.mjs +0 -37
  313. package/hooks/formatters/gemini-cli.mjs +0 -55
  314. package/hooks/formatters/vscode-copilot.mjs +0 -55
  315. package/hooks/gemini-cli/aftermodel.mjs +0 -70
  316. package/hooks/gemini-cli/aftertool.mjs +0 -61
  317. package/hooks/gemini-cli/beforeagent.mjs +0 -99
  318. package/hooks/gemini-cli/beforetool.mjs +0 -27
  319. package/hooks/gemini-cli/precompress.mjs +0 -55
  320. package/hooks/gemini-cli/sessionstart.mjs +0 -137
  321. package/hooks/heal-partial-install.mjs +0 -712
  322. package/hooks/jetbrains-copilot/posttooluse.mjs +0 -61
  323. package/hooks/jetbrains-copilot/precompact.mjs +0 -55
  324. package/hooks/jetbrains-copilot/pretooluse.mjs +0 -27
  325. package/hooks/jetbrains-copilot/sessionstart.mjs +0 -124
  326. package/hooks/kimi/platform.mjs +0 -1
  327. package/hooks/kimi/posttooluse.mjs +0 -72
  328. package/hooks/kimi/precompact.mjs +0 -80
  329. package/hooks/kimi/pretooluse.mjs +0 -42
  330. package/hooks/kimi/sessionend.mjs +0 -61
  331. package/hooks/kimi/sessionstart.mjs +0 -113
  332. package/hooks/kimi/stop.mjs +0 -132
  333. package/hooks/kimi/userpromptsubmit.mjs +0 -90
  334. package/hooks/kiro/agentspawn.mjs +0 -97
  335. package/hooks/kiro/posttooluse.mjs +0 -51
  336. package/hooks/kiro/pretooluse.mjs +0 -64
  337. package/hooks/kiro/userpromptsubmit.mjs +0 -88
  338. package/hooks/normalize-hooks.mjs +0 -323
  339. package/hooks/platform-bridge.mjs +0 -340
  340. package/hooks/posttooluse.mjs +0 -225
  341. package/hooks/precompact.mjs +0 -100
  342. package/hooks/pretooluse.mjs +0 -227
  343. package/hooks/qwen-code/platform.mjs +0 -1
  344. package/hooks/qwen-code/stop.mjs +0 -168
  345. package/hooks/routing-block.mjs +0 -105
  346. package/hooks/run-hook.mjs +0 -95
  347. package/hooks/security.bundle.mjs +0 -2
  348. package/hooks/session-attribution.bundle.mjs +0 -1
  349. package/hooks/session-db.bundle.mjs +0 -144
  350. package/hooks/session-directive.mjs +0 -520
  351. package/hooks/session-extract.bundle.mjs +0 -3
  352. package/hooks/session-helpers.mjs +0 -428
  353. package/hooks/session-loaders.mjs +0 -448
  354. package/hooks/session-snapshot.bundle.mjs +0 -32
  355. package/hooks/sessionstart.mjs +0 -464
  356. package/hooks/stop.mjs +0 -82
  357. package/hooks/suppress-stderr.mjs +0 -25
  358. package/hooks/userpromptsubmit.mjs +0 -108
  359. package/hooks/vscode-copilot/posttooluse.mjs +0 -61
  360. package/hooks/vscode-copilot/precompact.mjs +0 -55
  361. package/hooks/vscode-copilot/pretooluse.mjs +0 -27
  362. package/hooks/vscode-copilot/sessionstart.mjs +0 -129
  363. package/openclaw.plugin.json +0 -38
  364. package/scripts/heal-better-sqlite3.mjs +0 -430
  365. package/scripts/heal-installed-plugins.mjs +0 -598
  366. package/scripts/plugin-cache-integrity.mjs +0 -248
  367. package/scripts/postinstall.mjs +0 -384
  368. package/server.bundle.mjs +0 -1162
  369. package/skills/.ignore +0 -7
  370. package/skills/context-mode/SKILL.md +0 -300
  371. package/skills/context-mode/references/anti-patterns.md +0 -283
  372. package/skills/context-mode/references/patterns-javascript.md +0 -298
  373. package/skills/context-mode/references/patterns-python.md +0 -304
  374. package/skills/context-mode/references/patterns-shell.md +0 -277
  375. package/skills/ctx-index/SKILL.md +0 -46
  376. package/skills/ctx-insight/SKILL.md +0 -24
  377. package/skills/ctx-purge/SKILL.md +0 -49
  378. package/skills/ctx-search/SKILL.md +0 -35
  379. package/start.mjs +0 -616
@@ -1,26 +0,0 @@
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)";
@@ -1,29 +0,0 @@
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)";
@@ -1,40 +0,0 @@
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
- }
@@ -1,361 +0,0 @@
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
- }
@@ -1,90 +0,0 @@
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;