mixdog 0.9.151 → 0.9.153

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 (307) hide show
  1. package/LICENSES/browser-import-NOTICE.txt +11 -0
  2. package/NOTICE.md +11 -0
  3. package/README.md +108 -68
  4. package/package.json +17 -4
  5. package/scripts/computer-task-cost-report.mjs +144 -0
  6. package/scripts/run-office-live-tests.mjs +32 -0
  7. package/scripts/tool-stress.mjs +0 -2
  8. package/src/agents/front-worker/AGENT.md +13 -0
  9. package/src/agents/front-worker/agent.json +6 -0
  10. package/src/agents/heavy-worker/AGENT.md +10 -11
  11. package/src/agents/heavy-worker/agent.json +1 -1
  12. package/src/agents/maintainer/AGENT.md +0 -2
  13. package/src/agents/reviewer/AGENT.md +9 -13
  14. package/src/agents/reviewer/agent.json +1 -1
  15. package/src/agents/security/AGENT.md +14 -0
  16. package/src/agents/security/agent.json +6 -0
  17. package/src/agents/worker/AGENT.md +8 -8
  18. package/src/agents/worker/agent.json +1 -1
  19. package/src/agents/writer/AGENT.md +14 -0
  20. package/src/agents/writer/agent.json +6 -0
  21. package/src/defaults/skills/setup/SKILL.md +18 -27
  22. package/src/headless-exec.mjs +3 -10
  23. package/src/headless-exec.test.mjs +2 -7
  24. package/src/rules/agent/00-common.md +4 -7
  25. package/src/rules/lead/01-general.md +0 -3
  26. package/src/rules/shared/10-tool-workflow.md +10 -2
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +183 -26
  28. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.test.mjs +378 -0
  29. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +4 -0
  30. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +109 -0
  31. package/src/runtime/agent/orchestrator/cache-break-trace.test.mjs +115 -0
  32. package/src/runtime/agent/orchestrator/config.mjs +13 -68
  33. package/src/runtime/agent/orchestrator/context/collect-skills.test.mjs +153 -0
  34. package/src/runtime/agent/orchestrator/context/collect.mjs +49 -45
  35. package/src/runtime/agent/orchestrator/mcp/client.mjs +242 -15
  36. package/src/runtime/agent/orchestrator/mcp/features.test.mjs +66 -0
  37. package/src/runtime/agent/orchestrator/mcp/security.test.mjs +36 -20
  38. package/src/runtime/agent/orchestrator/providers/admission-scheduler-metrics.test.mjs +47 -0
  39. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +16 -3
  40. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +54 -33
  41. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +1 -0
  42. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  43. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +7 -0
  44. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +3 -8
  45. package/src/runtime/agent/orchestrator/providers/gemini.mjs +7 -0
  46. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +19 -3
  47. package/src/runtime/agent/orchestrator/providers/lib/provider-replay.mjs +50 -0
  48. package/src/runtime/agent/orchestrator/providers/lib/sse-framing.mjs +93 -0
  49. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +30 -9
  50. package/src/runtime/agent/orchestrator/providers/media-parity.test.mjs +59 -0
  51. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +3 -3
  52. package/src/runtime/agent/orchestrator/providers/openai-codex-identity.test.mjs +71 -0
  53. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +18 -26
  54. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +8 -0
  55. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -0
  56. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +25 -2
  57. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +35 -4
  58. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +47 -2
  59. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +103 -12
  60. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +13 -0
  61. package/src/runtime/agent/orchestrator/providers/openai-turn-state.mjs +68 -0
  62. package/src/runtime/agent/orchestrator/providers/openai-ws-delta-parity.test.mjs +122 -6
  63. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +36 -11
  64. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +144 -93
  65. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +18 -13
  66. package/src/runtime/agent/orchestrator/providers/provider-replay.test.mjs +288 -0
  67. package/src/runtime/agent/orchestrator/providers/sse-framing.test.mjs +719 -0
  68. package/src/runtime/agent/orchestrator/providers/stream-json-pool.mjs +399 -39
  69. package/src/runtime/agent/orchestrator/providers/stream-json-worker.mjs +26 -0
  70. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +86 -7
  71. package/src/runtime/agent/orchestrator/session/agent-loop.test.mjs +222 -0
  72. package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.mjs +61 -0
  73. package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.test.mjs +83 -0
  74. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +13 -0
  75. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +26 -2
  76. package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +112 -0
  77. package/src/runtime/agent/orchestrator/session/compaction-read-reset.test.mjs +192 -0
  78. package/src/runtime/agent/orchestrator/session/context-usage-restart.test.mjs +72 -0
  79. package/src/runtime/agent/orchestrator/session/context-utils.mjs +100 -15
  80. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +17 -1
  81. package/src/runtime/agent/orchestrator/session/eager-dispatch.test.mjs +74 -0
  82. package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +12 -8
  83. package/src/runtime/agent/orchestrator/session/image-strip-recovery.test.mjs +20 -1
  84. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +110 -2
  85. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +3 -16
  86. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.test.mjs +28 -0
  87. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +2 -2
  88. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +6 -0
  89. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  90. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +6 -0
  91. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +111 -39
  92. package/src/runtime/agent/orchestrator/session/manager/ask-session.test.mjs +46 -0
  93. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -6
  94. package/src/runtime/agent/orchestrator/session/manager/message-sanitize.mjs +3 -0
  95. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +27 -3
  96. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +26 -54
  97. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.test.mjs +63 -1
  98. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +3 -0
  99. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -110
  100. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +580 -0
  101. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.test.mjs +593 -0
  102. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +119 -190
  103. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +115 -0
  104. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +43 -8
  105. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +129 -12
  106. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +9 -2
  107. package/src/runtime/agent/orchestrator/session/store/listing.mjs +8 -1
  108. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +15 -1
  109. package/src/runtime/agent/orchestrator/session/store-live-publication.test.mjs +83 -0
  110. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +36 -2
  111. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +157 -30
  112. package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +64 -0
  113. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +57 -0
  114. package/src/runtime/agent/orchestrator/session/store-summary-visibility.test.mjs +219 -0
  115. package/src/runtime/agent/orchestrator/session/store.mjs +26 -2
  116. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +22 -0
  117. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool-cwd-env.test.mjs +14 -0
  118. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -10
  119. package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +30 -14
  120. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +15 -4
  121. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +73 -15
  122. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +76 -2
  123. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +24 -683
  124. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +64 -72
  125. package/src/runtime/agent/orchestrator/tools/builtin/native-search-runner.mjs +2 -5
  126. package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.mjs +75 -0
  127. package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.test.mjs +24 -0
  128. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +6 -6
  129. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +12 -0
  130. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +4 -1
  131. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +24 -5
  132. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.test.mjs +44 -0
  133. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +12 -2
  134. package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +35 -21
  135. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +28 -13
  136. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.test.mjs +54 -0
  137. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +11 -11
  138. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
  139. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +12 -0
  140. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +11 -11
  141. package/src/runtime/attachments/pdf-extract.mjs +3 -0
  142. package/src/runtime/attachments/pdfjs-runtime.mjs +13 -0
  143. package/src/runtime/bridge-clients.test.mjs +827 -0
  144. package/src/runtime/browser-bridge/action-schema.mjs +251 -0
  145. package/src/runtime/browser-bridge/client.mjs +152 -0
  146. package/src/runtime/browser-bridge/tool-defs.mjs +159 -0
  147. package/src/runtime/computer-bridge/action-schema.mjs +653 -0
  148. package/src/runtime/computer-bridge/client.mjs +231 -0
  149. package/src/runtime/computer-bridge/tool-defs.mjs +33 -0
  150. package/src/runtime/media/store.mjs +18 -8
  151. package/src/runtime/media/store.test.mjs +14 -0
  152. package/src/runtime/memory/index.mjs +1 -1
  153. package/src/runtime/memory/lib/transcript-ingest.mjs +8 -6
  154. package/src/runtime/memory/lib/transcript-ingest.test.mjs +52 -0
  155. package/src/runtime/office/assurance-benchmark.mjs +358 -0
  156. package/src/runtime/office/assurance.mjs +833 -0
  157. package/src/runtime/office/benchmark.mjs +496 -0
  158. package/src/runtime/office/capabilities.mjs +551 -0
  159. package/src/runtime/office/com-adapter.mjs +283 -0
  160. package/src/runtime/office/content-model.mjs +183 -0
  161. package/src/runtime/office/contract-benchmark.mjs +105 -0
  162. package/src/runtime/office/design-library.mjs +1562 -0
  163. package/src/runtime/office/design-system.mjs +1966 -0
  164. package/src/runtime/office/index.mjs +2413 -0
  165. package/src/runtime/office/journal.mjs +82 -0
  166. package/src/runtime/office/office-assurance.test.mjs +371 -0
  167. package/src/runtime/office/office-com-host.ps1 +3781 -0
  168. package/src/runtime/office/office-com-session-host.ps1 +855 -0
  169. package/src/runtime/office/office-live-runtime.test.mjs +819 -0
  170. package/src/runtime/office/office-runtime.test.mjs +2070 -0
  171. package/src/runtime/office/ooxml-validator.mjs +271 -0
  172. package/src/runtime/office/pagination.mjs +132 -0
  173. package/src/runtime/office/pdf-adapter.mjs +591 -0
  174. package/src/runtime/office/pdf-analysis.mjs +372 -0
  175. package/src/runtime/office/pdf-render.mjs +167 -0
  176. package/src/runtime/office/pdf-security.mjs +63 -0
  177. package/src/runtime/office/polish-benchmark.mjs +190 -0
  178. package/src/runtime/office/portable-ooxml.mjs +1867 -0
  179. package/src/runtime/office/quality-live-benchmark.mjs +486 -0
  180. package/src/runtime/office/quality-pipeline.mjs +136 -0
  181. package/src/runtime/office/tabular.mjs +302 -0
  182. package/src/runtime/office/templates/mixdog-executive.pptx +0 -0
  183. package/src/runtime/office/templates/mixdog-executive.pptx.mixdog.json +190 -0
  184. package/src/runtime/office/tool-defs.mjs +113 -0
  185. package/src/runtime/office/visual-diff.mjs +89 -0
  186. package/src/runtime/office/xlsx-assertions.mjs +172 -0
  187. package/src/runtime/office/xlsx-contract.mjs +147 -0
  188. package/src/runtime/shared/agent-route-config.mjs +9 -0
  189. package/src/runtime/shared/child-spawn-gate.mjs +17 -0
  190. package/src/runtime/shared/child-spawn-remote.mjs +69 -7
  191. package/src/runtime/shared/child-spawn-remote.test.mjs +124 -0
  192. package/src/runtime/shared/pristine-execution-contract.json +2 -1
  193. package/src/runtime/shared/provider-api-key.mjs +1 -0
  194. package/src/runtime/shared/session-runtime-health.mjs +91 -0
  195. package/src/runtime/shared/session-runtime-health.test.mjs +53 -0
  196. package/src/runtime/shared/skill-document.mjs +86 -0
  197. package/src/runtime/shared/skill-document.test.mjs +81 -0
  198. package/src/runtime/shared/tool-execution-contract.mjs +16 -0
  199. package/src/runtime/shared/tool-surface.mjs +27 -0
  200. package/src/runtime/shared/turn-snapshot-store.mjs +1 -0
  201. package/src/runtime/shared/turn-snapshot.mjs +32 -9
  202. package/src/runtime/shared/user-cwd.mjs +33 -14
  203. package/src/runtime/shared/user-cwd.test.mjs +43 -0
  204. package/src/session-runtime/agent-disable.test.mjs +20 -1
  205. package/src/session-runtime/context-status.mjs +9 -3
  206. package/src/session-runtime/cwd-plugins.mjs +26 -26
  207. package/src/session-runtime/cwd-plugins.test.mjs +75 -0
  208. package/src/session-runtime/cwd-tool-routing.test.mjs +5 -0
  209. package/src/session-runtime/deferred-tool-delta.mjs +104 -0
  210. package/src/session-runtime/deferred-tool-delta.test.mjs +40 -0
  211. package/src/session-runtime/global-extensions.mjs +26 -0
  212. package/src/session-runtime/global-extensions.test.mjs +28 -0
  213. package/src/session-runtime/global-settings-session-identity.test.mjs +76 -0
  214. package/src/session-runtime/goal-runtime.mjs +1141 -0
  215. package/src/session-runtime/goal-runtime.test.mjs +645 -0
  216. package/src/session-runtime/lifecycle-api.mjs +58 -11
  217. package/src/session-runtime/lifecycle-api.test.mjs +183 -0
  218. package/src/session-runtime/mcp-glue.mjs +49 -47
  219. package/src/session-runtime/plugin-mcp-standard.test.mjs +177 -0
  220. package/src/session-runtime/plugin-mcp.mjs +96 -22
  221. package/src/session-runtime/prewarm.mjs +1 -10
  222. package/src/session-runtime/provider-request-snapshot.mjs +33 -9
  223. package/src/session-runtime/provider-request-snapshot.test.mjs +27 -5
  224. package/src/session-runtime/resource-api-global.test.mjs +109 -0
  225. package/src/session-runtime/resource-api.mjs +168 -116
  226. package/src/session-runtime/runtime-core.mjs +208 -29
  227. package/src/session-runtime/runtime-tunables.mjs +6 -8
  228. package/src/session-runtime/session-lifecycle.mjs +34 -12
  229. package/src/session-runtime/session-title.mjs +2 -2
  230. package/src/session-runtime/session-turn-api.mjs +37 -25
  231. package/src/session-runtime/skills-api.mjs +79 -25
  232. package/src/session-runtime/skills-api.test.mjs +99 -0
  233. package/src/session-runtime/tool-catalog-data.mjs +1 -1
  234. package/src/session-runtime/tool-catalog-schema.mjs +0 -5
  235. package/src/session-runtime/tool-catalog.mjs +42 -112
  236. package/src/session-runtime/tool-defs.mjs +6 -1
  237. package/src/session-runtime/tool-policy-surface.test.mjs +93 -17
  238. package/src/session-runtime/tool-surface.mjs +30 -8
  239. package/src/session-runtime/workflow-agents-api.mjs +8 -25
  240. package/src/session-runtime/workflow.mjs +8 -6
  241. package/src/standalone/agent-dispatch-broker.mjs +5 -9
  242. package/src/standalone/agent-tool/helpers.mjs +2 -2
  243. package/src/standalone/agent-tool/job-views.mjs +3 -1
  244. package/src/standalone/agent-tool/notify.mjs +11 -9
  245. package/src/standalone/agent-tool/notify.test.mjs +37 -0
  246. package/src/standalone/agent-tool/render.mjs +3 -0
  247. package/src/standalone/agent-tool/spawn-flow.mjs +61 -16
  248. package/src/standalone/agent-tool/spawn-flow.test.mjs +41 -0
  249. package/src/standalone/agent-tool/tool-def.mjs +1 -1
  250. package/src/standalone/agent-tool/worker-index.mjs +123 -0
  251. package/src/standalone/agent-tool/worker-index.test.mjs +132 -0
  252. package/src/standalone/agent-tool/worker-rows.mjs +2 -1
  253. package/src/standalone/agent-tool.mjs +57 -10
  254. package/src/standalone/daemon.mjs +113 -15
  255. package/src/standalone/hook-bus/config.mjs +1 -0
  256. package/src/standalone/plugin-admin.mjs +17 -0
  257. package/src/standalone/plugin-admin.test.mjs +7 -0
  258. package/src/standalone/provider-admin.mjs +1 -0
  259. package/src/standalone/session-protocol.mjs +5 -0
  260. package/src/standalone/session-runtime-agent-control-client.mjs +133 -0
  261. package/src/standalone/session-runtime-agent-control-client.test.mjs +71 -0
  262. package/src/standalone/session-runtime-dispatch-cancel.test.mjs +139 -0
  263. package/src/standalone/session-runtime-host-factory.mjs +17 -0
  264. package/src/standalone/session-runtime-host-factory.test.mjs +31 -0
  265. package/src/standalone/session-runtime-host-health.test.mjs +5 -0
  266. package/src/standalone/session-runtime-host.mjs +709 -58
  267. package/src/standalone/session-runtime-inline-host.mjs +258 -0
  268. package/src/standalone/session-runtime-inline-host.test.mjs +385 -0
  269. package/src/standalone/session-runtime-provider-cooldown.mjs +78 -0
  270. package/src/standalone/session-runtime-provider-cooldown.test.mjs +80 -0
  271. package/src/standalone/session-runtime-shard-host.test.mjs +642 -0
  272. package/src/standalone/session-runtime-shard-router.mjs +149 -0
  273. package/src/standalone/session-runtime-shard-router.test.mjs +101 -0
  274. package/src/standalone/session-runtime-worker.mjs +302 -26
  275. package/src/standalone/session-service-agent-tree.test.mjs +984 -0
  276. package/src/standalone/session-service-goal-recovery.test.mjs +177 -0
  277. package/src/standalone/session-service.mjs +711 -11
  278. package/src/tui/app/app-view.jsx +1 -0
  279. package/src/tui/app/core-memory-picker.mjs +2 -0
  280. package/src/tui/app/extension-pickers.mjs +1 -1
  281. package/src/tui/app/maintenance-pickers.mjs +3 -3
  282. package/src/tui/app/model-options.mjs +2 -0
  283. package/src/tui/app/model-picker.mjs +14 -4
  284. package/src/tui/app/panel-handoff.test.mjs +311 -0
  285. package/src/tui/app/project-picker.mjs +1 -0
  286. package/src/tui/app/route-pickers.mjs +21 -6
  287. package/src/tui/app/settings-picker.mjs +26 -3
  288. package/src/tui/app/slash-commands.mjs +1 -0
  289. package/src/tui/app/slash-dispatch.mjs +73 -22
  290. package/src/tui/app/theme-effort-pickers.mjs +7 -2
  291. package/src/tui/components/Picker.jsx +10 -1
  292. package/src/tui/dist/index.mjs +187 -45
  293. package/src/tui/lib/voice-setup.mjs +4 -1
  294. package/src/tui/session/agent-message-source.test.mjs +37 -0
  295. package/src/tui/session/completion-card-restore.test.mjs +50 -0
  296. package/src/tui/session/context-state.mjs +3 -13
  297. package/src/tui/session/goal-continuation.mjs +141 -0
  298. package/src/tui/session/goal-continuation.test.mjs +203 -0
  299. package/src/tui/session/queue-helpers.mjs +5 -2
  300. package/src/tui/session/session-action-surface.test.mjs +190 -0
  301. package/src/tui/session/session-api-ext.mjs +48 -8
  302. package/src/tui/session/session-api.mjs +73 -1
  303. package/src/tui/session/session-flow.mjs +31 -1
  304. package/src/tui/session/turn.mjs +88 -15
  305. package/src/tui/session-local.mjs +39 -3
  306. package/src/vendor/statusline/src/gateway/route-meta.mjs +31 -0
  307. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +0 -301
@@ -0,0 +1,653 @@
1
+ const ACTIONS = [
2
+ 'list', 'diagnose', 'capture',
3
+ 'click', 'double_click', 'mouse_move', 'drag', 'type', 'key', 'scroll', 'wait',
4
+ 'sequence', 'window', 'clipboard', 'launch',
5
+ ];
6
+
7
+ const windowTarget = {
8
+ window_id: {
9
+ type: 'string',
10
+ description: 'Exact id returned by list(kind="windows"), e.g. hwnd:0x123ABC.',
11
+ },
12
+ };
13
+
14
+ const elementTarget = {
15
+ ref: {
16
+ type: 'string',
17
+ description: 'Fresh semantic ref from capture.',
18
+ },
19
+ element: {
20
+ type: 'integer',
21
+ minimum: 1,
22
+ description: 'Fresh 1-based SOM mark, including OCR marks.',
23
+ },
24
+ };
25
+
26
+ const framePoint = {
27
+ frame_id: {
28
+ type: 'string',
29
+ description: 'Fresh frame id from capture.',
30
+ },
31
+ x: {
32
+ type: 'integer',
33
+ description: 'Frame-relative X coordinate.',
34
+ },
35
+ y: {
36
+ type: 'integer',
37
+ description: 'Frame-relative Y coordinate.',
38
+ },
39
+ };
40
+
41
+ const delivery = {
42
+ delivery: {
43
+ type: 'string',
44
+ enum: ['background', 'foreground'],
45
+ description: 'Background by default. Foreground is an explicit visible escalation.',
46
+ },
47
+ };
48
+
49
+ const captureAfter = {
50
+ type: 'object',
51
+ description: 'Optional settings for the mandatory fresh observation returned after a UI mutation.',
52
+ properties: {
53
+ delay_ms: { type: 'integer', minimum: 0, maximum: 2000 },
54
+ mode: { type: 'string', enum: ['state', 'som', 'vision', 'ax'] },
55
+ max_elements: { type: 'integer', minimum: 1, maximum: 1000 },
56
+ include_ocr: { type: 'boolean' },
57
+ ocr_language: { type: 'string' },
58
+ max_ocr_words: { type: 'integer', minimum: 1, maximum: 1000 },
59
+ },
60
+ additionalProperties: false,
61
+ };
62
+
63
+ function input(properties = {}, required = []) {
64
+ return {
65
+ type: 'object',
66
+ properties,
67
+ ...(required.length ? { required } : {}),
68
+ additionalProperties: false,
69
+ };
70
+ }
71
+
72
+ function branch(actions, actionInput, inputRequired = true) {
73
+ const names = Array.isArray(actions) ? actions : [actions];
74
+ return {
75
+ properties: {
76
+ action: { enum: names },
77
+ input: actionInput,
78
+ },
79
+ required: inputRequired ? ['action', 'input'] : ['action'],
80
+ };
81
+ }
82
+
83
+ const captureProperties = {
84
+ ...windowTarget,
85
+ app: {
86
+ type: 'string',
87
+ description: 'App name used only when it resolves to one exact window.',
88
+ },
89
+ screen: {
90
+ type: 'integer',
91
+ minimum: 0,
92
+ description: 'Display index for a plain vision capture.',
93
+ },
94
+ mode: {
95
+ type: 'string',
96
+ enum: ['state', 'som', 'vision', 'ax', 'zoom'],
97
+ description: 'state (default) is structured UI plus image; som adds marks; vision is image only; ax is accessibility only; zoom crops a prior frame.',
98
+ },
99
+ frame_id: {
100
+ type: 'string',
101
+ description: 'Required with mode="zoom".',
102
+ },
103
+ region: {
104
+ type: 'array',
105
+ items: { type: 'integer' },
106
+ minItems: 4,
107
+ maxItems: 4,
108
+ description: 'mode="zoom": [x0,y0,x1,y1] in frame coordinates.',
109
+ },
110
+ include_ocr: {
111
+ type: 'boolean',
112
+ description: 'Allow offline Windows OCR only as a fallback when semantic accessibility targets are absent. OCR shares max_elements.',
113
+ },
114
+ ocr_language: {
115
+ type: 'string',
116
+ description: 'Installed Windows OCR language tag, e.g. ko or en-US.',
117
+ },
118
+ max_ocr_words: {
119
+ type: 'integer',
120
+ minimum: 1,
121
+ maximum: 1000,
122
+ },
123
+ query: { type: 'string' },
124
+ role: { type: 'string' },
125
+ visible_only: { type: 'boolean' },
126
+ include_noninteractive: { type: 'boolean' },
127
+ max_elements: {
128
+ type: 'integer',
129
+ minimum: 1,
130
+ maximum: 1000,
131
+ description: 'Total returned accessibility + OCR element budget. state defaults to 80.',
132
+ },
133
+ continuation: { type: 'string' },
134
+ quality: {
135
+ type: 'integer',
136
+ minimum: 0,
137
+ maximum: 100,
138
+ },
139
+ maxWidth: {
140
+ type: 'integer',
141
+ minimum: 256,
142
+ maximum: 3840,
143
+ },
144
+ };
145
+
146
+ const pointerProperties = {
147
+ ...windowTarget,
148
+ ...elementTarget,
149
+ ...framePoint,
150
+ modifiers: {
151
+ type: 'string',
152
+ description: 'ctrl, shift, alt, win, or a +-joined combination.',
153
+ },
154
+ ...delivery,
155
+ };
156
+
157
+ const sequenceStepSchemas = {
158
+ click: input({
159
+ ...elementTarget,
160
+ ...framePoint,
161
+ modifiers: {
162
+ type: 'string',
163
+ description: 'ctrl, shift, alt, win, or a +-joined combination.',
164
+ },
165
+ button: {
166
+ type: 'string',
167
+ enum: ['left', 'right', 'middle'],
168
+ },
169
+ }),
170
+ type: input({
171
+ ...elementTarget,
172
+ ...framePoint,
173
+ text: { type: 'string' },
174
+ }, ['text']),
175
+ key: input({
176
+ ...elementTarget,
177
+ keys: { type: 'string' },
178
+ }, ['keys']),
179
+ wait: input({
180
+ duration: {
181
+ type: 'number',
182
+ minimum: 0,
183
+ maximum: 30,
184
+ },
185
+ }, ['duration']),
186
+ };
187
+
188
+ const sequenceStep = {
189
+ type: 'object',
190
+ description: 'One focus-chain step. First: targeted click/type/key. Later: untargeted type/key/wait. Every nonfinal step must preserve the same target and focus.',
191
+ properties: {
192
+ action: { type: 'string', enum: ['click', 'type', 'key', 'wait'] },
193
+ ...elementTarget,
194
+ ...framePoint,
195
+ text: { type: 'string' },
196
+ keys: { type: 'string' },
197
+ duration: { type: 'number', minimum: 0, maximum: 30 },
198
+ modifiers: { type: 'string' },
199
+ button: { type: 'string', enum: ['left', 'right', 'middle'] },
200
+ },
201
+ required: ['action'],
202
+ additionalProperties: false,
203
+ };
204
+
205
+ export const COMPUTER_INPUT_SCHEMA = {
206
+ type: 'object',
207
+ description: 'One high-level Computer Use action with only its action-specific fields.',
208
+ properties: {
209
+ action: {
210
+ type: 'string',
211
+ enum: ACTIONS,
212
+ description: 'Use list for targets, capture for state/pixels/search/zoom, window for window lifecycle, and clipboard for clipboard I/O.',
213
+ },
214
+ input: {
215
+ type: 'object',
216
+ description: 'Fields for the selected action.',
217
+ },
218
+ capture_after: captureAfter,
219
+ },
220
+ required: ['action'],
221
+ additionalProperties: false,
222
+ oneOf: [
223
+ branch('list', input({
224
+ kind: { type: 'string', enum: ['windows', 'apps'] },
225
+ }, ['kind'])),
226
+ branch('diagnose', input({
227
+ ...windowTarget,
228
+ ocr_language: {
229
+ type: 'string',
230
+ description: 'Optional Windows OCR language tag to verify, e.g. ko or en-US.',
231
+ },
232
+ }), false),
233
+ branch('capture', input(captureProperties), false),
234
+ branch('click', input({
235
+ ...pointerProperties,
236
+ button: {
237
+ type: 'string',
238
+ enum: ['left', 'right', 'middle'],
239
+ description: 'Left + ref uses semantic activate/toggle. Left + element/frame and right/middle use pointer input.',
240
+ },
241
+ }, ['window_id'])),
242
+ branch('double_click', input(pointerProperties, ['window_id'])),
243
+ branch('mouse_move', input(pointerProperties, ['window_id'])),
244
+ branch('drag', input({
245
+ ...windowTarget,
246
+ ...elementTarget,
247
+ to: { type: 'string', description: 'Destination semantic ref.' },
248
+ to_element: { type: 'integer', minimum: 1 },
249
+ ...framePoint,
250
+ to_x: { type: 'integer' },
251
+ to_y: { type: 'integer' },
252
+ modifiers: { type: 'string' },
253
+ ...delivery,
254
+ }, ['window_id'])),
255
+ branch('type', input({
256
+ ...windowTarget,
257
+ ...elementTarget,
258
+ ...framePoint,
259
+ text: { type: 'string' },
260
+ ...delivery,
261
+ }, ['window_id', 'text'])),
262
+ branch('key', input({
263
+ ...windowTarget,
264
+ ...elementTarget,
265
+ keys: {
266
+ type: 'string',
267
+ description: 'SendKeys syntax, e.g. "^s", "%{F4}", or "Hello{ENTER}". Modifiers and groups require delivery="foreground".',
268
+ },
269
+ ...delivery,
270
+ }, ['window_id', 'keys'])),
271
+ branch('scroll', input({
272
+ ...windowTarget,
273
+ ...elementTarget,
274
+ ...framePoint,
275
+ direction: {
276
+ type: 'string',
277
+ enum: ['up', 'down', 'left', 'right'],
278
+ },
279
+ amount: {
280
+ type: 'integer',
281
+ minimum: 1,
282
+ maximum: 100,
283
+ },
284
+ ...delivery,
285
+ }, ['window_id', 'direction'])),
286
+ branch('wait', input({
287
+ duration: {
288
+ type: 'number',
289
+ minimum: 0,
290
+ maximum: 30,
291
+ },
292
+ }, ['duration'])),
293
+ branch('sequence', input({
294
+ ...windowTarget,
295
+ steps: {
296
+ type: 'array',
297
+ items: sequenceStep,
298
+ minItems: 2,
299
+ maxItems: 6,
300
+ description: 'Prefer this over separate calls for a deterministic same-window focus chain. A transition-capable step must be final; execution stops on failure or target transition.',
301
+ },
302
+ ...delivery,
303
+ }, ['window_id', 'steps'])),
304
+ branch('window', input({
305
+ ...windowTarget,
306
+ operation: {
307
+ type: 'string',
308
+ enum: ['focus', 'move', 'minimize', 'maximize', 'restore', 'close'],
309
+ },
310
+ x: { type: 'integer' },
311
+ y: { type: 'integer' },
312
+ width: { type: 'integer' },
313
+ height: { type: 'integer' },
314
+ }, ['window_id', 'operation'])),
315
+ branch('clipboard', input({
316
+ operation: { type: 'string', enum: ['read', 'write'] },
317
+ text: { type: 'string', description: 'Required for operation="write".' },
318
+ }, ['operation'])),
319
+ branch('launch', input({
320
+ app: {
321
+ type: 'string',
322
+ description: 'Executable name, exact path, file, or URL.',
323
+ },
324
+ }, ['app'])),
325
+ ],
326
+ };
327
+
328
+ const COMPUTER_ACTION_BRANCHES = new Map();
329
+ for (const actionBranch of COMPUTER_INPUT_SCHEMA.oneOf) {
330
+ for (const action of actionBranch.properties?.action?.enum || []) {
331
+ COMPUTER_ACTION_BRANCHES.set(action, actionBranch);
332
+ }
333
+ }
334
+
335
+ const CAPTURE_AFTER_ACTIONS = new Set([
336
+ 'click', 'double_click', 'mouse_move', 'drag', 'type', 'key', 'scroll',
337
+ 'sequence', 'window', 'launch',
338
+ ]);
339
+
340
+ function hasOwn(value, key) {
341
+ return Object.prototype.hasOwnProperty.call(value, key);
342
+ }
343
+
344
+ function schemaValueError(value, schema, path) {
345
+ if (schema.enum && !schema.enum.includes(value)) {
346
+ return `${path} must be one of: ${schema.enum.join(', ')}`;
347
+ }
348
+ if (schema.type === 'string' && typeof value !== 'string') return `${path} must be a string`;
349
+ if (schema.type === 'boolean' && typeof value !== 'boolean') return `${path} must be a boolean`;
350
+ if (schema.type === 'number' && (typeof value !== 'number' || !Number.isFinite(value))) {
351
+ return `${path} must be a finite number`;
352
+ }
353
+ if (schema.type === 'integer' && !Number.isInteger(value)) return `${path} must be an integer`;
354
+ if (schema.type === 'array') {
355
+ if (!Array.isArray(value)) return `${path} must be an array`;
356
+ if (schema.minItems !== undefined && value.length < schema.minItems) {
357
+ return `${path} requires at least ${schema.minItems} items`;
358
+ }
359
+ if (schema.maxItems !== undefined && value.length > schema.maxItems) {
360
+ return `${path} accepts at most ${schema.maxItems} items`;
361
+ }
362
+ for (let index = 0; index < value.length; index += 1) {
363
+ const itemError = schemaValueError(value[index], schema.items || {}, `${path}[${index}]`);
364
+ if (itemError) return itemError;
365
+ }
366
+ }
367
+ if (typeof value === 'number') {
368
+ if (schema.minimum !== undefined && value < schema.minimum) {
369
+ return `${path} must be at least ${schema.minimum}`;
370
+ }
371
+ if (schema.maximum !== undefined && value > schema.maximum) {
372
+ return `${path} must be at most ${schema.maximum}`;
373
+ }
374
+ }
375
+ return null;
376
+ }
377
+
378
+ function objectSchemaValueError(value, schema, path) {
379
+ for (const [name, item] of Object.entries(value)) {
380
+ const error = schemaValueError(item, schema.properties?.[name] || {}, `${path}.${name}`);
381
+ if (error) return error;
382
+ }
383
+ return null;
384
+ }
385
+
386
+ function validateTargetForm(name, inputValue, { required = true } = {}) {
387
+ const semantic = ['ref', 'element'].filter((key) => hasOwn(inputValue, key));
388
+ const pointFields = ['frame_id', 'x', 'y'].filter((key) => hasOwn(inputValue, key));
389
+ if (semantic.length > 1) return `${name} accepts only one of ref or element`;
390
+ if (pointFields.length && pointFields.length !== 3) {
391
+ return `${name} coordinate target requires frame_id, x, and y`;
392
+ }
393
+ const forms = semantic.length + (pointFields.length === 3 ? 1 : 0);
394
+ if (forms > 1) return `${name} accepts only one target form`;
395
+ if (required && forms === 0) return `${name} requires ref, element, or frame_id/x/y`;
396
+ return null;
397
+ }
398
+
399
+ export function validateComputerToolArgs(args) {
400
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
401
+ return 'Computer Use arguments must be an object';
402
+ }
403
+ const rootExtras = Object.keys(args).filter(
404
+ (key) => !['action', 'input', 'capture_after'].includes(key),
405
+ );
406
+ if (rootExtras.length) {
407
+ return `Computer Use does not accept root field(s): ${rootExtras.join(', ')}`;
408
+ }
409
+
410
+ const name = String(args.action || '');
411
+ const branch = COMPUTER_ACTION_BRANCHES.get(name);
412
+ if (!branch) return `unknown Computer Use action: ${name || '(empty)'}`;
413
+
414
+ const inputRequired = branch.required?.includes('input') === true;
415
+ const inputValue = args.input;
416
+ if (inputValue === undefined) {
417
+ if (inputRequired) return `Computer Use action "${name}" requires input`;
418
+ } else {
419
+ if (!inputValue || typeof inputValue !== 'object' || Array.isArray(inputValue)) {
420
+ return `Computer Use action "${name}" input must be an object`;
421
+ }
422
+
423
+ const strictInput = branch.properties?.input;
424
+ const allowed = new Set(Object.keys(strictInput?.properties || {}));
425
+ const extras = Object.keys(inputValue).filter((key) => !allowed.has(key));
426
+ if (extras.length) {
427
+ return `Computer Use action "${name}" does not accept input field(s): ${extras.join(', ')}`;
428
+ }
429
+
430
+ const missing = (strictInput?.required || []).filter((key) => !hasOwn(inputValue, key));
431
+ if (missing.length) {
432
+ return `Computer Use action "${name}" requires input field(s): ${missing.join(', ')}`;
433
+ }
434
+ const valueError = objectSchemaValueError(inputValue, strictInput, 'Computer Use input');
435
+ if (valueError) return valueError;
436
+ }
437
+
438
+ const inputObject = inputValue || {};
439
+ if (name === 'capture') {
440
+ const mode = inputObject.mode || 'state';
441
+ if (mode === 'zoom' && (!hasOwn(inputObject, 'frame_id') || !hasOwn(inputObject, 'region'))) {
442
+ return 'Computer Use capture mode="zoom" requires input field(s): frame_id, region';
443
+ }
444
+ if (mode !== 'zoom' && (hasOwn(inputObject, 'frame_id') || hasOwn(inputObject, 'region'))) {
445
+ return 'Computer Use capture frame_id/region requires mode="zoom"';
446
+ }
447
+ if (mode === 'ax' && inputObject.include_ocr === true) {
448
+ return 'Computer Use capture include_ocr is unavailable with mode="ax"';
449
+ }
450
+ if (hasOwn(inputObject, 'screen') && mode !== 'vision') {
451
+ return 'Computer Use capture screen requires mode="vision"';
452
+ }
453
+ }
454
+ if (['click', 'double_click', 'mouse_move'].includes(name)) {
455
+ const targetError = validateTargetForm(name, inputObject);
456
+ if (targetError) return `Computer Use ${targetError}`;
457
+ }
458
+ if (name === 'type') {
459
+ const targetError = validateTargetForm(name, inputObject, { required: false });
460
+ if (targetError) return `Computer Use ${targetError}`;
461
+ }
462
+ if (name === 'key') {
463
+ const targetError = validateTargetForm(name, inputObject, { required: false });
464
+ if (targetError) return `Computer Use ${targetError}`;
465
+ }
466
+ if (name === 'scroll') {
467
+ const targetError = validateTargetForm(name, inputObject, { required: false });
468
+ if (targetError) return `Computer Use ${targetError}`;
469
+ }
470
+ if (name === 'drag') {
471
+ const semanticSource = ['ref', 'element'].filter((key) => hasOwn(inputObject, key));
472
+ const semanticDestination = ['to', 'to_element'].filter((key) => hasOwn(inputObject, key));
473
+ const pointFields = ['frame_id', 'x', 'y', 'to_x', 'to_y'].filter(
474
+ (key) => hasOwn(inputObject, key),
475
+ );
476
+ const semantic = semanticSource.length === 1 && semanticDestination.length === 1;
477
+ const coordinate = pointFields.length === 5;
478
+ if (semanticSource.length > 1 || semanticDestination.length > 1 || (semantic && coordinate)) {
479
+ return 'Computer Use drag accepts one matching semantic or coordinate target pair';
480
+ }
481
+ if (!semantic && !coordinate) {
482
+ return 'Computer Use drag requires ref/element plus to/to_element, or frame_id/x/y/to_x/to_y';
483
+ }
484
+ }
485
+ if (name === 'sequence') {
486
+ const steps = inputObject.steps || [];
487
+ for (let index = 0; index < steps.length; index += 1) {
488
+ const step = steps[index];
489
+ if (!step || typeof step !== 'object' || Array.isArray(step)) {
490
+ return `Computer Use sequence step ${index + 1} must be an object`;
491
+ }
492
+ const stepAction = String(step.action || '');
493
+ const stepSchema = sequenceStepSchemas[stepAction];
494
+ if (!stepSchema) {
495
+ return `Computer Use sequence step ${index + 1} action must be one of: click, type, key, wait`;
496
+ }
497
+ const allowed = new Set(['action', ...Object.keys(stepSchema.properties)]);
498
+ const extras = Object.keys(step).filter((key) => !allowed.has(key));
499
+ if (extras.length) {
500
+ return `Computer Use sequence step ${index + 1} does not accept field(s): ${extras.join(', ')}`;
501
+ }
502
+ const missing = (stepSchema.required || []).filter((key) => !hasOwn(step, key));
503
+ if (missing.length) {
504
+ return `Computer Use sequence step ${index + 1} requires field(s): ${missing.join(', ')}`;
505
+ }
506
+ const valueError = objectSchemaValueError(step, {
507
+ properties: { action: { type: 'string', enum: [stepAction] }, ...stepSchema.properties },
508
+ }, `Computer Use sequence step ${index + 1}`);
509
+ if (valueError) return valueError;
510
+ if (stepAction === 'click') {
511
+ const targetError = validateTargetForm('sequence click', step);
512
+ if (targetError) return `Computer Use ${targetError}`;
513
+ } else if (stepAction === 'type' || stepAction === 'key') {
514
+ const targetError = validateTargetForm(`sequence ${stepAction}`, step, { required: false });
515
+ if (targetError) return `Computer Use ${targetError}`;
516
+ }
517
+ if (index === 0 && stepAction === 'wait') {
518
+ return 'Computer Use sequence must start with click, type, or key';
519
+ }
520
+ if (index > 0) {
521
+ if (!['type', 'key', 'wait'].includes(stepAction)) {
522
+ return 'Computer Use sequence steps after the first must be type, key, or wait';
523
+ }
524
+ if (['ref', 'element', 'frame_id', 'x', 'y'].some((key) => hasOwn(step, key))) {
525
+ return 'Computer Use sequence steps after the first reuse focus and cannot carry a target';
526
+ }
527
+ }
528
+ }
529
+ }
530
+ if (name === 'window' && inputObject.operation === 'move'
531
+ && !['x', 'y', 'width', 'height'].some((key) => hasOwn(inputObject, key))) {
532
+ return 'Computer Use window operation="move" requires x, y, width, or height';
533
+ }
534
+ if (name === 'clipboard') {
535
+ if (inputObject.operation === 'write' && !hasOwn(inputObject, 'text')) {
536
+ return 'Computer Use clipboard operation="write" requires input field: text';
537
+ }
538
+ if (inputObject.operation === 'read' && hasOwn(inputObject, 'text')) {
539
+ return 'Computer Use clipboard operation="read" does not accept input field: text';
540
+ }
541
+ }
542
+ if (name === 'launch') {
543
+ const app = String(inputObject.app || '').trim();
544
+ if (!app) return 'Computer Use launch app must not be empty';
545
+ const httpUrl = /^https?:\/\//i.test(app);
546
+ if (/[\r\n\0]|javascript:/i.test(app) || (!httpUrl && /&&|\|\|/.test(app))) {
547
+ return 'Computer Use launch app must be one executable, file, or URL without command syntax';
548
+ }
549
+ if (!httpUrl && (
550
+ /(?:^|[\\/"'])\s*(?:cmd|powershell|pwsh|wt|wsl|bash|sh|zsh|fish|nu|wscript|cscript|mshta|rundll32|regsvr32)(?:\.exe)?(?:["'\s]|$)/i.test(app)
551
+ || /\.(?:bat|cmd|ps1|vbs|vbe|js|jse|wsf|wsh|hta|lnk|url|appref-ms)(?:["']?\s*)$/i.test(app)
552
+ )) {
553
+ return 'Computer Use launch blocks shells, script hosts, and shortcut files; use an exact non-shell executable, document, or URL';
554
+ }
555
+ }
556
+ if (args.capture_after !== undefined) {
557
+ if (!CAPTURE_AFTER_ACTIONS.has(name)) {
558
+ return `Computer Use action "${name}" does not accept capture_after`;
559
+ }
560
+ if (!args.capture_after || typeof args.capture_after !== 'object'
561
+ || Array.isArray(args.capture_after)) {
562
+ return 'Computer Use capture_after must be an object';
563
+ }
564
+ const allowedAfter = new Set(Object.keys(captureAfter.properties));
565
+ const afterExtras = Object.keys(args.capture_after).filter((key) => !allowedAfter.has(key));
566
+ if (afterExtras.length) {
567
+ return `Computer Use capture_after does not accept field(s): ${afterExtras.join(', ')}`;
568
+ }
569
+ const afterValueError = objectSchemaValueError(
570
+ args.capture_after,
571
+ captureAfter,
572
+ 'Computer Use capture_after',
573
+ );
574
+ if (afterValueError) return afterValueError;
575
+ }
576
+ return null;
577
+ }
578
+
579
+ export function toComputerHostCommand(args) {
580
+ const inputValue = args.input || {};
581
+ const command = { ...inputValue };
582
+ switch (args.action) {
583
+ case 'list':
584
+ command.action = inputValue.kind === 'apps' ? 'list_apps' : 'list_windows';
585
+ delete command.kind;
586
+ break;
587
+ case 'capture':
588
+ command.action = inputValue.mode === 'zoom' ? 'zoom' : 'capture';
589
+ if (command.action === 'zoom') delete command.mode;
590
+ break;
591
+ case 'click':
592
+ command.action = inputValue.button === 'right'
593
+ ? 'right_click'
594
+ : inputValue.button === 'middle'
595
+ ? 'middle_click'
596
+ : inputValue.ref
597
+ ? 'invoke'
598
+ : 'click';
599
+ delete command.button;
600
+ break;
601
+ case 'sequence':
602
+ command.action = 'sequence';
603
+ command.steps = inputValue.steps.map((step) => {
604
+ const translated = { ...step };
605
+ if (step.action === 'click') {
606
+ translated.action = step.button === 'right'
607
+ ? 'right_click'
608
+ : step.button === 'middle'
609
+ ? 'middle_click'
610
+ : step.ref
611
+ ? 'invoke'
612
+ : 'click';
613
+ delete translated.button;
614
+ }
615
+ return translated;
616
+ });
617
+ break;
618
+ case 'window':
619
+ command.action = inputValue.operation === 'focus'
620
+ ? 'focus_window'
621
+ : inputValue.operation === 'move'
622
+ ? 'move_window'
623
+ : inputValue.operation === 'close'
624
+ ? 'close_window'
625
+ : 'window_state';
626
+ if (command.action === 'window_state') command.state = inputValue.operation;
627
+ delete command.operation;
628
+ break;
629
+ case 'clipboard':
630
+ command.action = inputValue.operation === 'write' ? 'clipboard_write' : 'clipboard_read';
631
+ delete command.operation;
632
+ break;
633
+ default:
634
+ command.action = args.action;
635
+ }
636
+ if (args.capture_after) {
637
+ command.capture_after = true;
638
+ const afterFields = {
639
+ delay_ms: 'capture_delay_ms',
640
+ mode: 'capture_after_mode',
641
+ max_elements: 'capture_after_max_elements',
642
+ include_ocr: 'capture_after_include_ocr',
643
+ ocr_language: 'capture_after_ocr_language',
644
+ max_ocr_words: 'capture_after_max_ocr_words',
645
+ };
646
+ for (const [source, target] of Object.entries(afterFields)) {
647
+ if (hasOwn(args.capture_after, source)) command[target] = args.capture_after[source];
648
+ }
649
+ }
650
+ return command;
651
+ }
652
+
653
+ export const COMPUTER_ACTIONS = Object.freeze([...ACTIONS]);