@adhdev/daemon-core 0.9.82-rc.49 → 0.9.82-rc.490

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 (473) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +9 -0
  2. package/dist/boot/process-hardening.d.ts +50 -0
  3. package/dist/build-info.d.ts +37 -0
  4. package/dist/chat/source-machine.d.ts +166 -0
  5. package/dist/chat/source-resolver.d.ts +104 -0
  6. package/dist/chat/subscription-updates.d.ts +1 -0
  7. package/dist/cli-adapter-types.d.ts +68 -2
  8. package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
  9. package/dist/cli-adapters/cli-state-engine.d.ts +220 -0
  10. package/dist/cli-adapters/provider-cli-adapter.d.ts +137 -64
  11. package/dist/cli-adapters/provider-cli-parse.d.ts +5 -0
  12. package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
  13. package/dist/cli-adapters/provider-cli-shared.d.ts +74 -0
  14. package/dist/cli-adapters/pty-write-chunking.d.ts +34 -0
  15. package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
  16. package/dist/cli-adapters/resolve-executable.d.ts +69 -0
  17. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
  18. package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
  19. package/dist/cli-adapters/terminal-screen.d.ts +4 -11
  20. package/dist/commands/chat-commands-debug-bundle.d.ts +14 -0
  21. package/dist/commands/chat-commands-read.d.ts +23 -0
  22. package/dist/commands/chat-commands-scope.d.ts +39 -0
  23. package/dist/commands/chat-commands-shared.d.ts +33 -0
  24. package/dist/commands/chat-commands-write.d.ts +14 -0
  25. package/dist/commands/chat-commands.d.ts +10 -23
  26. package/dist/commands/cli-manager.d.ts +71 -1
  27. package/dist/commands/handler.d.ts +125 -0
  28. package/dist/commands/high-family/index.d.ts +3 -0
  29. package/dist/commands/high-family/mesh-coordinator-launch.d.ts +2 -0
  30. package/dist/commands/high-family/mesh-events.d.ts +2 -0
  31. package/dist/commands/high-family/mesh-status.d.ts +2 -0
  32. package/dist/commands/high-family/types.d.ts +64 -0
  33. package/dist/commands/low-family/coordinator-prompt.d.ts +9 -0
  34. package/dist/commands/low-family/daemon-lifecycle.d.ts +2 -0
  35. package/dist/commands/low-family/diagnostics.d.ts +2 -0
  36. package/dist/commands/low-family/index.d.ts +3 -0
  37. package/dist/commands/low-family/mesh-ledger.d.ts +10 -0
  38. package/dist/commands/low-family/mesh-node-logs.d.ts +2 -0
  39. package/dist/commands/low-family/notification.d.ts +2 -0
  40. package/dist/commands/low-family/refine-config.d.ts +2 -0
  41. package/dist/commands/low-family/session-host.d.ts +2 -0
  42. package/dist/commands/low-family/spec-providerdev.d.ts +11 -0
  43. package/dist/commands/low-family/status-meta.d.ts +2 -0
  44. package/dist/commands/low-family/types.d.ts +33 -0
  45. package/dist/commands/med-family/cli-agent.d.ts +2 -0
  46. package/dist/commands/med-family/fast-forward.d.ts +2 -0
  47. package/dist/commands/med-family/ide.d.ts +10 -0
  48. package/dist/commands/med-family/index.d.ts +3 -0
  49. package/dist/commands/med-family/mesh-crud.d.ts +48 -0
  50. package/dist/commands/med-family/mesh-host-pairing.d.ts +2 -0
  51. package/dist/commands/med-family/mesh-queue.d.ts +2 -0
  52. package/dist/commands/med-family/mesh-restart.d.ts +2 -0
  53. package/dist/commands/med-family/types.d.ts +152 -0
  54. package/dist/commands/mesh-coordinator.d.ts +85 -1
  55. package/dist/commands/router-aggregate-status.d.ts +24 -0
  56. package/dist/commands/router-mesh-session-owner.d.ts +59 -0
  57. package/dist/commands/router-refine.d.ts +151 -0
  58. package/dist/commands/router-worktree-cleanup.d.ts +133 -0
  59. package/dist/commands/router.d.ts +203 -15
  60. package/dist/commands/upgrade-helper.d.ts +41 -1
  61. package/dist/config/chat-history.d.ts +11 -0
  62. package/dist/config/config.d.ts +19 -0
  63. package/dist/config/mesh-config.d.ts +65 -0
  64. package/dist/config/mesh-json-config.d.ts +199 -0
  65. package/dist/config/registry-resolver.d.ts +54 -0
  66. package/dist/config/repo-settings.d.ts +77 -0
  67. package/dist/config/state-store.d.ts +30 -0
  68. package/dist/daemon/dev-server.d.ts +0 -2
  69. package/dist/detection/cli-detector.d.ts +17 -0
  70. package/dist/detection/ide-detector.d.ts +13 -0
  71. package/dist/detection/win32-ide-version.d.ts +37 -0
  72. package/dist/git/change-impact-config.d.ts +159 -0
  73. package/dist/git/git-commands.d.ts +26 -2
  74. package/dist/git/git-diff.d.ts +6 -0
  75. package/dist/git/git-executor.d.ts +11 -0
  76. package/dist/git/git-status.d.ts +80 -0
  77. package/dist/git/git-types.d.ts +2 -50
  78. package/dist/git/git-worktree.d.ts +71 -1
  79. package/dist/git/index.d.ts +3 -1
  80. package/dist/index.d.ts +70 -17
  81. package/dist/index.js +53532 -19073
  82. package/dist/index.js.map +1 -1
  83. package/dist/index.mjs +53283 -18989
  84. package/dist/index.mjs.map +1 -1
  85. package/dist/installer.d.ts +1 -4
  86. package/dist/ipc/local-ipc-server.d.ts +91 -0
  87. package/dist/launch.d.ts +1 -1
  88. package/dist/logging/async-batch-writer.d.ts +10 -0
  89. package/dist/logging/debug-config.d.ts +16 -0
  90. package/dist/logging/log-redactor.d.ts +24 -0
  91. package/dist/logging/log-tail-reader.d.ts +81 -0
  92. package/dist/logging/logger.d.ts +1 -1
  93. package/dist/mesh/contracts.d.ts +256 -0
  94. package/dist/mesh/coordinator-prompt.d.ts +76 -0
  95. package/dist/mesh/coordinator-registry.d.ts +59 -0
  96. package/dist/mesh/mesh-active-work.d.ts +203 -0
  97. package/dist/mesh/mesh-clone-grace.d.ts +8 -0
  98. package/dist/mesh/mesh-completion-synthesis.d.ts +4 -0
  99. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  100. package/dist/mesh/mesh-delivery-policy.d.ts +104 -0
  101. package/dist/mesh/mesh-event-classify.d.ts +7 -0
  102. package/dist/mesh/mesh-event-forwarding.d.ts +58 -0
  103. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  104. package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
  105. package/dist/mesh/mesh-events-pending.d.ts +258 -0
  106. package/dist/mesh/mesh-events-stale.d.ts +61 -0
  107. package/dist/mesh/mesh-events-utils.d.ts +75 -0
  108. package/dist/mesh/mesh-events.d.ts +6 -49
  109. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  110. package/dist/mesh/mesh-host-ownership.d.ts +21 -1
  111. package/dist/mesh/mesh-init.d.ts +128 -0
  112. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  113. package/dist/mesh/mesh-ledger.d.ts +139 -1
  114. package/dist/mesh/mesh-magi-status.d.ts +63 -0
  115. package/dist/mesh/mesh-missions.d.ts +281 -0
  116. package/dist/mesh/mesh-node-identity.d.ts +310 -0
  117. package/dist/mesh/mesh-queue-assignment.d.ts +162 -0
  118. package/dist/mesh/mesh-reconcile-acked-hold.d.ts +17 -0
  119. package/dist/mesh/mesh-reconcile-config.d.ts +6 -0
  120. package/dist/mesh/mesh-reconcile-identity.d.ts +6 -0
  121. package/dist/mesh/mesh-reconcile-loop.d.ts +84 -0
  122. package/dist/mesh/mesh-reconcile-v2-backstop.d.ts +16 -0
  123. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  124. package/dist/mesh/mesh-refine-gates.d.ts +457 -0
  125. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  126. package/dist/mesh/mesh-remote-event-pull.d.ts +15 -0
  127. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  128. package/dist/mesh/mesh-routing.d.ts +70 -0
  129. package/dist/mesh/mesh-runtime-store.d.ts +567 -0
  130. package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
  131. package/dist/mesh/mesh-task-inflight.d.ts +46 -0
  132. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  133. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +34 -0
  134. package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
  135. package/dist/mesh/mesh-work-queue.d.ts +392 -1
  136. package/dist/mesh/preview-freshness.d.ts +28 -0
  137. package/dist/mesh/refine-config.d.ts +97 -0
  138. package/dist/mesh/worktree-bootstrap-config.d.ts +219 -0
  139. package/dist/providers/acp-provider-instance.d.ts +5 -0
  140. package/dist/providers/approval-utils.d.ts +46 -0
  141. package/dist/providers/chat-message-normalization.d.ts +58 -1
  142. package/dist/providers/cli-provider-effect-format.d.ts +30 -0
  143. package/dist/providers/cli-provider-history-dedup.d.ts +17 -0
  144. package/dist/providers/cli-provider-input-prompt.d.ts +12 -0
  145. package/dist/providers/cli-provider-instance-types.d.ts +45 -0
  146. package/dist/providers/cli-provider-instance.d.ts +426 -30
  147. package/dist/providers/cli-provider-status-helpers.d.ts +46 -0
  148. package/dist/providers/cli-provider-transcript-merge.d.ts +7 -0
  149. package/dist/providers/contracts.d.ts +196 -6
  150. package/dist/providers/external-sources.d.ts +71 -0
  151. package/dist/providers/manual-attendance.d.ts +79 -0
  152. package/dist/providers/native-history/antigravity-claim-registry.d.ts +39 -0
  153. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +137 -0
  154. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  155. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  156. package/dist/providers/native-history/constants.d.ts +12 -0
  157. package/dist/providers/native-history/dispatcher.d.ts +44 -0
  158. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  159. package/dist/providers/native-history/index.d.ts +13 -0
  160. package/dist/providers/provider-instance-manager.d.ts +30 -0
  161. package/dist/providers/provider-instance.d.ts +31 -1
  162. package/dist/providers/provider-loader.d.ts +42 -5
  163. package/dist/providers/provider-trust.d.ts +31 -0
  164. package/dist/providers/read-chat-contract.d.ts +29 -0
  165. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  166. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  167. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  168. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  169. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  170. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  171. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  172. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  173. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  174. package/dist/providers/sdk/v1/index.d.ts +30 -0
  175. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  176. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  177. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  178. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  179. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  180. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  181. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  182. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  183. package/dist/providers/spec/adapter.d.ts +98 -0
  184. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  185. package/dist/providers/spec/evaluator.d.ts +45 -0
  186. package/dist/providers/spec/fsm-driver.d.ts +449 -0
  187. package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
  188. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  189. package/dist/providers/spec/fsm-types.d.ts +202 -0
  190. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  191. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  192. package/dist/providers/spec/route.d.ts +4 -0
  193. package/dist/providers/spec/types.d.ts +244 -0
  194. package/dist/providers/status-monitor.d.ts +7 -7
  195. package/dist/providers/transcript-v2.d.ts +176 -0
  196. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  197. package/dist/providers/working-dir.d.ts +17 -0
  198. package/dist/repo-mesh-types.d.ts +616 -12
  199. package/dist/runtime-defaults.d.ts +2 -0
  200. package/dist/session-host/managed-host.d.ts +64 -0
  201. package/dist/session-host/runtime-surface.d.ts +10 -16
  202. package/dist/sessions/registry.d.ts +26 -0
  203. package/dist/shared-types-extra.d.ts +2 -4
  204. package/dist/shared-types.d.ts +110 -55
  205. package/dist/status/chat-tail-hot-sessions.d.ts +40 -0
  206. package/dist/status/normalize.d.ts +1 -1
  207. package/dist/status/normalize.js +1 -0
  208. package/dist/status/normalize.js.map +1 -1
  209. package/dist/status/normalize.mjs +1 -0
  210. package/dist/status/normalize.mjs.map +1 -1
  211. package/dist/status/reporter.d.ts +2 -0
  212. package/dist/status/snapshot.d.ts +27 -0
  213. package/dist/system/hash.d.ts +8 -0
  214. package/dist/system/load-better-sqlite3.d.ts +21 -0
  215. package/dist/types.d.ts +20 -6
  216. package/package.json +11 -4
  217. package/src/agent-stream/poller.ts +2 -3
  218. package/src/agent-stream/provider-adapter.ts +1 -1
  219. package/src/boot/daemon-lifecycle.ts +80 -14
  220. package/src/boot/process-hardening.ts +89 -0
  221. package/src/build-info.ts +73 -0
  222. package/src/chat/source-machine.ts +534 -0
  223. package/src/chat/source-resolver.ts +0 -0
  224. package/src/chat/subscription-updates.ts +20 -1
  225. package/src/cli-adapter-types.d.ts +3 -1
  226. package/src/cli-adapter-types.ts +68 -2
  227. package/src/cli-adapters/cli-script-runner.ts +421 -0
  228. package/src/cli-adapters/cli-state-engine.ts +1282 -0
  229. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  230. package/src/cli-adapters/provider-cli-adapter.ts +1048 -1143
  231. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  232. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  233. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  234. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  235. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  236. package/src/cli-adapters/pty-transport.ts +2 -1
  237. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  238. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  239. package/src/cli-adapters/resolve-executable.ts +204 -0
  240. package/src/cli-adapters/session-host-transport.ts +2 -1
  241. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  242. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  243. package/src/cli-adapters/terminal-screen.ts +16 -81
  244. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  245. package/src/commands/chat-commands-read.ts +2788 -0
  246. package/src/commands/chat-commands-scope.ts +54 -0
  247. package/src/commands/chat-commands-shared.ts +114 -0
  248. package/src/commands/chat-commands-write.ts +891 -0
  249. package/src/commands/chat-commands.ts +19 -1841
  250. package/src/commands/cli-manager.d.ts +2 -0
  251. package/src/commands/cli-manager.ts +724 -27
  252. package/src/commands/handler.ts +865 -2
  253. package/src/commands/high-family/index.ts +28 -0
  254. package/src/commands/high-family/mesh-coordinator-launch.ts +696 -0
  255. package/src/commands/high-family/mesh-events.ts +102 -0
  256. package/src/commands/high-family/mesh-status.ts +857 -0
  257. package/src/commands/high-family/types.ts +80 -0
  258. package/src/commands/low-family/coordinator-prompt.ts +125 -0
  259. package/src/commands/low-family/daemon-lifecycle.ts +120 -0
  260. package/src/commands/low-family/diagnostics.ts +57 -0
  261. package/src/commands/low-family/index.ts +37 -0
  262. package/src/commands/low-family/mesh-ledger.ts +62 -0
  263. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  264. package/src/commands/low-family/notification.ts +116 -0
  265. package/src/commands/low-family/refine-config.ts +106 -0
  266. package/src/commands/low-family/session-host.ts +282 -0
  267. package/src/commands/low-family/spec-providerdev.ts +217 -0
  268. package/src/commands/low-family/status-meta.ts +112 -0
  269. package/src/commands/low-family/types.ts +39 -0
  270. package/src/commands/med-family/cli-agent.ts +270 -0
  271. package/src/commands/med-family/fast-forward.ts +230 -0
  272. package/src/commands/med-family/ide.ts +163 -0
  273. package/src/commands/med-family/index.ts +37 -0
  274. package/src/commands/med-family/mesh-crud.ts +1268 -0
  275. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  276. package/src/commands/med-family/mesh-queue.ts +167 -0
  277. package/src/commands/med-family/mesh-restart.ts +92 -0
  278. package/src/commands/med-family/types.ts +153 -0
  279. package/src/commands/mesh-coordinator.ts +334 -124
  280. package/src/commands/router-aggregate-status.ts +209 -0
  281. package/src/commands/router-mesh-session-owner.ts +114 -0
  282. package/src/commands/router-refine.ts +1794 -0
  283. package/src/commands/router-worktree-cleanup.ts +870 -0
  284. package/src/commands/router.ts +567 -4149
  285. package/src/commands/stream-commands.ts +8 -0
  286. package/src/commands/upgrade-helper.ts +310 -45
  287. package/src/config/chat-history.ts +517 -24
  288. package/src/config/config.ts +30 -0
  289. package/src/config/mesh-config.ts +300 -24
  290. package/src/config/mesh-json-config.ts +376 -0
  291. package/src/config/recent-activity.ts +8 -2
  292. package/src/config/registry-resolver.ts +100 -0
  293. package/src/config/repo-settings.ts +111 -0
  294. package/src/config/state-store.ts +55 -0
  295. package/src/daemon/dev-auto-implement.ts +3 -2
  296. package/src/daemon/dev-cli-debug.ts +10 -1
  297. package/src/daemon/dev-server.ts +0 -541
  298. package/src/detection/cli-detector.ts +94 -9
  299. package/src/detection/ide-detector.ts +55 -16
  300. package/src/detection/win32-ide-version.ts +106 -0
  301. package/src/git/change-impact-config.ts +354 -0
  302. package/src/git/git-commands.ts +112 -16
  303. package/src/git/git-diff.ts +81 -11
  304. package/src/git/git-executor.ts +12 -0
  305. package/src/git/git-status.ts +822 -48
  306. package/src/git/git-types.ts +14 -62
  307. package/src/git/git-worktree.ts +261 -4
  308. package/src/git/index.ts +17 -0
  309. package/src/index.ts +190 -13
  310. package/src/installer.d.ts +1 -1
  311. package/src/installer.ts +8 -6
  312. package/src/ipc/local-ipc-server.ts +278 -0
  313. package/src/launch.d.ts +1 -1
  314. package/src/launch.ts +37 -28
  315. package/src/logging/async-batch-writer.ts +55 -0
  316. package/src/logging/command-log.ts +7 -5
  317. package/src/logging/debug-config.ts +25 -0
  318. package/src/logging/debug-trace.ts +7 -2
  319. package/src/logging/log-redactor.ts +100 -0
  320. package/src/logging/log-tail-reader.ts +341 -0
  321. package/src/logging/logger.ts +14 -7
  322. package/src/mesh/contracts.ts +510 -0
  323. package/src/mesh/coordinator-prompt.ts +627 -34
  324. package/src/mesh/coordinator-registry.ts +121 -0
  325. package/src/mesh/mesh-active-work.ts +706 -0
  326. package/src/mesh/mesh-clone-grace.ts +68 -0
  327. package/src/mesh/mesh-completion-synthesis.ts +416 -0
  328. package/src/mesh/mesh-coordinator-config.ts +97 -0
  329. package/src/mesh/mesh-delivery-policy.ts +284 -0
  330. package/src/mesh/mesh-event-classify.ts +78 -0
  331. package/src/mesh/mesh-event-forwarding.ts +2030 -0
  332. package/src/mesh/mesh-event-trace.ts +67 -0
  333. package/src/mesh/mesh-events-coordinator.ts +32 -0
  334. package/src/mesh/mesh-events-pending.ts +1548 -0
  335. package/src/mesh/mesh-events-stale.ts +452 -0
  336. package/src/mesh/mesh-events-utils.ts +443 -0
  337. package/src/mesh/mesh-events.ts +43 -1035
  338. package/src/mesh/mesh-fast-forward.ts +856 -0
  339. package/src/mesh/mesh-host-ownership.ts +41 -3
  340. package/src/mesh/mesh-init.ts +350 -0
  341. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  342. package/src/mesh/mesh-ledger.ts +897 -102
  343. package/src/mesh/mesh-magi-status.ts +223 -0
  344. package/src/mesh/mesh-missions.ts +695 -0
  345. package/src/mesh/mesh-node-identity.ts +2065 -0
  346. package/src/mesh/mesh-queue-assignment.ts +2498 -0
  347. package/src/mesh/mesh-reconcile-acked-hold.ts +230 -0
  348. package/src/mesh/mesh-reconcile-config.ts +66 -0
  349. package/src/mesh/mesh-reconcile-identity.ts +103 -0
  350. package/src/mesh/mesh-reconcile-loop.ts +1696 -0
  351. package/src/mesh/mesh-reconcile-v2-backstop.ts +62 -0
  352. package/src/mesh/mesh-refine-batch.ts +205 -0
  353. package/src/mesh/mesh-refine-gates.ts +1792 -0
  354. package/src/mesh/mesh-refine-status.ts +231 -0
  355. package/src/mesh/mesh-remote-event-pull.ts +279 -0
  356. package/src/mesh/mesh-review-inbox.ts +308 -0
  357. package/src/mesh/mesh-routing.ts +291 -0
  358. package/src/mesh/mesh-runtime-store.ts +2292 -0
  359. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  360. package/src/mesh/mesh-task-inflight.ts +70 -0
  361. package/src/mesh/mesh-task-stats.ts +161 -0
  362. package/src/mesh/mesh-unresolved-forward-outbox.ts +215 -0
  363. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  364. package/src/mesh/mesh-work-queue.ts +1489 -145
  365. package/src/mesh/preview-freshness.ts +163 -0
  366. package/src/mesh/refine-config.ts +129 -12
  367. package/src/mesh/worktree-bootstrap-config.ts +599 -0
  368. package/src/providers/acp-provider-instance.ts +43 -10
  369. package/src/providers/approval-utils.d.ts +5 -0
  370. package/src/providers/approval-utils.ts +100 -6
  371. package/src/providers/chat-message-normalization.ts +126 -4
  372. package/src/providers/cli-provider-effect-format.ts +53 -0
  373. package/src/providers/cli-provider-history-dedup.ts +75 -0
  374. package/src/providers/cli-provider-input-prompt.ts +133 -0
  375. package/src/providers/cli-provider-instance-types.ts +131 -0
  376. package/src/providers/cli-provider-instance.ts +2771 -499
  377. package/src/providers/cli-provider-status-helpers.ts +123 -0
  378. package/src/providers/cli-provider-transcript-merge.ts +114 -0
  379. package/src/providers/contracts.d.ts +55 -0
  380. package/src/providers/contracts.ts +207 -6
  381. package/src/providers/extension-provider-instance.ts +12 -7
  382. package/src/providers/external-sources.ts +218 -0
  383. package/src/providers/ide-provider-instance.ts +35 -12
  384. package/src/providers/manual-attendance.ts +105 -0
  385. package/src/providers/native-history/antigravity-claim-registry.ts +138 -0
  386. package/src/providers/native-history/antigravity-cli-transcript.ts +1275 -0
  387. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  388. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  389. package/src/providers/native-history/constants.ts +19 -0
  390. package/src/providers/native-history/dispatcher.ts +617 -0
  391. package/src/providers/native-history/hermes-cli-transcript.ts +312 -0
  392. package/src/providers/native-history/index.ts +30 -0
  393. package/src/providers/provider-instance-manager.ts +71 -0
  394. package/src/providers/provider-instance.ts +24 -1
  395. package/src/providers/provider-loader.ts +700 -55
  396. package/src/providers/provider-schema.ts +93 -14
  397. package/src/providers/provider-trust.ts +114 -0
  398. package/src/providers/read-chat-contract.ts +76 -16
  399. package/src/providers/sdk/README.md +49 -0
  400. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  401. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  402. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  403. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +261 -0
  404. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  405. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  406. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  407. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  408. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  409. package/src/providers/sdk/v1/index.ts +152 -0
  410. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  411. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  412. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  413. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +538 -0
  414. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  415. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  416. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  417. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  418. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  419. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  420. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  421. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  422. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  423. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  424. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  425. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  426. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  427. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  428. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  429. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  430. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  431. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  432. package/src/providers/sdk/v1/validators/index.ts +19 -0
  433. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  434. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  435. package/src/providers/spec/adapter.ts +246 -0
  436. package/src/providers/spec/cli-adapter.ts +1064 -0
  437. package/src/providers/spec/evaluator.ts +407 -0
  438. package/src/providers/spec/fsm-driver.ts +1528 -0
  439. package/src/providers/spec/fsm-evaluator.ts +290 -0
  440. package/src/providers/spec/fsm-loader.ts +128 -0
  441. package/src/providers/spec/fsm-types.ts +301 -0
  442. package/src/providers/spec/native-history-executor.ts +1241 -0
  443. package/src/providers/spec/pre-launch-trust.ts +104 -0
  444. package/src/providers/spec/route.ts +51 -0
  445. package/src/providers/spec/types.ts +284 -0
  446. package/src/providers/status-monitor.d.ts +7 -7
  447. package/src/providers/status-monitor.ts +37 -22
  448. package/src/providers/transcript-v2.ts +567 -0
  449. package/src/providers/types/interactive-prompt.ts +536 -0
  450. package/src/providers/version-archive.ts +64 -24
  451. package/src/providers/working-dir.ts +23 -0
  452. package/src/repo-mesh-types.ts +861 -14
  453. package/src/runtime-defaults.ts +39 -0
  454. package/src/session-host/managed-host.ts +218 -0
  455. package/src/session-host/runtime-surface.ts +20 -80
  456. package/src/sessions/registry.ts +44 -0
  457. package/src/shared-types-extra.ts +2 -4
  458. package/src/shared-types.d.ts +8 -0
  459. package/src/shared-types.ts +148 -55
  460. package/src/status/builders.ts +69 -6
  461. package/src/status/chat-tail-hot-sessions.ts +117 -2
  462. package/src/status/normalize.ts +2 -0
  463. package/src/status/reporter.ts +19 -1
  464. package/src/status/snapshot.ts +100 -27
  465. package/src/system/hash.ts +23 -0
  466. package/src/system/host-memory.ts +29 -12
  467. package/src/system/load-better-sqlite3.ts +68 -0
  468. package/src/types.ts +26 -6
  469. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  470. package/dist/mesh/mesh-sync.d.ts +0 -53
  471. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  472. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  473. package/src/mesh/mesh-sync.ts +0 -111
@@ -1,1846 +1,24 @@
1
1
  /**
2
2
  * Chat Commands — readChat, sendChat, listChats, newChat, switchChat,
3
3
  * setMode, changeModel, setThoughtLevel, resolveAction, chatHistory
4
+ *
5
+ * This module is a re-export barrel. The implementation was split into focused
6
+ * sub-modules (chat-commands-shared / -scope / -debug-bundle / -read / -write)
7
+ * as a pure move; the public export surface here is unchanged. handler.ts does
8
+ * `import * as Chat from './chat-commands.js'` and keeps working unchanged.
4
9
  */
5
10
 
6
- import * as fs from 'node:fs';
7
- import * as os from 'node:os';
8
- import * as path from 'node:path';
9
- import { randomUUID } from 'node:crypto';
10
- import type { CommandResult, CommandHelpers } from './handler.js';
11
- import type { CliAdapter } from '../cli-adapter-types.js';
12
- import { flattenContent, normalizeInputEnvelope, type InputEnvelope, type ProviderModule, type ProviderScripts } from '../providers/contracts.js';
13
- import { assertProviderSupportsDeclaredInput, assertTextOnlyInput } from '../providers/provider-input-support.js';
14
- import { validateReadChatResultPayload } from '../providers/read-chat-contract.js';
15
- import type { ProviderInstance } from '../providers/provider-instance.js';
16
- import { readProviderChatHistory } from '../config/chat-history.js';
17
- import { LOG, getRecentLogs } from '../logging/logger.js';
18
- import { getRecentDebugTrace, recordDebugTrace } from '../logging/debug-trace.js';
19
- import { buildChatMessageSignature, hashSignatureParts } from '../chat/chat-signatures.js';
20
- import type { ChatMessage } from '../types.js';
21
- import type { SessionTransport } from '../shared-types.js';
22
- import { filterUserFacingChatMessages, normalizeChatMessages } from '../providers/chat-message-normalization.js';
23
-
24
- const RECENT_SEND_WINDOW_MS = 1200;
25
- export const READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25_000;
26
- const HERMES_CLI_STARTING_SEND_SETTLE_MS = 2_000;
27
- const recentSendByTarget = new Map<string, number>();
28
-
29
- interface ApprovalSelectableInstance extends ProviderInstance {
30
- recordApprovalSelection?(buttonText: string): void;
31
- }
32
-
33
- interface RuntimeChatMessageMerger extends ProviderInstance {
34
- mergeRuntimeChatMessages?(messages: ChatMessage[]): ChatMessage[];
35
- }
36
-
37
- type LegacyStringScript = (params?: Record<string, unknown> | string) => string;
38
-
39
- function getCurrentProviderType(h: CommandHelpers, fallback = ''): string {
40
- return h.currentSession?.providerType || h.currentProviderType || fallback;
41
- }
42
-
43
- function getCurrentManagerKey(h: CommandHelpers): string {
44
- return h.currentSession?.cdpManagerKey || h.currentManagerKey || '';
45
- }
46
-
47
- function getTargetedCliAdapter(h: CommandHelpers, args: any, providerType?: string): CliAdapter | null {
48
- return h.getCliAdapter(args?.targetSessionId || providerType || h.currentSession?.providerType || h.currentManagerKey);
49
- }
50
-
51
- function getTargetInstance(h: CommandHelpers, args: any): ApprovalSelectableInstance | null {
52
- const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId.trim() : '';
53
- const sessionId = targetSessionId || h.currentSession?.sessionId || '';
54
- if (!sessionId) return null;
55
- const session = h.ctx.sessionRegistry?.get(sessionId);
56
- const instanceKey = session?.adapterKey || session?.instanceKey || sessionId;
57
- return (h.ctx.instanceManager?.getInstance(instanceKey) as ApprovalSelectableInstance | undefined) || null;
58
- }
59
-
60
- function getTargetTransport(h: CommandHelpers, provider?: ProviderModule): SessionTransport | null {
61
- if (h.currentSession?.transport) return h.currentSession.transport;
62
- switch (provider?.category) {
63
- case 'cli':
64
- return 'pty';
65
- case 'acp':
66
- return 'acp';
67
- case 'extension':
68
- return 'cdp-webview';
69
- case 'ide':
70
- return 'cdp-page';
71
- default:
72
- return null;
73
- }
74
- }
75
-
76
- function isCliLikeTransport(transport: SessionTransport | null): boolean {
77
- return transport === 'pty' || transport === 'acp';
78
- }
79
-
80
- function isExtensionTransport(transport: SessionTransport | null): boolean {
81
- return transport === 'cdp-webview';
82
- }
83
-
84
- function buildRecentSendKey(h: CommandHelpers, args: any, provider: ProviderModule | undefined, signature: string): string {
85
- const transport = getTargetTransport(h, provider) || 'unknown';
86
- const target =
87
- args?.targetSessionId
88
- || args?.agentType
89
- || h.currentSession?.providerType
90
- || h.currentProviderType
91
- || h.currentManagerKey
92
- || 'unknown';
93
- return `${transport}:${target}:${signature.trim()}`;
94
- }
95
-
96
- function summarizeSendInputPart(part: any): string {
97
- if (!part || typeof part !== 'object') return String(part ?? '');
98
- if (part.type === 'text') return `text:${String(part.text || '').trim()}`;
99
- const fields = [
100
- `type=${String(part.type || '')}`,
101
- `mime=${String(part.mimeType || '')}`,
102
- `uri=${String(part.uri || '')}`,
103
- `name=${String(part.name || '')}`,
104
- ];
105
- const data = typeof part.data === 'string'
106
- ? part.data
107
- : typeof part.resource?.blob === 'string'
108
- ? part.resource.blob
109
- : '';
110
- if (data) fields.push(`dataLen=${data.length}`, `dataHash=${hashSignatureParts([data]).slice(0, 12)}`);
111
- const textish = [part.alt, part.transcript, part.description, part.title, part.resource?.uri]
112
- .filter((value) => typeof value === 'string' && value.trim())
113
- .join('\u001f');
114
- if (textish) fields.push(`meta=${hashSignatureParts([textish]).slice(0, 12)}`);
115
- return fields.join(';');
116
- }
117
-
118
- export function buildSendInputSignature(input: InputEnvelope): string {
119
- const text = typeof input.textFallback === 'string' ? input.textFallback.trim() : '';
120
- const partSummaries = (input.parts || []).map(summarizeSendInputPart);
121
- return hashSignatureParts([text, ...partSummaries]);
122
- }
123
-
124
- function getSendChatInputEnvelope(args: any): InputEnvelope {
125
- return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
126
- }
127
-
128
- function sleep(ms: number): Promise<void> {
129
- return new Promise((resolve) => setTimeout(resolve, ms));
130
- }
131
-
132
- async function waitOnceForFreshHermesCliStart(adapter: CliAdapter, log: (msg: string) => void): Promise<void> {
133
- if (adapter.cliType !== 'hermes-cli') return;
134
- const status = typeof adapter.getStatus === 'function' ? adapter.getStatus()?.status : undefined;
135
- if (status !== 'starting') return;
136
-
137
- log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
138
- await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
139
- }
140
-
141
- function getHistorySessionId(h: CommandHelpers, args: any): string | undefined {
142
- const explicit = typeof args?.historySessionId === 'string' ? args.historySessionId.trim() : '';
143
- if (explicit) return explicit;
144
-
145
- const explicitProviderSessionId = typeof args?.providerSessionId === 'string' ? args.providerSessionId.trim() : '';
146
- if (explicitProviderSessionId) return explicitProviderSessionId;
147
-
148
- const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId.trim() : '';
149
- if (!targetSessionId) return undefined;
150
-
151
- const instance = h.ctx.instanceManager?.getInstance(targetSessionId);
152
- const state = instance?.getState?.();
153
- const providerSessionId = typeof state?.providerSessionId === 'string' ? state.providerSessionId.trim() : '';
154
- return providerSessionId || targetSessionId;
155
- }
156
-
157
- function getInteractionId(args: any): string | undefined {
158
- return typeof args?._interactionId === 'string' && args._interactionId.trim()
159
- ? args._interactionId.trim()
160
- : undefined;
161
- }
162
-
163
- function traceProviderEvent(
164
- args: any,
165
- category: 'provider' | 'parser',
166
- stage: string,
167
- options: {
168
- h: CommandHelpers;
169
- provider?: ProviderModule;
170
- payload?: Record<string, unknown>;
171
- level?: 'debug' | 'info' | 'warn' | 'error';
172
- },
173
- ): void {
174
- recordDebugTrace({
175
- interactionId: getInteractionId(args),
176
- category,
177
- stage,
178
- level: options.level || 'info',
179
- sessionId: typeof args?.targetSessionId === 'string' ? args.targetSessionId : options.h.currentSession?.sessionId,
180
- providerType: options.provider?.type || options.h.currentProviderType || options.h.currentSession?.providerType,
181
- payload: options.payload,
182
- });
183
- }
184
-
185
- function callLegacyTextScript(script: ProviderScripts[keyof ProviderScripts] | undefined, text: string): string | null {
186
- if (typeof script !== 'function') return null;
187
- return (script as LegacyStringScript)(text);
188
- }
189
-
190
- function isRecentDuplicateSend(key: string): boolean {
191
- const now = Date.now();
192
- for (const [candidate, ts] of recentSendByTarget.entries()) {
193
- if (now - ts > RECENT_SEND_WINDOW_MS) recentSendByTarget.delete(candidate);
194
- }
195
- const previous = recentSendByTarget.get(key);
196
- if (previous && (now - previous) <= RECENT_SEND_WINDOW_MS) return true;
197
- recentSendByTarget.set(key, now);
198
- return false;
199
- }
200
-
201
- function parseMaybeJson(value: any): any {
202
- if (typeof value !== 'string') return value;
203
- try {
204
- return JSON.parse(value);
205
- } catch {
206
- return value;
207
- }
208
- }
209
-
210
- function getChatMessageSignature(message: ChatMessage | null | undefined): string {
211
- return buildChatMessageSignature(message);
212
- }
213
-
214
- function normalizeReadChatTailLimit(args: any): number {
215
- const value = Number(args?.tailLimit || 0);
216
- return Number.isFinite(value) ? Math.max(0, value) : 0;
217
- }
218
-
219
- function normalizeReadChatMessages(payload: Record<string, any>): ChatMessage[] {
220
- const messages = Array.isArray(payload.messages) ? payload.messages as ChatMessage[] : [];
221
- return normalizeChatMessages(messages);
222
- }
223
-
224
-
225
- function deriveHistoryDedupKey(message: ChatMessage & { _unitKey?: string; _turnKey?: string }): string | undefined {
226
- const unitKey = typeof message._unitKey === 'string' ? message._unitKey.trim() : '';
227
- if (unitKey) return `read_chat:${unitKey}`;
228
-
229
- const turnKey = typeof message._turnKey === 'string' ? message._turnKey.trim() : '';
230
- if (!turnKey) return undefined;
231
-
232
- let content = '';
233
- try {
234
- content = JSON.stringify(message.content ?? '');
235
- } catch {
236
- content = String(message.content ?? '');
237
- }
238
- return `read_chat:${turnKey}:${String(message.role || '').toLowerCase()}:${content}`;
239
- }
240
-
241
- function toHistoryPersistedMessages(messages: ChatMessage[]): Array<{
242
- role: string;
243
- content: string;
244
- receivedAt?: number;
245
- kind?: string;
246
- senderName?: string;
247
- historyDedupKey?: string;
248
- }> {
249
- return messages.map((message) => ({
250
- role: message.role,
251
- content: flattenContent(message.content),
252
- receivedAt: typeof message.receivedAt === 'number' ? message.receivedAt : undefined,
253
- kind: typeof message.kind === 'string' ? message.kind : undefined,
254
- senderName: typeof message.senderName === 'string' ? message.senderName : undefined,
255
- historyDedupKey: deriveHistoryDedupKey(message as ChatMessage & { _unitKey?: string; _turnKey?: string }),
256
- }));
257
- }
258
-
259
- function buildFullTail(messages: ChatMessage[], tailLimit: number): {
260
- messages: ChatMessage[];
261
- totalMessages: number;
262
- } {
263
- const totalMessages = messages.length;
264
- const tailMessages = tailLimit > 0 ? messages.slice(-tailLimit) : messages;
265
- return {
266
- messages: tailMessages,
267
- totalMessages,
268
- };
269
- }
270
-
271
- function hasNonEmptyModalButtons(activeModal: unknown): boolean {
272
- if (!activeModal || typeof activeModal !== 'object') return false;
273
- const buttons = (activeModal as { buttons?: unknown }).buttons;
274
- return Array.isArray(buttons) && buttons.some((button) => typeof button === 'string' && button.trim().length > 0);
275
- }
276
-
277
- function normalizeReadChatCommandStatus(status: unknown, activeModal: unknown): string {
278
- const raw = typeof status === 'string' ? status.trim() : '';
279
- if (!raw) {
280
- return hasNonEmptyModalButtons(activeModal) ? 'waiting_approval' : 'idle';
281
- }
282
- switch (raw) {
283
- case 'starting':
284
- return hasNonEmptyModalButtons(activeModal) ? 'waiting_approval' : 'generating';
285
- case 'stopped':
286
- case 'disconnected':
287
- case 'not_monitored':
288
- return 'error';
289
- default:
290
- return raw;
291
- }
292
- }
293
-
294
- function isGeneratingLikeStatus(status: unknown): boolean {
295
- return status === 'generating' || status === 'streaming' || status === 'long_generating' || status === 'starting';
296
- }
297
-
298
- function shouldTrustCliAdapterTerminalStatus(parsedStatus: unknown, activeModal: unknown, adapter: CliAdapter, adapterStatus: any): boolean {
299
- if (!isGeneratingLikeStatus(parsedStatus)) return false;
300
- if (hasNonEmptyModalButtons(activeModal)) return false;
301
- const adapterRawStatus = typeof adapterStatus?.status === 'string' ? adapterStatus.status.trim() : '';
302
- if (adapterRawStatus !== 'idle') return false;
303
- if (typeof adapter.isProcessing === 'function' && adapter.isProcessing()) return false;
304
- return true;
305
- }
306
-
307
- function normalizeCliReadChatStatus(parsedStatus: unknown, activeModal: unknown, adapter: CliAdapter, adapterStatus: any): string {
308
- if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return 'idle';
309
- return typeof parsedStatus === 'string' && parsedStatus.trim() ? parsedStatus : 'idle';
310
- }
311
-
312
- function finalizeStreamingMessagesWhenIdle(messages: ChatMessage[], status: string): ChatMessage[] {
313
- if (status !== 'idle') return messages;
314
- return messages.map((message) => {
315
- const meta = message.meta && typeof message.meta === 'object'
316
- ? message.meta as Record<string, unknown>
317
- : undefined;
318
- const hasStreamingMeta = meta?.streaming === true;
319
- if (message.bubbleState !== 'streaming' && !hasStreamingMeta) return message;
320
- return {
321
- ...message,
322
- ...(message.bubbleState === 'streaming' ? { bubbleState: 'final' as const } : {}),
323
- ...(hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}),
324
- };
325
- });
326
- }
327
-
328
- function buildReadChatCommandResult(payload: Record<string, any>, args: any): CommandResult {
329
- let validatedPayload: Record<string, any>;
330
- const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === 'object'
331
- ? payload.debugReadChat
332
- : undefined;
333
- try {
334
- validatedPayload = validateReadChatResultPayload({
335
- ...payload,
336
- status: normalizeReadChatCommandStatus(payload?.status, payload?.activeModal),
337
- }, 'read_chat command result') as Record<string, any>;
338
- } catch (error: any) {
339
- return { success: false, error: error?.message || String(error) };
340
- }
341
- const messages = normalizeReadChatMessages(validatedPayload);
342
- const visibleMessages = filterUserFacingChatMessages(messages);
343
- const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
344
- const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
345
- const returnedDebugReadChat = debugReadChat
346
- ? {
347
- ...debugReadChat,
348
- fullMsgCount: typeof debugReadChat.fullMsgCount === 'number'
349
- ? debugReadChat.fullMsgCount
350
- : messages.length,
351
- visibleMsgCount: visibleMessages.length,
352
- hiddenMsgCount,
353
- returnedMsgCount: sync.messages.length,
354
- }
355
- : undefined;
356
- return {
357
- success: true,
358
- ...validatedPayload,
359
- messages: sync.messages,
360
- totalMessages: sync.totalMessages,
361
- ...(returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}),
362
- };
363
- }
364
-
365
-
366
- interface DebugSanitizeOptions {
367
- maxDepth?: number;
368
- maxArrayLength?: number;
369
- maxObjectKeys?: number;
370
- maxStringLength?: number;
371
- }
372
-
373
- const DEFAULT_DEBUG_SANITIZE_OPTIONS: Required<DebugSanitizeOptions> = {
374
- maxDepth: 8,
375
- maxArrayLength: 80,
376
- maxObjectKeys: 120,
377
- maxStringLength: 16_000,
378
- };
379
-
380
- const SECRET_KEY_PATTERN = /(?:token|secret|password|passwd|authorization|cookie|api[_-]?key|access[_-]?key|refresh[_-]?token|client[_-]?secret|private[_-]?key)/i;
381
-
382
- function truncateDebugString(value: string, maxLength: number): string {
383
- if (value.length <= maxLength) return value;
384
- return `${value.slice(0, maxLength)}…[truncated ${value.length - maxLength} chars]`;
385
- }
386
-
387
- function redactDebugSecrets(value: string): string {
388
- return value
389
- .replace(/(Authorization\s*:\s*Bearer\s+)[^\s'"`]+/gi, '$1[REDACTED:bearer]')
390
- .replace(/(Bearer\s+)[A-Za-z0-9._~+\/-]{16,}=*/gi, '$1[REDACTED:bearer]')
391
- .replace(/\b(?:gh[pousr]|github_pat)_[A-Za-z0-9_]{20,}\b/g, '[REDACTED:github-token]')
392
- .replace(/\bsk-[A-Za-z0-9_-]{16,}\b/g, '[REDACTED:api-key]')
393
- .replace(/\bxox[baprs]-[A-Za-z0-9-]{12,}\b/g, '[REDACTED:slack-token]')
394
- .replace(/\b(?:adk|adm)_[A-Za-z0-9_-]{16,}\b/g, '[REDACTED:adhdev-token]')
395
- .replace(/((?:api[_-]?key|token|secret|password|passwd|client[_-]?secret)\s*[:=]\s*)[^\s,'"`}&]+/gi, '$1[REDACTED:secret]')
396
- .replace(/([?&](?:api[_-]?key|token|secret|password|client_secret)=)[^&#\s]+/gi, '$1[REDACTED:secret]');
397
- }
398
-
399
- export function sanitizeDebugBundleValue(
400
- value: unknown,
401
- options: DebugSanitizeOptions = {},
402
- depth = 0,
403
- keyHint = '',
404
- ): unknown {
405
- const normalizedOptions = { ...DEFAULT_DEBUG_SANITIZE_OPTIONS, ...options };
406
- if (value === null || value === undefined) return value;
407
- if (typeof value === 'number' || typeof value === 'boolean') return value;
408
- if (typeof value === 'bigint') return String(value);
409
- if (typeof value === 'string') {
410
- if (SECRET_KEY_PATTERN.test(keyHint) && value.trim()) return '[REDACTED:secret-field]';
411
- return truncateDebugString(redactDebugSecrets(value), normalizedOptions.maxStringLength);
412
- }
413
- if (typeof value === 'function') return `[Function ${value.name || 'anonymous'}]`;
414
- if (typeof value !== 'object') return String(value);
415
- if (depth >= normalizedOptions.maxDepth) return '[MaxDepth]';
416
-
417
- if (Array.isArray(value)) {
418
- const items = value
419
- .slice(0, normalizedOptions.maxArrayLength)
420
- .map((item) => sanitizeDebugBundleValue(item, normalizedOptions, depth + 1, keyHint));
421
- if (value.length > normalizedOptions.maxArrayLength) {
422
- items.push(`[truncated ${value.length - normalizedOptions.maxArrayLength} items]`);
423
- }
424
- return items;
425
- }
426
-
427
- const record = value as Record<string, unknown>;
428
- const result: Record<string, unknown> = {};
429
- const entries = Object.entries(record).slice(0, normalizedOptions.maxObjectKeys);
430
- for (const [key, item] of entries) {
431
- result[key] = sanitizeDebugBundleValue(item, normalizedOptions, depth + 1, key);
432
- }
433
- const remaining = Object.keys(record).length - entries.length;
434
- if (remaining > 0) result.__truncatedKeys = remaining;
435
- return result;
436
- }
437
-
438
- function summarizeProviderForDebug(provider: ProviderModule | undefined): Record<string, unknown> | null {
439
- if (!provider) return null;
440
- const scripts = provider.scripts && typeof provider.scripts === 'object'
441
- ? Object.keys(provider.scripts)
442
- : [];
443
- const controls = Array.isArray((provider as any).controls)
444
- ? (provider as any).controls.map((control: any) => ({
445
- id: control?.id,
446
- label: control?.label,
447
- type: control?.type,
448
- settingKey: control?.settingKey,
449
- invokeScript: control?.invokeScript,
450
- listScript: control?.listScript,
451
- location: control?.location,
452
- }))
453
- : [];
454
- return {
455
- type: provider.type,
456
- name: provider.name,
457
- category: provider.category,
458
- version: (provider as any).version,
459
- canonicalHistory: provider.canonicalHistory,
460
- historyBehavior: provider.historyBehavior,
461
- webviewMatchText: provider.webviewMatchText,
462
- scriptNames: scripts,
463
- controls,
464
- resume: provider.resume,
465
- };
466
- }
467
-
468
- function summarizeSessionForDebug(session: any): Record<string, unknown> | null {
469
- if (!session || typeof session !== 'object') return null;
470
- return {
471
- sessionId: session.sessionId,
472
- instanceKey: session.instanceKey,
473
- adapterKey: session.adapterKey,
474
- providerType: session.providerType,
475
- providerName: session.providerName,
476
- transport: session.transport,
477
- kind: session.kind,
478
- cdpManagerKey: session.cdpManagerKey,
479
- parentSessionId: session.parentSessionId,
480
- providerSessionId: session.providerSessionId,
481
- workspace: session.workspace,
482
- title: session.title,
483
- status: session.status,
484
- mode: session.mode,
485
- capabilities: session.capabilities,
486
- };
487
- }
488
-
489
- function summarizeStateForDebug(state: any): Record<string, unknown> | null {
490
- if (!state || typeof state !== 'object') return null;
491
- const activeChat = state.activeChat && typeof state.activeChat === 'object' ? state.activeChat : null;
492
- return {
493
- type: state.type,
494
- name: state.name,
495
- category: state.category,
496
- status: state.status,
497
- instanceId: state.instanceId,
498
- providerSessionId: state.providerSessionId,
499
- title: state.title,
500
- transport: state.transport,
501
- mode: state.mode,
502
- workspace: state.workspace,
503
- runtime: state.runtime,
504
- errorMessage: state.errorMessage,
505
- errorReason: state.errorReason,
506
- activeChat: activeChat ? {
507
- status: activeChat.status,
508
- title: activeChat.title,
509
- messageCount: Array.isArray(activeChat.messages) ? activeChat.messages.length : undefined,
510
- activeModal: activeChat.activeModal,
511
- messagesTail: Array.isArray(activeChat.messages) ? activeChat.messages.slice(-10) : undefined,
512
- } : null,
513
- controlValues: state.controlValues,
514
- summaryMetadata: state.summaryMetadata,
515
- };
516
- }
517
-
518
- function buildDebugBundleText(bundle: Record<string, unknown>): string {
519
- return [
520
- '# ADHDev Chat Debug Bundle',
521
- '',
522
- '```json',
523
- JSON.stringify(bundle, null, 2),
524
- '```',
525
- ].join('\n');
526
- }
527
-
528
- function getChatDebugBundleDir(): string {
529
- const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === 'string'
530
- ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim()
531
- : '';
532
- return override || path.join(os.homedir(), '.adhdev', 'debug-bundles', 'chat');
533
- }
534
-
535
- function safeBundleIdSegment(value: unknown, fallback: string): string {
536
- const normalized = String(value || fallback)
537
- .trim()
538
- .replace(/[^A-Za-z0-9_.-]+/g, '-')
539
- .replace(/^-+|-+$/g, '')
540
- .slice(0, 80);
541
- return normalized || fallback;
542
- }
543
-
544
- function createChatDebugBundleId(targetSessionId: string): string {
545
- const timestamp = new Date().toISOString().replace(/[-:.]/g, '').replace('T', 'T').replace('Z', 'Z');
546
- const sessionSegment = safeBundleIdSegment(targetSessionId, 'unknown-session');
547
- return `chat-debug-${timestamp}-${sessionSegment}-${randomUUID().slice(0, 8)}`;
548
- }
549
-
550
- function buildChatDebugBundleSummary(bundle: Record<string, unknown>): Record<string, unknown> {
551
- const target = bundle.target && typeof bundle.target === 'object' ? bundle.target as Record<string, unknown> : {};
552
- const readChat = bundle.readChat && typeof bundle.readChat === 'object' ? bundle.readChat as Record<string, unknown> : {};
553
- const cli = bundle.cli && typeof bundle.cli === 'object' ? bundle.cli as Record<string, unknown> : null;
554
- const frontend = bundle.frontend && typeof bundle.frontend === 'object' ? bundle.frontend as Record<string, unknown> : null;
555
- const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === 'object'
556
- ? readChat.debugReadChat as Record<string, unknown>
557
- : {};
558
- const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === 'object'
559
- ? cli.parsedStatus as Record<string, unknown>
560
- : null;
561
- const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : undefined;
562
- const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : undefined;
563
- const cliPartialResponse = typeof cli?.partialResponse === 'string' ? cli.partialResponse : '';
564
- const readChatStatus = typeof readChat.status === 'string' ? readChat.status : '';
565
- const cliStatus = typeof cli?.status === 'string' ? cli.status : '';
566
- const cliParsedStatus = typeof parsedStatus?.status === 'string' ? parsedStatus.status : '';
567
- return {
568
- createdAt: bundle.createdAt,
569
- targetSessionId: target.targetSessionId,
570
- providerType: target.providerType,
571
- transport: target.transport,
572
- readChatSuccess: readChat.success,
573
- readChatStatus: readChat.status,
574
- readChatTotalMessages: readChat.totalMessages,
575
- readChatReturnedMessages,
576
- cliStatus: cli?.status,
577
- cliParsedStatus: cliParsedStatus || undefined,
578
- cliMessageCount: cli?.messageCount,
579
- cliParsedMessageCount,
580
- cliPartialResponseChars: cliPartialResponse.length,
581
- parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
582
- parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
583
- readChatDebug: Object.keys(debugReadChat).length ? {
584
- adapterStatus: debugReadChat.adapterStatus,
585
- parsedStatus: debugReadChat.parsedStatus,
586
- returnedStatus: debugReadChat.returnedStatus,
587
- parsedMsgCount: debugReadChat.parsedMsgCount,
588
- returnedMsgCount: debugReadChat.returnedMsgCount,
589
- shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages,
590
- } : undefined,
591
- hasFrontendSnapshot: !!frontend,
592
- };
593
- }
594
-
595
- function storeChatDebugBundleOnDaemon(bundle: Record<string, unknown>, targetSessionId: string): { bundleId: string; savedPath: string; sizeBytes: number } {
596
- const bundleId = createChatDebugBundleId(targetSessionId);
597
- const dir = getChatDebugBundleDir();
598
- fs.mkdirSync(dir, { recursive: true });
599
- const savedPath = path.join(dir, `${bundleId}.json`);
600
- const json = `${JSON.stringify(bundle, null, 2)}\n`;
601
- fs.writeFileSync(savedPath, json, { encoding: 'utf8', mode: 0o600 });
602
- return { bundleId, savedPath, sizeBytes: Buffer.byteLength(json, 'utf8') };
603
- }
604
-
605
- function isDaemonFileDebugDelivery(args: any): boolean {
606
- return args?.delivery === 'daemon_file' || args?.delivery === 'file';
607
- }
608
-
609
- export async function handleGetChatDebugBundle(h: CommandHelpers, args: any): Promise<CommandResult> {
610
- const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId.trim() : '';
611
- if (!targetSessionId && !h.currentSession) {
612
- return { success: false, error: 'No targetSessionId specified — cannot route command' };
613
- }
614
-
615
- const provider = h.getProvider(args?.agentType);
616
- const transport = getTargetTransport(h, provider);
617
- const providerType = provider?.type || getCurrentProviderType(h, args?.agentType || '');
618
- const adapter = isCliLikeTransport(transport) ? getTargetedCliAdapter(h, args, provider?.type) : null;
619
- const targetInstance = getTargetInstance(h, args);
620
-
621
- let adapterStatus: unknown = null;
622
- let parsedStatus: unknown = null;
623
- let adapterDebugSnapshot: unknown = null;
624
- let partialResponse = '';
625
- if (adapter) {
626
- try { adapterStatus = adapter.getStatus?.(); } catch (error: any) { adapterStatus = { error: error?.message || String(error) }; }
627
- try { parsedStatus = typeof adapter.getScriptParsedStatus === 'function' ? parseMaybeJson(adapter.getScriptParsedStatus()) : null; } catch (error: any) { parsedStatus = { error: error?.message || String(error) }; }
628
- try { adapterDebugSnapshot = typeof adapter.getDebugSnapshot === 'function' ? adapter.getDebugSnapshot() : null; } catch (error: any) { adapterDebugSnapshot = { error: error?.message || String(error) }; }
629
- try { partialResponse = adapter.getPartialResponse?.() || ''; } catch { partialResponse = ''; }
630
- }
631
-
632
- let instanceState: unknown = null;
633
- if (targetInstance?.getState) {
634
- try { instanceState = summarizeStateForDebug(targetInstance.getState()); } catch (error: any) { instanceState = { error: error?.message || String(error) }; }
635
- }
636
-
637
- let readChat: unknown = null;
638
- try {
639
- const readResult = await handleReadChat(h, { ...args, tailLimit: Math.max(1, Math.min(40, Number(args?.tailLimit || 40))) });
640
- readChat = readResult.success
641
- ? {
642
- success: true,
643
- status: readResult.status,
644
- title: readResult.title,
645
- totalMessages: readResult.totalMessages,
646
- providerSessionId: readResult.providerSessionId,
647
- transcriptAuthority: readResult.transcriptAuthority,
648
- coverage: readResult.coverage,
649
- activeModal: readResult.activeModal,
650
- messagesTail: Array.isArray(readResult.messages) ? readResult.messages.slice(-20) : [],
651
- debugReadChat: readResult.debugReadChat,
652
- }
653
- : { success: false, error: readResult.error };
654
- } catch (error: any) {
655
- readChat = { success: false, error: error?.message || String(error) };
656
- }
657
-
658
- const cdp = h.getCdp();
659
- const rawBundle: Record<string, unknown> = {
660
- version: 1,
661
- createdAt: new Date().toISOString(),
662
- target: {
663
- targetSessionId,
664
- providerType,
665
- transport,
666
- routeManagerKey: h.currentManagerKey,
667
- currentIdeType: h.currentIdeType,
668
- },
669
- session: summarizeSessionForDebug(h.currentSession),
670
- provider: summarizeProviderForDebug(provider),
671
- daemon: {
672
- pid: process.pid,
673
- platform: process.platform,
674
- nodeVersion: process.version,
675
- cwd: process.cwd(),
676
- },
677
- cdp: {
678
- requested: !!cdp,
679
- connected: !!cdp?.isConnected,
680
- managerKey: getCurrentManagerKey(h),
681
- },
682
- instanceState,
683
- cli: adapter ? {
684
- cliType: adapter.cliType,
685
- cliName: adapter.cliName,
686
- workingDir: adapter.workingDir,
687
- status: (adapterStatus as any)?.status,
688
- activeModal: (adapterStatus as any)?.activeModal,
689
- messageCount: Array.isArray((adapterStatus as any)?.messages) ? (adapterStatus as any).messages.length : undefined,
690
- messagesTail: Array.isArray((adapterStatus as any)?.messages) ? (adapterStatus as any).messages.slice(-20) : undefined,
691
- parsedStatus,
692
- partialResponse,
693
- ready: typeof adapter.isReady === 'function' ? adapter.isReady() : undefined,
694
- processing: typeof adapter.isProcessing === 'function' ? adapter.isProcessing() : undefined,
695
- debugSnapshot: adapterDebugSnapshot,
696
- } : null,
697
- readChat,
698
- frontend: args?.frontendSnapshot && typeof args.frontendSnapshot === 'object' ? args.frontendSnapshot : null,
699
- recentLogs: getRecentLogs(80, 'debug'),
700
- recentDebugTrace: getRecentDebugTrace({ limit: 120 }),
701
- };
702
-
703
- const bundle = sanitizeDebugBundleValue(rawBundle) as Record<string, unknown>;
704
- if (isDaemonFileDebugDelivery(args)) {
705
- const summary = buildChatDebugBundleSummary(bundle);
706
- const stored = storeChatDebugBundleOnDaemon(bundle, targetSessionId || String(summary.targetSessionId || 'unknown-session'));
707
- LOG.info('Command', `[get_chat_debug_bundle] saved daemon_file bundle id=${stored.bundleId} path=${stored.savedPath} sizeBytes=${stored.sizeBytes} targetSessionId=${summary.targetSessionId || ''} providerType=${summary.providerType || ''} transport=${summary.transport || ''}`);
708
- return {
709
- success: true,
710
- delivery: 'daemon_file',
711
- bundleId: stored.bundleId,
712
- savedPath: stored.savedPath,
713
- sizeBytes: stored.sizeBytes,
714
- createdAt: bundle.createdAt,
715
- summary,
716
- };
717
- }
718
- return {
719
- success: true,
720
- bundle,
721
- text: buildDebugBundleText(bundle),
722
- };
723
- }
724
-
725
- function didProviderConfirmSend(result: any): boolean {
726
- const parsed = parseMaybeJson(result);
727
- if (parsed === true) return true;
728
- if (typeof parsed === 'string') {
729
- const normalized = parsed.trim().toLowerCase();
730
- return normalized === 'ok' || normalized === 'sent' || normalized === 'success' || normalized === 'true';
731
- }
732
- if (!parsed || typeof parsed !== 'object') return false;
733
-
734
- return parsed.sent === true
735
- || parsed.success === true
736
- || parsed.ok === true
737
- || parsed.submitted === true
738
- || parsed.dispatched === true;
739
- }
740
-
741
- async function readExtensionChatState(h: CommandHelpers): Promise<any | null> {
742
- try {
743
- const evalResult = await h.evaluateProviderScript('readChat', undefined, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS);
744
- if (!evalResult?.result) return null;
745
- const parsed = parseMaybeJson(evalResult.result);
746
- return parsed && typeof parsed === 'object' ? parsed : null;
747
- } catch {
748
- return null;
749
- }
750
- }
751
-
752
- function getStateMessageCount(state: any): number {
753
- return Array.isArray(state?.messages) ? state.messages.length : 0;
754
- }
755
-
756
- function getStateLastSignature(state: any): string {
757
- const messages = Array.isArray(state?.messages) ? state.messages : [];
758
- const last = messages[messages.length - 1];
759
- if (!last) return '';
760
- return `${last.role || ''}:${String(last.content || '').replace(/\s+/g, ' ').trim()}`;
761
- }
762
-
763
- function toNonNegativeNumber(value: any): number {
764
- const numeric = Number(value ?? 0);
765
- return Number.isFinite(numeric) ? Math.max(0, numeric) : 0;
766
- }
767
-
768
- function getCliVisibleTranscriptCount(adapter: any): number {
769
- if (typeof adapter?.getScriptParsedStatus !== 'function') return 0;
770
- try {
771
- const parsed = parseMaybeJson(adapter.getScriptParsedStatus());
772
- return Array.isArray(parsed?.messages) ? parsed.messages.length : 0;
773
- } catch {
774
- return 0;
775
- }
776
- }
777
-
778
- async function getStableExtensionBaseline(h: CommandHelpers): Promise<any | null> {
779
- const first = await readExtensionChatState(h);
780
- if (getStateMessageCount(first) > 0 || getStateLastSignature(first)) return first;
781
- await new Promise((resolve) => setTimeout(resolve, 150));
782
- const second = await readExtensionChatState(h);
783
- return getStateMessageCount(second) >= getStateMessageCount(first) ? second : first;
784
- }
785
-
786
- async function verifyExtensionSendObserved(h: CommandHelpers, before: any): Promise<boolean> {
787
- const beforeCount = getStateMessageCount(before);
788
- const beforeSignature = getStateLastSignature(before);
789
- for (let attempt = 0; attempt < 12; attempt += 1) {
790
- await new Promise((resolve) => setTimeout(resolve, 250));
791
- const state = await readExtensionChatState(h);
792
- if (state?.status === 'waiting_approval') return true;
793
- const afterCount = getStateMessageCount(state);
794
- const afterSignature = getStateLastSignature(state);
795
- if (afterCount > beforeCount) return true;
796
- if (afterSignature && afterSignature !== beforeSignature) return true;
797
- }
798
- return false;
799
- }
800
-
801
- export async function handleChatHistory(h: CommandHelpers, args: any): Promise<CommandResult> {
802
- const { agentType, offset, limit } = args;
803
- const historySessionId = getHistorySessionId(h, args);
804
- try {
805
- const provider = h.getProvider(agentType);
806
- const agentStr = provider?.type || agentType || getCurrentProviderType(h);
807
- const transport = getTargetTransport(h, provider);
808
- const hasExplicitExcludeRecentCount = args?.excludeRecentCount !== undefined && args?.excludeRecentCount !== null;
809
- let excludeRecentCount = toNonNegativeNumber(args?.excludeRecentCount);
810
- if (!hasExplicitExcludeRecentCount && isCliLikeTransport(transport)) {
811
- const adapter = getTargetedCliAdapter(h, args, provider?.type);
812
- const visibleCount = getCliVisibleTranscriptCount(adapter);
813
- if (visibleCount > excludeRecentCount) excludeRecentCount = visibleCount;
814
- }
815
- const workspace = typeof args?.workspace === 'string'
816
- ? args.workspace
817
- : typeof (h.currentSession as any)?.workspace === 'string'
818
- ? (h.currentSession as any).workspace
819
- : undefined;
820
- const result = readProviderChatHistory(agentStr, {
821
- canonicalHistory: provider?.canonicalHistory,
822
- historySessionId,
823
- workspace,
824
- offset: offset || 0,
825
- limit: limit || 30,
826
- excludeRecentCount,
827
- historyBehavior: provider?.historyBehavior,
828
- scripts: provider?.scripts as any,
829
- });
830
- return { success: true, ...result, agent: agentStr };
831
- } catch (e: any) {
832
- return { success: false, error: e.message };
833
- }
834
- }
835
-
836
- export async function handleReadChat(h: CommandHelpers, args: any): Promise<CommandResult> {
837
- const provider = h.getProvider(args?.agentType || args?.providerType);
838
- const transport = getTargetTransport(h, provider);
839
- const historySessionId = getHistorySessionId(h, args);
840
-
841
- const _log = (msg: string) => LOG.debug('Command', `[read_chat] ${msg}`);
842
-
843
- // PTY / ACP transport: read from adapter
844
- if (isCliLikeTransport(transport)) {
845
- const adapter = getTargetedCliAdapter(h, args, provider?.type);
846
- if (adapter) {
847
- _log(`${transport} adapter: ${adapter.cliType}`);
848
- if (typeof adapter.getScriptParsedStatus !== 'function') {
849
- return { success: false, error: `${transport} adapter parseSession unavailable` };
850
- }
851
- let parsedStatus: any = null;
852
- try {
853
- parsedStatus = parseMaybeJson(adapter.getScriptParsedStatus());
854
- } catch (error: any) {
855
- return { success: false, error: error?.message || String(error) };
856
- }
857
- const parsedRecord = parsedStatus && typeof parsedStatus === 'object'
858
- ? parsedStatus as Record<string, any>
859
- : null;
860
- if (!parsedRecord || !Array.isArray(parsedRecord.messages)) {
861
- return { success: false, error: `${transport} parser did not return messages` };
862
- }
863
- const adapterStatus = typeof adapter.getStatus === 'function'
864
- ? adapter.getStatus()
865
- : {};
866
- const title = typeof parsedRecord.title === 'string' ? parsedRecord.title : undefined;
867
- const providerSessionId = typeof parsedRecord.providerSessionId === 'string'
868
- ? parsedRecord.providerSessionId
869
- : undefined;
870
- const transcriptAuthority = parsedRecord.transcriptAuthority === 'provider' || parsedRecord.transcriptAuthority === 'daemon'
871
- ? parsedRecord.transcriptAuthority
872
- : undefined;
873
- const coverage = parsedRecord.coverage === 'full' || parsedRecord.coverage === 'tail' || parsedRecord.coverage === 'current-turn'
874
- ? parsedRecord.coverage
875
- : undefined;
876
- const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
877
- const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
878
- const runtimeMessageMerger = getTargetInstance(h, args) as RuntimeChatMessageMerger | null;
879
- const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages as ChatMessage[], returnedStatus);
880
- const returnedMessages = runtimeMessageMerger?.category === 'cli'
881
- && runtimeMessageMerger.type === adapter.cliType
882
- && typeof runtimeMessageMerger.mergeRuntimeChatMessages === 'function'
883
- ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages)
884
- : parsedMessages;
885
- LOG.debug('Command', `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || '')} adapterStatus=${String(adapterStatus.status || '')} parsedStatus=${String(parsedRecord.status || '')} parsedMsgCount=${parsedRecord.messages.length} returnedMsgCount=${returnedMessages.length}`);
886
- return buildReadChatCommandResult({
887
- messages: returnedMessages,
888
- status: returnedStatus,
889
- activeModal,
890
- debugReadChat: {
891
- provider: adapter.cliType,
892
- targetSessionId: String(args?.targetSessionId || ''),
893
- adapterStatus: String(adapterStatus.status || ''),
894
- parsedStatus: String(parsedRecord.status || ''),
895
- returnedStatus: String(returnedStatus || ''),
896
- shouldPreferAdapterMessages: false,
897
- parsedMsgCount: parsedRecord.messages.length,
898
- returnedMsgCount: returnedMessages.length,
899
- },
900
- ...(title ? { title } : {}),
901
- ...(providerSessionId ? { providerSessionId } : {}),
902
- ...(transcriptAuthority ? { transcriptAuthority } : {}),
903
- ...(coverage ? { coverage } : {}),
904
- }, args);
905
- }
906
- const historyLimit = normalizeReadChatTailLimit(args);
907
- try {
908
- const agentStr = provider?.type || args?.agentType || getCurrentProviderType(h);
909
- const workspace = typeof args?.workspace === 'string'
910
- ? args.workspace
911
- : typeof (h.currentSession as any)?.workspace === 'string'
912
- ? (h.currentSession as any).workspace
913
- : undefined;
914
- const history = readProviderChatHistory(agentStr, {
915
- canonicalHistory: provider?.canonicalHistory,
916
- historySessionId,
917
- workspace,
918
- offset: 0,
919
- limit: historyLimit,
920
- excludeRecentCount: 0,
921
- historyBehavior: provider?.historyBehavior,
922
- scripts: provider?.scripts as any,
923
- });
924
- const historyProviderSessionId = typeof (history as any)?.providerSessionId === 'string'
925
- ? (history as any).providerSessionId
926
- : historySessionId;
927
- return buildReadChatCommandResult({
928
- messages: Array.isArray((history as any)?.messages) ? (history as any).messages : [],
929
- status: 'idle',
930
- ...(typeof (history as any)?.title === 'string' ? { title: (history as any).title } : {}),
931
- ...(historyProviderSessionId ? { providerSessionId: historyProviderSessionId } : {}),
932
- ...(((provider?.historyBehavior as any)?.transcriptAuthority === 'provider' || (provider?.historyBehavior as any)?.transcriptAuthority === 'daemon')
933
- ? { transcriptAuthority: (provider?.historyBehavior as any).transcriptAuthority }
934
- : {}),
935
- coverage: 'tail',
936
- }, args);
937
- } catch (error: any) {
938
- return { success: false, error: error?.message || `${transport} adapter not found` };
939
- }
940
- }
941
-
942
- // Extension transport: evaluateInSession
943
- if (isExtensionTransport(transport)) {
944
- let extensionReadChatError = '';
945
- try {
946
- const evalResult = await h.evaluateProviderScript('readChat', undefined, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS);
947
- if (evalResult?.result) {
948
- let parsed = evalResult.result;
949
- if (typeof parsed === 'string') {
950
- try {
951
- parsed = JSON.parse(parsed);
952
- } catch (e: any) {
953
- extensionReadChatError = `extension read_chat parse failed: ${e?.message || String(e)}`;
954
- }
955
- }
956
- if (parsed && typeof parsed === 'object') {
957
- const validated = validateReadChatResultPayload(parsed, 'extension read_chat');
958
- _log(`Extension OK: ${validated.messages?.length || 0} msgs`);
959
- traceProviderEvent(args, 'provider', 'extension.read_chat.success', {
960
- h,
961
- provider,
962
- payload: {
963
- method: 'evaluateProviderScript',
964
- result: evalResult.result,
965
- parsed: validated,
966
- messageCount: Array.isArray(validated.messages) ? validated.messages.length : 0,
967
- },
968
- });
969
- h.historyWriter.appendNewMessages(
970
- provider?.type || 'unknown_extension',
971
- toHistoryPersistedMessages(normalizeReadChatMessages(validated)),
972
- validated.title,
973
- args?.targetSessionId,
974
- historySessionId,
975
- );
976
- return buildReadChatCommandResult(validated as Record<string, any>, args);
977
- }
978
- if (!extensionReadChatError) {
979
- extensionReadChatError = 'extension read_chat returned a non-object payload';
980
- }
981
- } else {
982
- extensionReadChatError = 'extension read_chat returned no payload';
983
- }
984
- } catch (e: any) {
985
- extensionReadChatError = `extension read_chat failed: ${e?.message || String(e)}`;
986
- _log(`Extension error: ${e.message}`);
987
- traceProviderEvent(args, 'provider', 'extension.read_chat.error', {
988
- h,
989
- provider,
990
- level: 'warn',
991
- payload: { method: 'evaluateProviderScript', error: e.message },
992
- });
993
- }
994
- // Alternative: AgentStreamManager (script fail when)
995
- if (h.agentStream) {
996
- const cdp = h.getCdp();
997
- const parentSessionId = h.currentSession?.parentSessionId;
998
- if (cdp && parentSessionId) {
999
- const stream = await h.agentStream.collectActiveSession(cdp, parentSessionId);
1000
- if (stream && stream.agentType !== provider?.type) {
1001
- return { success: false, error: `extension read_chat stream agent mismatch for ${provider?.type || 'unknown_extension'}` };
1002
- }
1003
- if (stream) {
1004
- h.historyWriter.appendNewMessages(
1005
- stream.agentType,
1006
- toHistoryPersistedMessages(stream.messages || []),
1007
- undefined,
1008
- args?.targetSessionId,
1009
- historySessionId,
1010
- );
1011
- return buildReadChatCommandResult({
1012
- messages: stream.messages || [],
1013
- status: stream.status,
1014
- agentType: stream.agentType,
1015
- }, args);
1016
- }
1017
- }
1018
- }
1019
- return { success: false, error: extensionReadChatError || 'extension read_chat unavailable' };
1020
- }
1021
-
1022
- // IDE category (default): cdp.evaluate
1023
- const cdp = h.getCdp();
1024
- if (!cdp?.isConnected) return { success: false, error: 'CDP not connected' };
1025
-
1026
- // webview IDE (Kiro, PearAI) → evaluateInWebviewFrame directly use
1027
- const webviewScript = h.getProviderScript('webviewReadChat') || h.getProviderScript('webview_read_chat');
1028
- if (webviewScript) {
1029
- let webviewReadChatError = '';
1030
- try {
1031
- const matchText = provider?.webviewMatchText;
1032
- const matchFn = matchText
1033
- ? (body: string) => body.includes(matchText)
1034
- : undefined;
1035
- const raw = await cdp.evaluateInWebviewFrame(webviewScript, matchFn);
1036
- if (raw) {
1037
- let parsed: any = raw;
1038
- if (typeof parsed === 'string') {
1039
- try {
1040
- parsed = JSON.parse(parsed);
1041
- } catch (e: any) {
1042
- webviewReadChatError = `webview read_chat parse failed: ${e?.message || String(e)}`;
1043
- }
1044
- }
1045
- if (parsed && typeof parsed === 'object') {
1046
- const validated = validateReadChatResultPayload(parsed, 'webview read_chat');
1047
- _log(`Webview OK: ${validated.messages?.length || 0} msgs`);
1048
- h.historyWriter.appendNewMessages(
1049
- provider?.type || getCurrentProviderType(h, 'unknown_webview'),
1050
- toHistoryPersistedMessages(normalizeReadChatMessages(validated)),
1051
- validated.title,
1052
- args?.targetSessionId,
1053
- historySessionId,
1054
- );
1055
- return buildReadChatCommandResult(validated as Record<string, any>, args);
1056
- }
1057
- if (!webviewReadChatError) {
1058
- webviewReadChatError = 'webview read_chat returned a non-object payload';
1059
- }
1060
- } else {
1061
- webviewReadChatError = 'webview read_chat returned no payload';
1062
- }
1063
- } catch (e: any) {
1064
- webviewReadChatError = `webview read_chat failed: ${e?.message || String(e)}`;
1065
- _log(`Webview readChat error: ${e.message}`);
1066
- }
1067
- return { success: false, error: webviewReadChatError || 'webview read_chat unavailable' };
1068
- }
1069
-
1070
- // Regular IDE (Cursor, Windsurf, Trae etc) → main DOM evaluate
1071
- const script = h.getProviderScript('readChat') || h.getProviderScript('read_chat');
1072
- if (script) {
1073
- let ideReadChatError = '';
1074
- try {
1075
- const evalResult = await h.evaluateProviderScript('readChat', undefined, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS);
1076
- if (evalResult?.result) {
1077
- let parsed: any = evalResult.result;
1078
- if (typeof parsed === 'string') {
1079
- try {
1080
- parsed = JSON.parse(parsed);
1081
- } catch (e: any) {
1082
- ideReadChatError = `ide read_chat parse failed: ${e?.message || String(e)}`;
1083
- }
1084
- }
1085
- if (parsed && typeof parsed === 'object') {
1086
- const validated = validateReadChatResultPayload(parsed, 'ide read_chat');
1087
- _log(`OK: ${validated.messages?.length || 0} msgs`);
1088
- traceProviderEvent(args, 'provider', 'ide.read_chat.success', {
1089
- h,
1090
- provider,
1091
- payload: {
1092
- method: 'evaluate',
1093
- result: evalResult.result,
1094
- parsed: validated,
1095
- messageCount: Array.isArray(validated.messages) ? validated.messages.length : 0,
1096
- },
1097
- });
1098
- h.historyWriter.appendNewMessages(
1099
- provider?.type || getCurrentProviderType(h, 'unknown_ide'),
1100
- toHistoryPersistedMessages(normalizeReadChatMessages(validated)),
1101
- validated.title,
1102
- args?.targetSessionId,
1103
- historySessionId,
1104
- );
1105
- return buildReadChatCommandResult(validated as Record<string, any>, args);
1106
- }
1107
- if (!ideReadChatError) {
1108
- ideReadChatError = 'ide read_chat returned a non-object payload';
1109
- }
1110
- } else {
1111
- ideReadChatError = 'ide read_chat returned no payload';
1112
- }
1113
- } catch (e: any) {
1114
- ideReadChatError = `ide read_chat failed: ${e?.message || String(e)}`;
1115
- LOG.info('Command', `[read_chat] Script error: ${e.message}`);
1116
- traceProviderEvent(args, 'provider', 'ide.read_chat.error', {
1117
- h,
1118
- provider,
1119
- level: 'warn',
1120
- payload: { method: 'evaluate', error: e.message },
1121
- });
1122
- }
1123
- return { success: false, error: ideReadChatError || 'ide read_chat unavailable' };
1124
- }
1125
-
1126
- return { success: false, error: 'read_chat unavailable' };
1127
- }
1128
-
1129
- export async function handleSendChat(h: CommandHelpers, args: any): Promise<CommandResult> {
1130
- const input = getSendChatInputEnvelope(args);
1131
- const text = input.textFallback;
1132
- const hasInput = input.parts.length > 0 || (typeof text === 'string' && text.trim().length > 0);
1133
- if (!hasInput) return { success: false, error: 'input required' };
1134
- const _log = (msg: string) => LOG.debug('Command', `[send_chat] ${msg}`);
1135
- const provider = h.getProvider(args?.agentType);
1136
- const transport = getTargetTransport(h, provider);
1137
- const dedupeKey = buildRecentSendKey(h, args, provider, buildSendInputSignature(input));
1138
-
1139
- const _logSendSuccess = (method: string, targetAgent?: string) => {
1140
- // Sending and transcript persistence are intentionally decoupled.
1141
- // User turns should reach history through read_chat/runtime transcript sync,
1142
- // not by eagerly appending the outgoing input here.
1143
- return { success: true, sent: true, method, targetAgent };
1144
- };
1145
-
1146
- if (isRecentDuplicateSend(dedupeKey)) {
1147
- _log(`Suppressed duplicate send for ${dedupeKey}`);
1148
- return { success: true, sent: false, deduplicated: true };
1149
- }
1150
-
1151
- if (transport === 'acp') {
1152
- const target = getTargetInstance(h, args);
1153
- if (!target || target.category !== 'acp') {
1154
- return { success: false, error: `ACP instance not found for ${provider?.type || args?.agentType || 'unknown'}` };
1155
- }
1156
- try {
1157
- assertProviderSupportsDeclaredInput(provider, input);
1158
- target.onEvent('send_message', { input });
1159
- return _logSendSuccess('acp-instance', target.type);
1160
- } catch (e: any) {
1161
- return { success: false, error: `acp send failed: ${e.message}` };
1162
- }
1163
- }
1164
-
1165
- // PTY transport: route structured input through the provider instance so
1166
- // provider-specific CLI attachment strategies (for example Hermes file-path
1167
- // image prompts) are applied instead of collapsing everything to text.
1168
- if (transport === 'pty') {
1169
- const adapter = getTargetedCliAdapter(h, args, provider?.type);
1170
- if (adapter) {
1171
- _log(`${transport} adapter: ${adapter.cliType}`);
1172
- try {
1173
- const hasStructuredParts = input.parts.some((part) => part.type !== 'text');
1174
- if (hasStructuredParts) {
1175
- const target = getTargetInstance(h, args);
1176
- if (!target || target.category !== 'cli') {
1177
- return { success: false, error: `CLI instance not found for ${provider?.type || args?.agentType || 'unknown'}` };
1178
- }
1179
- assertProviderSupportsDeclaredInput(provider, input);
1180
- await waitOnceForFreshHermesCliStart(adapter, _log);
1181
- target.onEvent('send_message', { input });
1182
- return _logSendSuccess(`${transport}-instance`, target.type);
1183
- }
1184
- assertTextOnlyInput(provider, input);
1185
- if (!text) return { success: false, error: 'text required for PTY send' };
1186
- await waitOnceForFreshHermesCliStart(adapter, _log);
1187
- await adapter.sendMessage(text);
1188
- return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
1189
- } catch (e: any) {
1190
- return { success: false, error: `${transport} send failed: ${e.message}` };
1191
- }
1192
- }
1193
- }
1194
-
1195
- assertTextOnlyInput(provider, input);
1196
- if (!text) return { success: false, error: 'text required' };
1197
-
1198
- // Extension transport: via AgentStreamManager
1199
- if (isExtensionTransport(transport)) {
1200
- _log(`Extension: ${provider?.type || 'unknown_extension'}`);
1201
- // Method 1: provider sendMessage script via evaluateInSession
1202
- try {
1203
- const beforeState = await getStableExtensionBaseline(h);
1204
- const evalResult = await h.evaluateProviderScript('sendMessage', { message: text }, 30000);
1205
- if (evalResult?.result) {
1206
- const parsed = parseMaybeJson(evalResult.result);
1207
- if (didProviderConfirmSend(parsed)) {
1208
- const observed = await verifyExtensionSendObserved(h, beforeState);
1209
- if (observed) {
1210
- _log(`Extension script sent OK`);
1211
- return _logSendSuccess('extension-script');
1212
- }
1213
- _log(`Extension script reported send but no chat-state change was observed`);
1214
- }
1215
- if (parsed?.needsTypeAndSend) {
1216
- _log(`Extension needsTypeAndSend → AgentStreamManager`);
1217
- }
1218
- }
1219
- } catch (e: any) {
1220
- _log(`Extension script error: ${e.message}`);
1221
- }
1222
- // Method 2: AgentStreamManager
1223
- const extensionSessionId = h.currentSession?.sessionId;
1224
- if (h.agentStream && h.getCdp() && extensionSessionId) {
1225
- const ok = await h.agentStream.sendToSession(h.getCdp()!, extensionSessionId, text);
1226
- if (ok) {
1227
- _log(`AgentStreamManager sent OK`);
1228
- return _logSendSuccess('agent-stream');
1229
- }
1230
- }
1231
- return { success: false, error: `Extension '${provider?.type || 'unknown_extension'}' send failed` };
1232
- }
1233
-
1234
- // IDE category (default): provider sendMessage script is authoritative when present.
1235
- const targetCdp = h.getCdp();
1236
- if (!targetCdp?.isConnected) {
1237
- const managerKey = getCurrentManagerKey(h);
1238
- _log(`No CDP for ${managerKey}`);
1239
- return { success: false, error: `CDP for ${managerKey || 'unknown'} not connected` };
1240
- }
1241
-
1242
- _log(`Targeting IDE: ${getCurrentManagerKey(h)}`);
1243
- const sendScript = h.getProviderScript('sendMessage', { message: text });
1244
- if (sendScript) {
1245
- try {
1246
- const result = await targetCdp.evaluate(sendScript, 30000);
1247
- const parsed: any = parseMaybeJson(result);
1248
- if (didProviderConfirmSend(parsed)) {
1249
- _log(`sendMessage script OK`);
1250
- return _logSendSuccess('script');
1251
- }
1252
- if (parsed?.needsTypeAndSend && parsed?.selector) {
1253
- try {
1254
- const sent = await targetCdp.typeAndSend(parsed.selector, text);
1255
- if (sent) {
1256
- _log(`typeAndSend(script.selector=${parsed.selector}) success`);
1257
- return _logSendSuccess('typeAndSend-script');
1258
- }
1259
- } catch (e: any) {
1260
- _log(`typeAndSend(script.selector) failed: ${e.message}`);
1261
- }
1262
- }
1263
- if (parsed?.needsTypeAndSend && parsed?.clickCoords) {
1264
- try {
1265
- const { x, y } = parsed.clickCoords;
1266
- const sent = await targetCdp.typeAndSendAt(x, y, text);
1267
- if (sent) {
1268
- _log(`typeAndSendAt(${x},${y}) success`);
1269
- return _logSendSuccess('typeAndSendAt-script');
1270
- }
1271
- } catch (e: any) {
1272
- _log(`typeAndSendAt failed: ${e.message}`);
1273
- }
1274
- }
1275
- if (parsed?.needsTypeAndSend && provider?.inputMethod === 'cdp-type-and-send' && provider.inputSelector) {
1276
- try {
1277
- const sent = await targetCdp.typeAndSend(provider.inputSelector, text);
1278
- if (sent) {
1279
- _log(`typeAndSend(provider.inputSelector=${provider.inputSelector}) success`);
1280
- return _logSendSuccess('typeAndSend-provider');
1281
- }
1282
- } catch (e: any) {
1283
- _log(`typeAndSend(provider) failed: ${e.message}`);
1284
- }
1285
- }
1286
- if (parsed?.needsTypeAndSend && provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
1287
- try {
1288
- const webviewScript = callLegacyTextScript(provider.scripts.webviewSendMessage, text);
1289
- if (webviewScript && targetCdp.evaluateInWebviewFrame) {
1290
- const matchText = provider.webviewMatchText;
1291
- const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
1292
- const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
1293
- const wvParsed: any = parseMaybeJson(wvResult);
1294
- if (didProviderConfirmSend(wvParsed)) {
1295
- _log(`webviewSendMessage OK`);
1296
- return _logSendSuccess('webview-script');
1297
- }
1298
- }
1299
- } catch (e: any) {
1300
- _log(`webviewSendMessage failed: ${e.message}`);
1301
- }
1302
- }
1303
- return { success: false, error: parsed?.error || 'Provider sendMessage did not confirm send' };
1304
- } catch (e: any) {
1305
- _log(`sendMessage script failed: ${e.message}`);
1306
- return { success: false, error: `Provider sendMessage failed: ${e.message}` };
1307
- }
1308
- }
1309
-
1310
- if (provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
1311
- try {
1312
- const webviewScript = callLegacyTextScript(provider.scripts.webviewSendMessage, text);
1313
- if (webviewScript && targetCdp.evaluateInWebviewFrame) {
1314
- const matchText = provider.webviewMatchText;
1315
- const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
1316
- const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
1317
- const wvParsed: any = parseMaybeJson(wvResult);
1318
- if (didProviderConfirmSend(wvParsed)) {
1319
- _log(`webviewSendMessage OK`);
1320
- return _logSendSuccess('webview-script');
1321
- }
1322
- }
1323
- } catch (e: any) {
1324
- _log(`webviewSendMessage failed: ${e.message}`);
1325
- }
1326
- }
1327
-
1328
- if (provider?.inputMethod === 'cdp-type-and-send' && provider.inputSelector) {
1329
- try {
1330
- const sent = await targetCdp.typeAndSend(provider.inputSelector, text);
1331
- if (sent) {
1332
- _log(`typeAndSend(provider.inputSelector=${provider.inputSelector}) success`);
1333
- return _logSendSuccess('typeAndSend-provider');
1334
- }
1335
- } catch (e: any) {
1336
- _log(`typeAndSend(provider) failed: ${e.message}`);
1337
- }
1338
- }
1339
-
1340
- _log('All methods failed');
1341
- return { success: false, error: 'No provider method could send the message' };
1342
- }
1343
-
1344
- export async function handleListChats(h: CommandHelpers, args: any): Promise<CommandResult> {
1345
- const provider = h.getProvider(args?.agentType);
1346
- const transport = getTargetTransport(h, provider);
1347
-
1348
- // Extension transport: via AgentStreamManager
1349
- if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
1350
- try {
1351
- const chats = await h.agentStream.listSessionChats(h.getCdp()!, h.currentSession.sessionId);
1352
- LOG.info('Command', `[list_chats] Extension: ${chats.length} chats`);
1353
- return { success: true, chats };
1354
- } catch (e: any) {
1355
- LOG.info('Command', `[list_chats] Extension error: ${e.message}`);
1356
- }
1357
- }
1358
-
1359
- // webview IDE
1360
- try {
1361
- const webviewScript = h.getProviderScript('webviewListSessions') || h.getProviderScript('webview_list_sessions');
1362
- if (webviewScript) {
1363
- const matchText = provider?.webviewMatchText;
1364
- const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
1365
- const raw = await h.getCdp()?.evaluateInWebviewFrame?.(webviewScript, matchFn);
1366
- let parsed: any = raw;
1367
- if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { } }
1368
- if (parsed?.sessions) {
1369
- LOG.info('Command', `[list_chats] Webview OK: ${parsed.sessions.length} chats`);
1370
- return { success: true, chats: parsed.sessions };
1371
- }
1372
- }
1373
- } catch (e: any) {
1374
- LOG.info('Command', `[list_chats] Webview error: ${e.message}`);
1375
- }
1376
-
1377
- // IDE/default: evaluateProviderScript
1378
- try {
1379
- const evalResult = await h.evaluateProviderScript('listSessions');
1380
- if (evalResult) {
1381
- let parsed = evalResult.result;
1382
- if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { } }
1383
- if (parsed?.sessions && Array.isArray(parsed.sessions)) {
1384
- LOG.info('Command', `[list_chats] OK: ${parsed.sessions.length} chats`);
1385
- return { success: true, chats: parsed.sessions };
1386
- }
1387
- if (parsed?.chats && Array.isArray(parsed.chats)) {
1388
- LOG.info('Command', `[list_chats] OK: ${parsed.chats.length} chats`);
1389
- return { success: true, chats: parsed.chats };
1390
- }
1391
- if (Array.isArray(parsed)) {
1392
- LOG.info('Command', `[list_chats] OK: ${parsed.length} chats`);
1393
- return { success: true, chats: parsed };
1394
- }
1395
- }
1396
- } catch (e: any) {
1397
- LOG.info('Command', `[list_chats] error: ${e.message}`);
1398
- }
1399
-
1400
- return { success: false, error: 'listSessions script not available for this provider' };
1401
- }
1402
-
1403
- export async function handleNewChat(h: CommandHelpers, args: any): Promise<CommandResult> {
1404
- const provider = h.getProvider(args?.agentType);
1405
- const transport = getTargetTransport(h, provider);
1406
-
1407
- if (transport === 'pty') {
1408
- const adapter = getTargetedCliAdapter(h, args, provider?.type);
1409
- if (!adapter) return { success: false, error: 'CLI adapter not running' };
1410
- if (typeof adapter.clearHistory === 'function') {
1411
- adapter.clearHistory();
1412
- return { success: true, cleared: true };
1413
- }
1414
- return { success: false, error: 'new_chat not supported by this CLI provider' };
1415
- }
1416
-
1417
- if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
1418
- const ok = await h.agentStream.newSession(h.getCdp()!, h.currentSession.sessionId);
1419
- return { success: ok };
1420
- }
1421
-
1422
- // webview IDE
1423
- try {
1424
- const webviewScript = h.getProviderScript('webviewNewSession') || h.getProviderScript('webview_new_session');
1425
- if (webviewScript) {
1426
- const matchText = provider?.webviewMatchText;
1427
- const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
1428
- const raw = await h.getCdp()?.evaluateInWebviewFrame?.(webviewScript, matchFn);
1429
- if (raw) return { success: true, result: raw };
1430
- }
1431
- } catch (e: any) {
1432
- return { success: false, error: `webviewNewSession failed: ${e.message}` };
1433
- }
1434
-
1435
- try {
1436
- const evalResult = await h.evaluateProviderScript('newSession');
1437
- if (evalResult) return { success: true };
1438
- } catch (e: any) {
1439
- return { success: false, error: `newSession failed: ${e.message}` };
1440
- }
1441
-
1442
- return { success: false, error: 'newSession script not available for this provider' };
1443
- }
1444
-
1445
- export async function handleSwitchChat(h: CommandHelpers, args: any): Promise<CommandResult> {
1446
- const provider = h.getProvider(args?.agentType);
1447
- const transport = getTargetTransport(h, provider);
1448
- const managerKey = getCurrentManagerKey(h);
1449
- const sessionId = args?.sessionId || args?.id || args?.chatId;
1450
- if (!sessionId) return { success: false, error: 'sessionId required' };
1451
- LOG.info('Command', `[switch_chat] sessionId=${sessionId}, manager=${managerKey}`);
1452
-
1453
- if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
1454
- const ok = await h.agentStream.switchConversation(h.getCdp()!, h.currentSession.sessionId, sessionId);
1455
- return { success: ok, result: ok ? 'switched' : 'failed' };
1456
- }
1457
-
1458
- const cdp = h.getCdp(managerKey);
1459
- if (!cdp?.isConnected) return { success: false, error: 'CDP not connected' };
1460
-
1461
- // webview IDE
1462
- try {
1463
- const webviewScript = h.getProviderScript('webviewSwitchSession', { SESSION_ID: JSON.stringify(sessionId) });
1464
- if (webviewScript) {
1465
- const matchText = provider?.webviewMatchText;
1466
- const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
1467
- const raw = await cdp.evaluateInWebviewFrame?.(webviewScript, matchFn);
1468
- if (raw) return { success: true, result: raw };
1469
- }
1470
- } catch (e: any) {
1471
- return { success: false, error: `webviewSwitchSession failed: ${e.message}` };
1472
- }
1473
-
1474
- const switchParams = {
1475
- sessionId,
1476
- title: sessionId,
1477
- id: sessionId,
1478
- SESSION_ID: JSON.stringify(sessionId),
1479
- };
1480
- const script = h.getProviderScript('switchSession', switchParams)
1481
- || h.getProviderScript('switch_session', switchParams);
1482
- if (!script) return { success: false, error: 'switch_session script not available' };
1483
-
1484
- try {
1485
- const raw = await cdp.evaluate(script, 15000);
1486
- LOG.info('Command', `[switch_chat] result: ${raw}`);
1487
-
1488
- let parsed: any = null;
1489
- try { parsed = typeof raw === 'string' ? JSON.parse(raw) : raw; } catch { }
1490
-
1491
- if (parsed?.action === 'click' && parsed.clickX && parsed.clickY) {
1492
- const x = Math.round(parsed.clickX);
1493
- const y = Math.round(parsed.clickY);
1494
- LOG.info('Command', `[switch_chat] CDP click at (${x}, ${y}) for "${parsed.title}"`);
1495
- await cdp.send('Input.dispatchMouseEvent', {
1496
- type: 'mousePressed', x, y, button: 'left', clickCount: 1
1497
- });
1498
- await cdp.send('Input.dispatchMouseEvent', {
1499
- type: 'mouseReleased', x, y, button: 'left', clickCount: 1
1500
- });
1501
- await new Promise(r => setTimeout(r, 2000));
1502
-
1503
- // Auto-handle workspace selection dialog
1504
- const wsResult = await cdp.evaluate(`
1505
- (() => {
1506
- const inp = Array.from(document.querySelectorAll('input[type="text"]'))
1507
- .find(i => i.offsetWidth > 0 && (i.placeholder || '').includes('Select where'));
1508
- if (!inp) return null;
1509
- const rows = inp.closest('[class*="quickInput"]')?.querySelectorAll('[class*="cursor-pointer"]');
1510
- if (rows && rows.length > 0) {
1511
- const r = rows[0].getBoundingClientRect();
1512
- return JSON.stringify({ x: Math.round(r.left + r.width/2), y: Math.round(r.top + r.height/2) });
1513
- }
1514
- return null;
1515
- })()
1516
- `, 5000);
1517
- if (wsResult) {
1518
- try {
1519
- const ws = JSON.parse(wsResult as string);
1520
- await cdp.send('Input.dispatchMouseEvent', {
1521
- type: 'mousePressed', x: ws.x, y: ws.y, button: 'left', clickCount: 1
1522
- });
1523
- await cdp.send('Input.dispatchMouseEvent', {
1524
- type: 'mouseReleased', x: ws.x, y: ws.y, button: 'left', clickCount: 1
1525
- });
1526
- } catch { }
1527
- }
1528
- return { success: true, result: 'switched' };
1529
- }
1530
-
1531
- if (parsed?.error) return { success: false, error: parsed.error };
1532
- return { success: true, result: raw };
1533
- } catch (e: any) {
1534
- LOG.error('Command', `[switch_chat] error: ${e.message}`);
1535
- return { success: false, error: e.message };
1536
- }
1537
- }
1538
-
1539
- export async function handleSetMode(h: CommandHelpers, args: any): Promise<CommandResult> {
1540
- const provider = h.getProvider(args?.agentType);
1541
- const transport = getTargetTransport(h, provider);
1542
- const mode = args?.mode || 'agent';
1543
-
1544
- // ACP transport
1545
- if (transport === 'acp') {
1546
- const adapter = getTargetedCliAdapter(h, args, provider?.type);
1547
- const acpInstance = adapter?._acpInstance;
1548
- if (acpInstance && typeof acpInstance.setMode === 'function') {
1549
- await acpInstance.setMode(mode);
1550
- return { success: true, mode };
1551
- }
1552
- return { success: false, error: 'ACP adapter not found' };
1553
- }
1554
-
1555
- // 1. webview setMode
1556
- const webviewScript = h.getProviderScript('webviewSetMode', { MODE: JSON.stringify(mode) });
1557
- if (webviewScript) {
1558
- const cdp = h.getCdp();
1559
- if (cdp?.isConnected) {
1560
- try {
1561
- const matchText = provider?.webviewMatchText;
1562
- const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
1563
- const raw = await cdp.evaluateInWebviewFrame?.(webviewScript, matchFn);
1564
- let result: any = raw;
1565
- if (typeof raw === 'string') { try { result = JSON.parse(raw); } catch { } }
1566
- if (result?.success) return { success: true, mode, method: 'webview-script' };
1567
- } catch (e: any) {
1568
- LOG.info('Command', `[set_mode] webview script error: ${e.message}`);
1569
- }
1570
- }
1571
- }
1572
-
1573
- // 2. main frame setMode
1574
- const mainScript = h.getProviderScript('setMode', { MODE: JSON.stringify(mode) });
1575
- if (mainScript) {
1576
- try {
1577
- const evalResult = await h.evaluateProviderScript('setMode', { MODE: JSON.stringify(mode) }, 15000);
1578
- if (evalResult?.result) {
1579
- let parsed = evalResult.result;
1580
- if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { } }
1581
- if (parsed?.success) return { success: true, mode, method: 'script' };
1582
- }
1583
- } catch (e: any) {
1584
- LOG.info('Command', `[set_mode] script error: ${e.message}`);
1585
- }
1586
- }
1587
-
1588
- return { success: false, error: `setMode '${mode}' not supported by this provider` };
1589
- }
1590
-
1591
- export async function handleChangeModel(h: CommandHelpers, args: any): Promise<CommandResult> {
1592
- const provider = h.getProvider(args?.agentType);
1593
- const transport = getTargetTransport(h, provider);
1594
- const model = args?.model;
1595
-
1596
- LOG.info('Command', `[change_model] model=${model} provider=${provider?.type} transport=${transport} manager=${getCurrentManagerKey(h)} providerType=${getCurrentProviderType(h)}`);
1597
-
1598
- // ACP transport
1599
- if (transport === 'acp') {
1600
- const adapter = getTargetedCliAdapter(h, args, provider?.type);
1601
- LOG.info('Command', `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
1602
- const acpInstance = adapter?._acpInstance;
1603
- if (acpInstance && typeof acpInstance.setConfigOption === 'function') {
1604
- await acpInstance.setConfigOption('model', model);
1605
- LOG.info('Command', `[change_model] Updated ACP model to ${model}`);
1606
- return { success: true, model };
1607
- }
1608
- return { success: false, error: 'ACP adapter not found' };
1609
- }
1610
-
1611
- // 1. webview setModel
1612
- const webviewScript = h.getProviderScript('webviewSetModel', { MODEL: JSON.stringify(model) });
1613
- if (webviewScript) {
1614
- const cdp = h.getCdp();
1615
- if (cdp?.isConnected) {
1616
- try {
1617
- const matchText = provider?.webviewMatchText;
1618
- const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
1619
- const raw = await cdp.evaluateInWebviewFrame?.(webviewScript, matchFn);
1620
- let result: any = raw;
1621
- if (typeof raw === 'string') { try { result = JSON.parse(raw); } catch { } }
1622
- if (result?.success) return { success: true, model, method: 'webview-script' };
1623
- } catch (e: any) {
1624
- LOG.info('Command', `[change_model] webview script error: ${e.message}`);
1625
- }
1626
- }
1627
- }
1628
-
1629
- // 2. main frame setModel
1630
- const mainScript = h.getProviderScript('setModel', { MODEL: JSON.stringify(model) });
1631
- if (mainScript) {
1632
- try {
1633
- const evalResult = await h.evaluateProviderScript('setModel', { MODEL: JSON.stringify(model) }, 15000);
1634
- if (evalResult?.result) {
1635
- let parsed = evalResult.result;
1636
- if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { } }
1637
- if (parsed?.success) return { success: true, model, method: 'script' };
1638
- }
1639
- } catch (e: any) {
1640
- LOG.info('Command', `[change_model] script error: ${e.message}`);
1641
- }
1642
- }
1643
-
1644
- return { success: false, error: 'changeModel not supported by this IDE provider' };
1645
- }
1646
-
1647
- export async function handleSetThoughtLevel(h: CommandHelpers, args: any): Promise<CommandResult> {
1648
- const configId = args?.configId;
1649
- const value = args?.value;
1650
- if (!configId || !value) return { success: false, error: 'configId and value required' };
1651
-
1652
- const provider = h.getProvider(args?.agentType);
1653
- const transport = getTargetTransport(h, provider);
1654
- if (transport !== 'acp') {
1655
- return { success: false, error: 'set_thought_level only for ACP providers' };
1656
- }
1657
- const adapter = getTargetedCliAdapter(h, args, provider?.type);
1658
- const acpInstance = adapter?._acpInstance;
1659
- if (!acpInstance) return { success: false, error: 'ACP instance not found' };
1660
- if (typeof acpInstance.setConfigOption !== 'function') {
1661
- return { success: false, error: 'ACP setConfigOption not available' };
1662
- }
1663
-
1664
- try {
1665
- await acpInstance.setConfigOption(configId, value);
1666
- LOG.info('Command', `[set_thought_level] ${configId}=${value} for ${provider?.type || 'unknown_acp'}`);
1667
- return { success: true, configId, value };
1668
- } catch (e: any) {
1669
- return { success: false, error: e?.message };
1670
- }
1671
- }
1672
-
1673
- export async function handleResolveAction(h: CommandHelpers, args: any): Promise<CommandResult> {
1674
- const provider = h.getProvider(args?.agentType);
1675
- const transport = getTargetTransport(h, provider);
1676
- const action = args?.action || 'approve';
1677
- const button = args?.button || args?.buttonText
1678
- || (action === 'approve' ? 'Accept' : action === 'reject' ? 'Reject' : 'Accept');
1679
-
1680
- LOG.info('Command', `[resolveAction] action=${action} button="${button}" provider=${provider?.type}`);
1681
-
1682
- // 0. PTY transport: navigate approval dialog via PTY arrow keys + Enter
1683
- if (transport === 'pty') {
1684
- const adapter = getTargetedCliAdapter(h, args, provider?.type);
1685
- if (!adapter) return { success: false, error: 'CLI adapter not running' };
1686
-
1687
- // Handle data-driven resolve actions (like from the dashboard 'Fix' button)
1688
- if (args?.data && typeof adapter.resolveAction === 'function') {
1689
- try {
1690
- await adapter.resolveAction(args.data);
1691
- LOG.info('Command', `[resolveAction] CLI PTY → resolveAction triggered with data payload`);
1692
- return { success: true, method: 'cli-resolve-action' };
1693
- } catch (e: any) {
1694
- return { success: false, error: `CLI resolveAction failed: ${e.message}` };
1695
- }
1696
- }
1697
-
1698
- const status = adapter.getStatus();
1699
- const targetInstance = getTargetInstance(h, args);
1700
- const targetState = targetInstance?.getState?.() as { activeChat?: { status?: string; activeModal?: { message?: string; buttons?: string[] } | null } } | undefined;
1701
- const surfacedModal = targetState?.activeChat?.activeModal && Array.isArray(targetState.activeChat.activeModal.buttons)
1702
- && targetState.activeChat.activeModal.buttons.some((candidate) => typeof candidate === 'string' && candidate.trim())
1703
- ? targetState.activeChat.activeModal
1704
- : null;
1705
- const statusModal = status?.activeModal && Array.isArray(status.activeModal.buttons)
1706
- && status.activeModal.buttons.some((candidate) => typeof candidate === 'string' && candidate.trim())
1707
- ? status.activeModal
1708
- : null;
1709
- const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === 'function'
1710
- ? (() => {
1711
- try {
1712
- return parseMaybeJson(adapter.getScriptParsedStatus());
1713
- } catch {
1714
- return null;
1715
- }
1716
- })()
1717
- : null;
1718
- const parsedModal = parsedStatus?.status === 'waiting_approval'
1719
- && parsedStatus?.activeModal
1720
- && Array.isArray(parsedStatus.activeModal.buttons)
1721
- && parsedStatus.activeModal.buttons.some((candidate: unknown) => typeof candidate === 'string' && candidate.trim())
1722
- ? parsedStatus.activeModal
1723
- : null;
1724
- const effectiveModal = statusModal || surfacedModal || parsedModal;
1725
- const effectiveStatus = status?.status === 'waiting_approval' || targetState?.activeChat?.status === 'waiting_approval' || parsedStatus?.status === 'waiting_approval'
1726
- ? 'waiting_approval'
1727
- : status?.status;
1728
- LOG.info('Command', `[resolveAction] CLI PTY gate target=${String(args?.targetSessionId || '')} rawStatus=${String(status?.status || '')} effectiveStatus=${String(effectiveStatus || '')} statusModal=${statusModal ? 'yes' : 'no'} surfacedModal=${surfacedModal ? 'yes' : 'no'} parsedModal=${parsedModal ? 'yes' : 'no'} instance=${targetInstance ? 'yes' : 'no'}`);
1729
- if (!effectiveModal) {
1730
- return { success: false, error: 'Not in approval state' };
1731
- }
1732
- const buttons: string[] = Array.isArray(effectiveModal.buttons) ? effectiveModal.buttons : [];
1733
- // Resolve button index: explicit buttonIndex arg → exact text match → explicit action mapping
1734
- let buttonIndex = typeof args?.buttonIndex === 'number' ? args.buttonIndex : -1;
1735
- if (buttonIndex < 0 && button) {
1736
- const btnLower = button.toLowerCase();
1737
- buttonIndex = buttons.findIndex(b => b.toLowerCase().includes(btnLower));
1738
- }
1739
- if (buttonIndex < 0 && (action === 'reject' || action === 'deny')) {
1740
- buttonIndex = buttons.findIndex(b => /deny|reject|no/i.test(b));
1741
- }
1742
- if (buttonIndex < 0 && (action === 'always' || /always/i.test(button))) {
1743
- buttonIndex = buttons.findIndex(b => /always/i.test(b));
1744
- }
1745
- if (buttonIndex < 0) {
1746
- return { success: false, error: 'Approval action did not match any visible button' };
1747
- }
1748
- if (typeof adapter.resolveModal === 'function') {
1749
- adapter.resolveModal(buttonIndex);
1750
- } else {
1751
- const keys = '\x1B[B'.repeat(Math.max(0, buttonIndex)) + '\r';
1752
- adapter.writeRaw?.(keys);
1753
- }
1754
- LOG.info('Command', `[resolveAction] CLI PTY → buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? '?'}"`);
1755
- getTargetInstance(h, args)?.recordApprovalSelection?.(buttons[buttonIndex] ?? button);
1756
- return { success: true, buttonIndex, button: buttons[buttonIndex] ?? button };
1757
- }
1758
-
1759
- // 1. Extension transport: via AgentStreamManager
1760
- if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
1761
- const ok = await h.agentStream.resolveSessionAction(h.getCdp()!, h.currentSession.sessionId, action, button);
1762
- return { success: ok };
1763
- }
1764
-
1765
- // 1.5 ACP transport: resolve protocol permission request directly
1766
- if (transport === 'acp') {
1767
- const adapter = getTargetedCliAdapter(h, args, provider?.type);
1768
- const acpInstance = adapter?._acpInstance;
1769
- if (!acpInstance) return { success: false, error: 'ACP instance not found' };
1770
- if (typeof acpInstance.resolvePermission !== 'function') {
1771
- return { success: false, error: 'ACP resolvePermission not available' };
1772
- }
1773
-
1774
- try {
1775
- await acpInstance.resolvePermission(action === 'approve' || action === 'accept' || action === 'always');
1776
- LOG.info('Command', `[resolveAction] ACP → ${action}`);
1777
- return { success: true, action };
1778
- } catch (e: any) {
1779
- return { success: false, error: e?.message || 'ACP resolve action failed' };
1780
- }
1781
- }
1782
-
1783
- // 2. Webview Provider script
1784
- if (provider?.scripts?.webviewResolveAction || provider?.scripts?.webview_resolve_action) {
1785
- const script = h.getProviderScript('webviewResolveAction', { action, button, buttonText: button })
1786
- || h.getProviderScript('webview_resolve_action', { action, button, buttonText: button });
1787
- if (script) {
1788
- const cdp = h.getCdp();
1789
- if (cdp?.isConnected) {
1790
- try {
1791
- const matchText = provider?.webviewMatchText;
1792
- const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
1793
- const raw = await cdp.evaluateInWebviewFrame?.(script, matchFn);
1794
- let result: any = raw;
1795
- if (typeof raw === 'string') { try { result = JSON.parse(raw); } catch { } }
1796
- LOG.info('Command', `[resolveAction] webview script result: ${JSON.stringify(result)}`);
1797
-
1798
- if (result?.resolved) return { success: true, clicked: result.clicked };
1799
- if (result?.found && result.x != null && result.y != null) {
1800
- LOG.info('Command', `[resolveAction] Webview coordinate click not fully supported via CDP. Click directly in script.`);
1801
- }
1802
- if (result?.found || result?.resolved) return { success: true };
1803
- } catch (e: any) {
1804
- return { success: false, error: `webviewResolveAction failed: ${e.message}` };
1805
- }
1806
- }
1807
- }
1808
- }
1809
-
1810
- // 3. Provider script (Main DOM) → returns coords → CDP mouse click
1811
- if (provider?.scripts?.resolveAction) {
1812
- const script = provider.scripts.resolveAction({ action, button, buttonText: button });
1813
- if (script) {
1814
- const cdp = h.getCdp();
1815
- if (!cdp?.isConnected) return { success: false, error: 'CDP not connected' };
1816
- try {
1817
- const raw = await cdp.evaluate(script, 30000);
1818
- let result: any = raw;
1819
- if (typeof raw === 'string') { try { result = JSON.parse(raw); } catch {} }
1820
- LOG.info('Command', `[resolveAction] script result: ${JSON.stringify(result)}`);
1821
-
1822
- if (result?.resolved) {
1823
- LOG.info('Command', `[resolveAction] script-click resolved — "${result.clicked}"`);
1824
- return { success: true, clicked: result.clicked };
1825
- }
1826
- if (result?.found && result.x != null && result.y != null) {
1827
- const x = result.x;
1828
- const y = result.y;
1829
- await cdp.send('Input.dispatchMouseEvent', {
1830
- type: 'mousePressed', x, y, button: 'left', clickCount: 1
1831
- });
1832
- await cdp.send('Input.dispatchMouseEvent', {
1833
- type: 'mouseReleased', x, y, button: 'left', clickCount: 1
1834
- });
1835
- LOG.info('Command', `[resolveAction] CDP click at (${x}, ${y}) — "${result.text}"`);
1836
- return { success: true, clicked: result.text };
1837
- }
1838
- return { success: false, error: result?.found === false ? `Button not found: ${button}` : 'No coordinates' };
1839
- } catch (e: any) {
1840
- return { success: false, error: `resolveAction failed: ${e.message}` };
1841
- }
1842
- }
1843
- }
1844
-
1845
- return { success: false, error: 'resolveAction script not available for this provider' };
1846
- }
11
+ export { READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS, buildSendInputSignature } from './chat-commands-shared.js';
12
+ export { evaluateReadChatNodeWorkspaceScope } from './chat-commands-scope.js';
13
+ export { sanitizeDebugBundleValue, handleGetChatDebugBundle } from './chat-commands-debug-bundle.js';
14
+ export { handleChatHistory, handleReadChat, __resetProviderSessionPinsForTest, __getProviderSessionPinForTest } from './chat-commands-read.js';
15
+ export {
16
+ handleSendChat,
17
+ handleListChats,
18
+ handleNewChat,
19
+ handleSwitchChat,
20
+ handleSetMode,
21
+ handleChangeModel,
22
+ handleSetThoughtLevel,
23
+ handleResolveAction,
24
+ } from './chat-commands-write.js';