@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
@@ -2809,20 +2809,20 @@ function createNativeHostState(directory, access5) {
2809
2809
  let connectionPath = join(directory, "connection.json"), statusPath = join(directory, "status.json");
2810
2810
  async function inspectPrivate(path) {
2811
2811
  await access5.ensureDirectory(directory);
2812
- let stat4 = await lstat(path).catch((error) => {
2812
+ let stat3 = await lstat(path).catch((error) => {
2813
2813
  if (!isAbsentFile(error))
2814
2814
  throw error;
2815
2815
  });
2816
- if (stat4) {
2817
- if (!stat4.isFile() || stat4.isSymbolicLink())
2816
+ if (stat3) {
2817
+ if (!stat3.isFile() || stat3.isSymbolicLink())
2818
2818
  throw new Error("Host companion state must be a private regular file.");
2819
- return await access5.assertFile(path, stat4), stat4;
2819
+ return await access5.assertFile(path, stat3), stat3;
2820
2820
  }
2821
2821
  }
2822
2822
  async function readPrivate(path) {
2823
- let stat4 = await inspectPrivate(path);
2824
- if (stat4) {
2825
- if (stat4.size > 16384)
2823
+ let stat3 = await inspectPrivate(path);
2824
+ if (stat3) {
2825
+ if (stat3.size > 16384)
2826
2826
  throw new Error("Host companion state exceeds its size limit.");
2827
2827
  return JSON.parse(await readFile(path, "utf8"));
2828
2828
  }
@@ -4073,14 +4073,58 @@ function identityExcerpt(identity) {
4073
4073
  }
4074
4074
 
4075
4075
  // src/computer-access/handlers.ts
4076
- function withSystemOperationErrors(operation) {
4076
+ var PROTECTION_FAILURE = "The system result could not be protected for delivery.";
4077
+ function protectSystemResult(operation) {
4078
+ try {
4079
+ return operation();
4080
+ } catch {
4081
+ throw new SystemOperationError("system_result_protection_failed", PROTECTION_FAILURE);
4082
+ }
4083
+ }
4084
+ function failedSystemProtectionReceipt(target, result, evidenceScope) {
4085
+ let safeProcess = {
4086
+ status: result.status,
4087
+ exitCode: result.exitCode,
4088
+ outputTruncated: result.outputTruncated,
4089
+ stdout: "[UNAVAILABLE: result protection failed]",
4090
+ stderr: "[UNAVAILABLE: result protection failed]",
4091
+ ...result.spawnedProcess ? {
4092
+ spawnedProcess: {
4093
+ pid: result.spawnedProcess.pid,
4094
+ pidNamespace: result.spawnedProcess.pidNamespace,
4095
+ identitySource: result.spawnedProcess.identitySource,
4096
+ executable: "[REDACTED]"
4097
+ }
4098
+ } : {}
4099
+ }, receipt = systemProcessResult(target, safeProcess, evidenceScope);
4100
+ return failureResult({
4101
+ errorCode: "system_result_protection_failed",
4102
+ message: PROTECTION_FAILURE,
4103
+ output: `The operation was dispatched. Inspect the process receipt before another action; the command was not replayed.
4104
+ ` + receipt.output,
4105
+ stdout: safeProcess.stdout,
4106
+ stderr: safeProcess.stderr,
4107
+ ...result.exitCode !== null ? { exitCode: result.exitCode } : {},
4108
+ data: receipt.data
4109
+ });
4110
+ }
4111
+ function withSystemOperationErrors(operation, protection) {
4077
4112
  return async (params, context) => {
4078
4113
  try {
4079
4114
  return await operation(params, context);
4080
4115
  } catch (error) {
4116
+ let message = error instanceof Error ? error.message : void 0;
4117
+ try {
4118
+ protection && message !== void 0 && (message = protection.protectMessage(message));
4119
+ } catch {
4120
+ return failureResult({
4121
+ errorCode: "system_result_protection_failed",
4122
+ message: PROTECTION_FAILURE
4123
+ });
4124
+ }
4081
4125
  return error instanceof SystemOperationError ? failureResult({
4082
4126
  errorCode: error.code,
4083
- message: error.message,
4127
+ message,
4084
4128
  data: {
4085
4129
  humanActionRequired: error.code === "system_authorization_required"
4086
4130
  }
@@ -4092,9 +4136,9 @@ function withSystemOperationErrors(operation) {
4092
4136
  }
4093
4137
  };
4094
4138
  }
4095
- function createSystemHandlers(run2 = runSystemProcess, resolveTarget = (id) => resolveSystemTarget(id, run2), commandOutput) {
4139
+ function createSystemHandlers(run2 = runSystemProcess, resolveTarget = (id) => resolveSystemTarget(id, run2), commandOutput, protection) {
4096
4140
  let targets = async () => {
4097
- let observation = await observeSystemTargets(run2);
4141
+ let observed = await observeSystemTargets(run2), observation = protection ? protectSystemResult(() => protection.protectTargets(observed)) : observed;
4098
4142
  return successResult({
4099
4143
  output: JSON.stringify(observation),
4100
4144
  data: {
@@ -4103,20 +4147,25 @@ function createSystemHandlers(run2 = runSystemProcess, resolveTarget = (id) => r
4103
4147
  }
4104
4148
  });
4105
4149
  }, command = async (params, context) => {
4106
- let target = await resolveTarget(readSystemTargetId(params.target)), output = commandOutput?.(context), result = await executeSystemCommand({
4150
+ let target = await resolveTarget(readSystemTargetId(params.target)), output = commandOutput?.(context), observed = await executeSystemCommand({
4107
4151
  target,
4108
4152
  params,
4109
4153
  run: run2,
4110
4154
  ...output ? { runCommand: output.run } : {},
4111
4155
  ...context?.abortSignal ? { abortSignal: context.abortSignal } : {}
4112
- });
4156
+ }), result = observed;
4157
+ try {
4158
+ protection && (result = protection.protectProcess(observed));
4159
+ } catch {
4160
+ return failedSystemProtectionReceipt(target, observed, "command_process_completion");
4161
+ }
4113
4162
  return output ? output.present(target, result) : systemProcessResult(target, result, "command_process_completion");
4114
4163
  }, applications = async (params) => {
4115
4164
  let target = await resolveTarget(readSystemTargetId(params.target)), query = (readOptionalString(params.query) ?? "").toLowerCase(), limit = params.limit === void 0 ? 50 : readBoundedInteger(params.limit, {
4116
4165
  name: "limit",
4117
4166
  minimum: 1,
4118
4167
  maximum: 100
4119
- }), catalog = await readSystemApplications(target, run2), { output, data } = systemApplicationObservation(
4168
+ }), observed = await readSystemApplications(target, run2), catalog = protection ? protectSystemResult(() => protection.protectCatalog(observed)) : observed, { output, data } = systemApplicationObservation(
4120
4169
  target,
4121
4170
  catalog,
4122
4171
  query,
@@ -4135,19 +4184,24 @@ function createSystemHandlers(run2 = runSystemProcess, resolveTarget = (id) => r
4135
4184
  params,
4136
4185
  run: run2,
4137
4186
  ...context?.abortSignal ? { abortSignal: context.abortSignal } : {}
4138
- });
4187
+ }), process2 = result.process, application = result.application;
4188
+ try {
4189
+ protection && (process2 = protection.protectProcess(result.process), application = protection.protectApplication(result.application));
4190
+ } catch {
4191
+ return failedSystemProtectionReceipt(target, result.process, "launch_request_dispatch");
4192
+ }
4139
4193
  return systemProcessResult(
4140
4194
  target,
4141
- result.process,
4195
+ process2,
4142
4196
  "launch_request_dispatch",
4143
- result.application
4197
+ application
4144
4198
  );
4145
4199
  };
4146
4200
  return {
4147
- system_targets: withSystemOperationErrors(targets),
4148
- system_command: withSystemOperationErrors(command),
4149
- system_applications: withSystemOperationErrors(applications),
4150
- system_launch: withSystemOperationErrors(launch)
4201
+ system_targets: withSystemOperationErrors(targets, protection),
4202
+ system_command: withSystemOperationErrors(command, protection),
4203
+ system_applications: withSystemOperationErrors(applications, protection),
4204
+ system_launch: withSystemOperationErrors(launch, protection)
4151
4205
  };
4152
4206
  }
4153
4207
 
@@ -4155,12 +4209,62 @@ function createSystemHandlers(run2 = runSystemProcess, resolveTarget = (id) => r
4155
4209
  import { createHash, randomUUID as randomUUID2 } from "node:crypto";
4156
4210
  import { once } from "node:events";
4157
4211
  import { createWriteStream } from "node:fs";
4158
- import { mkdir, open, readFile as readFile4, rename as rename2, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
4212
+ import { mkdir, open, rename as rename2, writeFile as writeFile3 } from "node:fs/promises";
4159
4213
  import { join as join5 } from "node:path";
4160
4214
  import { finished } from "node:stream/promises";
4161
4215
 
4216
+ // src/computer-access/command-output-protection.ts
4217
+ import { readFile as readFile3, rm, writeFile as writeFile2 } from "node:fs/promises";
4218
+ var CapturedOutputProtectionError = class extends Error {
4219
+ constructor(reason) {
4220
+ super(reason);
4221
+ this.reason = reason;
4222
+ }
4223
+ reason;
4224
+ };
4225
+ async function protectCapturedOutput(paths, redact) {
4226
+ let stdout2, stderr;
4227
+ try {
4228
+ stdout2 = await protectStream(paths.stdout, redact), stderr = await protectStream(paths.stderr, redact);
4229
+ let writes = await Promise.allSettled([
4230
+ writeFile2(paths.stdout, stdout2, { flag: "w", mode: 384, flush: !0 }),
4231
+ writeFile2(paths.stderr, stderr, { flag: "w", mode: 384, flush: !0 })
4232
+ ]);
4233
+ if (hasRejectedOutputWrite(writes)) throw new CapturedOutputProtectionError("output_storage_failed");
4234
+ return { stdout: stdout2, stderr };
4235
+ } catch (error) {
4236
+ throw stdout2?.fill(0), stderr?.fill(0), error;
4237
+ }
4238
+ }
4239
+ async function protectStream(path, redact) {
4240
+ let bytes;
4241
+ try {
4242
+ bytes = await readFile3(path);
4243
+ } catch {
4244
+ throw new CapturedOutputProtectionError("output_storage_failed");
4245
+ }
4246
+ try {
4247
+ let text = new TextDecoder("utf-8", { fatal: !0, ignoreBOM: !0 }).decode(bytes), protectedText = redact(text);
4248
+ if (!isProtectedOutputText(protectedText)) throw new Error("output_protection_failed");
4249
+ return Buffer.from(protectedText, "utf8");
4250
+ } catch {
4251
+ throw new CapturedOutputProtectionError("output_protection_failed");
4252
+ } finally {
4253
+ bytes.fill(0);
4254
+ }
4255
+ }
4256
+ async function discardCapturedOutput(paths) {
4257
+ return (await Promise.allSettled(Object.values(paths).map((path) => rm(path, { force: !0 })))).every((entry) => entry.status === "fulfilled");
4258
+ }
4259
+ function isProtectedOutputText(value) {
4260
+ return typeof value == "string";
4261
+ }
4262
+ function hasRejectedOutputWrite(writes) {
4263
+ return writes.some((entry) => entry.status === "rejected");
4264
+ }
4265
+
4162
4266
  // src/computer-access/command-output-retention.ts
4163
- import { readFile as readFile3, readdir as readdir2, rm, stat as stat2 } from "node:fs/promises";
4267
+ import { readFile as readFile4, readdir as readdir2, rm as rm2, stat as stat2 } from "node:fs/promises";
4164
4268
  import { join as join4 } from "node:path";
4165
4269
  var DEFAULT_SYSTEM_OUTPUT_RETENTION_MS = 10080 * 6e4, activeSystemCaptures = /* @__PURE__ */ new Set(), jobs = /* @__PURE__ */ new Map(), CAPTURE_ID = /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/;
4166
4270
  async function cleanupSystemOutput(root, retentionMs) {
@@ -4173,14 +4277,14 @@ async function cleanupSystemOutput(root, retentionMs) {
4173
4277
  let directory = join4(root, entry.name);
4174
4278
  if (activeSystemCaptures.has(directory)) continue;
4175
4279
  let files = await readdir2(directory), times = await Promise.all(files.map(async (file) => (await stat2(join4(directory, file))).mtimeMs)), completedAt = Math.max((await stat2(directory)).mtimeMs, ...times), captureRetentionMs = await readCaptureRetention(directory, entry.name, retentionMs);
4176
- Date.now() - completedAt < captureRetentionMs || activeSystemCaptures.has(directory) || (await rm(directory, { recursive: !0 }), removed += 1);
4280
+ Date.now() - completedAt < captureRetentionMs || activeSystemCaptures.has(directory) || (await rm2(directory, { recursive: !0 }), removed += 1);
4177
4281
  }
4178
4282
  return removed;
4179
4283
  }
4180
4284
  async function readCaptureRetention(directory, id, fallbackMs) {
4181
4285
  let receipt;
4182
4286
  try {
4183
- receipt = JSON.parse(await readFile3(join4(directory, "receipt.json"), "utf8"));
4287
+ receipt = JSON.parse(await readFile4(join4(directory, "receipt.json"), "utf8"));
4184
4288
  } catch (error) {
4185
4289
  if (error.code === "ENOENT" || error instanceof SyntaxError) return fallbackMs;
4186
4290
  throw error;
@@ -4218,8 +4322,10 @@ function scheduleSystemOutputCleanup(root, retentionMs) {
4218
4322
  }
4219
4323
 
4220
4324
  // src/computer-access/command-output-capture.ts
4221
- var OUTPUT_IO_CHUNK_BYTES = 64 * 1024;
4222
- async function createSystemOutputCapture(root, retentionMs) {
4325
+ var STREAMS = ["stdout", "stderr"], OUTPUT_IO_CHUNK_BYTES = 64 * 1024;
4326
+ async function createSystemOutputCapture(root, retentionMs, redact) {
4327
+ if (!hasOutputProtection(redact))
4328
+ throw new SystemOperationError("system_output_protection_failed", "Command output protection is unavailable. The command was not dispatched.");
4223
4329
  let id = randomUUID2(), directory = join5(root, id);
4224
4330
  activeSystemCaptures.add(directory);
4225
4331
  try {
@@ -4227,11 +4333,11 @@ async function createSystemOutputCapture(root, retentionMs) {
4227
4333
  } catch {
4228
4334
  throw activeSystemCaptures.delete(directory), new SystemOperationError("system_output_storage_failed", "Output storage could not be prepared. The command was not dispatched.");
4229
4335
  }
4230
- let failure, stop, ended = !1, retained = !1, sources = [], streams = ["stdout", "stderr"].map((name) => {
4231
- let path = join5(directory, name + ".bytes"), sink = createWriteStream(path, { flags: "wx", mode: 384, highWaterMark: OUTPUT_IO_CHUNK_BYTES, flush: !0 }), completion = finished(sink).catch(() => {
4232
- failure ??= "write_failed", stop?.();
4336
+ let storageFailure, securityFailure, stop, ended = !1, retained = !1, admitted = !1, receipt, processResult, finishing, sources = [], completeStreams = /* @__PURE__ */ new Set(), paths = { stdout: join5(directory, "stdout.bytes"), stderr: join5(directory, "stderr.bytes") }, streams = STREAMS.map((name) => {
4337
+ let sink = createWriteStream(paths[name], { flags: "wx", mode: 384, highWaterMark: OUTPUT_IO_CHUNK_BYTES, flush: !0 }), completion = finished(sink).catch(() => {
4338
+ storageFailure ??= "write_failed", stop?.();
4233
4339
  });
4234
- return { name, path, sink, completion, hash: createHash("sha256") };
4340
+ return { sink, completion };
4235
4341
  });
4236
4342
  try {
4237
4343
  await Promise.all(streams.map(({ sink }) => once(sink, "open")));
@@ -4240,26 +4346,113 @@ async function createSystemOutputCapture(root, retentionMs) {
4240
4346
  throw await Promise.all(streams.map(({ completion }) => completion)), activeSystemCaptures.delete(directory), scheduleSystemOutputCleanup(root, retentionMs), new SystemOperationError("system_output_storage_failed", "Output files could not be opened. The command was not dispatched.");
4241
4347
  }
4242
4348
  scheduleSystemOutputCleanup(root, retentionMs);
4243
- let capture = {
4349
+ let failure = () => storageFailure ?? securityFailure, capture = {
4244
4350
  attach(stdout2, stderr, onFailure) {
4245
- stop = onFailure, sources.push(stdout2, stderr), stdout2.on("data", (bytes) => streams[0].hash.update(bytes)), stderr.on("data", (bytes) => streams[1].hash.update(bytes)), stdout2.pipe(streams[0].sink), stderr.pipe(streams[1].sink), failure && onFailure();
4351
+ if (!canAttachCapture()) {
4352
+ securityFailure ??= "output_protection_failed", onFailure();
4353
+ return;
4354
+ }
4355
+ stop = onFailure, sources.push(stdout2, stderr);
4356
+ for (let [index, source] of sources.entries())
4357
+ source.once("end", () => completeStreams.add(STREAMS[index])), source.once("error", () => {
4358
+ securityFailure ??= "output_incomplete", stop?.();
4359
+ }), source.pipe(streams[index].sink);
4360
+ failure() && onFailure();
4246
4361
  },
4247
4362
  end() {
4248
4363
  if (!ended) {
4249
- ended = !0;
4364
+ ended = !0, hasCompleteStreams() || (securityFailure ??= "output_incomplete");
4250
4365
  for (let source of sources)
4251
4366
  source.unpipe(), source.destroy();
4252
4367
  for (let { sink } of streams) !sink.destroyed && !sink.writableEnded && sink.end();
4253
4368
  }
4254
4369
  }
4255
- }, receipt;
4370
+ };
4371
+ function canAttachCapture() {
4372
+ return sources.length === 0 && !ended;
4373
+ }
4374
+ function hasCompleteStreams() {
4375
+ return completeStreams.size === 2;
4376
+ }
4377
+ function protectProcess2(result) {
4378
+ if (!result) return;
4379
+ let spawnedProcess = result.spawnedProcess;
4380
+ if (spawnedProcess) {
4381
+ let executable = "[REDACTED]";
4382
+ try {
4383
+ if (executable = redact(spawnedProcess.executable), !hasProtectedIdentity(executable)) throw new Error("output_protection_failed");
4384
+ } catch {
4385
+ securityFailure ??= "output_protection_failed", executable = "[REDACTED]";
4386
+ }
4387
+ spawnedProcess = { ...spawnedProcess, executable };
4388
+ }
4389
+ processResult = {
4390
+ exitCode: result.exitCode,
4391
+ status: result.status,
4392
+ outputTruncated: result.outputTruncated,
4393
+ stdout: "",
4394
+ stderr: "",
4395
+ ...spawnedProcess ? { spawnedProcess } : {}
4396
+ };
4397
+ }
4398
+ async function finish(result, materialize = !0) {
4399
+ capture.end(), await Promise.all(streams.map(({ completion }) => completion)), protectProcess2(result);
4400
+ let protectedBytes;
4401
+ try {
4402
+ if (!failure())
4403
+ try {
4404
+ protectedBytes = await protectCapturedOutput(paths, redact);
4405
+ } catch (error) {
4406
+ isOutputStorageFailure(error) ? storageFailure ??= "write_failed" : securityFailure ??= "output_protection_failed";
4407
+ }
4408
+ failure() && !await discardCapturedOutput(paths) && (storageFailure = "capture_purge_failed"), receipt = {
4409
+ id,
4410
+ stdoutBytes: protectedBytes?.stdout.length ?? 0,
4411
+ stderrBytes: protectedBytes?.stderr.length ?? 0,
4412
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
4413
+ retentionMs,
4414
+ complete: !failure(),
4415
+ ...!materialize && protectedBytes ? {
4416
+ stdoutSha256: createHash("sha256").update(protectedBytes.stdout).digest("hex"),
4417
+ stderrSha256: createHash("sha256").update(protectedBytes.stderr).digest("hex")
4418
+ } : {}
4419
+ };
4420
+ try {
4421
+ let temporary = join5(directory, "receipt.tmp");
4422
+ await writeFile3(
4423
+ temporary,
4424
+ JSON.stringify({
4425
+ kind: "system_command_output_v1",
4426
+ ...receipt,
4427
+ processStatus: processResult?.status,
4428
+ exitCode: processResult?.exitCode,
4429
+ spawnedProcess: processResult?.spawnedProcess,
4430
+ ...securityFailure ? { securityFailure } : {},
4431
+ ...storageFailure ? { storageFailure } : {}
4432
+ }),
4433
+ { flag: "wx", mode: 384, flush: !0 }
4434
+ ), await rename2(temporary, join5(directory, "receipt.json"));
4435
+ } catch {
4436
+ storageFailure ??= "receipt_write_failed", receipt = { ...receipt, complete: !1 };
4437
+ }
4438
+ return admitted = receipt.complete, !admitted || !materialize || !protectedBytes ? { stdout: "", stderr: "" } : { stdout: protectedBytes.stdout.toString("utf8"), stderr: protectedBytes.stderr.toString("utf8") };
4439
+ } finally {
4440
+ protectedBytes?.stdout.fill(0), protectedBytes?.stderr.fill(0), retained || activeSystemCaptures.delete(directory);
4441
+ }
4442
+ }
4256
4443
  return {
4257
4444
  capture,
4258
4445
  get receipt() {
4259
4446
  return receipt;
4260
4447
  },
4261
4448
  get failure() {
4262
- return failure;
4449
+ return failure();
4450
+ },
4451
+ get failureKind() {
4452
+ return storageFailure ? "storage" : securityFailure ? "security" : void 0;
4453
+ },
4454
+ get processResult() {
4455
+ return processResult;
4263
4456
  },
4264
4457
  retain() {
4265
4458
  retained = !0, activeSystemCaptures.add(directory);
@@ -4268,61 +4461,35 @@ async function createSystemOutputCapture(root, retentionMs) {
4268
4461
  retained = !1, activeSystemCaptures.delete(directory);
4269
4462
  },
4270
4463
  async read(stream, offset, length) {
4271
- let path = streams.find((entry) => entry.name === stream).path, file = await open(path, "r");
4464
+ if (!admitted) throw new Error("system_output_unavailable");
4465
+ if (!isAdmittedOutputRead(stream, offset, length, receipt)) throw new Error("system_output_reference_invalid");
4466
+ let file = await open(paths[stream], "r");
4272
4467
  try {
4273
- let bytes = Buffer.alloc(length), { bytesRead } = await file.read(bytes, 0, length, offset);
4468
+ let size = stream === "stdout" ? receipt.stdoutBytes : receipt.stderrBytes, bytes = Buffer.alloc(Math.min(length, size - offset)), { bytesRead } = await file.read(bytes, 0, bytes.length, offset);
4274
4469
  return bytes.subarray(0, bytesRead);
4275
4470
  } finally {
4276
4471
  await file.close();
4277
4472
  }
4278
4473
  },
4279
- async finish(result, materialize = !0) {
4280
- capture.end();
4281
- try {
4282
- await Promise.all(streams.map(({ completion }) => completion));
4283
- let sizes = await Promise.all(streams.map(async ({ path }) => {
4284
- try {
4285
- return (await stat3(path)).size;
4286
- } catch {
4287
- return failure ??= "read_failed", 0;
4288
- }
4289
- })), stdout2 = "", stderr = "";
4290
- if (!failure && materialize)
4291
- try {
4292
- [stdout2, stderr] = await Promise.all(streams.map(({ path }) => readFile4(path, "utf8")));
4293
- } catch {
4294
- failure = "read_failed";
4295
- }
4296
- let completedAt = Date.now();
4297
- receipt = {
4298
- id,
4299
- stdoutBytes: sizes[0],
4300
- stderrBytes: sizes[1],
4301
- completedAt: new Date(completedAt).toISOString(),
4302
- retentionMs,
4303
- complete: !failure,
4304
- ...materialize ? {} : { stdoutSha256: streams[0].hash.digest("hex"), stderrSha256: streams[1].hash.digest("hex") }
4305
- };
4306
- try {
4307
- let temporary = join5(directory, "receipt.tmp");
4308
- await writeFile2(temporary, JSON.stringify({
4309
- kind: "system_command_output_v1",
4310
- ...receipt,
4311
- processStatus: result?.status,
4312
- exitCode: result?.exitCode,
4313
- spawnedProcess: result?.spawnedProcess,
4314
- ...failure ? { storageFailure: failure } : {}
4315
- }), { flag: "wx", mode: 384, flush: !0 }), await rename2(temporary, join5(directory, "receipt.json"));
4316
- } catch {
4317
- failure ??= "receipt_write_failed", receipt = { ...receipt, complete: !1 };
4318
- }
4319
- return { stdout: stdout2, stderr };
4320
- } finally {
4321
- retained || activeSystemCaptures.delete(directory);
4322
- }
4474
+ finish(result, materialize = !0) {
4475
+ return finishing ??= finish(result, materialize), finishing;
4323
4476
  }
4324
4477
  };
4325
4478
  }
4479
+ function hasOutputProtection(value) {
4480
+ return typeof value == "function";
4481
+ }
4482
+ function hasProtectedIdentity(value) {
4483
+ return typeof value == "string";
4484
+ }
4485
+ function isOutputStorageFailure(error) {
4486
+ return error instanceof CapturedOutputProtectionError && error.reason === "output_storage_failed";
4487
+ }
4488
+ function isAdmittedOutputRead(stream, offset, length, receipt) {
4489
+ if (stream !== "stdout" && stream !== "stderr" || !Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(length) || length < 0) return !1;
4490
+ let size = stream === "stdout" ? receipt.stdoutBytes : receipt.stderrBytes;
4491
+ return offset <= size;
4492
+ }
4326
4493
 
4327
4494
  // src/computer-access/companion/command-output-protocol.ts
4328
4495
  var SYSTEM_OUTPUT_CAPABILITY = "system_command_output_v1", SYSTEM_OUTPUT_CHUNK_BYTES = 64 * 1024;
@@ -4350,6 +4517,133 @@ function readSystemOutputTransfer(value) {
4350
4517
  };
4351
4518
  }
4352
4519
 
4520
+ // src/computer-access/security/secret-text.ts
4521
+ var REDACTED = "[REDACTED]", CREDENTIAL_KEY_SOURCE = String.raw`(?:[A-Za-z][A-Za-z0-9_-]*\.)*(?:[A-Za-z][A-Za-z0-9]*[-_])*(?:password|passwd|pwd|api[_ -]?key|access[_ -]?token|refresh[_ -]?token|client[_ -]?secret|secret[_ -]?access[_ -]?key|recovery[_ -]?code)`, credentialIndicator = new RegExp(
4522
+ String.raw`(?<![\p{L}\p{N}_.-])(?:-{1,2})?(?:${CREDENTIAL_KEY_SOURCE}|(?:proxy-)?authorization)[\s"'\\]*[:=]`,
4523
+ "iu"
4524
+ );
4525
+ function detectionText(input) {
4526
+ return input.replace(
4527
+ /%([0-7][0-9a-f])/giu,
4528
+ (_, hex) => String.fromCharCode(Number.parseInt(hex, 16))
4529
+ ).replace(
4530
+ /\\(?:u00|x|U000000)([0-7][0-9a-fA-F])/gu,
4531
+ (_, hex) => String.fromCharCode(Number.parseInt(hex, 16))
4532
+ );
4533
+ }
4534
+ function hasPrivateKeyIndicator(text) {
4535
+ return /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----/u.test(text);
4536
+ }
4537
+ function hasUrlCredentials(text) {
4538
+ return /\b[a-z][a-z0-9+.-]*(?::|%3a)(?:\/|%2f){2}[^\s/?#<>]*(?:@|%40)/iu.test(text);
4539
+ }
4540
+ function hasAuthorizationCredentials(text) {
4541
+ for (let match of text.matchAll(
4542
+ /\b(Bearer|Basic)[ \t]+([A-Za-z0-9._~+/-]+={0,2})/giu
4543
+ )) {
4544
+ if (match[1].toLowerCase() === "bearer") return !0;
4545
+ let value = match[2];
4546
+ if (/^[A-Za-z0-9+/]+={0,2}$/u.test(value) && !(value.length < 8) && Buffer.from(value, "base64").toString("utf8").includes(":"))
4547
+ return !0;
4548
+ }
4549
+ return !1;
4550
+ }
4551
+ function isAwsAccessKeyValue(value, atEnd) {
4552
+ return /^[A-Z0-9]{16}$/u.test(value) ? !0 : atEnd ? /^[A-Z0-9]{4,15}$/u.test(value) : !1;
4553
+ }
4554
+ function isRecognizedProviderToken(prefix, value, atEnd) {
4555
+ if (prefix === "AKIA" || prefix === "ASIA")
4556
+ return isAwsAccessKeyValue(value, atEnd);
4557
+ if (value.length >= 20) return !0;
4558
+ let partialMinimum = prefix === "sk-" ? 8 : 1;
4559
+ return atEnd && value.length >= partialMinimum;
4560
+ }
4561
+ function hasProviderToken(text) {
4562
+ let provider = /\b(sk-(?:proj-|svcacct-)?|gh[pousr]_|github_pat_|xox[baprs]-|AKIA|ASIA)([A-Za-z0-9_-]+)/gu;
4563
+ for (let match of text.matchAll(provider)) {
4564
+ let atEnd = match.index + match[0].length === text.length;
4565
+ if (isRecognizedProviderToken(match[1], match[2], atEnd)) return !0;
4566
+ }
4567
+ return !1;
4568
+ }
4569
+ function compactJoseSegmentCount(header) {
4570
+ try {
4571
+ let value = JSON.parse(
4572
+ Buffer.from(header, "base64url").toString("utf8")
4573
+ );
4574
+ if (typeof value != "object" || value === null || Array.isArray(value))
4575
+ return;
4576
+ let fields = value;
4577
+ return typeof fields.alg != "string" ? void 0 : typeof fields.enc == "string" ? 5 : 3;
4578
+ } catch {
4579
+ return;
4580
+ }
4581
+ }
4582
+ function hasCompactJoseToken(text) {
4583
+ let jose = /\b([A-Za-z0-9_-]+)(?:\.[A-Za-z0-9_-]*)+/gu;
4584
+ for (let match of text.matchAll(jose)) {
4585
+ let parts = match[0].split("."), capturedAtEnd = match.index + match[0].length === text.length;
4586
+ for (let index = 0; index < parts.length - 1; index += 1) {
4587
+ let expected = compactJoseSegmentCount(parts[index]);
4588
+ if (expected !== void 0 && !(expected === 3 && parts[index + 1] === "") && (parts.length - index >= expected || capturedAtEnd))
4589
+ return !0;
4590
+ }
4591
+ }
4592
+ return !1;
4593
+ }
4594
+ function hasSecretIndicator(text) {
4595
+ return credentialIndicator.test(text) || hasPrivateKeyIndicator(text) || hasUrlCredentials(text) || hasAuthorizationCredentials(text) || hasProviderToken(text) ? !0 : hasCompactJoseToken(text);
4596
+ }
4597
+ function redactSecretText(input) {
4598
+ return hasSecretIndicator(input) || hasSecretIndicator(detectionText(input)) ? REDACTED : input;
4599
+ }
4600
+
4601
+ // src/computer-access/security/system-results.ts
4602
+ var INCOMPLETE_STREAM = "[UNAVAILABLE: incomplete output cannot be scanned for secrets]", SENSITIVE_TARGET = "Target unavailable because its shell identity contains sensitive text.";
4603
+ function protectApplication(application) {
4604
+ if (redactSecretText(application.id) === application.id)
4605
+ return { ...application, name: redactSecretText(application.name) };
4606
+ }
4607
+ function protectCatalog(catalog) {
4608
+ let applications = catalog.applications.flatMap((application) => {
4609
+ let protectedApplication = protectApplication(application);
4610
+ return protectedApplication ? [protectedApplication] : [];
4611
+ });
4612
+ return {
4613
+ ...catalog,
4614
+ applications,
4615
+ complete: catalog.complete && applications.length === catalog.applications.length,
4616
+ scope: { ...catalog.scope, roots: catalog.scope.roots.map(redactSecretText) }
4617
+ };
4618
+ }
4619
+ function protectTargets(observation) {
4620
+ return {
4621
+ ...observation,
4622
+ host: { ...observation.host, kernelRelease: redactSecretText(observation.host.kernelRelease) },
4623
+ targets: observation.targets.map((target) => target.available ? redactSecretText(target.shell) !== target.shell ? { id: target.id, available: !1, reason: SENSITIVE_TARGET } : target : { ...target, reason: redactSecretText(target.reason) })
4624
+ };
4625
+ }
4626
+ function protectProcess(result) {
4627
+ return {
4628
+ ...result,
4629
+ stdout: result.outputTruncated ? INCOMPLETE_STREAM : redactSecretText(result.stdout),
4630
+ stderr: result.outputTruncated ? INCOMPLETE_STREAM : redactSecretText(result.stderr),
4631
+ ...result.spawnedProcess ? {
4632
+ spawnedProcess: {
4633
+ ...result.spawnedProcess,
4634
+ executable: redactSecretText(result.spawnedProcess.executable)
4635
+ }
4636
+ } : {}
4637
+ };
4638
+ }
4639
+ var systemResultProtection = Object.freeze({
4640
+ protectTargets,
4641
+ protectCatalog,
4642
+ protectProcess,
4643
+ protectApplication,
4644
+ protectMessage: redactSecretText
4645
+ });
4646
+
4353
4647
  // src/computer-access/companion/command-output.ts
4354
4648
  var CompanionCommandOutput = class {
4355
4649
  constructor(stateDir) {
@@ -4390,10 +4684,10 @@ var CompanionCommandOutput = class {
4390
4684
  }), captured, handlers = createSystemHandlers(void 0, void 0, () => ({
4391
4685
  run: async (input) => {
4392
4686
  if (input.abortSignal?.aborted) return runSystemProcess(input);
4393
- captured = await createSystemOutputCapture(join6(this.stateDir, "command-output"), retentionMs), captured.retain();
4687
+ captured = await createSystemOutputCapture(join6(this.stateDir, "command-output"), retentionMs, redactSecretText), captured.retain();
4394
4688
  try {
4395
4689
  let result = await runSystemProcess(input, captured.capture);
4396
- return await captured.finish(result, !1), { ...result, outputTruncated: !!captured.failure };
4690
+ return await captured.finish(result, !1), { ...captured.processResult, outputTruncated: !!captured.failure };
4397
4691
  } catch (error) {
4398
4692
  throw await captured.finish(void 0, !1), captured.release(), error;
4399
4693
  }
@@ -4402,13 +4696,16 @@ var CompanionCommandOutput = class {
4402
4696
  let receipt = buildSystemProcessResult(target, result, "command_process_completion");
4403
4697
  if (!captured?.receipt) return receipt;
4404
4698
  let data = { ...receipt.data, outputCapture: captured.receipt };
4405
- if (captured.failure)
4406
- return captured.release(), failureResult({
4407
- errorCode: "system_output_storage_failed",
4408
- message: "Command output storage failed after dispatch; inspect the process receipt before another action.",
4409
- data: { ...data, storageFailure: captured.failure },
4699
+ if (captured.failure) {
4700
+ captured.release();
4701
+ let errorCode2 = captured.failureKind === "security" ? "system_output_protection_failed" : "system_output_storage_failed";
4702
+ return failureResult({
4703
+ errorCode: errorCode2,
4704
+ message: "Command output could not be admitted after dispatch; inspect the process receipt before another action. The command was not replayed.",
4705
+ data: { ...data, ...captured.failureKind === "security" ? { securityFailure: captured.failure } : { storageFailure: captured.failure } },
4410
4706
  ...result.exitCode !== null ? { exitCode: result.exitCode } : {}
4411
4707
  });
4708
+ }
4412
4709
  if (this.closed || context?.abortSignal?.aborted)
4413
4710
  return captured.release(), { ...receipt, data };
4414
4711
  let transfer = readSystemOutputTransfer({ kind: SYSTEM_OUTPUT_CAPABILITY, ...captured.receipt });
@@ -4421,8 +4718,16 @@ Streams retained for exact transfer.`,
4421
4718
  data: { ...data, outputTransfer: transfer }
4422
4719
  };
4423
4720
  }
4424
- })), { outputRetentionMs: _retention, ...command } = params;
4425
- return handlers.system_command(command, context);
4721
+ }), systemResultProtection), { outputRetentionMs: _retention, ...command } = params;
4722
+ try {
4723
+ return await handlers.system_command(command, context);
4724
+ } finally {
4725
+ this.hasRegisteredTransfer(captured) || captured?.release();
4726
+ }
4727
+ }
4728
+ hasRegisteredTransfer(capture) {
4729
+ let id = capture?.receipt?.id;
4730
+ return id ? this.captures.get(id) === capture : !1;
4426
4731
  }
4427
4732
  async read(params) {
4428
4733
  if (!isHostIdentifier(params.captureId)) throw new Error("system_output_reference_invalid");
@@ -4439,6 +4744,9 @@ Streams retained for exact transfer.`,
4439
4744
  }
4440
4745
  };
4441
4746
 
4747
+ // src/computer-access/companion/secret-protection-protocol.ts
4748
+ var HOST_SECRET_PROTECTION_CAPABILITY = "host_secret_protection_v1";
4749
+
4442
4750
  // src/computer-access/companion/native-permissions.ts
4443
4751
  import { execFile as execFile3 } from "node:child_process";
4444
4752
  import { promisify as promisify3 } from "node:util";
@@ -4771,7 +5079,7 @@ async function sendWindowsNotification(notification, signal, run2 = runNotificat
4771
5079
 
4772
5080
  // src/computer-access/companion/notification-macos.ts
4773
5081
  import { randomUUID as randomUUID3 } from "node:crypto";
4774
- import { readFile as readFile5, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
5082
+ import { readFile as readFile5, unlink as unlink2, writeFile as writeFile4 } from "node:fs/promises";
4775
5083
  import { join as join8 } from "node:path";
4776
5084
  import { setTimeout as delay } from "node:timers/promises";
4777
5085
  function renderMacNotificationApplet(stateDir) {
@@ -4858,7 +5166,7 @@ async function sendMacNotification(notification, locations, signal, run2 = runNo
4858
5166
  "pending",
4859
5167
  randomUUID3() + ".json"
4860
5168
  ), resultFile = file + ".result";
4861
- await writeFile3(
5169
+ await writeFile4(
4862
5170
  file,
4863
5171
  JSON.stringify({ ...notification, expiresAt: Date.now() + 15e3 }),
4864
5172
  { flag: "wx", mode: 384 }
@@ -5073,14 +5381,14 @@ import {
5073
5381
  open as open2,
5074
5382
  readFile as readFile7,
5075
5383
  rename as rename3,
5076
- rm as rm3,
5077
- writeFile as writeFile5
5384
+ rm as rm4,
5385
+ writeFile as writeFile6
5078
5386
  } from "node:fs/promises";
5079
5387
  import { dirname as dirname3, isAbsolute as isAbsolute2, join as join12 } from "node:path";
5080
5388
 
5081
5389
  // src/computer-access/companion/notification-directory.ts
5082
5390
  import { randomUUID as randomUUID4 } from "node:crypto";
5083
- import { mkdir as mkdir2, rm as rm2, symlink, unlink as unlink3, writeFile as writeFile4 } from "node:fs/promises";
5391
+ import { mkdir as mkdir2, rm as rm3, symlink, unlink as unlink3, writeFile as writeFile5 } from "node:fs/promises";
5084
5392
  import { basename as basename3, dirname as dirname2, join as join10 } from "node:path";
5085
5393
 
5086
5394
  // src/computer-access/companion/notification-directory-ownership.ts
@@ -5094,9 +5402,9 @@ function renderNotificationLinkOwner(directory, backing) {
5094
5402
  });
5095
5403
  }
5096
5404
  async function readNotificationOwnerFile(path) {
5097
- let stat4 = await lstat2(path);
5098
- if (!stat4.isFile()) throw new Error("notification_directory_not_owned");
5099
- if (stat4.size > 4096) throw new Error("notification_directory_not_owned");
5405
+ let stat3 = await lstat2(path);
5406
+ if (!stat3.isFile()) throw new Error("notification_directory_not_owned");
5407
+ if (stat3.size > 4096) throw new Error("notification_directory_not_owned");
5100
5408
  return readFile6(path, "utf8");
5101
5409
  }
5102
5410
  async function assertNotificationDirectoryMarker(directory) {
@@ -5119,21 +5427,21 @@ function hasSameNotificationFileIdentity(left, right) {
5119
5427
  return left.dev !== right.dev ? !1 : left.ino === right.ino;
5120
5428
  }
5121
5429
  async function readOwnedNotificationPath(directory) {
5122
- let stat4 = await lstat2(directory, { bigint: !0 }).catch(
5430
+ let stat3 = await lstat2(directory, { bigint: !0 }).catch(
5123
5431
  (error) => {
5124
5432
  if (error.code !== "ENOENT")
5125
5433
  throw error;
5126
5434
  }
5127
5435
  );
5128
- if (!stat4) return;
5129
- if (stat4.isDirectory())
5436
+ if (!stat3) return;
5437
+ if (stat3.isDirectory())
5130
5438
  return await assertNotificationDirectoryMarker(directory), {
5131
5439
  directory,
5132
5440
  backing: directory,
5133
- aliasIdentity: stat4,
5134
- backingIdentity: stat4
5441
+ aliasIdentity: stat3,
5442
+ backingIdentity: stat3
5135
5443
  };
5136
- if (!stat4.isSymbolicLink())
5444
+ if (!stat3.isSymbolicLink())
5137
5445
  throw new Error("notification_directory_not_owned");
5138
5446
  let target = await readlink(directory);
5139
5447
  if (!isNotificationBackingName(directory, target))
@@ -5148,12 +5456,12 @@ async function readOwnedNotificationPath(directory) {
5148
5456
  if (!hasBoundNotificationLinkOwner(record, directory, target))
5149
5457
  throw new Error("notification_directory_not_owned");
5150
5458
  let currentAlias = await lstat2(directory, { bigint: !0 });
5151
- if (!hasSameNotificationFileIdentity(stat4, currentAlias))
5459
+ if (!hasSameNotificationFileIdentity(stat3, currentAlias))
5152
5460
  throw new Error("notification_directory_changed");
5153
5461
  return {
5154
5462
  directory,
5155
5463
  backing,
5156
- aliasIdentity: stat4,
5464
+ aliasIdentity: stat3,
5157
5465
  backingIdentity,
5158
5466
  linkTarget: target
5159
5467
  };
@@ -5229,11 +5537,11 @@ async function ensureOwnedNotificationDirectory(locations, run2 = runNotificatio
5229
5537
  await mkdir2(staged, { mode: 448 });
5230
5538
  let retainBacking = !1;
5231
5539
  try {
5232
- await writeFile4(join10(staged, ".owner"), NOTIFICATION_OWNER_MARKER, {
5540
+ await writeFile5(join10(staged, ".owner"), NOTIFICATION_OWNER_MARKER, {
5233
5541
  flag: "wx",
5234
5542
  mode: 384,
5235
5543
  flush: !0
5236
- }), requiresNotificationDirectoryLink() && await writeFile4(
5544
+ }), requiresNotificationDirectoryLink() && await writeFile5(
5237
5545
  join10(staged, ".owner-link"),
5238
5546
  renderNotificationLinkOwner(directory, staged),
5239
5547
  {
@@ -5247,17 +5555,17 @@ async function ensureOwnedNotificationDirectory(locations, run2 = runNotificatio
5247
5555
  run2
5248
5556
  );
5249
5557
  } finally {
5250
- retainBacking || await rm2(staged, { recursive: !0, force: !0 });
5558
+ retainBacking || await rm3(staged, { recursive: !0, force: !0 });
5251
5559
  }
5252
5560
  }
5253
5561
  async function removeOwnedNotificationDirectory(locations) {
5254
5562
  let owner = await readOwnedNotificationDirectory(locations);
5255
5563
  if (owner) {
5256
5564
  if (await assertNotificationOwnershipUnchanged(owner), owner.linkTarget === void 0) {
5257
- await rm2(owner.directory, { recursive: !0 });
5565
+ await rm3(owner.directory, { recursive: !0 });
5258
5566
  return;
5259
5567
  }
5260
- await unlink3(owner.directory), await assertNotificationBackingUnchanged(owner), await rm2(owner.backing, { recursive: !0 });
5568
+ await unlink3(owner.directory), await assertNotificationBackingUnchanged(owner), await rm3(owner.backing, { recursive: !0 });
5261
5569
  }
5262
5570
  }
5263
5571
 
@@ -5288,13 +5596,13 @@ function isBundleExecutableName(value) {
5288
5596
  return typeof value != "string" || value.length === 0 || value === "." || value === ".." ? !1 : !/[\\/\u0000-\u001f\u007f]/.test(value);
5289
5597
  }
5290
5598
  async function assertBundleDirectory(path) {
5291
- let stat4 = await lstat3(path);
5292
- if (!stat4.isDirectory() || stat4.isSymbolicLink())
5599
+ let stat3 = await lstat3(path);
5600
+ if (!stat3.isDirectory() || stat3.isSymbolicLink())
5293
5601
  throw new Error("notification_bundle_directory_invalid");
5294
5602
  }
5295
5603
  async function assertBundleFile(path) {
5296
- let stat4 = await lstat3(path);
5297
- if (!stat4.isFile() || stat4.isSymbolicLink())
5604
+ let stat3 = await lstat3(path);
5605
+ if (!stat3.isFile() || stat3.isSymbolicLink())
5298
5606
  throw new Error("notification_bundle_file_invalid");
5299
5607
  }
5300
5608
  async function readBundleMetadata(app, run2, signal) {
@@ -5374,12 +5682,12 @@ function renderLinuxNotificationDesktop(runtimeUrl) {
5374
5682
  `);
5375
5683
  }
5376
5684
  async function assertLinuxDesktopOwnership(path) {
5377
- let stat4 = await lstat4(path).catch((error) => {
5685
+ let stat3 = await lstat4(path).catch((error) => {
5378
5686
  if (error.code !== "ENOENT")
5379
5687
  throw error;
5380
5688
  });
5381
- if (!stat4) return !1;
5382
- if (!stat4.isFile() || stat4.isSymbolicLink())
5689
+ if (!stat3) return !1;
5690
+ if (!stat3.isFile() || stat3.isSymbolicLink())
5383
5691
  throw new Error("notification_registration_not_owned");
5384
5692
  if (!(await readFile7(path, "utf8")).includes("# " + NOTIFICATION_OWNER_MARKER))
5385
5693
  throw new Error("notification_registration_not_owned");
@@ -5399,9 +5707,9 @@ async function stopMacNotificationApp(locations, run2) {
5399
5707
  }
5400
5708
  async function installMacNotificationApp(locations, run2) {
5401
5709
  let directory = notificationInstallDirectory(locations), source = join12(directory, "notification-helper.js"), temporary = join12(directory, "ABot.next.app"), app = macNotificationAppPath(locations);
5402
- await writeFile5(source, renderMacNotificationApplet(locations.stateDir), {
5710
+ await writeFile6(source, renderMacNotificationApplet(locations.stateDir), {
5403
5711
  mode: 384
5404
- }), await rm3(temporary, { recursive: !0, force: !0 }), await run2({
5712
+ }), await rm4(temporary, { recursive: !0, force: !0 }), await run2({
5405
5713
  file: "/usr/bin/osacompile",
5406
5714
  args: ["-l", "JavaScript", "-s", "-o", temporary, source],
5407
5715
  timeoutMs: 3e4
@@ -5416,19 +5724,19 @@ async function installMacNotificationApp(locations, run2) {
5416
5724
  temporary
5417
5725
  ],
5418
5726
  timeoutMs: 3e4
5419
- }), await stopMacNotificationApp(locations, run2), await rm3(app, { recursive: !0, force: !0 }), await rename3(temporary, app), await run2({
5727
+ }), await stopMacNotificationApp(locations, run2), await rm4(app, { recursive: !0, force: !0 }), await rename3(temporary, app), await run2({
5420
5728
  file: "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister",
5421
5729
  args: ["-f", app]
5422
5730
  });
5423
5731
  }
5424
5732
  async function installDesktopNotificationIdentity(startup, runtimeUrl, run2 = runNotificationProcess) {
5425
5733
  let locations = notificationLocationsFromStartup(startup), directory = notificationInstallDirectory(locations);
5426
- await ensureOwnedNotificationDirectory(locations, run2), await rm3(join12(directory, ".ready"), { force: !0 }), await mkdir3(join12(directory, "pending"), { recursive: !0, mode: 448 }), await registerDesktopNotificationIdentity(
5734
+ await ensureOwnedNotificationDirectory(locations, run2), await rm4(join12(directory, ".ready"), { force: !0 }), await mkdir3(join12(directory, "pending"), { recursive: !0, mode: 448 }), await registerDesktopNotificationIdentity(
5427
5735
  startup.platform,
5428
5736
  locations,
5429
5737
  runtimeUrl,
5430
5738
  run2
5431
- ), await writeFile5(join12(directory, ".ready"), startup.platform, { mode: 384 });
5739
+ ), await writeFile6(join12(directory, ".ready"), startup.platform, { mode: 384 });
5432
5740
  }
5433
5741
  async function registerDesktopNotificationIdentity(platform, locations, runtimeUrl, run2) {
5434
5742
  if (platform === "win32") {
@@ -5450,12 +5758,12 @@ async function registerDesktopNotificationIdentity(platform, locations, runtimeU
5450
5758
  throw new Error("notification_platform_unsupported");
5451
5759
  }
5452
5760
  async function uninstallMacNotificationApp(locations, run2) {
5453
- let app = macNotificationAppPath(locations), stat4 = await lstat4(app).catch((error) => {
5761
+ let app = macNotificationAppPath(locations), stat3 = await lstat4(app).catch((error) => {
5454
5762
  if (error.code !== "ENOENT")
5455
5763
  throw error;
5456
5764
  });
5457
- if (stat4) {
5458
- if (!stat4.isDirectory() || stat4.isSymbolicLink())
5765
+ if (stat3) {
5766
+ if (!stat3.isDirectory() || stat3.isSymbolicLink())
5459
5767
  throw new Error("notification_registration_not_owned");
5460
5768
  await stopMacNotificationApp(locations, run2), await run2({
5461
5769
  file: "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister",
@@ -5488,7 +5796,7 @@ async function installLinuxNotificationIdentity(locations, runtimeUrl, run2) {
5488
5796
  try {
5489
5797
  await file.writeFile(content).finally(() => file.close()), await assertLinuxDesktopOwnership(path), await rename3(temporary, path);
5490
5798
  } finally {
5491
- await rm3(temporary, { force: !0 });
5799
+ await rm4(temporary, { force: !0 });
5492
5800
  }
5493
5801
  }
5494
5802
  async function uninstallDesktopNotificationIdentity(startup, run2 = runNotificationProcess) {
@@ -5502,7 +5810,7 @@ async function uninstallDesktopNotificationIdentity(startup, run2 = runNotificat
5502
5810
  input: JSON.stringify({ action: "uninstall" })
5503
5811
  }), startup.platform === "darwin" && await uninstallMacNotificationApp(locations, run2), startup.platform === "linux") {
5504
5812
  let path = linuxNotificationDesktopPath(locations);
5505
- await assertLinuxDesktopOwnership(path) && await rm3(path);
5813
+ await assertLinuxDesktopOwnership(path) && await rm4(path);
5506
5814
  }
5507
5815
  await removeOwnedNotificationDirectory(locations);
5508
5816
  }
@@ -5587,7 +5895,7 @@ function createNotificationSession(platform, runtimeUrl, ready, renderer, probe)
5587
5895
  } catch (error) {
5588
5896
  return failureResult({
5589
5897
  errorCode: hasUnknownNotificationOutcome(error) ? "notification_outcome_unknown" : "notification_native_failed",
5590
- message: error instanceof Error ? error.message.slice(0, 1e3) : "Desktop notification submission failed."
5898
+ message: error instanceof Error ? redactSecretText(error.message).slice(0, 1e3) : "Desktop notification submission failed."
5591
5899
  });
5592
5900
  }
5593
5901
  }
@@ -5616,7 +5924,7 @@ async function createNativeNotificationSession(platform, runtimeUrl, locations =
5616
5924
  linux.close(), platform === "macos" && session.ready && await stopMacNotificationApp(locations, runNotificationProcess).catch(
5617
5925
  (error) => {
5618
5926
  console.warn(
5619
- "Desktop notification helper could not stop: " + (error instanceof Error ? error.message : String(error))
5927
+ "Desktop notification helper could not stop: " + redactSecretText(error instanceof Error ? error.message : String(error))
5620
5928
  );
5621
5929
  }
5622
5930
  );
@@ -6864,18 +7172,14 @@ function readUnixNativeResult(value, platform) {
6864
7172
 
6865
7173
  // src/computer-access/computer/unix-native-process.ts
6866
7174
  function createUnixNativeProcess(options) {
6867
- let child, pending, closed = !1, failedReason, buffer = Buffer.alloc(0), queue = Promise.resolve(), lastResult;
7175
+ let child, pending, closed = !1, failedReason, buffer = Buffer.alloc(0), queue = Promise.resolve(), lastDesktop;
6868
7176
  function interruptedResult(reason) {
6869
7177
  let dispatch = pending?.request.operation === "act" ? pending.dispatch ?? {
6870
7178
  status: "unknown",
6871
7179
  requestedInputCount: 1,
6872
7180
  reason
6873
7181
  } : void 0, result = unavailableUnixDesktop(options.platform, reason, dispatch);
6874
- return lastResult ? {
6875
- ...result,
6876
- desktop: { ...lastResult.desktop, available: !1, reason },
6877
- windows: lastResult.windows
6878
- } : result;
7182
+ return lastDesktop ? { ...result, desktop: { ...result.desktop, ...lastDesktop } } : result;
6879
7183
  }
6880
7184
  function terminate(reason) {
6881
7185
  failedReason = reason, pending?.finish(interruptedResult(reason));
@@ -6884,7 +7188,7 @@ function createUnixNativeProcess(options) {
6884
7188
  let hardStop = setTimeout(() => retiring.kill("SIGKILL"), 3e3);
6885
7189
  hardStop.unref(), retiring.once("exit", () => clearTimeout(hardStop));
6886
7190
  }
6887
- child = void 0, buffer = Buffer.alloc(0);
7191
+ child = void 0, buffer.fill(0), buffer = Buffer.alloc(0);
6888
7192
  }
6889
7193
  function receiveLine(line) {
6890
7194
  let value = JSON.parse(line);
@@ -6899,7 +7203,17 @@ function createUnixNativeProcess(options) {
6899
7203
  }
6900
7204
  if (message.type !== "result") throw new Error("native_protocol_invalid");
6901
7205
  let result = readUnixNativeResult(message.result, options.platform);
6902
- lastResult = result, pending.finish(result);
7206
+ lastDesktop = {
7207
+ binding: result.desktop.binding,
7208
+ bounds: {
7209
+ x: result.desktop.bounds.x,
7210
+ y: result.desktop.bounds.y,
7211
+ width: result.desktop.bounds.width,
7212
+ height: result.desktop.bounds.height
7213
+ },
7214
+ coordinateSpace: result.desktop.coordinateSpace,
7215
+ targetingGuarantee: result.desktop.targetingGuarantee
7216
+ }, pending.finish(result);
6903
7217
  }
6904
7218
  function ensureHelper() {
6905
7219
  child || (child = (options.spawnProcess ?? spawn5)(options.file, [...options.args], {
@@ -6907,14 +7221,15 @@ function createUnixNativeProcess(options) {
6907
7221
  windowsHide: !0
6908
7222
  }), child.stdin.on("error", () => terminate("computer_native_pipe_failed")), child.stderr.resume(), child.stdout.on("data", (chunk) => {
6909
7223
  if (closed || failedReason) return;
6910
- if (buffer = Buffer.concat([buffer, chunk]), buffer.length > NATIVE_JSON_LIMIT) {
7224
+ let previous = buffer;
7225
+ if (buffer = Buffer.concat([previous, chunk]), previous.fill(0), buffer.length > NATIVE_JSON_LIMIT) {
6911
7226
  terminate("computer_native_result_limit");
6912
7227
  return;
6913
7228
  }
6914
7229
  let boundary = buffer.indexOf(10);
6915
7230
  for (; boundary >= 0; ) {
6916
- let line = buffer.subarray(0, boundary).toString("utf8");
6917
- buffer = buffer.subarray(boundary + 1);
7231
+ let received = buffer, line = received.subarray(0, boundary).toString("utf8");
7232
+ buffer = Buffer.from(received.subarray(boundary + 1)), received.fill(0);
6918
7233
  try {
6919
7234
  receiveLine(line);
6920
7235
  } catch {
@@ -8950,6 +9265,127 @@ function waitForDesktopTurn(previous, signal) {
8950
9265
  })) : previous;
8951
9266
  }
8952
9267
 
9268
+ // src/computer-access/security/desktop-result.ts
9269
+ function rectangle(value) {
9270
+ return { x: value.x, y: value.y, width: value.width, height: value.height };
9271
+ }
9272
+ function projectDesktopFields(result, text) {
9273
+ let capability = (value) => ({
9274
+ supported: value.supported,
9275
+ available: value.available,
9276
+ ...value.reason === void 0 ? {} : { reason: text(value.reason) }
9277
+ }), desktop = result.desktop;
9278
+ return {
9279
+ desktop: {
9280
+ platform: desktop.platform,
9281
+ binding: desktop.binding,
9282
+ name: text(desktop.name),
9283
+ available: desktop.available,
9284
+ ...desktop.reason === void 0 ? {} : { reason: text(desktop.reason) },
9285
+ bounds: rectangle(desktop.bounds),
9286
+ ...desktop.coordinateSpace === void 0 ? {} : { coordinateSpace: desktop.coordinateSpace },
9287
+ capabilities: {
9288
+ capture: capability(desktop.capabilities.capture),
9289
+ accessibility: capability(desktop.capabilities.accessibility),
9290
+ input: capability(desktop.capabilities.input),
9291
+ windows: capability(desktop.capabilities.windows)
9292
+ },
9293
+ targetingGuarantee: desktop.targetingGuarantee
9294
+ },
9295
+ windows: result.windows.map((window) => ({
9296
+ binding: window.binding,
9297
+ title: text(window.title),
9298
+ ...window.application === void 0 ? {} : { application: text(window.application) },
9299
+ bounds: rectangle(window.bounds),
9300
+ focused: window.focused
9301
+ })),
9302
+ ...result.focusedWindow === void 0 ? {} : { focusedWindow: result.focusedWindow },
9303
+ ...result.observation ? {
9304
+ observation: {
9305
+ capturedAt: text(result.observation.capturedAt),
9306
+ region: rectangle(result.observation.region),
9307
+ imageWidth: result.observation.imageWidth,
9308
+ imageHeight: result.observation.imageHeight,
9309
+ accessibility: result.observation.accessibility.map((node) => ({
9310
+ role: text(node.role),
9311
+ ...node.name === void 0 ? {} : { name: text(node.name) },
9312
+ ...node.value === void 0 ? {} : { value: text(node.value) },
9313
+ ...node.bounds === void 0 ? {} : { bounds: rectangle(node.bounds) },
9314
+ ...node.focused === void 0 ? {} : { focused: node.focused }
9315
+ })),
9316
+ accessibilityTruncated: result.observation.accessibilityTruncated
9317
+ }
9318
+ } : {},
9319
+ ...result.dispatch ? {
9320
+ dispatch: {
9321
+ status: result.dispatch.status,
9322
+ requestedInputCount: result.dispatch.requestedInputCount,
9323
+ ...result.dispatch.acceptedInputCount === void 0 ? {} : { acceptedInputCount: result.dispatch.acceptedInputCount },
9324
+ ...result.dispatch.reason === void 0 ? {} : { reason: text(result.dispatch.reason) }
9325
+ }
9326
+ } : {},
9327
+ ...result.error ? {
9328
+ error: {
9329
+ code: text(result.error.code),
9330
+ message: text(result.error.message)
9331
+ }
9332
+ } : {}
9333
+ };
9334
+ }
9335
+ function protectDesktopResult(result, scan = redactSecretText) {
9336
+ let suspected = !1;
9337
+ try {
9338
+ let protectedResult = projectDesktopFields(result, (input) => {
9339
+ let output = scan(input);
9340
+ if (typeof output != "string")
9341
+ throw new Error("desktop_text_scan_failed");
9342
+ return suspected ||= output !== input, output;
9343
+ });
9344
+ return suspected ? (result.image?.bytes.fill(0), {
9345
+ ...protectedResult,
9346
+ ...result.image && !protectedResult.error ? {
9347
+ error: {
9348
+ code: "computer_image_secret_blocked",
9349
+ message: "Image withheld because desktop text contained a suspected secret. The dispatch receipt is unchanged."
9350
+ }
9351
+ } : {}
9352
+ }) : {
9353
+ ...protectedResult,
9354
+ ...result.image ? {
9355
+ image: {
9356
+ mimeType: result.image.mimeType,
9357
+ bytes: result.image.bytes
9358
+ }
9359
+ } : {}
9360
+ };
9361
+ } catch {
9362
+ result.image?.bytes.fill(0);
9363
+ let safe = projectDesktopFields(result, () => "[REDACTED]");
9364
+ return {
9365
+ desktop: {
9366
+ ...safe.desktop,
9367
+ reason: "Desktop content withheld because its protection check failed."
9368
+ },
9369
+ windows: [],
9370
+ ...safe.focusedWindow === void 0 ? {} : { focusedWindow: safe.focusedWindow },
9371
+ ...safe.dispatch ? { dispatch: safe.dispatch } : {},
9372
+ error: {
9373
+ code: "computer_observation_protection_failed",
9374
+ message: "Desktop content withheld because its protection check failed. The dispatch receipt is unchanged."
9375
+ }
9376
+ };
9377
+ }
9378
+ }
9379
+
9380
+ // src/computer-access/security/observed-error.ts
9381
+ function protectObservedError(error, fallback) {
9382
+ try {
9383
+ return redactSecretText(error instanceof Error ? error.message : fallback);
9384
+ } catch {
9385
+ return "Observed error details withheld because the protection check failed.";
9386
+ }
9387
+ }
9388
+
8953
9389
  // src/computer-access/computer/companion-sessions.ts
8954
9390
  var CompanionComputerSessions = class {
8955
9391
  constructor(platform, createBackend = createNativeComputerBackend, resolveTarget = resolveSystemTarget) {
@@ -8973,7 +9409,10 @@ var CompanionComputerSessions = class {
8973
9409
  } catch (error) {
8974
9410
  return failureResult({
8975
9411
  errorCode: "computer_native_operation_failed",
8976
- message: error instanceof Error ? error.message : "The computer operation failed; observe before retrying."
9412
+ message: protectObservedError(
9413
+ error,
9414
+ "The computer operation failed; observe before retrying."
9415
+ )
8977
9416
  });
8978
9417
  }
8979
9418
  };
@@ -9033,12 +9472,13 @@ var CompanionComputerSessions = class {
9033
9472
  async () => {
9034
9473
  let session = await this.acquire(id);
9035
9474
  this.eraseFrame(session);
9036
- let result = await session.backend.execute(request, signal), { image, ...metadata } = result;
9475
+ let result = await session.backend.execute(request, signal), { image: rawImage, ...rawMetadata } = result;
9037
9476
  try {
9038
- readNativeComputerResult(metadata);
9477
+ readNativeComputerResult(rawMetadata);
9039
9478
  } catch (error) {
9040
- throw image?.bytes.fill(0), error;
9479
+ throw rawImage?.bytes.fill(0), error;
9041
9480
  }
9481
+ let { image, ...metadata } = protectDesktopResult(result);
9042
9482
  if (!image)
9043
9483
  return successResult({
9044
9484
  output: "Native desktop observation.",
@@ -9117,96 +9557,45 @@ import { existsSync as existsSync2 } from "node:fs";
9117
9557
  // src/computer-access/companion/observation-filter.ts
9118
9558
  import { createHash as createHash3, createHmac, randomBytes, randomUUID as randomUUID8 } from "node:crypto";
9119
9559
 
9120
- // src/computer-access/companion/observation-redaction.ts
9121
- var REDACTED = "[REDACTED]", CREDENTIAL_KEY_SOURCE = String.raw`(?:[A-Za-z][A-Za-z0-9_-]*\.)*(?:[A-Za-z][A-Za-z0-9]*[-_])*(?:password|passwd|pwd|api[_ -]?key|access[_ -]?token|refresh[_ -]?token|client[_ -]?secret|secret[_ -]?access[_ -]?key|recovery[_ -]?code)`, credentialIndicator = new RegExp(
9122
- String.raw`(?<![\p{L}\p{N}_.-])(?:-{1,2})?(?:${CREDENTIAL_KEY_SOURCE}|(?:proxy-)?authorization)[\s"'\\]*[:=]`,
9123
- "iu"
9124
- );
9125
- function detectionText(input) {
9126
- return input.replace(
9127
- /%([0-7][0-9a-f])/giu,
9128
- (_, hex) => String.fromCharCode(Number.parseInt(hex, 16))
9129
- ).replace(
9130
- /\\(?:u00|x|U000000)([0-7][0-9a-fA-F])/gu,
9131
- (_, hex) => String.fromCharCode(Number.parseInt(hex, 16))
9560
+ // src/shared/passive-observation-self-exclusion.ts
9561
+ var OWN_WEB_UI_TITLES = ["ABot Runtime — Workspace", "ABot Runtime"], BROWSER_WINDOW_NAMES = [
9562
+ "Mozilla Firefox",
9563
+ "Mozilla Firefox (Private Browsing)",
9564
+ "Google Chrome",
9565
+ "Chromium",
9566
+ "Microsoft Edge",
9567
+ "Brave",
9568
+ "Safari"
9569
+ ], BROWSER_WINDOW_SUFFIXES = BROWSER_WINDOW_NAMES.flatMap((browser) => [
9570
+ ` — ${browser}`,
9571
+ ` - ${browser}`
9572
+ ]);
9573
+ function isOwnWebUiWindowTitle(title) {
9574
+ if (typeof title != "string") return !1;
9575
+ if (OWN_WEB_UI_TITLES.includes(title)) return !0;
9576
+ let suffix = BROWSER_WINDOW_SUFFIXES.find(
9577
+ (candidate) => title.endsWith(candidate)
9132
9578
  );
9579
+ return suffix ? OWN_WEB_UI_TITLES.includes(title.slice(0, -suffix.length)) : !1;
9133
9580
  }
9134
- function hasPrivateKeyIndicator(text) {
9135
- return /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----/u.test(text);
9136
- }
9137
- function hasUrlCredentials(text) {
9138
- return /\b[a-z][a-z0-9+.-]*(?::|%3a)(?:\/|%2f){2}[^\s/?#<>]*(?:@|%40)/iu.test(text);
9139
- }
9140
- function hasAuthorizationCredentials(text) {
9141
- for (let match of text.matchAll(
9142
- /\b(Bearer|Basic)[ \t]+([A-Za-z0-9._~+/-]+={0,2})/giu
9143
- )) {
9144
- if (match[1].toLowerCase() === "bearer") return !0;
9145
- let value = match[2];
9146
- if (/^[A-Za-z0-9+/]+={0,2}$/u.test(value) && !(value.length < 8) && Buffer.from(value, "base64").toString("utf8").includes(":"))
9147
- return !0;
9148
- }
9149
- return !1;
9150
- }
9151
- function isAwsAccessKeyValue(value, atEnd) {
9152
- return /^[A-Z0-9]{16}$/u.test(value) ? !0 : atEnd ? /^[A-Z0-9]{4,15}$/u.test(value) : !1;
9153
- }
9154
- function isRecognizedProviderToken(prefix, value, atEnd) {
9155
- if (prefix === "AKIA" || prefix === "ASIA")
9156
- return isAwsAccessKeyValue(value, atEnd);
9157
- if (value.length >= 20) return !0;
9158
- let partialMinimum = prefix === "sk-" ? 8 : 1;
9159
- return atEnd && value.length >= partialMinimum;
9160
- }
9161
- function hasProviderToken(text) {
9162
- let provider = /\b(sk-(?:proj-|svcacct-)?|gh[pousr]_|github_pat_|xox[baprs]-|AKIA|ASIA)([A-Za-z0-9_-]+)/gu;
9163
- for (let match of text.matchAll(provider)) {
9164
- let atEnd = match.index + match[0].length === text.length;
9165
- if (isRecognizedProviderToken(match[1], match[2], atEnd)) return !0;
9166
- }
9167
- return !1;
9168
- }
9169
- function compactJoseSegmentCount(header) {
9170
- try {
9171
- let value = JSON.parse(
9172
- Buffer.from(header, "base64url").toString("utf8")
9173
- );
9174
- if (typeof value != "object" || value === null || Array.isArray(value))
9175
- return;
9176
- let fields = value;
9177
- return typeof fields.alg != "string" ? void 0 : typeof fields.enc == "string" ? 5 : 3;
9178
- } catch {
9179
- return;
9180
- }
9181
- }
9182
- function hasCompactJoseToken(text) {
9183
- let jose = /\b([A-Za-z0-9_-]+)(?:\.[A-Za-z0-9_-]*)+/gu;
9184
- for (let match of text.matchAll(jose)) {
9185
- let parts = match[0].split("."), capturedAtEnd = match.index + match[0].length === text.length;
9186
- for (let index = 0; index < parts.length - 1; index += 1) {
9187
- let expected = compactJoseSegmentCount(parts[index]);
9188
- if (expected !== void 0 && !(expected === 3 && parts[index + 1] === "") && (parts.length - index >= expected || capturedAtEnd))
9189
- return !0;
9190
- }
9191
- }
9192
- return !1;
9581
+ function isOwnObservationApplication(app) {
9582
+ return app.toLowerCase() === "abot";
9193
9583
  }
9194
- function hasSecretIndicator(text) {
9195
- return credentialIndicator.test(text) || hasPrivateKeyIndicator(text) || hasUrlCredentials(text) || hasAuthorizationCredentials(text) || hasProviderToken(text) ? !0 : hasCompactJoseToken(text);
9196
- }
9197
- function redactObservationText(input) {
9198
- return hasSecretIndicator(input) || hasSecretIndicator(detectionText(input)) ? REDACTED : input;
9584
+ function isOwnApplicationObservation(source) {
9585
+ return isOwnObservationApplication(source.app) ? !0 : isOwnWebUiWindowTitle(source.title);
9199
9586
  }
9587
+
9588
+ // src/computer-access/companion/observation-redaction.ts
9200
9589
  function redactObservationSource(source, sourceKey) {
9201
9590
  let redacted = {
9202
- app: redactObservationText(source.app).slice(0, 128),
9203
- windowId: redactObservationText(source.windowId).slice(0, 256),
9591
+ app: redactSecretText(source.app).slice(0, 128),
9592
+ windowId: redactSecretText(source.windowId).slice(0, 256),
9204
9593
  ...source.processId === void 0 ? {} : { processId: source.processId },
9205
9594
  ...source.documentId === void 0 ? {} : {
9206
- documentId: redactObservationText(source.documentId).slice(0, 4096)
9595
+ documentId: redactSecretText(source.documentId).slice(0, 4096)
9207
9596
  },
9208
- ...source.title === void 0 ? {} : { title: redactObservationText(source.title).slice(0, 4096) },
9209
- ...source.url === void 0 ? {} : { url: redactObservationText(source.url).slice(0, 4096) }
9597
+ ...source.title === void 0 ? {} : { title: redactSecretText(source.title).slice(0, 4096) },
9598
+ ...source.url === void 0 ? {} : { url: redactSecretText(source.url).slice(0, 4096) }
9210
9599
  };
9211
9600
  return [
9212
9601
  "app",
@@ -9267,26 +9656,6 @@ function isPassiveCollectorEvent(value) {
9267
9656
  }
9268
9657
 
9269
9658
  // src/computer-access/companion/observation-filter.ts
9270
- var OWN_WEB_UI_TITLES = ["ABot Runtime — Workspace", "ABot Runtime"], BROWSER_WINDOW_NAMES = [
9271
- "Mozilla Firefox",
9272
- "Mozilla Firefox (Private Browsing)",
9273
- "Google Chrome",
9274
- "Chromium",
9275
- "Microsoft Edge",
9276
- "Brave",
9277
- "Safari"
9278
- ], BROWSER_WINDOW_SUFFIXES = BROWSER_WINDOW_NAMES.flatMap((browser) => [
9279
- ` — ${browser}`,
9280
- ` - ${browser}`
9281
- ]);
9282
- function isOwnWebUiWindowTitle(title) {
9283
- if (typeof title != "string") return !1;
9284
- if (OWN_WEB_UI_TITLES.includes(title)) return !0;
9285
- let suffix = BROWSER_WINDOW_SUFFIXES.find(
9286
- (candidate) => title.endsWith(candidate)
9287
- );
9288
- return suffix ? OWN_WEB_UI_TITLES.includes(title.slice(0, -suffix.length)) : !1;
9289
- }
9290
9659
  function hasBoundedSourceMetadata(source) {
9291
9660
  if (!isObservationOwner(source.app) || typeof source.windowId != "string" || source.windowId.length === 0 || source.windowId.length > 256) return !1;
9292
9661
  for (let field of ["documentId", "title", "url"])
@@ -9322,7 +9691,7 @@ var ObservationFilter = class {
9322
9691
  accept(value) {
9323
9692
  if (isPassiveCollectorEvent(value) && value.type === "status") {
9324
9693
  value.state === "paused" && (this.lastSource = void 0);
9325
- let reason = value.reason === void 0 ? void 0 : redactObservationText(value.reason).slice(0, 512), identity = JSON.stringify([value.state, reason]);
9694
+ let reason = value.reason === void 0 ? void 0 : redactSecretText(value.reason).slice(0, 512), identity = JSON.stringify([value.state, reason]);
9326
9695
  return identity === this.lastStatus ? void 0 : (this.lastStatus = identity, {
9327
9696
  type: "status",
9328
9697
  state: value.state,
@@ -9340,7 +9709,7 @@ var ObservationFilter = class {
9340
9709
  url: value.source.url
9341
9710
  };
9342
9711
  if (!hasBoundedSourceMetadata(rawSource)) return;
9343
- if (isOwnWebUiWindowTitle(rawSource.title)) {
9712
+ if (isOwnApplicationObservation(rawSource)) {
9344
9713
  this.lastSource = void 0;
9345
9714
  return;
9346
9715
  }
@@ -9359,11 +9728,11 @@ var ObservationFilter = class {
9359
9728
  rawSource.title,
9360
9729
  rawSource.url
9361
9730
  ])
9362
- ).digest("hex"), source = redactObservationSource(rawSource, sourceKey), content = redactObservationText(value.content).replace(/\r\n?/gu, `
9731
+ ).digest("hex"), source = redactObservationSource(rawSource, sourceKey), content = redactSecretText(value.content).replace(/\r\n?/gu, `
9363
9732
  `).replace(/[ \t]+\n/gu, `
9364
9733
  `).trim(), fingerprint = createHash3("sha256").update(content).digest("hex"), previous = this.fingerprints.get(sourceKey), duplicate = previous?.fingerprint === fingerprint;
9365
9734
  if (duplicate && this.lastSource === sourceKey) return;
9366
- let truncated = content.length > OBSERVATION_CONTENT_LIMIT, coverageReason = typeof value.coverageReason == "string" ? redactObservationText(value.coverageReason).slice(0, 512) : void 0;
9735
+ let truncated = content.length > OBSERVATION_CONTENT_LIMIT, coverageReason = typeof value.coverageReason == "string" ? redactSecretText(value.coverageReason).slice(0, 512) : void 0;
9367
9736
  truncated && (coverageReason = "content_limit");
9368
9737
  let observation = {
9369
9738
  id: randomUUID8(),
@@ -10038,8 +10407,10 @@ function desktopCollectorCommand(platform) {
10038
10407
  return { file: "python3", args: ["-u", "-c", LINUX_OBSERVATION_SCRIPT] };
10039
10408
  }
10040
10409
  function startDesktopCollector(options) {
10041
- let command = desktopCollectorCommand(options.platform ?? process.platform), child, closed = !1, received = Buffer.alloc(0), terminalStatus = !1, filter = new ObservationFilter(options.excludedApplications), close = () => {
10042
- if (closed = !0, !!child?.pid) {
10410
+ let command = desktopCollectorCommand(options.platform ?? process.platform), child, closed = !1, stopped = !1, confirmStopped = () => {
10411
+ stopped || (stopped = !0, options.onStopped?.());
10412
+ }, received = Buffer.alloc(0), terminalStatus = !1, filter = new ObservationFilter(options.excludedApplications), close = () => {
10413
+ if (closed = !0, !(stopped || !child?.pid)) {
10043
10414
  if (process.platform !== "win32") {
10044
10415
  try {
10045
10416
  process.kill(-child.pid, "SIGTERM");
@@ -10056,7 +10427,7 @@ function startDesktopCollector(options) {
10056
10427
  type: "status",
10057
10428
  state: "unavailable",
10058
10429
  reason: "platform_unsupported"
10059
- }), { close };
10430
+ }), confirmStopped(), { close };
10060
10431
  if (process.platform === "darwin")
10061
10432
  try {
10062
10433
  let developerDirectory = execFileSync("/usr/bin/xcode-select", ["-p"], {
@@ -10070,17 +10441,23 @@ function startDesktopCollector(options) {
10070
10441
  type: "status",
10071
10442
  state: "unavailable",
10072
10443
  reason: "macos_swift_tools_unavailable"
10073
- }), { close };
10444
+ }), confirmStopped(), { close };
10074
10445
  }
10075
- return options.onEvent({ type: "status", state: "starting" }), child = (options.spawnProcess ?? spawn6)(command.file, command.args, {
10076
- windowsHide: !0,
10077
- detached: process.platform !== "win32",
10078
- stdio: ["pipe", "pipe", "pipe"],
10079
- env: {
10080
- ...process.env,
10081
- ABOT_OBSERVATION_EXCLUSIONS: JSON.stringify(options.excludedApplications)
10082
- }
10083
- }), child.stdin?.on("error", () => {
10446
+ options.onEvent({ type: "status", state: "starting" });
10447
+ try {
10448
+ child = (options.spawnProcess ?? spawn6)(command.file, command.args, {
10449
+ windowsHide: !0,
10450
+ detached: process.platform !== "win32",
10451
+ stdio: ["pipe", "pipe", "pipe"],
10452
+ env: {
10453
+ ...process.env,
10454
+ ABOT_OBSERVATION_EXCLUSIONS: JSON.stringify(options.excludedApplications)
10455
+ }
10456
+ });
10457
+ } catch {
10458
+ return options.onEvent({ type: "status", state: "failed", reason: "collector_start_failed" }), closed = !0, confirmStopped(), { close };
10459
+ }
10460
+ return child.stdin?.on("error", () => {
10084
10461
  }), child.stdin?.end(command.input), child.stderr?.resume(), child.stdout?.on("data", (chunk) => {
10085
10462
  if (closed) return;
10086
10463
  if (received = Buffer.concat([received, chunk]), received.length > OBSERVATION_WIRE_LIMIT * 2) {
@@ -10109,17 +10486,26 @@ function startDesktopCollector(options) {
10109
10486
  received = received.subarray(boundary + 1), boundary = received.indexOf(10);
10110
10487
  }
10111
10488
  }), child.once("error", () => {
10112
- closed || (options.onEvent({
10113
- type: "status",
10114
- state: "unavailable",
10115
- reason: "collector_dependency_unavailable"
10116
- }), close());
10489
+ try {
10490
+ if (closed) return;
10491
+ options.onEvent({
10492
+ type: "status",
10493
+ state: "unavailable",
10494
+ reason: "collector_dependency_unavailable"
10495
+ }), close();
10496
+ } finally {
10497
+ child?.pid || confirmStopped();
10498
+ }
10117
10499
  }), child.once("exit", (code) => {
10118
- closed || (terminalStatus || options.onEvent({
10119
- type: "status",
10120
- state: "unavailable",
10121
- reason: code === 0 ? "collector_stopped" : "collector_start_failed"
10122
- }), close());
10500
+ try {
10501
+ !closed && !terminalStatus && options.onEvent({
10502
+ type: "status",
10503
+ state: "unavailable",
10504
+ reason: code === 0 ? "collector_stopped" : "collector_start_failed"
10505
+ });
10506
+ } finally {
10507
+ closed = !0, confirmStopped();
10508
+ }
10123
10509
  }), { close };
10124
10510
  }
10125
10511
 
@@ -10298,7 +10684,7 @@ async function connectNativeHost(options) {
10298
10684
  options.signal.aborted && (await ownedNotifications?.close(), options.signal.throwIfAborted());
10299
10685
  let commandOutput = options.commandOutputStateDir && !options.handlers ? new CompanionCommandOutput(options.commandOutputStateDir) : void 0, handlers = options.handlers ?? {
10300
10686
  ...commandOutput?.handlers(),
10301
- ...createSystemHandlers(),
10687
+ ...createSystemHandlers(void 0, void 0, void 0, systemResultProtection),
10302
10688
  ...computers.handlers(),
10303
10689
  ...notifications.handlers(),
10304
10690
  ...createNativePermissionHandlers(options.identity.os)
@@ -10393,7 +10779,7 @@ async function connectNativeHost(options) {
10393
10779
  assertNativeOperationTarget(message, options.identity.os);
10394
10780
  } catch (error) {
10395
10781
  if (!(error instanceof NativeOperationInputError)) throw error;
10396
- sendResult(message.id, operationFailure(error.message, error.code));
10782
+ sendResult(message.id, operationFailure(redactSecretText(error.message), error.code));
10397
10783
  return;
10398
10784
  }
10399
10785
  let handler = handlers[message.operation];
@@ -10447,6 +10833,7 @@ async function connectNativeHost(options) {
10447
10833
  version: 1,
10448
10834
  identity: options.identity,
10449
10835
  capabilities: [
10836
+ ...options.handlers ? [] : [HOST_SECRET_PROTECTION_CAPABILITY],
10450
10837
  OBSERVATION_CAPABILITY,
10451
10838
  COMPUTER_CAPABILITY,
10452
10839
  ...commandOutput ? [SYSTEM_OUTPUT_CAPABILITY] : [],
@@ -10793,8 +11180,23 @@ async function installLockDirectory(lockPath, token, ownerIdentity) {
10793
11180
  }
10794
11181
  }
10795
11182
 
11183
+ // src/runtime/adapters/long-term-memory/file-lock/path-observation.ts
11184
+ import { lstat as lstat5 } from "node:fs/promises";
11185
+ async function observeLockReadFailure(path, error) {
11186
+ if (!isWindowsLockReadDenial(error)) return error;
11187
+ try {
11188
+ await lstat5(path);
11189
+ } catch (observedError) {
11190
+ if (fileSystemErrorCode(observedError) === "ENOENT") return observedError;
11191
+ }
11192
+ return error;
11193
+ }
11194
+ function isWindowsLockReadDenial(error) {
11195
+ return process.platform !== "win32" ? !1 : fileSystemErrorCode(error) === "EPERM";
11196
+ }
11197
+
10796
11198
  // src/runtime/adapters/long-term-memory/file-lock/snapshot.ts
10797
- import { lstat as lstat5, readdir as readdir3 } from "node:fs/promises";
11199
+ import { lstat as lstat6, readdir as readdir3 } from "node:fs/promises";
10798
11200
  import { join as join17 } from "node:path";
10799
11201
 
10800
11202
  // src/runtime/adapters/long-term-memory/file-lock/owner-record.ts
@@ -10804,10 +11206,13 @@ import { join as join16 } from "node:path";
10804
11206
  async function readOwnerRecord(lockPath, entryName, expectedToken, directoryModifiedAtMs) {
10805
11207
  let handle;
10806
11208
  try {
11209
+ let ownerPath = join16(lockPath, LEASE_DIRECTORY_NAME, entryName);
10807
11210
  handle = await open4(
10808
- join16(lockPath, LEASE_DIRECTORY_NAME, entryName),
11211
+ ownerPath,
10809
11212
  constants3.O_RDONLY | constants3.O_NOFOLLOW
10810
- );
11213
+ ).catch(async (error) => {
11214
+ throw await observeLockReadFailure(ownerPath, error);
11215
+ });
10811
11216
  let before = await handle.stat({ bigint: !0 }), modifiedAtMs = Math.max(
10812
11217
  directoryModifiedAtMs,
10813
11218
  Number(before.mtimeMs)
@@ -10904,8 +11309,8 @@ async function readLockSnapshot(lockPath) {
10904
11309
  let lockEntries;
10905
11310
  try {
10906
11311
  lockEntries = await readdir3(lockPath, { withFileTypes: !0 });
10907
- } catch (error) {
10908
- let code = fileSystemErrorCode(error);
11312
+ } catch (readError) {
11313
+ let error = await observeLockReadFailure(lockPath, readError), code = fileSystemErrorCode(error);
10909
11314
  if (code === "ENOENT") return;
10910
11315
  if (code === "ENOTDIR")
10911
11316
  return Object.freeze({ kind: "legacy_file" });
@@ -10923,8 +11328,9 @@ async function readLockSnapshot(lockPath) {
10923
11328
  }
10924
11329
  async function readLockInfo(lockPath) {
10925
11330
  try {
10926
- return await lstat5(lockPath);
10927
- } catch (error) {
11331
+ return await lstat6(lockPath);
11332
+ } catch (readError) {
11333
+ let error = await observeLockReadFailure(lockPath, readError);
10928
11334
  if (fileSystemErrorCode(error) === "ENOENT") return;
10929
11335
  throw error;
10930
11336
  }
@@ -10932,10 +11338,11 @@ async function readLockInfo(lockPath) {
10932
11338
  async function readLeaseSnapshot(lockPath, lockModifiedAtMs) {
10933
11339
  let leasePath = join17(lockPath, LEASE_DIRECTORY_NAME), leaseInfo, leaseEntries;
10934
11340
  try {
10935
- if (leaseInfo = await lstat5(leasePath), !leaseInfo.isDirectory())
11341
+ if (leaseInfo = await lstat6(leasePath), !leaseInfo.isDirectory())
10936
11342
  return invalidLeaseSnapshot(lockModifiedAtMs);
10937
11343
  leaseEntries = await readdir3(leasePath, { withFileTypes: !0 });
10938
- } catch (error) {
11344
+ } catch (readError) {
11345
+ let error = await observeLockReadFailure(leasePath, readError);
10939
11346
  if (fileSystemErrorCode(error) === "ENOENT")
10940
11347
  return invalidLeaseSnapshot(lockModifiedAtMs);
10941
11348
  throw error;
@@ -11009,7 +11416,7 @@ async function acquireFileLock(lockPath, options) {
11009
11416
  return await installLockDirectory(lockPath, token, options.ownerIdentity), createRelease(lockPath, token, options.releaseMode);
11010
11417
  } catch (error) {
11011
11418
  if (!isLockContention(error)) throw error;
11012
- if (await removeAbandonedLock(lockPath, processIsAlive)) continue;
11419
+ if (await removeAbandonedLock(lockPath, processIsAlive, deadline, retryDelayMs)) continue;
11013
11420
  if (Date.now() >= deadline)
11014
11421
  throw new Error("long_term_memory_store_lock_timeout");
11015
11422
  await delay3(Math.min(retryDelayMs, Math.max(deadline - Date.now(), 0)));
@@ -11031,10 +11438,19 @@ function createRelease(lockPath, token, releaseMode) {
11031
11438
  function requiresSynchronousRelease(mode) {
11032
11439
  return mode === "synchronous";
11033
11440
  }
11034
- async function removeAbandonedLock(lockPath, processIsAlive) {
11035
- let snapshot = await readLockSnapshot(lockPath);
11441
+ async function removeAbandonedLock(lockPath, processIsAlive, deadline, retryDelayMs) {
11442
+ let snapshot = await readContendedSnapshot(lockPath, deadline, retryDelayMs);
11036
11443
  return snapshot ? snapshot.kind === "legacy_file" || !snapshot.reclaimable || await hasLiveObservedOwner(snapshot, processIsAlive) ? !1 : snapshot.record && snapshot.ownerFileName ? removeObservedOwner(lockPath, snapshot.ownerFileName) : Date.now() - snapshot.modifiedAtMs < 3e4 ? !1 : snapshot.ownerFileName ? removeObservedOwner(lockPath, snapshot.ownerFileName) : removeEmptyLockTree(lockPath, snapshot.hasLeaseDirectory) : !0;
11037
11444
  }
11445
+ async function readContendedSnapshot(lockPath, deadline, retryDelayMs) {
11446
+ for (; ; )
11447
+ try {
11448
+ return await readLockSnapshot(lockPath);
11449
+ } catch (error) {
11450
+ if (!isWindowsLockReadDenial(error) || Date.now() >= deadline) throw error;
11451
+ await delay3(Math.min(retryDelayMs, Math.max(deadline - Date.now(), 0)));
11452
+ }
11453
+ }
11038
11454
  async function hasLiveObservedOwner(snapshot, processIsAlive) {
11039
11455
  return snapshot.ownerPid === void 0 ? !1 : processIsAlive(snapshot.ownerPid, snapshot.record?.ownerIdentity);
11040
11456
  }
@@ -11054,13 +11470,14 @@ function delay3(milliseconds) {
11054
11470
  }
11055
11471
 
11056
11472
  // src/runtime/local-host/private-directory.ts
11057
- import { lstat as lstat6, mkdir as mkdir5, mkdtemp, rename as rename5, rmdir as rmdir2 } from "node:fs/promises";
11473
+ import { lstat as lstat7, mkdir as mkdir5, mkdtemp, rename as rename5, rmdir as rmdir2 } from "node:fs/promises";
11058
11474
  import { basename as basename4, dirname as dirname4, join as join19 } from "node:path";
11059
11475
 
11060
11476
  // src/runtime/local-host/windows-private-access.ts
11061
11477
  import { execFile as execFile5 } from "node:child_process";
11062
11478
  import { promisify as promisify5 } from "node:util";
11063
11479
  var execute = promisify5(execFile5), privateAccessScript = `
11480
+ $env:PSModulePath = "$PSHOME\\Modules"
11064
11481
  $ErrorActionPreference = 'Stop'
11065
11482
  $target = $env:ABOT_LOCAL_HOST_PRIVATE_PATH
11066
11483
  $current = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
@@ -11113,7 +11530,7 @@ async function verifyWindowsPrivateAccess(path, newlyCreatedDirectory = !1) {
11113
11530
  }
11114
11531
 
11115
11532
  // src/runtime/local-host/private-access.ts
11116
- async function assertPrivateRuntimeAccess(path, stat4, errorCode2, newlyCreatedDirectory = !1) {
11533
+ async function assertPrivateRuntimeAccess(path, stat3, errorCode2, newlyCreatedDirectory = !1) {
11117
11534
  if (process.platform === "win32")
11118
11535
  try {
11119
11536
  await verifyWindowsPrivateAccess(path, newlyCreatedDirectory);
@@ -11121,19 +11538,19 @@ async function assertPrivateRuntimeAccess(path, stat4, errorCode2, newlyCreatedD
11121
11538
  } catch {
11122
11539
  throw new Error(errorCode2);
11123
11540
  }
11124
- if ((stat4.mode & 63) !== 0) throw new Error(errorCode2);
11125
- if (process.getuid?.() !== stat4.uid) throw new Error(errorCode2);
11541
+ if ((stat3.mode & 63) !== 0) throw new Error(errorCode2);
11542
+ if (process.getuid?.() !== stat3.uid) throw new Error(errorCode2);
11126
11543
  }
11127
11544
 
11128
11545
  // src/runtime/local-host/private-directory.ts
11129
11546
  async function ensurePrivateRuntimeDirectory(directory) {
11130
11547
  process.platform === "win32" ? await installWindowsPrivateDirectory(directory) : await mkdir5(directory, { recursive: !0, mode: 448 });
11131
- let stat4 = await lstat6(directory);
11132
- if (!stat4.isDirectory() || stat4.isSymbolicLink())
11548
+ let stat3 = await lstat7(directory);
11549
+ if (!stat3.isDirectory() || stat3.isSymbolicLink())
11133
11550
  throw new Error("local_runtime_directory_not_private");
11134
11551
  await assertPrivateRuntimeAccess(
11135
11552
  directory,
11136
- stat4,
11553
+ stat3,
11137
11554
  "local_runtime_directory_not_private"
11138
11555
  );
11139
11556
  }
@@ -11161,7 +11578,7 @@ async function installWindowsPrivateDirectory(directory) {
11161
11578
  }
11162
11579
  async function hasExistingPath(path) {
11163
11580
  try {
11164
- return await lstat6(path), !0;
11581
+ return await lstat7(path), !0;
11165
11582
  } catch (error) {
11166
11583
  if (isMissingPath(error)) return !1;
11167
11584
  throw error;
@@ -11177,12 +11594,12 @@ import { join as join25 } from "node:path";
11177
11594
  // src/computer-access/companion/autostart.ts
11178
11595
  import { execFile as execFile6 } from "node:child_process";
11179
11596
  import {
11180
- lstat as lstat7,
11597
+ lstat as lstat8,
11181
11598
  mkdir as mkdir6,
11182
11599
  readFile as readFile10,
11183
11600
  rename as rename6,
11184
11601
  unlink as unlink5,
11185
- writeFile as writeFile6
11602
+ writeFile as writeFile7
11186
11603
  } from "node:fs/promises";
11187
11604
  import { dirname as dirname5, join as join20, posix } from "node:path";
11188
11605
  import { promisify as promisify6 } from "node:util";
@@ -11279,12 +11696,12 @@ function errorCode(error) {
11279
11696
  return error && typeof error == "object" && "code" in error ? error.code : void 0;
11280
11697
  }
11281
11698
  async function existingOwnedRegistration(path) {
11282
- let stat4 = await lstat7(path).catch((error) => {
11699
+ let stat3 = await lstat8(path).catch((error) => {
11283
11700
  if (errorCode(error) !== "ENOENT")
11284
11701
  throw error;
11285
11702
  });
11286
- if (!stat4) return !1;
11287
- if (!stat4.isFile() || stat4.isSymbolicLink() || stat4.size > 16384)
11703
+ if (!stat3) return !1;
11704
+ if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.size > 16384)
11288
11705
  throw new Error(
11289
11706
  "Refusing to change an unexpected host startup registration."
11290
11707
  );
@@ -11321,7 +11738,7 @@ async function installNativeAutostart(options) {
11321
11738
  await existingOwnedRegistration(path) && options.platform === "darwin" && await unloadMacRegistration(options), await mkdir6(dirname5(path), { recursive: !0 });
11322
11739
  let temporary = `${path}.${randomUUID10()}.tmp`;
11323
11740
  try {
11324
- await writeFile6(temporary, renderNativeAutostart(options), {
11741
+ await writeFile7(temporary, renderNativeAutostart(options), {
11325
11742
  encoding: "utf8",
11326
11743
  mode: 384,
11327
11744
  flag: "wx"
@@ -11344,7 +11761,7 @@ async function uninstallNativeAutostart(options) {
11344
11761
 
11345
11762
  // src/computer-access/companion/install-link-registration.ts
11346
11763
  import { execFile as execFile8 } from "node:child_process";
11347
- import { lstat as lstat8, mkdir as mkdir7, readFile as readFile11, rm as rm4, writeFile as writeFile7 } from "node:fs/promises";
11764
+ import { lstat as lstat9, mkdir as mkdir7, readFile as readFile11, rm as rm5, writeFile as writeFile8 } from "node:fs/promises";
11348
11765
  import { dirname as dirname6, join as join22, posix as posix2 } from "node:path";
11349
11766
  import { promisify as promisify8 } from "node:util";
11350
11767
 
@@ -11419,7 +11836,8 @@ function renderMacInstallLinkHandler(options) {
11419
11836
  let literal = (value) => JSON.stringify(value);
11420
11837
  return `ObjC.import('Foundation');
11421
11838
  function openDocuments() {}
11422
- function openLocation(url) {
11839
+ // JXA dispatches the macOS Get URL (GURL/GURL) AppleEvent to this exact name.
11840
+ function GURLGURL(url) {
11423
11841
  var task = $.NSTask.alloc.init;
11424
11842
  task.launchPath = ${literal(options.nodePath)};
11425
11843
  task.arguments = [${literal(options.cliPath)}, 'host', 'open-link', String(url)];
@@ -11490,12 +11908,12 @@ async function run(options, file, args) {
11490
11908
  });
11491
11909
  }
11492
11910
  async function existingOwnedDirectory(path) {
11493
- let stat4 = await lstat8(path).catch((error) => {
11911
+ let stat3 = await lstat9(path).catch((error) => {
11494
11912
  if (error.code !== "ENOENT")
11495
11913
  throw error;
11496
11914
  });
11497
- if (!stat4) return !1;
11498
- if (!stat4.isDirectory() || stat4.isSymbolicLink())
11915
+ if (!stat3) return !1;
11916
+ if (!stat3.isDirectory() || stat3.isSymbolicLink())
11499
11917
  throw new Error("Installation-link directory is not owned.");
11500
11918
  if (await readFile11(join22(path, ".owner"), "utf8") !== OWNER)
11501
11919
  throw new Error("Installation-link directory is not owned.");
@@ -11515,11 +11933,11 @@ function linuxDesktopPath(options) {
11515
11933
  );
11516
11934
  }
11517
11935
  async function requireOwnedLinuxRegistration(path) {
11518
- let stat4 = await lstat8(path).catch((error) => {
11936
+ let stat3 = await lstat9(path).catch((error) => {
11519
11937
  if (error.code !== "ENOENT")
11520
11938
  throw error;
11521
11939
  });
11522
- if (stat4 && (!stat4.isFile() || stat4.isSymbolicLink() || !(await readFile11(path, "utf8")).includes("# " + OWNER)))
11940
+ if (stat3 && (!stat3.isFile() || stat3.isSymbolicLink() || !(await readFile11(path, "utf8")).includes("# " + OWNER)))
11523
11941
  throw new Error("Installation-link desktop registration is not owned.");
11524
11942
  }
11525
11943
  function isAvailableLinuxInstallScheme(handler) {
@@ -11536,12 +11954,12 @@ async function requireAvailableLinuxInstallScheme() {
11536
11954
  }
11537
11955
  async function installCompanionInstallLinks(options) {
11538
11956
  let directory = registrationDirectory(options);
11539
- if (await existingOwnedDirectory(directory) || (await ensurePrivateRuntimeDirectory(directory), await writeFile7(join22(directory, ".owner"), OWNER, {
11957
+ if (await existingOwnedDirectory(directory) || (await ensurePrivateRuntimeDirectory(directory), await writeFile8(join22(directory, ".owner"), OWNER, {
11540
11958
  flag: "wx",
11541
11959
  mode: 384
11542
11960
  })), options.platform === "win32") {
11543
11961
  let launcher = windowsInstallLinkLauncherPath(options);
11544
- await writeFile7(launcher, renderWindowsInstallLinkLauncher(options), {
11962
+ await writeFile8(launcher, renderWindowsInstallLinkLauncher(options), {
11545
11963
  mode: 384
11546
11964
  }), await run(options, "powershell.exe", [
11547
11965
  "-NoProfile",
@@ -11556,7 +11974,7 @@ async function installCompanionInstallLinks(options) {
11556
11974
  }
11557
11975
  if (options.platform === "linux") {
11558
11976
  let desktop = linuxDesktopPath(options);
11559
- await requireOwnedLinuxRegistration(desktop), await requireAvailableLinuxInstallScheme(), await mkdir7(dirname6(desktop), { recursive: !0, mode: 448 }), await writeFile7(desktop, renderLinuxInstallLinkDesktop(options), {
11977
+ await requireOwnedLinuxRegistration(desktop), await requireAvailableLinuxInstallScheme(), await mkdir7(dirname6(desktop), { recursive: !0, mode: 448 }), await writeFile8(desktop, renderLinuxInstallLinkDesktop(options), {
11560
11978
  mode: 384
11561
11979
  }), await run(options, "xdg-mime", [
11562
11980
  "default",
@@ -11568,9 +11986,9 @@ async function installCompanionInstallLinks(options) {
11568
11986
  if (options.platform === "darwin") {
11569
11987
  await requireAvailableMacInstallScheme();
11570
11988
  let source = join22(directory, "handler.js"), app = join22(directory, "ABot Install.app");
11571
- await writeFile7(source, renderMacInstallLinkHandler(options), {
11989
+ await writeFile8(source, renderMacInstallLinkHandler(options), {
11572
11990
  mode: 384
11573
- }), await rm4(app, { recursive: !0, force: !0 }), await run(options, "/usr/bin/osacompile", [
11991
+ }), await rm5(app, { recursive: !0, force: !0 }), await run(options, "/usr/bin/osacompile", [
11574
11992
  "-l",
11575
11993
  "JavaScript",
11576
11994
  "-o",
@@ -11614,13 +12032,13 @@ async function uninstallCompanionInstallLinks(options) {
11614
12032
  ).toString("base64")
11615
12033
  ]), options.platform === "linux") {
11616
12034
  let desktop = linuxDesktopPath(options);
11617
- await requireOwnedLinuxRegistration(desktop), await rm4(desktop, { force: !0 });
12035
+ await requireOwnedLinuxRegistration(desktop), await rm5(desktop, { force: !0 });
11618
12036
  }
11619
12037
  options.platform === "darwin" && await run(
11620
12038
  options,
11621
12039
  "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister",
11622
12040
  ["-u", join22(directory, "ABot Install.app")]
11623
- ), await rm4(directory, { recursive: !0 });
12041
+ ), await rm5(directory, { recursive: !0 });
11624
12042
  }
11625
12043
  }
11626
12044
 
@@ -11738,7 +12156,7 @@ async function stopOwnedNativeCompanion(stateDir, overrides = {}) {
11738
12156
  import { execFile as execFile10 } from "node:child_process";
11739
12157
  import { createHash as createHash5, randomUUID as randomUUID11 } from "node:crypto";
11740
12158
  import { constants as constants4 } from "node:fs";
11741
- import { lstat as lstat9, open as open5, rename as rename7, unlink as unlink6 } from "node:fs/promises";
12159
+ import { lstat as lstat10, open as open5, rename as rename7, unlink as unlink6 } from "node:fs/promises";
11742
12160
  import { join as join24 } from "node:path";
11743
12161
  import { promisify as promisify10 } from "node:util";
11744
12162
  var executeFile8 = promisify10(execFile10), NATIVE_RUNTIME_INSTALLATION_FAILURE = "The Mac companion runtime could not be prepared safely. The saved pairing was not changed. Check the local Node.js installation and run setup again.";
@@ -11751,14 +12169,14 @@ function isAbsentRuntimePath(error) {
11751
12169
  function hasSameRuntimeIdentity(left, right) {
11752
12170
  return left.dev !== right.dev || left.ino !== right.ino || left.size !== right.size || left.mtimeMs !== right.mtimeMs ? !1 : left.ctimeMs === right.ctimeMs;
11753
12171
  }
11754
- function hasTrustedRuntimeSource(stat4) {
11755
- return !stat4.isFile() || stat4.isSymbolicLink() || (stat4.mode & 73) === 0 || (stat4.mode & 18) !== 0 ? !1 : stat4.uid === 0 ? !0 : stat4.uid === process.getuid?.();
12172
+ function hasTrustedRuntimeSource(stat3) {
12173
+ return !stat3.isFile() || stat3.isSymbolicLink() || (stat3.mode & 73) === 0 || (stat3.mode & 18) !== 0 ? !1 : stat3.uid === 0 ? !0 : stat3.uid === process.getuid?.();
11756
12174
  }
11757
- async function requireManagedRuntimeFile(path, stat4) {
11758
- if (!stat4.isFile() || stat4.isSymbolicLink() || stat4.nlink !== 1 || (stat4.mode & 511) !== 320) throw runtimeInstallationFailure();
12175
+ async function requireManagedRuntimeFile(path, stat3) {
12176
+ if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.nlink !== 1 || (stat3.mode & 511) !== 320) throw runtimeInstallationFailure();
11759
12177
  await assertPrivateRuntimeAccess(
11760
12178
  path,
11761
- stat4,
12179
+ stat3,
11762
12180
  NATIVE_RUNTIME_INSTALLATION_FAILURE
11763
12181
  );
11764
12182
  }
@@ -11772,21 +12190,21 @@ async function streamRuntimeDigest(handle) {
11772
12190
  return hash.digest("hex");
11773
12191
  }
11774
12192
  async function readRuntimeFile(path, managed) {
11775
- let stat4 = await lstat9(path).catch((error) => {
12193
+ let stat3 = await lstat10(path).catch((error) => {
11776
12194
  if (!isAbsentRuntimePath(error))
11777
12195
  throw error;
11778
12196
  });
11779
- if (!stat4) return;
11780
- if (managed && await requireManagedRuntimeFile(path, stat4), !managed && !hasTrustedRuntimeSource(stat4))
12197
+ if (!stat3) return;
12198
+ if (managed && await requireManagedRuntimeFile(path, stat3), !managed && !hasTrustedRuntimeSource(stat3))
11781
12199
  throw runtimeInstallationFailure();
11782
12200
  let handle = await open5(path, constants4.O_RDONLY | constants4.O_NOFOLLOW);
11783
12201
  try {
11784
- if (!hasSameRuntimeIdentity(stat4, await handle.stat()))
12202
+ if (!hasSameRuntimeIdentity(stat3, await handle.stat()))
11785
12203
  throw runtimeInstallationFailure();
11786
12204
  let digest = await streamRuntimeDigest(handle);
11787
- if (!hasSameRuntimeIdentity(stat4, await handle.stat()) || !hasSameRuntimeIdentity(stat4, await lstat9(path)))
12205
+ if (!hasSameRuntimeIdentity(stat3, await handle.stat()) || !hasSameRuntimeIdentity(stat3, await lstat10(path)))
11788
12206
  throw runtimeInstallationFailure();
11789
- return { stat: stat4, digest };
12207
+ return { stat: stat3, digest };
11790
12208
  } finally {
11791
12209
  await handle.close();
11792
12210
  }
@@ -11844,14 +12262,14 @@ async function requireUnchangedRuntimeTarget(path, expected) {
11844
12262
  }
11845
12263
  async function requireUnchangedRuntimeDirectory(path, expected) {
11846
12264
  await ensurePrivateRuntimeDirectory(path);
11847
- let current = await lstat9(path);
12265
+ let current = await lstat10(path);
11848
12266
  if (expected.dev !== current.dev || expected.ino !== current.ino) throw runtimeInstallationFailure();
11849
12267
  }
11850
12268
  async function installManagedRuntime(startup, dependencies) {
11851
12269
  await ensurePrivateRuntimeDirectory(startup.stateDir);
11852
- let stateIdentity = await lstat9(startup.stateDir), directory = join24(startup.stateDir, "runtime");
12270
+ let stateIdentity = await lstat10(startup.stateDir), directory = join24(startup.stateDir, "runtime");
11853
12271
  await ensurePrivateRuntimeDirectory(directory);
11854
- let directoryIdentity = await lstat9(directory), target = join24(directory, "node"), source = await readRuntimeFile(startup.nodePath, !1);
12272
+ let directoryIdentity = await lstat10(directory), target = join24(directory, "node"), source = await readRuntimeFile(startup.nodePath, !1);
11855
12273
  if (!source) throw runtimeInstallationFailure();
11856
12274
  let existing = await readRuntimeFile(target, !0), expectedVersion = await runtimeVersion(startup.nodePath, dependencies);
11857
12275
  if (existing?.digest === source.digest)
@@ -12042,9 +12460,9 @@ function printHostHelp() {
12042
12460
  function createHostCompanionState() {
12043
12461
  return createNativeHostState(join26(homedir4(), ".abot", "host-companion"), {
12044
12462
  ensureDirectory: ensurePrivateRuntimeDirectory,
12045
- assertFile: (path, stat4) => assertPrivateRuntimeAccess(
12463
+ assertFile: (path, stat3) => assertPrivateRuntimeAccess(
12046
12464
  path,
12047
- stat4,
12465
+ stat3,
12048
12466
  "host_companion_state_not_private"
12049
12467
  )
12050
12468
  });