@abot-ai/runtime 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (443) hide show
  1. package/dist/src/capabilities/tool-request-resources.d.ts +3 -0
  2. package/dist/src/cli/abot.js +2 -0
  3. package/dist/src/cli/host-companion-bundle.mjs +751 -333
  4. package/dist/src/computer-access/collection-consent.d.ts +9 -0
  5. package/dist/src/computer-access/collection-consent.js +47 -0
  6. package/dist/src/computer-access/command-output-capture.d.ts +17 -6
  7. package/dist/src/computer-access/command-output-capture.js +134 -68
  8. package/dist/src/computer-access/command-output-protection.d.ts +17 -0
  9. package/dist/src/computer-access/command-output-protection.js +59 -0
  10. package/dist/src/computer-access/companion/command-output.d.ts +1 -0
  11. package/dist/src/computer-access/companion/command-output.js +23 -6
  12. package/dist/src/computer-access/companion/install-link-macos.js +2 -1
  13. package/dist/src/computer-access/companion/native-notifications.js +3 -2
  14. package/dist/src/computer-access/companion/native-session.js +6 -2
  15. package/dist/src/computer-access/companion/observation-filter.js +2 -26
  16. package/dist/src/computer-access/companion/observation-process.d.ts +2 -0
  17. package/dist/src/computer-access/companion/observation-process.js +51 -25
  18. package/dist/src/computer-access/companion/observation-redaction.d.ts +2 -7
  19. package/dist/src/computer-access/companion/observation-redaction.js +2 -111
  20. package/dist/src/computer-access/companion/secret-protection-protocol.d.ts +6 -0
  21. package/dist/src/computer-access/companion/secret-protection-protocol.js +6 -0
  22. package/dist/src/computer-access/computer/companion-sessions.js +7 -6
  23. package/dist/src/computer-access/computer/unix-native-process.js +23 -11
  24. package/dist/src/computer-access/handlers.d.ts +2 -1
  25. package/dist/src/computer-access/handlers.js +79 -11
  26. package/dist/src/computer-access/host-observation.d.ts +3 -3
  27. package/dist/src/computer-access/native-observation-connection.d.ts +12 -0
  28. package/dist/src/computer-access/native-observation-connection.js +78 -0
  29. package/dist/src/computer-access/native-observation-ownership.d.ts +6 -0
  30. package/dist/src/computer-access/native-observation-ownership.js +55 -0
  31. package/dist/src/computer-access/native-observation-shutdown.d.ts +7 -0
  32. package/dist/src/computer-access/native-observation-shutdown.js +58 -0
  33. package/dist/src/computer-access/observation-source.d.ts +6 -0
  34. package/dist/src/computer-access/observation-source.js +10 -0
  35. package/dist/src/computer-access/security/desktop-result.d.ts +8 -0
  36. package/dist/src/computer-access/security/desktop-result.js +146 -0
  37. package/dist/src/computer-access/security/observed-error.d.ts +2 -0
  38. package/dist/src/computer-access/security/observed-error.js +10 -0
  39. package/dist/src/computer-access/security/secret-text.d.ts +7 -0
  40. package/dist/src/computer-access/security/secret-text.js +111 -0
  41. package/dist/src/computer-access/security/system-results.d.ts +2 -0
  42. package/dist/src/computer-access/security/system-results.js +53 -0
  43. package/dist/src/computer-access/system-result-protection.d.ts +11 -0
  44. package/dist/src/computer-access/system-result-protection.js +1 -0
  45. package/dist/src/model-gateway/observability/provider-response-capture.d.ts +60 -0
  46. package/dist/src/model-gateway/observability/provider-response-capture.js +68 -0
  47. package/dist/src/model-gateway/observability/provider-response-prefix.d.ts +7 -0
  48. package/dist/src/model-gateway/observability/provider-response-prefix.js +14 -0
  49. package/dist/src/model-gateway/observability/provider-response-tail.d.ts +8 -0
  50. package/dist/src/model-gateway/observability/provider-response-tail.js +28 -0
  51. package/dist/src/model-gateway/observability/provider-sse-diagnostics.d.ts +30 -0
  52. package/dist/src/model-gateway/observability/provider-sse-diagnostics.js +119 -0
  53. package/dist/src/model-gateway/observability/provider-trace.js +30 -8
  54. package/dist/src/model-gateway/providers/ollama/adapter.js +8 -2
  55. package/dist/src/model-gateway/providers/ollama/stream-normalizer.js +70 -50
  56. package/dist/src/model-gateway/providers/ollama/stream-termination.d.ts +6 -0
  57. package/dist/src/model-gateway/providers/ollama/stream-termination.js +20 -0
  58. package/dist/src/model-gateway/providers/openai/adapter.js +9 -7
  59. package/dist/src/model-gateway/providers/openai/diagnostics.d.ts +0 -1
  60. package/dist/src/model-gateway/providers/openai/diagnostics.js +0 -9
  61. package/dist/src/model-gateway/providers/openai/function-output.d.ts +11 -0
  62. package/dist/src/model-gateway/providers/openai/function-output.js +37 -0
  63. package/dist/src/model-gateway/providers/openai/function-result.d.ts +7 -0
  64. package/dist/src/model-gateway/providers/openai/function-result.js +35 -0
  65. package/dist/src/model-gateway/providers/openai/message-output-policy.d.ts +3 -0
  66. package/dist/src/model-gateway/providers/openai/message-output-policy.js +16 -0
  67. package/dist/src/model-gateway/providers/openai/payload.d.ts +0 -2
  68. package/dist/src/model-gateway/providers/openai/payload.js +6 -23
  69. package/dist/src/model-gateway/providers/openai/response-lifetime.d.ts +2 -0
  70. package/dist/src/model-gateway/providers/openai/response-lifetime.js +64 -0
  71. package/dist/src/model-gateway/providers/openai/sse-data.d.ts +9 -0
  72. package/dist/src/model-gateway/providers/openai/sse-data.js +67 -0
  73. package/dist/src/model-gateway/providers/openai/stream-normalizer.d.ts +10 -22
  74. package/dist/src/model-gateway/providers/openai/stream-normalizer.js +78 -79
  75. package/dist/src/model-gateway/providers/openai/stream.js +13 -41
  76. package/dist/src/model-gateway/providers/openai/structured-message-output.d.ts +42 -0
  77. package/dist/src/model-gateway/providers/openai/structured-message-output.js +175 -0
  78. package/dist/src/model-gateway/server.js +5 -1
  79. package/dist/src/plugin-contract/index.d.ts +1 -0
  80. package/dist/src/plugin-contract/index.js +1 -0
  81. package/dist/src/plugin-contract/manifest.d.ts +2 -0
  82. package/dist/src/plugin-contract/manifest.js +1 -0
  83. package/dist/src/plugin-contract/platform-compatibility.d.ts +16 -0
  84. package/dist/src/plugin-contract/platform-compatibility.js +3 -0
  85. package/dist/src/plugin-sdk/computer-access.d.ts +4 -0
  86. package/dist/src/plugin-sdk/computer-access.js +1 -0
  87. package/dist/src/plugin-sdk/files-windows/process.d.ts +3 -0
  88. package/dist/src/plugin-sdk/files-windows/process.js +93 -0
  89. package/dist/src/plugin-sdk/files-windows/read-script.d.ts +1 -0
  90. package/dist/src/plugin-sdk/files-windows/read-script.js +43 -0
  91. package/dist/src/plugin-sdk/files-windows/read.d.ts +6 -0
  92. package/dist/src/plugin-sdk/files-windows/read.js +56 -0
  93. package/dist/src/plugin-sdk/files-windows/result.d.ts +4 -0
  94. package/dist/src/plugin-sdk/files-windows/result.js +67 -0
  95. package/dist/src/plugin-sdk/files.js +4 -0
  96. package/dist/src/plugin-sdk/index.d.ts +1 -0
  97. package/dist/src/plugin-sdk/index.js +1 -0
  98. package/dist/src/plugin-sdk/mutation-result.d.ts +7 -0
  99. package/dist/src/plugin-sdk/mutation-result.js +11 -0
  100. package/dist/src/runtime/adapters/long-term-memory/file-lock/acquisition.js +20 -3
  101. package/dist/src/runtime/adapters/long-term-memory/file-lock/owner-record.js +3 -1
  102. package/dist/src/runtime/adapters/long-term-memory/file-lock/path-observation.d.ts +3 -0
  103. package/dist/src/runtime/adapters/long-term-memory/file-lock/path-observation.js +20 -0
  104. package/dist/src/runtime/adapters/long-term-memory/file-lock/snapshot.js +7 -3
  105. package/dist/src/runtime/adapters/passive-learning-runtime.d.ts +1 -1
  106. package/dist/src/runtime/adapters/passive-learning-runtime.js +3 -3
  107. package/dist/src/runtime/adapters/runtime-observation-connection.d.ts +5 -0
  108. package/dist/src/runtime/adapters/runtime-observation-connection.js +13 -0
  109. package/dist/src/runtime/local-host/windows-private-access.js +2 -0
  110. package/dist/src/runtime/passive-learning/application-catalog.js +3 -1
  111. package/dist/src/runtime/passive-learning/collection-source.js +7 -0
  112. package/dist/src/runtime/passive-learning/service.js +2 -3
  113. package/dist/src/runtime/passive-learning/status-projection.d.ts +2 -0
  114. package/dist/src/runtime/passive-learning/status-projection.js +9 -0
  115. package/dist/src/runtime/plugins/installation/package.d.ts +8 -0
  116. package/dist/src/runtime/plugins/installation/package.js +2 -0
  117. package/dist/src/runtime/plugins/installation/service.d.ts +7 -0
  118. package/dist/src/runtime/plugins/loader.js +24 -14
  119. package/dist/src/runtime/plugins/manifest-platform-compatibility.d.ts +2 -0
  120. package/dist/src/runtime/plugins/manifest-platform-compatibility.js +39 -0
  121. package/dist/src/runtime/plugins/manifest-validator.js +9 -1
  122. package/dist/src/runtime/plugins/platform-compatibility.d.ts +4 -0
  123. package/dist/src/runtime/plugins/platform-compatibility.js +44 -0
  124. package/dist/src/runtime/request/approval-wait/activation-events.js +19 -7
  125. package/dist/src/runtime/request/approval-wait/execution-compaction-restore.d.ts +20 -0
  126. package/dist/src/runtime/request/approval-wait/execution-compaction-restore.js +118 -0
  127. package/dist/src/runtime/request/approval-wait/super-compaction-restore.js +2 -1
  128. package/dist/src/runtime/request/prepared-execution.js +3 -0
  129. package/dist/src/runtime/steps/execution-agent/capability-result-context.d.ts +6 -0
  130. package/dist/src/runtime/steps/execution-agent/capability-result-context.js +29 -0
  131. package/dist/src/runtime/steps/execution-agent/format.js +2 -3
  132. package/dist/src/runtime/steps/execution-agent/input.js +1 -1
  133. package/dist/src/runtime/steps/execution-agent/prompt.js +5 -5
  134. package/dist/src/runtime/steps/execution-agent/response-prompt.js +1 -0
  135. package/dist/src/runtime/steps/execution-agent/state-context.d.ts +2 -3
  136. package/dist/src/runtime/steps/execution-agent/state-context.js +26 -35
  137. package/dist/src/runtime/steps/execution-agent/work-plan-contract.d.ts +1 -3
  138. package/dist/src/runtime/steps/execution-agent/work-plan-contract.js +0 -55
  139. package/dist/src/runtime/steps/execution-agent/work-plan-schema.d.ts +3 -0
  140. package/dist/src/runtime/steps/execution-agent/work-plan-schema.js +61 -0
  141. package/dist/src/sessions/durable-session-commit.js +3 -3
  142. package/dist/src/sessions/prepared-session-replacement.d.ts +6 -0
  143. package/dist/src/sessions/prepared-session-replacement.js +46 -0
  144. package/dist/src/sessions/session-store.js +3 -3
  145. package/dist/src/shared/passive-observation-self-exclusion.d.ts +5 -0
  146. package/dist/src/shared/passive-observation-self-exclusion.js +37 -0
  147. package/dist/src/shared/windows-file-io/authority-script.d.ts +1 -0
  148. package/dist/src/shared/windows-file-io/authority-script.js +94 -0
  149. package/dist/src/shared/windows-file-io/native-script.d.ts +2 -0
  150. package/dist/src/shared/windows-file-io/native-script.js +120 -0
  151. package/dist/src/shared/windows-file-io/read-bytes-script.d.ts +1 -0
  152. package/dist/src/shared/windows-file-io/read-bytes-script.js +18 -0
  153. package/dist/src/shared/windows-job-object.d.ts +2 -0
  154. package/dist/src/shared/windows-job-object.js +66 -0
  155. package/dist/src/web-ui/app/app-bootstrap.js +14 -1
  156. package/dist/src/web-ui/app/app-state.js +0 -7
  157. package/dist/src/web-ui/app/app.js +53 -156
  158. package/dist/src/web-ui/app/components/automations/node-inspector.js +3 -2
  159. package/dist/src/web-ui/app/components/automations/step-editor-dialog.js +3 -0
  160. package/dist/src/web-ui/app/components/composer-submission-notice.js +50 -0
  161. package/dist/src/web-ui/app/components/config-workspace/model-plugin-permissions.js +7 -1
  162. package/dist/src/web-ui/app/components/config-workspace/workspace-mutations.js +22 -2
  163. package/dist/src/web-ui/app/components/home-guidance/daily-review.js +2 -2
  164. package/dist/src/web-ui/app/components/home-guidance/home-guidance.js +20 -6
  165. package/dist/src/web-ui/app/components/model-setup/context-window-feedback.js +53 -0
  166. package/dist/src/web-ui/app/components/model-setup/save-flow.js +3 -1
  167. package/dist/src/web-ui/app/components/model-setup/save-outcome.js +1 -0
  168. package/dist/src/web-ui/app/components/model-setup/wizard.js +12 -0
  169. package/dist/src/web-ui/app/components/passive-learning/activity-controls.js +4 -0
  170. package/dist/src/web-ui/app/components/passive-learning/collection-access.js +35 -0
  171. package/dist/src/web-ui/app/components/passive-learning/collection-consent-dialog.js +59 -0
  172. package/dist/src/web-ui/app/components/passive-learning/collection-consent-gate.js +94 -0
  173. package/dist/src/web-ui/app/components/passive-learning/computer-update-notice.js +6 -0
  174. package/dist/src/web-ui/app/components/passive-learning/failure-copy.js +1 -0
  175. package/dist/src/web-ui/app/components/passive-learning/home.js +7 -2
  176. package/dist/src/web-ui/app/components/passive-learning/macos-collection-restart-notice.js +1 -0
  177. package/dist/src/web-ui/app/components/passive-learning/memory.js +2 -4
  178. package/dist/src/web-ui/app/components/passive-learning/workspace-view.js +2 -2
  179. package/dist/src/web-ui/app/components/plugins/compatibility.js +13 -0
  180. package/dist/src/web-ui/app/components/plugins/discovery-rendering.js +9 -1
  181. package/dist/src/web-ui/app/components/plugins/installation-compatibility.js +7 -0
  182. package/dist/src/web-ui/app/components/plugins/installation.js +2 -1
  183. package/dist/src/web-ui/app/components/plugins/rendering.js +3 -0
  184. package/dist/src/web-ui/app/components/reasoning-override-prompt.js +82 -0
  185. package/dist/src/web-ui/app/components/runtime-config-activation.js +22 -8
  186. package/dist/src/web-ui/app/components/runtime-setup/optional-steps.js +7 -4
  187. package/dist/src/web-ui/app/components/runtime-setup/plugins.js +3 -1
  188. package/dist/src/web-ui/app/components/runtime-setup/rendering.js +6 -4
  189. package/dist/src/web-ui/app/components/runtime-setup-guide.d.ts +1 -0
  190. package/dist/src/web-ui/app/components/schedules/form.js +10 -8
  191. package/dist/src/web-ui/app/components/schedules/workspace.js +23 -4
  192. package/dist/src/web-ui/app/components/session-sidebar-sections.js +2 -2
  193. package/dist/src/web-ui/app/components/spark-chat/handoff-actions.js +9 -3
  194. package/dist/src/web-ui/app/components/spark-chat/placement.js +4 -7
  195. package/dist/src/web-ui/app/components/spark-chat/settings.js +7 -3
  196. package/dist/src/web-ui/app/components/system-host/macos-permissions.js +2 -0
  197. package/dist/src/web-ui/app/components/system-host/native-windows-access.js +50 -0
  198. package/dist/src/web-ui/app/components/system-host/rendering.js +3 -0
  199. package/dist/src/web-ui/app/components/workspace-storage-notice.js +37 -0
  200. package/dist/src/web-ui/app/configuration-environment-refresh.js +27 -34
  201. package/dist/src/web-ui/app/configuration-feature.js +9 -1
  202. package/dist/src/web-ui/app/controllers/app-event-bindings.js +38 -105
  203. package/dist/src/web-ui/app/controllers/chat-request-controller.d.ts +28 -0
  204. package/dist/src/web-ui/app/controllers/chat-request-controller.js +34 -66
  205. package/dist/src/web-ui/app/controllers/composer-attachments-controller.d.ts +15 -40
  206. package/dist/src/web-ui/app/controllers/composer-attachments-controller.js +26 -69
  207. package/dist/src/web-ui/app/controllers/composer-draft-view.d.ts +27 -0
  208. package/dist/src/web-ui/app/controllers/composer-draft-view.js +48 -0
  209. package/dist/src/web-ui/app/controllers/composer-drafts.d.ts +55 -0
  210. package/dist/src/web-ui/app/controllers/composer-drafts.js +120 -0
  211. package/dist/src/web-ui/app/controllers/composer-feature.d.ts +65 -0
  212. package/dist/src/web-ui/app/controllers/composer-feature.js +124 -0
  213. package/dist/src/web-ui/app/controllers/composer-queue-controller.d.ts +33 -94
  214. package/dist/src/web-ui/app/controllers/composer-queue-controller.js +185 -251
  215. package/dist/src/web-ui/app/controllers/composer-submission-lifecycle.d.ts +48 -0
  216. package/dist/src/web-ui/app/controllers/composer-submission-lifecycle.js +97 -0
  217. package/dist/src/web-ui/app/controllers/composer-submit-controller.d.ts +30 -61
  218. package/dist/src/web-ui/app/controllers/composer-submit-controller.js +56 -138
  219. package/dist/src/web-ui/app/controllers/composer-surface-controller.js +6 -0
  220. package/dist/src/web-ui/app/controllers/composer-workspace-controller.d.ts +22 -40
  221. package/dist/src/web-ui/app/controllers/composer-workspace-controller.js +49 -165
  222. package/dist/src/web-ui/app/controllers/conversation-navigation-intent.js +15 -0
  223. package/dist/src/web-ui/app/controllers/conversation-request-hydration.js +20 -17
  224. package/dist/src/web-ui/app/controllers/conversation-session-controller.d.ts +1 -2
  225. package/dist/src/web-ui/app/controllers/conversation-session-controller.js +49 -22
  226. package/dist/src/web-ui/app/controllers/conversation-workspace-activation.js +27 -0
  227. package/dist/src/web-ui/app/controllers/daily-memory-review.js +15 -16
  228. package/dist/src/web-ui/app/controllers/environment-transition.js +126 -0
  229. package/dist/src/web-ui/app/controllers/environment-workspace-preparation.js +18 -0
  230. package/dist/src/web-ui/app/controllers/home-composer-feature.d.ts +14 -36
  231. package/dist/src/web-ui/app/controllers/home-composer-feature.js +17 -114
  232. package/dist/src/web-ui/app/controllers/home-conversation-activation.js +6 -8
  233. package/dist/src/web-ui/app/controllers/passive-learning-controller.js +56 -0
  234. package/dist/src/web-ui/app/controllers/projects-controller.d.ts +1 -1
  235. package/dist/src/web-ui/app/controllers/projects-controller.js +6 -1
  236. package/dist/src/web-ui/app/controllers/reasoning-mode-controller.js +174 -0
  237. package/dist/src/web-ui/app/controllers/runtime-selection-controller.d.ts +7 -0
  238. package/dist/src/web-ui/app/controllers/runtime-selection-controller.js +20 -155
  239. package/dist/src/web-ui/app/controllers/session-controller.js +33 -17
  240. package/dist/src/web-ui/app/controllers/session-pin-updates.js +14 -0
  241. package/dist/src/web-ui/app/controllers/session-sidebar-controller.js +12 -14
  242. package/dist/src/web-ui/app/controllers/spark-chat-sync.js +2 -2
  243. package/dist/src/web-ui/app/controllers/steer-controller.js +9 -7
  244. package/dist/src/web-ui/app/controllers/tool-permission-mode-controller.js +1 -1
  245. package/dist/src/web-ui/app/controllers/workspace-conversation-opener.js +34 -0
  246. package/dist/src/web-ui/app/dashboard-feature.js +3 -2
  247. package/dist/src/web-ui/app/lib/reasoning-controls.js +35 -0
  248. package/dist/src/web-ui/app/lib/session-composer-queue-ownership.js +58 -0
  249. package/dist/src/web-ui/app/lib/session-composer-queue.d.ts +12 -0
  250. package/dist/src/web-ui/app/lib/session-composer-queue.js +25 -6
  251. package/dist/src/web-ui/app/passive-learning-feature.js +16 -3
  252. package/dist/src/web-ui/app/schedules-feature.js +5 -3
  253. package/dist/src/web-ui/app/services/client-preferences.d.ts +18 -10
  254. package/dist/src/web-ui/app/services/client-preferences.js +25 -16
  255. package/dist/src/web-ui/app/services/home-guidance-preferences.js +13 -13
  256. package/dist/src/web-ui/app/services/reasoning-override.js +12 -0
  257. package/dist/src/web-ui/app/services/runtime-web-client/automations.js +10 -2
  258. package/dist/src/web-ui/app/services/runtime-web-client/memory.js +7 -2
  259. package/dist/src/web-ui/app/services/runtime-web-client/system-host.js +2 -0
  260. package/dist/src/web-ui/app/services/runtime-web-client.d.ts +2 -0
  261. package/dist/src/web-ui/app/services/runtime-web-client.js +2 -0
  262. package/dist/src/web-ui/app/services/server-composer-queue.js +32 -0
  263. package/dist/src/web-ui/app/services/session-sidebar-preferences.js +5 -5
  264. package/dist/src/web-ui/app/services/workspace-state-storage.js +116 -0
  265. package/dist/src/web-ui/app/services/workspace-state.js +27 -0
  266. package/dist/src/web-ui/app/spark-chat-conversation.js +34 -45
  267. package/dist/src/web-ui/app/spark-chat-feature.js +10 -4
  268. package/dist/src/web-ui/app/styles/21-composer-controls.css +16 -0
  269. package/dist/src/web-ui/app/styles/41-plugin-management.css +8 -0
  270. package/dist/src/web-ui/app/styles/42-model-plugin-permissions.css +1 -0
  271. package/dist/src/web-ui/app/styles/49-collection-consent.css +30 -0
  272. package/dist/src/web-ui/app/styles/64-workspace-storage.css +23 -0
  273. package/dist/src/web-ui/app/styles.css +2 -0
  274. package/dist/src/web-ui/client-state/contracts.d.ts +15 -0
  275. package/dist/src/web-ui/client-state/contracts.js +13 -0
  276. package/dist/src/web-ui/client-state/preference-shapes.d.ts +2 -0
  277. package/dist/src/web-ui/client-state/preference-shapes.js +80 -0
  278. package/dist/src/web-ui/client-state/preferences.d.ts +3 -0
  279. package/dist/src/web-ui/client-state/preferences.js +84 -0
  280. package/dist/src/web-ui/client-state/queue.d.ts +3 -0
  281. package/dist/src/web-ui/client-state/queue.js +43 -0
  282. package/dist/src/web-ui/client-state/routes.d.ts +7 -0
  283. package/dist/src/web-ui/client-state/routes.js +58 -0
  284. package/dist/src/web-ui/client-state/store.d.ts +14 -0
  285. package/dist/src/web-ui/client-state/store.js +88 -0
  286. package/dist/src/web-ui/local-runtime/configuration-activation-source.js +2 -0
  287. package/dist/src/web-ui/local-runtime/http.js +11 -2
  288. package/dist/src/web-ui/local-runtime/model-context-capacity-error.d.ts +14 -0
  289. package/dist/src/web-ui/local-runtime/model-context-capacity-error.js +28 -0
  290. package/dist/src/web-ui/local-runtime/model-setup-context-window.d.ts +15 -0
  291. package/dist/src/web-ui/local-runtime/model-setup-context-window.js +25 -0
  292. package/dist/src/web-ui/local-runtime/model-setup-routes.js +2 -0
  293. package/dist/src/web-ui/local-runtime/model-setup-service.js +5 -2
  294. package/dist/src/web-ui/local-runtime/model-setup-validation.d.ts +1 -0
  295. package/dist/src/web-ui/local-runtime/model-setup-validation.js +14 -7
  296. package/dist/src/web-ui/local-runtime/request-body-error.d.ts +11 -0
  297. package/dist/src/web-ui/local-runtime/request-body-error.js +14 -0
  298. package/dist/src/web-ui/local-runtime/request-control-observation.js +2 -2
  299. package/dist/src/web-ui/local-runtime/request-execution.js +18 -18
  300. package/dist/src/web-ui/local-runtime/runtime-setup-connection-edit.d.ts +2 -0
  301. package/dist/src/web-ui/local-runtime/runtime-setup-connection-edit.js +35 -22
  302. package/dist/src/web-ui/local-runtime/runtime-setup-context-window.d.ts +2 -9
  303. package/dist/src/web-ui/local-runtime/runtime-setup-context-window.js +4 -27
  304. package/dist/src/web-ui/local-runtime/runtime-setup-credentials.d.ts +15 -1
  305. package/dist/src/web-ui/local-runtime/runtime-setup-credentials.js +30 -11
  306. package/dist/src/web-ui/local-runtime/runtime-setup-edit-files.d.ts +20 -0
  307. package/dist/src/web-ui/local-runtime/runtime-setup-edit-files.js +104 -0
  308. package/dist/src/web-ui/local-runtime/runtime-setup-edit-journal.d.ts +29 -0
  309. package/dist/src/web-ui/local-runtime/runtime-setup-edit-journal.js +151 -0
  310. package/dist/src/web-ui/local-runtime/runtime-setup-edit-recovery.d.ts +7 -0
  311. package/dist/src/web-ui/local-runtime/runtime-setup-edit-recovery.js +87 -0
  312. package/dist/src/web-ui/local-runtime/runtime-setup-edit-transaction.d.ts +3 -0
  313. package/dist/src/web-ui/local-runtime/runtime-setup-edit-transaction.js +37 -0
  314. package/dist/src/web-ui/local-runtime/runtime-setup-service.js +4 -0
  315. package/dist/src/web-ui/local-runtime-backend.js +14 -0
  316. package/dist/src/web-ui/plugin-management-catalog.d.ts +3 -1
  317. package/dist/src/web-ui/plugin-management-catalog.js +3 -1
  318. package/dist/src/web-ui/plugin-management-service.d.ts +1 -0
  319. package/dist/src/web-ui/plugin-removal-service.d.ts +1 -0
  320. package/dist/src/web-ui/server-readiness.d.ts +3 -0
  321. package/dist/src/web-ui/server-readiness.js +36 -0
  322. package/dist/src/web-ui/server.d.ts +2 -0
  323. package/dist/src/web-ui/server.js +23 -1
  324. package/dist/src/web-ui/system-host-service.js +13 -2
  325. package/dist/src/web-ui/system-host-setup/collection-consent-route.d.ts +3 -0
  326. package/dist/src/web-ui/system-host-setup/collection-consent-route.js +30 -0
  327. package/docs/installation.md +44 -5
  328. package/docs/plugins.md +145 -4
  329. package/docs/tool-execution-result-evidence-contract.md +57 -0
  330. package/docs/windows-companion-store.md +5 -0
  331. package/package.json +4 -2
  332. package/plugins/capability-brief/plugin.json +4 -0
  333. package/plugins/code-outline/README.md +20 -0
  334. package/plugins/code-outline/plugin.json +1 -0
  335. package/plugins/code-outline/source/index.ts +16 -20
  336. package/plugins/code-outline/source/read-failure.ts +40 -0
  337. package/plugins/code-outline/src/index.cjs +614 -29
  338. package/plugins/document-reader/README.md +33 -0
  339. package/plugins/document-reader/plugin.json +1 -0
  340. package/plugins/document-reader/source/pdf-contract.ts +57 -0
  341. package/plugins/document-reader/source/pdf-parser.ts +139 -0
  342. package/plugins/document-reader/source/pdf-process-main.ts +56 -0
  343. package/plugins/document-reader/source/pdf-process.ts +207 -0
  344. package/plugins/document-reader/source/pdf-result.ts +79 -0
  345. package/plugins/document-reader/source/pdf-worker.ts +39 -303
  346. package/plugins/document-reader/source/pdf.ts +4 -1
  347. package/plugins/document-reader/source/read-failure.ts +37 -0
  348. package/plugins/document-reader/source/reader.ts +3 -19
  349. package/plugins/document-reader/src/index.cjs +995 -211
  350. package/plugins/exec/README.md +19 -0
  351. package/plugins/exec/plugin.json +4 -3
  352. package/plugins/exec/skills/exec_skill/SKILL.md +3 -2
  353. package/plugins/exec/source/filesystem-file-observer.ts +98 -0
  354. package/plugins/exec/source/filesystem-observer.ts +8 -79
  355. package/plugins/exec/source/output-files.ts +12 -6
  356. package/plugins/exec/source/paths.ts +3 -1
  357. package/plugins/exec/source/process-manager.ts +8 -24
  358. package/plugins/exec/source/shell-platform.ts +19 -3
  359. package/plugins/exec/source/shell-process.ts +55 -0
  360. package/plugins/exec/source/windows-job-source.ts +1 -0
  361. package/plugins/exec/source/windows-shell-bootstrap.ts +20 -0
  362. package/plugins/exec/src/index.cjs +252 -96
  363. package/plugins/filesystem/README.md +65 -0
  364. package/plugins/filesystem/plugin.json +6 -2
  365. package/plugins/filesystem/source/atomic-write.ts +2 -0
  366. package/plugins/filesystem/source/bounded-io.ts +80 -306
  367. package/plugins/filesystem/source/directory-sample.ts +2 -0
  368. package/plugins/filesystem/source/errors.ts +14 -0
  369. package/plugins/filesystem/source/file-observation.ts +151 -0
  370. package/plugins/filesystem/source/file-version.ts +41 -0
  371. package/plugins/filesystem/source/index.ts +6 -0
  372. package/plugins/filesystem/source/mutation-coordinator.ts +1 -0
  373. package/plugins/filesystem/source/windows/authority-script.ts +1 -0
  374. package/plugins/filesystem/source/windows/native-script.ts +1 -0
  375. package/plugins/filesystem/source/windows/operations.ts +197 -0
  376. package/plugins/filesystem/source/windows/process.ts +214 -0
  377. package/plugins/filesystem/source/windows/publication-script.ts +29 -0
  378. package/plugins/filesystem/source/windows/read-script.ts +63 -0
  379. package/plugins/filesystem/source/windows/request-availability.ts +67 -0
  380. package/plugins/filesystem/source/windows/source.ts +42 -0
  381. package/plugins/filesystem/source/windows/storage-script.ts +11 -0
  382. package/plugins/filesystem/source/windows/streams-script.ts +24 -0
  383. package/plugins/filesystem/source/windows/write-script.ts +86 -0
  384. package/plugins/filesystem/src/index.cjs +1208 -322
  385. package/plugins/json-inspector/README.md +18 -0
  386. package/plugins/json-inspector/plugin.json +1 -0
  387. package/plugins/json-inspector/source/index.ts +16 -19
  388. package/plugins/json-inspector/source/read-failure.ts +42 -0
  389. package/plugins/json-inspector/src/index.cjs +612 -27
  390. package/plugins/local-search/README.md +29 -0
  391. package/plugins/local-search/plugin.json +1 -0
  392. package/plugins/local-search/source/errors.ts +2 -0
  393. package/plugins/local-search/source/paths.ts +3 -0
  394. package/plugins/local-search/source/ripgrep-process.ts +31 -5
  395. package/plugins/local-search/source/ripgrep.ts +3 -3
  396. package/plugins/local-search/source/windows-authority.ts +99 -0
  397. package/plugins/local-search/source/windows-search-lease.ts +49 -0
  398. package/plugins/local-search/source/windows-search-process.ts +91 -0
  399. package/plugins/local-search/source/windows-search-script.ts +52 -0
  400. package/plugins/local-search/src/index.cjs +595 -26
  401. package/plugins/memory/plugin.json +4 -0
  402. package/plugins/memory/source/lock-directory-claim.ts +56 -0
  403. package/plugins/memory/source/lock-owner-file.ts +71 -0
  404. package/plugins/memory/source/lock-path-observation.ts +26 -0
  405. package/plugins/memory/source/prepared-memory-replacement.ts +40 -0
  406. package/plugins/memory/source/store-lock.ts +12 -7
  407. package/plugins/memory/source/store.ts +3 -2
  408. package/plugins/memory/src/index.cjs +174 -25
  409. package/plugins/project-orientation/README.md +23 -0
  410. package/plugins/project-orientation/plugin.json +1 -0
  411. package/plugins/project-orientation/source/index.ts +12 -9
  412. package/plugins/project-orientation/source/inspection-failure.ts +70 -0
  413. package/plugins/project-orientation/source/manifest-summary.ts +9 -2
  414. package/plugins/project-orientation/source/tree.ts +6 -0
  415. package/plugins/project-orientation/src/index.cjs +647 -31
  416. package/plugins/system/README.md +51 -15
  417. package/plugins/system/plugin.json +5 -1
  418. package/plugins/system/skills/system_actions/SKILL.md +1 -1
  419. package/plugins/system/source/command-working-directory.ts +47 -0
  420. package/plugins/system/source/computer/handlers.ts +13 -9
  421. package/plugins/system/source/computer/observation-result.ts +10 -5
  422. package/plugins/system/source/computer/request-computers.ts +10 -3
  423. package/plugins/system/source/computer/request-modules.ts +3 -6
  424. package/plugins/system/source/computer/runtime-platform.ts +18 -0
  425. package/plugins/system/source/host-dispatch.ts +18 -2
  426. package/plugins/system/source/index.ts +5 -3
  427. package/plugins/system/source/local-command-output-retention.ts +16 -0
  428. package/plugins/system/source/local-command-output.ts +16 -8
  429. package/plugins/system/source/request-system-modules.ts +12 -2
  430. package/plugins/system/source/request-target-snapshot.ts +2 -1
  431. package/plugins/system/source/security/desktop-result.ts +177 -0
  432. package/plugins/system/source/security/observed-error.ts +10 -0
  433. package/plugins/system/source/security/secret-text.ts +118 -0
  434. package/plugins/system/source/security/system-results.ts +62 -0
  435. package/plugins/system/source/security/windows-output-directory.ts +82 -0
  436. package/plugins/system/src/index.cjs +837 -151
  437. package/plugins/system-probe/plugin.json +8 -2
  438. package/plugins/system-probe/source/disk-path.ts +8 -0
  439. package/plugins/system-probe/source/index.ts +10 -5
  440. package/plugins/system-probe/source/machine-load.ts +33 -0
  441. package/plugins/system-probe/source/metrics.ts +6 -8
  442. package/plugins/system-probe/src/index.cjs +49 -16
  443. package/plugins/web/plugin.json +4 -0
@@ -1,286 +1,220 @@
1
+ import { ComposerSubmissionRefused, isDefiniteSubmissionRefusal } from "./composer-submission-lifecycle.js";
2
+
3
+ const scopeKey = (scope) => JSON.stringify([scope.environmentId, scope.sessionId]);
4
+
5
+ function hasConversationQueueScope(scope) {
6
+ if (!scope.environmentId) return false;
7
+ return Boolean(scope.sessionId);
8
+ }
9
+
10
+ /** Sole owner of queue ordering. Drafts and submissions own their respective payloads. */
1
11
  export function createComposerQueueController({
2
- state,
3
- dom,
4
- queue,
5
- selectedEnvironmentId,
6
- getToolPermissionMode,
7
- getModelPreference,
8
- rememberModelSelection,
9
- attachments,
10
- updateSendState,
11
- postChatMessage,
12
- appendLocalUserMessage,
13
- activateRequestForScope,
14
- renderMessages,
15
- setMessageStatus,
16
- recordControlEvent,
17
- resizeComposer,
12
+ queue, drafts, lifecycle, getDraft, requests, getSettings,
13
+ isCurrentScope, reportFailure, reportRecovery = () => {}, onChange = () => {},
14
+ confirmTakeover = (message) => globalThis.confirm?.(message) === true,
18
15
  }) {
19
- const scopeKey = (scope) =>
20
- JSON.stringify([scope.environmentId, scope.sessionId]);
21
- const currentScope = () => ({
22
- environmentId: selectedEnvironmentId(),
23
- sessionId: state.currentSessionId,
24
- });
25
- const isCurrentScope = (scope) =>
26
- selectedEnvironmentId() === scope.environmentId &&
27
- state.currentSessionId === scope.sessionId;
28
- const isCurrentDraining = () =>
29
- state.composerQueueDrainingScopes.has(scopeKey(currentScope()));
30
- const queuedCount = () => {
31
- const scope = currentScope();
32
- if (!scope.environmentId || !scope.sessionId) return 0;
33
- return queue.list(scope).length;
34
- };
16
+ const processing = new Map();
17
+ const bindings = new Map();
18
+ const terminals = new Map();
35
19
 
36
- async function enqueue(text) {
37
- const scope = currentScope();
38
- const waitForRequestId = state.activeRequestId;
39
- if (!scope.sessionId || !waitForRequestId) {
40
- throw new Error("Send next requires an active request.");
41
- }
42
- const queuedAttachments = [...state.pendingAttachments];
43
- rememberModelSelection();
44
- queue.enqueue(scope, {
45
- waitForRequestId,
46
- text,
47
- attachments: queuedAttachments,
48
- agentMode: state.agentMode,
49
- toolPermissionMode: getToolPermissionMode(),
50
- modelPreference: getModelPreference(),
51
- });
52
- attachments.invalidateCompletions();
53
- state.pendingAttachments = [];
54
- attachments.render();
20
+ function queuedCount() {
21
+ const scope = getDraft().scope;
22
+ if (!hasConversationQueueScope(scope)) return 0;
23
+ return queue.list(scope).length;
55
24
  }
25
+ function isCurrentDraining() { return processing.has(scopeKey(getDraft().scope)); }
56
26
 
57
- function reportFailure(scope, summary, tone = "failed") {
58
- if (!isCurrentScope(scope)) return;
59
- state.messages.push({
60
- id: `queue-error-${Date.now()}`,
61
- role: "assistant",
62
- text: summary,
63
- createdAt: Date.now(),
64
- requestId: "",
65
- streaming: false,
66
- });
67
- renderMessages();
68
- setMessageStatus("Send next queue is paused.");
69
- recordControlEvent({
70
- type: "control",
71
- name: "Send next queue paused",
72
- tone,
73
- summary,
74
- });
27
+ function queueItem(payload, settings, requestId) {
28
+ return { text: payload.text, attachments: [...payload.attachments], ...settings, waitForRequestId: requestId };
75
29
  }
76
30
 
77
- function restoreText(text, scope) {
78
- if (!isCurrentScope(scope)) return;
79
- const current = dom.composerInput.value.trim();
80
- dom.composerInput.value = current ? `${text}\n${current}` : text;
81
- resizeComposer();
31
+ async function prepareManualSend(attempt) {
32
+ const { payload, settings } = attempt;
33
+ if (!payload.release) return;
34
+ const { scope, release } = payload;
35
+ const item = queueItem(payload, settings, release.item.waitForRequestId);
36
+ const updated = await queue.updateBlockedRelease(scope, release.releaseToken, item);
37
+ if (!updated) throw new ComposerSubmissionRefused("This queued message changed in another window. Reload before sending it.");
38
+ const begun = await queue.beginBlockedSend(scope, release.releaseToken);
39
+ if (!begun) throw new ComposerSubmissionRefused("This window no longer owns the queued message. Reload before sending it.");
82
40
  }
83
41
 
84
- function restoreItem(item, scope) {
85
- if (!isCurrentScope(scope)) return false;
86
- restoreText(item.text, scope);
87
- state.pendingAttachments = [
88
- ...item.attachments,
89
- ...state.pendingAttachments,
90
- ];
91
- attachments.render();
92
- return true;
42
+ async function send(attempt) {
43
+ try { return await requests.send(attempt); }
44
+ catch (error) {
45
+ if (attempt.payload.release && !isDefiniteSubmissionRefusal(error)) {
46
+ try { await queue.markBlockedUncertain(attempt.payload.scope, attempt.payload.release.releaseToken); }
47
+ catch (markError) { reportFailure(attempt.payload.scope, `The queued message remains paused: ${markError.message}`); }
48
+ }
49
+ throw error;
50
+ }
93
51
  }
94
52
 
95
- function clearRecovery(scope) {
96
- const active = state.activeComposerQueueRecovery;
97
- if (!active || scopeKey(active.scope) !== scopeKey(scope)) return;
98
- state.composerQueueRecoveredReleaseTokens.delete(active.releaseToken);
99
- state.activeComposerQueueRecovery = null;
53
+ async function prepareRestore(attempt) {
54
+ const { payload } = attempt;
55
+ // Only a confirmed request rejection can return a sending lease to editing.
56
+ // A failed preparation has not submitted anything and retains its existing lease.
57
+ if (!payload.release || attempt.phase !== "sending") return payload;
58
+ const claimed = await queue.claimBlockedRelease(payload.scope, payload.release.releaseToken, { takeover: true });
59
+ if (!claimed) throw new Error("The rejected message remains paused because its queue ownership changed.");
60
+ return { ...payload, release: claimed };
100
61
  }
101
62
 
102
- async function drain({ environmentId, sessionId, terminalRequestId, cancelled = false }) {
103
- const scope = { environmentId, sessionId };
63
+ async function bindAccepted(attempt, requestId) {
64
+ const { scope, release } = attempt.payload;
65
+ if (!release) { requests.activate(attempt, requestId); return; }
104
66
  const key = scopeKey(scope);
105
- if (state.composerQueueDrainingScopes.has(key)) return;
106
- state.composerQueueDrainingScopes.add(key);
107
- if (isCurrentScope(scope)) updateSendState();
108
- let released;
109
- try {
110
- released = queue.releaseForTerminal(scope, terminalRequestId);
111
- } catch (error) {
112
- reportFailure(
113
- scope,
114
- `The queued message was not released: ${
115
- error instanceof Error ? error.message : String(error)
116
- }`,
117
- );
118
- state.composerQueueDrainingScopes.delete(key);
119
- if (isCurrentScope(scope)) updateSendState();
120
- return;
121
- }
122
- if (!released) {
123
- state.composerQueueDrainingScopes.delete(key);
124
- if (isCurrentScope(scope)) updateSendState();
125
- return;
126
- }
127
- if (cancelled) {
128
- state.composerQueueDrainingScopes.delete(key);
129
- recoverForManualSend(scope, "Response stopped. The next queued message is back in the composer; send it when you are ready to continue.", "neutral");
130
- if (isCurrentScope(scope)) updateSendState();
131
- return;
132
- }
133
- updateSendState();
134
- const { item, releaseToken } = released;
135
- let requestId;
136
- try {
137
- requestId = await postChatMessage({
138
- text: item.text,
139
- attachments: item.attachments,
140
- environmentId,
141
- sessionId,
142
- agentMode: item.agentMode,
143
- toolPermissionMode: item.toolPermissionMode,
144
- modelPreference: item.modelPreference,
145
- });
146
- } catch (error) {
147
- const restored = restoreItem(item, scope);
148
- if (restored) {
149
- state.composerQueueRecoveredReleaseTokens.add(releaseToken);
150
- state.activeComposerQueueRecovery = {
151
- scope: { ...scope },
152
- releaseToken,
153
- };
154
- }
155
- reportFailure(
156
- scope,
157
- `The queued message could not be confirmed and will not be retried automatically: ${
158
- error instanceof Error ? error.message : String(error)
159
- }.${restored ? " It was restored to the composer for a manual send." : ""}`,
160
- );
161
- state.composerQueueDrainingScopes.delete(key);
162
- if (isCurrentScope(scope)) updateSendState();
163
- return;
67
+ const binding = Promise.resolve().then(async () => {
68
+ const bound = await queue.bindReleasedSuccess(scope, release.releaseToken, requestId);
69
+ if (!bound) throw new Error("The remaining queue could not be bound to the accepted request.");
70
+ return true;
71
+ }).catch((error) => {
72
+ reportFailure(scope, `The request started, but the remaining Send next queue is paused: ${error.message}`);
73
+ return false;
74
+ });
75
+ bindings.set(key, binding);
76
+ onChange();
77
+ requests.activate(attempt, requestId);
78
+ try { await binding; }
79
+ finally {
80
+ if (bindings.get(key) === binding) bindings.delete(key);
81
+ onChange();
164
82
  }
165
- let queueBound = false;
166
- try {
167
- queueBound = queue.bindReleasedSuccess(scope, releaseToken, requestId);
168
- } catch (error) {
169
- queueBound = null;
170
- reportFailure(
171
- scope,
172
- `The queued message started, but the remaining queue is paused: ${
173
- error instanceof Error ? error.message : String(error)
174
- }`,
175
- );
83
+ }
84
+
85
+ async function enqueue(attempt, waitForRequestId) {
86
+ if (!waitForRequestId) throw new ComposerSubmissionRefused("Send next requires an active request.");
87
+ try { return await queue.enqueue(attempt.payload.scope, queueItem(attempt.payload, attempt.settings, waitForRequestId)); }
88
+ catch (error) {
89
+ if (error?.workspaceMutationMayHaveCommitted !== true)
90
+ throw new ComposerSubmissionRefused(error.message, { cause: error });
91
+ throw error;
176
92
  }
177
- if (queueBound === false) {
178
- reportFailure(
179
- scope,
180
- "The queued message started, but the remaining queue could not be rebound and is paused.",
181
- );
93
+ }
94
+
95
+ function hasManualRecovery(scope) {
96
+ if (!hasConversationQueueScope(scope)) return false;
97
+ if (bindings.has(scopeKey(scope))) return false;
98
+ if (lifecycle.hasPendingScope(scope)) return false;
99
+ const release = queue.getBlockedRelease(scope);
100
+ if (!release) return false;
101
+ if (drafts.open(scope).release?.releaseToken === release.releaseToken) return false;
102
+ return !lifecycle.paused(scope).some((attempt) => attempt.payload.release?.releaseToken === release.releaseToken);
103
+ }
104
+
105
+ async function recoverForManualSend(scope) {
106
+ const draft = drafts.open(scope);
107
+ const release = queue.getBlockedRelease(scope);
108
+ if (!release || draft.release?.releaseToken === release.releaseToken) return false;
109
+ if (!draft.isEmpty()) {
110
+ reportFailure(scope, "Send next is paused. Finish or clear your current draft before reviewing the queued message.");
111
+ return false;
182
112
  }
183
- if (isCurrentScope(scope)) {
184
- appendLocalUserMessage({
185
- text: item.text,
186
- attachments: item.attachments,
187
- requestId,
188
- });
113
+ let claimed = await queue.claimBlockedRelease(scope, release.releaseToken);
114
+ if (!claimed) {
115
+ const approved = confirmTakeover("This queued message may have been sent or may belong to another window. Close that window and check the conversation before taking ownership for manual review. Sending it again may repeat its actions. Continue?");
116
+ if (!approved) return false;
117
+ claimed = await queue.claimBlockedRelease(scope, release.releaseToken, { takeover: true });
189
118
  }
190
- state.composerQueueDrainingScopes.delete(key);
191
- activateRequestForScope(scope, requestId);
119
+ if (!claimed) throw new Error("This queued message changed before it could be recovered.");
120
+ // Ownership can be acknowledged after navigation. Restore only to its own draft,
121
+ // and never merge a second recovery over input typed during that acknowledgement.
122
+ if (!draft.isEmpty()) return false;
123
+ draft.restore({ scope, text: claimed.item.text, attachments: claimed.item.attachments, release: claimed });
124
+ onChange();
125
+ reportRecovery(scope, "Send next is paused. Review the recovered message and send it manually when ready.");
126
+ return true;
192
127
  }
193
128
 
194
129
  function prepareRecoveryForNavigation() {
195
- const active = state.activeComposerQueueRecovery;
196
- if (!active) return () => {};
130
+ const draft = getDraft();
131
+ if (!draft.release) return () => {};
132
+ return persistRecoveryDraft(draft);
133
+ }
134
+
135
+ async function persistRecoveryDraft(draft) {
136
+ const snapshot = draft.snapshot();
137
+ const revision = draft.revision;
197
138
  try {
198
- const blockedRelease = queue.getBlockedRelease(active.scope);
199
- const hasMatchingRecoveryRelease = blockedRelease?.releaseToken === active.releaseToken;
200
- if (!hasMatchingRecoveryRelease) {
201
- return () => clearRecovery(active.scope);
202
- }
203
- const updated = queue.updateBlockedRelease(
204
- active.scope,
205
- active.releaseToken,
206
- {
207
- ...blockedRelease.item,
208
- text: dom.composerInput.value,
209
- attachments: [...state.pendingAttachments],
210
- },
211
- );
212
- if (!updated)
213
- throw new Error("blocked release changed before it was saved");
139
+ const updated = await queue.updateBlockedRelease(snapshot.scope, snapshot.release.releaseToken,
140
+ queueItem(snapshot, getSettings(), snapshot.release.item.waitForRequestId));
141
+ if (!updated) throw new Error("The queued message changed in another window.");
142
+ const commit = () => {};
143
+ commit.canCommit = () => draft.revision === revision;
144
+ return commit;
214
145
  } catch (error) {
215
- reportFailure(
216
- active.scope,
217
- `The recovered Send next draft could not be saved before navigation: ${
218
- error instanceof Error ? error.message : String(error)
219
- }`,
220
- );
146
+ reportFailure(snapshot.scope, `The recovered draft could not be saved: ${error.message}`);
221
147
  return false;
222
148
  }
223
- return () => {
224
- dom.composerInput.value = "";
225
- resizeComposer();
226
- attachments.clear({ cleanup: false });
227
- clearRecovery(active.scope);
149
+ }
150
+
151
+ function suspendRecoveryForNavigation(canNavigate = () => true) {
152
+ const prepared = prepareRecoveryForNavigation();
153
+ const commit = (action) => {
154
+ if (!action || !canNavigate() || action.canCommit?.() === false) return false;
155
+ action();
156
+ return true;
228
157
  };
158
+ return typeof prepared?.then === "function" ? prepared.then(commit) : commit(prepared);
229
159
  }
230
160
 
231
- function suspendRecoveryForNavigation() {
232
- const commit = prepareRecoveryForNavigation();
233
- if (!commit) return false;
234
- commit();
235
- return true;
161
+ async function processTerminal(input) {
162
+ const scope = { environmentId: input.environmentId, sessionId: input.sessionId };
163
+ const binding = bindings.get(scopeKey(scope));
164
+ if (binding && await binding !== true) return;
165
+ const released = await queue.releaseForTerminal(scope, input.terminalRequestId);
166
+ if (!released) return;
167
+ if (input.cancelled) { await recoverForManualSend(scope); return; }
168
+ const item = released.item;
169
+ const attempt = await lifecycle.submitCaptured({
170
+ action: "send", payload: { scope, text: item.text, attachments: item.attachments, release: released },
171
+ settings: { agentMode: item.agentMode, toolPermissionMode: item.toolPermissionMode, modelPreference: item.modelPreference },
172
+ prepare: async (submission) => { await prepareManualSend(submission); requests.prepareView(submission); },
173
+ execute: send, accepted: bindAccepted, prepareRestore,
174
+ });
175
+ if (attempt.status !== "accepted")
176
+ reportFailure(scope, "The queued message could not be confirmed. It is paused and will not be retried automatically.");
236
177
  }
237
178
 
238
- function recoverForManualSend(scope, message = "Send next is paused. The queued message was restored to the composer for review and will not be sent automatically.", tone = "neutral") {
239
- let blockedRelease;
240
- try {
241
- blockedRelease = queue.getBlockedRelease(scope);
242
- } catch (error) {
243
- reportFailure(
244
- scope,
245
- `The paused Send next message could not be recovered: ${
246
- error instanceof Error ? error.message : String(error)
247
- }`,
248
- );
249
- return false;
250
- }
251
- if (
252
- !blockedRelease ||
253
- state.composerQueueRecoveredReleaseTokens.has(blockedRelease.releaseToken)
254
- ) {
255
- return false;
256
- }
257
- if (!restoreItem(blockedRelease.item, scope)) return false;
258
- state.composerQueueRecoveredReleaseTokens.add(blockedRelease.releaseToken);
259
- state.activeComposerQueueRecovery = {
260
- scope: { ...scope },
261
- releaseToken: blockedRelease.releaseToken,
262
- };
263
- reportFailure(
264
- scope,
265
- message,
266
- tone,
267
- );
268
- return true;
179
+ function drain(input) {
180
+ const key = scopeKey(input);
181
+ let pending = terminals.get(key);
182
+ if (!pending) { pending = new Map(); terminals.set(key, pending); }
183
+ pending.set(input.terminalRequestId, input);
184
+ if (processing.has(key)) return processing.get(key);
185
+ const operation = Promise.resolve().then(async () => {
186
+ while (pending.size) {
187
+ const [requestId, terminal] = pending.entries().next().value;
188
+ pending.delete(requestId);
189
+ try { await processTerminal(terminal); }
190
+ catch (error) { reportFailure(input, `Send next remains paused: ${error.message}`); }
191
+ }
192
+ }).finally(() => {
193
+ processing.delete(key);
194
+ terminals.delete(key);
195
+ onChange();
196
+ });
197
+ processing.set(key, operation);
198
+ onChange();
199
+ return operation;
269
200
  }
270
201
 
271
202
  return {
272
- clearRecovery,
273
- currentScope,
274
- drain,
275
- enqueue,
276
- isCurrentDraining,
277
- isCurrentScope,
278
- prepareRecoveryForNavigation,
279
- queuedCount,
280
- recoverForManualSend,
281
- reportFailure,
282
- restoreText,
283
- scopeKey,
284
- suspendRecoveryForNavigation,
203
+ queuedCount, isCurrentDraining, enqueue, prepareManualSend, send, bindAccepted, drain, prepareRestore,
204
+ recoverForManualSend, hasManualRecovery, prepareRecoveryForNavigation, suspendRecoveryForNavigation,
205
+ isCurrentScope, scopeKey, currentScope: () => getDraft().scope, reportFailure,
206
+ async authorizeReview(attempt) {
207
+ if (!attempt.payload.release) return true;
208
+ const { scope, release } = attempt.payload;
209
+ const claimed = await queue.claimBlockedRelease(scope, release.releaseToken, { takeover: true });
210
+ return claimed ? { release: claimed } : false;
211
+ },
212
+ ownsAttachment(attachment) {
213
+ const scope = { environmentId: attachment.environment, sessionId: attachment.sessionId };
214
+ if (!scope.environmentId || !scope.sessionId) return false;
215
+ const release = queue.getBlockedRelease(scope);
216
+ const items = [...queue.list(scope), ...(release ? [release.item] : [])];
217
+ return items.some((item) => item.attachments.some((file) => file.id === attachment.id && file.storageRef === attachment.storageRef));
218
+ },
285
219
  };
286
220
  }
@@ -0,0 +1,48 @@
1
+ import type { SessionComposerQueueItem, ReleasedSessionComposerQueueItem } from "../lib/session-composer-queue.js";
2
+ import type { ComposerAttachment, ComposerDraft, ComposerDraftSnapshot, ComposerDrafts, ComposerScope } from "./composer-drafts.js";
3
+
4
+ export type ComposerSubmissionAction = "send" | "send_next" | "steer";
5
+ export type ComposerSubmissionSettings = Pick<SessionComposerQueueItem, "agentMode" | "toolPermissionMode" | "modelPreference">;
6
+ export type ComposerSubmissionPhase = "preparing" | "sending" | "accepted" | "refused" | "uncertain" | "restored";
7
+
8
+ export interface ComposerSubmissionAttempt<Settings = unknown, Result = unknown> {
9
+ readonly id: number;
10
+ readonly action: ComposerSubmissionAction;
11
+ readonly settings: Settings;
12
+ readonly payload: ComposerDraftSnapshot;
13
+ phase: ComposerSubmissionPhase;
14
+ error: unknown;
15
+ result?: Result;
16
+ }
17
+
18
+ export type ComposerSubmissionResult<Settings = unknown, Result = unknown> =
19
+ | { status: "accepted"; attempt: ComposerSubmissionAttempt<Settings, Result>; result: Result; bookkeepingError?: unknown }
20
+ | { status: "refused" | "uncertain"; attempt: ComposerSubmissionAttempt<Settings, Result>; error: unknown };
21
+
22
+ export type ComposerReviewAuthorization = boolean | { release: ReleasedSessionComposerQueueItem };
23
+ export interface ComposerSubmissionOptions<Settings = unknown, Result = unknown> {
24
+ action: ComposerSubmissionAction;
25
+ settings?: Settings;
26
+ prepare?(attempt: ComposerSubmissionAttempt<Settings, Result>): void | Promise<void>;
27
+ execute(attempt: ComposerSubmissionAttempt<Settings, Result>): Result | Promise<Result>;
28
+ accepted?(attempt: ComposerSubmissionAttempt<Settings, Result>, result: Result): void | Promise<void>;
29
+ prepareRestore?(attempt: ComposerSubmissionAttempt<Settings, Result>): ComposerDraftSnapshot | Promise<ComposerDraftSnapshot>;
30
+ }
31
+
32
+ export interface ComposerSubmissionLifecycle {
33
+ submit<Settings = unknown, Result = unknown>(options: ComposerSubmissionOptions<Settings, Result> & { draft: ComposerDraft }): Promise<ComposerSubmissionResult<Settings, Result>>;
34
+ submitCaptured<Settings = unknown, Result = unknown>(options: ComposerSubmissionOptions<Settings, Result> & { payload: ComposerDraftSnapshot }): Promise<ComposerSubmissionResult<Settings, Result>>;
35
+ hasPendingScope(scope: ComposerScope): boolean;
36
+ restoreForManualReview(id: number, authorize: (attempt: ComposerSubmissionAttempt) => ComposerReviewAuthorization | Promise<ComposerReviewAuthorization>): Promise<boolean>;
37
+ paused(scope: ComposerScope): ComposerSubmissionAttempt[];
38
+ ownsAttachment(attachment: ComposerAttachment): boolean;
39
+ }
40
+
41
+ export declare class ComposerSubmissionRefused extends Error {
42
+ constructor(message: string, options?: ErrorOptions);
43
+ }
44
+ export declare function isDefiniteSubmissionRefusal(error: unknown): error is ComposerSubmissionRefused;
45
+ export declare function createComposerSubmissionLifecycle(options: {
46
+ drafts: ComposerDrafts;
47
+ onChange?(attempt: ComposerSubmissionAttempt): void;
48
+ }): ComposerSubmissionLifecycle;
@@ -0,0 +1,97 @@
1
+ function scopeKey(scope) {
2
+ return JSON.stringify([scope.environmentId, scope.sessionId]);
3
+ }
4
+
5
+ /** Explicit refusal is distinct from a missing acknowledgement after an effect. */
6
+ export class ComposerSubmissionRefused extends Error {
7
+ constructor(message, options) {
8
+ super(message, options);
9
+ this.name = "ComposerSubmissionRefused";
10
+ }
11
+ }
12
+
13
+ export function isDefiniteSubmissionRefusal(error) {
14
+ return error instanceof ComposerSubmissionRefused;
15
+ }
16
+
17
+ /** Owns captured payloads from take() until acceptance, restoration or manual review. */
18
+ export function createComposerSubmissionLifecycle({ drafts, onChange = () => {} }) {
19
+ const attempts = new Map();
20
+ let sequence = 0;
21
+
22
+ function hasPendingScope(scope) {
23
+ const key = scopeKey(scope);
24
+ return [...attempts.values()].some((attempt) =>
25
+ scopeKey(attempt.payload.scope) === key && ["preparing", "sending"].includes(attempt.phase));
26
+ }
27
+
28
+ function publish(attempt, phase) {
29
+ attempt.phase = phase;
30
+ onChange(attempt);
31
+ }
32
+
33
+ async function submitCaptured({ payload, action, settings, prepare = async () => {}, execute, accepted = async () => {}, prepareRestore = async (attempt) => attempt.payload }) {
34
+ const attempt = { id: ++sequence, action, settings, payload, phase: "preparing", error: null };
35
+ attempts.set(attempt.id, attempt);
36
+ publish(attempt, "preparing");
37
+ let result;
38
+ try {
39
+ await prepare(attempt);
40
+ publish(attempt, "sending");
41
+ result = await execute(attempt);
42
+ } catch (error) {
43
+ attempt.error = error;
44
+ if (canRestoreRejectedSubmission(attempt, error)) {
45
+ try {
46
+ const restored = await prepareRestore(attempt);
47
+ drafts.restore(restored);
48
+ attempts.delete(attempt.id);
49
+ publish(attempt, "refused");
50
+ return { status: "refused", attempt, error };
51
+ } catch (restoreError) { attempt.error = restoreError; }
52
+ }
53
+ publish(attempt, "uncertain");
54
+ return { status: "uncertain", attempt, error };
55
+ }
56
+ attempt.result = result;
57
+ attempts.delete(attempt.id);
58
+ publish(attempt, "accepted");
59
+ // Acceptance cannot turn into a rejected send because post-send bookkeeping fails.
60
+ try { await accepted(attempt, result); }
61
+ catch (error) { return { status: "accepted", attempt, result, bookkeepingError: error }; }
62
+ return { status: "accepted", attempt, result };
63
+ }
64
+
65
+ async function restoreForManualReview(id, authorize) {
66
+ const attempt = attempts.get(id);
67
+ if (!attempt || attempt.phase !== "uncertain") return false;
68
+ const approval = await authorize(attempt);
69
+ if (approval !== true && !approval?.release) return false;
70
+ if (attempts.get(id) !== attempt || attempt.phase !== "uncertain") return false;
71
+ drafts.restore(approval?.release ? { ...attempt.payload, release: approval.release } : attempt.payload);
72
+ attempts.delete(id);
73
+ publish(attempt, "restored");
74
+ return true;
75
+ }
76
+
77
+ return {
78
+ submit(options) {
79
+ if (hasPendingScope(options.draft.scope))
80
+ return Promise.reject(new ComposerSubmissionRefused("A message is already being submitted for this conversation."));
81
+ return submitCaptured({ ...options, payload: options.draft.take() });
82
+ },
83
+ submitCaptured,
84
+ hasPendingScope,
85
+ restoreForManualReview,
86
+ paused: (scope) => [...attempts.values()].filter((attempt) =>
87
+ attempt.phase === "uncertain" && scopeKey(attempt.payload.scope) === scopeKey(scope)),
88
+ ownsAttachment: (attachment) => [...attempts.values()].some((attempt) =>
89
+ attempt.payload.attachments.some((file) => file.id === attachment.id && file.storageRef === attachment.storageRef)),
90
+ };
91
+ }
92
+
93
+ function canRestoreRejectedSubmission(attempt, error) {
94
+ if (error?.workspaceMutationMayHaveCommitted === true) return false;
95
+ if (isDefiniteSubmissionRefusal(error)) return true;
96
+ return attempt.phase === "preparing";
97
+ }