@abot-ai/runtime 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (443) hide show
  1. package/dist/src/capabilities/tool-request-resources.d.ts +3 -0
  2. package/dist/src/cli/abot.js +2 -0
  3. package/dist/src/cli/host-companion-bundle.mjs +751 -333
  4. package/dist/src/computer-access/collection-consent.d.ts +9 -0
  5. package/dist/src/computer-access/collection-consent.js +47 -0
  6. package/dist/src/computer-access/command-output-capture.d.ts +17 -6
  7. package/dist/src/computer-access/command-output-capture.js +134 -68
  8. package/dist/src/computer-access/command-output-protection.d.ts +17 -0
  9. package/dist/src/computer-access/command-output-protection.js +59 -0
  10. package/dist/src/computer-access/companion/command-output.d.ts +1 -0
  11. package/dist/src/computer-access/companion/command-output.js +23 -6
  12. package/dist/src/computer-access/companion/install-link-macos.js +2 -1
  13. package/dist/src/computer-access/companion/native-notifications.js +3 -2
  14. package/dist/src/computer-access/companion/native-session.js +6 -2
  15. package/dist/src/computer-access/companion/observation-filter.js +2 -26
  16. package/dist/src/computer-access/companion/observation-process.d.ts +2 -0
  17. package/dist/src/computer-access/companion/observation-process.js +51 -25
  18. package/dist/src/computer-access/companion/observation-redaction.d.ts +2 -7
  19. package/dist/src/computer-access/companion/observation-redaction.js +2 -111
  20. package/dist/src/computer-access/companion/secret-protection-protocol.d.ts +6 -0
  21. package/dist/src/computer-access/companion/secret-protection-protocol.js +6 -0
  22. package/dist/src/computer-access/computer/companion-sessions.js +7 -6
  23. package/dist/src/computer-access/computer/unix-native-process.js +23 -11
  24. package/dist/src/computer-access/handlers.d.ts +2 -1
  25. package/dist/src/computer-access/handlers.js +79 -11
  26. package/dist/src/computer-access/host-observation.d.ts +3 -3
  27. package/dist/src/computer-access/native-observation-connection.d.ts +12 -0
  28. package/dist/src/computer-access/native-observation-connection.js +78 -0
  29. package/dist/src/computer-access/native-observation-ownership.d.ts +6 -0
  30. package/dist/src/computer-access/native-observation-ownership.js +55 -0
  31. package/dist/src/computer-access/native-observation-shutdown.d.ts +7 -0
  32. package/dist/src/computer-access/native-observation-shutdown.js +58 -0
  33. package/dist/src/computer-access/observation-source.d.ts +6 -0
  34. package/dist/src/computer-access/observation-source.js +10 -0
  35. package/dist/src/computer-access/security/desktop-result.d.ts +8 -0
  36. package/dist/src/computer-access/security/desktop-result.js +146 -0
  37. package/dist/src/computer-access/security/observed-error.d.ts +2 -0
  38. package/dist/src/computer-access/security/observed-error.js +10 -0
  39. package/dist/src/computer-access/security/secret-text.d.ts +7 -0
  40. package/dist/src/computer-access/security/secret-text.js +111 -0
  41. package/dist/src/computer-access/security/system-results.d.ts +2 -0
  42. package/dist/src/computer-access/security/system-results.js +53 -0
  43. package/dist/src/computer-access/system-result-protection.d.ts +11 -0
  44. package/dist/src/computer-access/system-result-protection.js +1 -0
  45. package/dist/src/model-gateway/observability/provider-response-capture.d.ts +60 -0
  46. package/dist/src/model-gateway/observability/provider-response-capture.js +68 -0
  47. package/dist/src/model-gateway/observability/provider-response-prefix.d.ts +7 -0
  48. package/dist/src/model-gateway/observability/provider-response-prefix.js +14 -0
  49. package/dist/src/model-gateway/observability/provider-response-tail.d.ts +8 -0
  50. package/dist/src/model-gateway/observability/provider-response-tail.js +28 -0
  51. package/dist/src/model-gateway/observability/provider-sse-diagnostics.d.ts +30 -0
  52. package/dist/src/model-gateway/observability/provider-sse-diagnostics.js +119 -0
  53. package/dist/src/model-gateway/observability/provider-trace.js +30 -8
  54. package/dist/src/model-gateway/providers/ollama/adapter.js +8 -2
  55. package/dist/src/model-gateway/providers/ollama/stream-normalizer.js +70 -50
  56. package/dist/src/model-gateway/providers/ollama/stream-termination.d.ts +6 -0
  57. package/dist/src/model-gateway/providers/ollama/stream-termination.js +20 -0
  58. package/dist/src/model-gateway/providers/openai/adapter.js +9 -7
  59. package/dist/src/model-gateway/providers/openai/diagnostics.d.ts +0 -1
  60. package/dist/src/model-gateway/providers/openai/diagnostics.js +0 -9
  61. package/dist/src/model-gateway/providers/openai/function-output.d.ts +11 -0
  62. package/dist/src/model-gateway/providers/openai/function-output.js +37 -0
  63. package/dist/src/model-gateway/providers/openai/function-result.d.ts +7 -0
  64. package/dist/src/model-gateway/providers/openai/function-result.js +35 -0
  65. package/dist/src/model-gateway/providers/openai/message-output-policy.d.ts +3 -0
  66. package/dist/src/model-gateway/providers/openai/message-output-policy.js +16 -0
  67. package/dist/src/model-gateway/providers/openai/payload.d.ts +0 -2
  68. package/dist/src/model-gateway/providers/openai/payload.js +6 -23
  69. package/dist/src/model-gateway/providers/openai/response-lifetime.d.ts +2 -0
  70. package/dist/src/model-gateway/providers/openai/response-lifetime.js +64 -0
  71. package/dist/src/model-gateway/providers/openai/sse-data.d.ts +9 -0
  72. package/dist/src/model-gateway/providers/openai/sse-data.js +67 -0
  73. package/dist/src/model-gateway/providers/openai/stream-normalizer.d.ts +10 -22
  74. package/dist/src/model-gateway/providers/openai/stream-normalizer.js +78 -79
  75. package/dist/src/model-gateway/providers/openai/stream.js +13 -41
  76. package/dist/src/model-gateway/providers/openai/structured-message-output.d.ts +42 -0
  77. package/dist/src/model-gateway/providers/openai/structured-message-output.js +175 -0
  78. package/dist/src/model-gateway/server.js +5 -1
  79. package/dist/src/plugin-contract/index.d.ts +1 -0
  80. package/dist/src/plugin-contract/index.js +1 -0
  81. package/dist/src/plugin-contract/manifest.d.ts +2 -0
  82. package/dist/src/plugin-contract/manifest.js +1 -0
  83. package/dist/src/plugin-contract/platform-compatibility.d.ts +16 -0
  84. package/dist/src/plugin-contract/platform-compatibility.js +3 -0
  85. package/dist/src/plugin-sdk/computer-access.d.ts +4 -0
  86. package/dist/src/plugin-sdk/computer-access.js +1 -0
  87. package/dist/src/plugin-sdk/files-windows/process.d.ts +3 -0
  88. package/dist/src/plugin-sdk/files-windows/process.js +93 -0
  89. package/dist/src/plugin-sdk/files-windows/read-script.d.ts +1 -0
  90. package/dist/src/plugin-sdk/files-windows/read-script.js +43 -0
  91. package/dist/src/plugin-sdk/files-windows/read.d.ts +6 -0
  92. package/dist/src/plugin-sdk/files-windows/read.js +56 -0
  93. package/dist/src/plugin-sdk/files-windows/result.d.ts +4 -0
  94. package/dist/src/plugin-sdk/files-windows/result.js +67 -0
  95. package/dist/src/plugin-sdk/files.js +4 -0
  96. package/dist/src/plugin-sdk/index.d.ts +1 -0
  97. package/dist/src/plugin-sdk/index.js +1 -0
  98. package/dist/src/plugin-sdk/mutation-result.d.ts +7 -0
  99. package/dist/src/plugin-sdk/mutation-result.js +11 -0
  100. package/dist/src/runtime/adapters/long-term-memory/file-lock/acquisition.js +20 -3
  101. package/dist/src/runtime/adapters/long-term-memory/file-lock/owner-record.js +3 -1
  102. package/dist/src/runtime/adapters/long-term-memory/file-lock/path-observation.d.ts +3 -0
  103. package/dist/src/runtime/adapters/long-term-memory/file-lock/path-observation.js +20 -0
  104. package/dist/src/runtime/adapters/long-term-memory/file-lock/snapshot.js +7 -3
  105. package/dist/src/runtime/adapters/passive-learning-runtime.d.ts +1 -1
  106. package/dist/src/runtime/adapters/passive-learning-runtime.js +3 -3
  107. package/dist/src/runtime/adapters/runtime-observation-connection.d.ts +5 -0
  108. package/dist/src/runtime/adapters/runtime-observation-connection.js +13 -0
  109. package/dist/src/runtime/local-host/windows-private-access.js +2 -0
  110. package/dist/src/runtime/passive-learning/application-catalog.js +3 -1
  111. package/dist/src/runtime/passive-learning/collection-source.js +7 -0
  112. package/dist/src/runtime/passive-learning/service.js +2 -3
  113. package/dist/src/runtime/passive-learning/status-projection.d.ts +2 -0
  114. package/dist/src/runtime/passive-learning/status-projection.js +9 -0
  115. package/dist/src/runtime/plugins/installation/package.d.ts +8 -0
  116. package/dist/src/runtime/plugins/installation/package.js +2 -0
  117. package/dist/src/runtime/plugins/installation/service.d.ts +7 -0
  118. package/dist/src/runtime/plugins/loader.js +24 -14
  119. package/dist/src/runtime/plugins/manifest-platform-compatibility.d.ts +2 -0
  120. package/dist/src/runtime/plugins/manifest-platform-compatibility.js +39 -0
  121. package/dist/src/runtime/plugins/manifest-validator.js +9 -1
  122. package/dist/src/runtime/plugins/platform-compatibility.d.ts +4 -0
  123. package/dist/src/runtime/plugins/platform-compatibility.js +44 -0
  124. package/dist/src/runtime/request/approval-wait/activation-events.js +19 -7
  125. package/dist/src/runtime/request/approval-wait/execution-compaction-restore.d.ts +20 -0
  126. package/dist/src/runtime/request/approval-wait/execution-compaction-restore.js +118 -0
  127. package/dist/src/runtime/request/approval-wait/super-compaction-restore.js +2 -1
  128. package/dist/src/runtime/request/prepared-execution.js +3 -0
  129. package/dist/src/runtime/steps/execution-agent/capability-result-context.d.ts +6 -0
  130. package/dist/src/runtime/steps/execution-agent/capability-result-context.js +29 -0
  131. package/dist/src/runtime/steps/execution-agent/format.js +2 -3
  132. package/dist/src/runtime/steps/execution-agent/input.js +1 -1
  133. package/dist/src/runtime/steps/execution-agent/prompt.js +5 -5
  134. package/dist/src/runtime/steps/execution-agent/response-prompt.js +1 -0
  135. package/dist/src/runtime/steps/execution-agent/state-context.d.ts +2 -3
  136. package/dist/src/runtime/steps/execution-agent/state-context.js +26 -35
  137. package/dist/src/runtime/steps/execution-agent/work-plan-contract.d.ts +1 -3
  138. package/dist/src/runtime/steps/execution-agent/work-plan-contract.js +0 -55
  139. package/dist/src/runtime/steps/execution-agent/work-plan-schema.d.ts +3 -0
  140. package/dist/src/runtime/steps/execution-agent/work-plan-schema.js +61 -0
  141. package/dist/src/sessions/durable-session-commit.js +3 -3
  142. package/dist/src/sessions/prepared-session-replacement.d.ts +6 -0
  143. package/dist/src/sessions/prepared-session-replacement.js +46 -0
  144. package/dist/src/sessions/session-store.js +3 -3
  145. package/dist/src/shared/passive-observation-self-exclusion.d.ts +5 -0
  146. package/dist/src/shared/passive-observation-self-exclusion.js +37 -0
  147. package/dist/src/shared/windows-file-io/authority-script.d.ts +1 -0
  148. package/dist/src/shared/windows-file-io/authority-script.js +94 -0
  149. package/dist/src/shared/windows-file-io/native-script.d.ts +2 -0
  150. package/dist/src/shared/windows-file-io/native-script.js +120 -0
  151. package/dist/src/shared/windows-file-io/read-bytes-script.d.ts +1 -0
  152. package/dist/src/shared/windows-file-io/read-bytes-script.js +18 -0
  153. package/dist/src/shared/windows-job-object.d.ts +2 -0
  154. package/dist/src/shared/windows-job-object.js +66 -0
  155. package/dist/src/web-ui/app/app-bootstrap.js +14 -1
  156. package/dist/src/web-ui/app/app-state.js +0 -7
  157. package/dist/src/web-ui/app/app.js +53 -156
  158. package/dist/src/web-ui/app/components/automations/node-inspector.js +3 -2
  159. package/dist/src/web-ui/app/components/automations/step-editor-dialog.js +3 -0
  160. package/dist/src/web-ui/app/components/composer-submission-notice.js +50 -0
  161. package/dist/src/web-ui/app/components/config-workspace/model-plugin-permissions.js +7 -1
  162. package/dist/src/web-ui/app/components/config-workspace/workspace-mutations.js +22 -2
  163. package/dist/src/web-ui/app/components/home-guidance/daily-review.js +2 -2
  164. package/dist/src/web-ui/app/components/home-guidance/home-guidance.js +20 -6
  165. package/dist/src/web-ui/app/components/model-setup/context-window-feedback.js +53 -0
  166. package/dist/src/web-ui/app/components/model-setup/save-flow.js +3 -1
  167. package/dist/src/web-ui/app/components/model-setup/save-outcome.js +1 -0
  168. package/dist/src/web-ui/app/components/model-setup/wizard.js +12 -0
  169. package/dist/src/web-ui/app/components/passive-learning/activity-controls.js +4 -0
  170. package/dist/src/web-ui/app/components/passive-learning/collection-access.js +35 -0
  171. package/dist/src/web-ui/app/components/passive-learning/collection-consent-dialog.js +59 -0
  172. package/dist/src/web-ui/app/components/passive-learning/collection-consent-gate.js +94 -0
  173. package/dist/src/web-ui/app/components/passive-learning/computer-update-notice.js +6 -0
  174. package/dist/src/web-ui/app/components/passive-learning/failure-copy.js +1 -0
  175. package/dist/src/web-ui/app/components/passive-learning/home.js +7 -2
  176. package/dist/src/web-ui/app/components/passive-learning/macos-collection-restart-notice.js +1 -0
  177. package/dist/src/web-ui/app/components/passive-learning/memory.js +2 -4
  178. package/dist/src/web-ui/app/components/passive-learning/workspace-view.js +2 -2
  179. package/dist/src/web-ui/app/components/plugins/compatibility.js +13 -0
  180. package/dist/src/web-ui/app/components/plugins/discovery-rendering.js +9 -1
  181. package/dist/src/web-ui/app/components/plugins/installation-compatibility.js +7 -0
  182. package/dist/src/web-ui/app/components/plugins/installation.js +2 -1
  183. package/dist/src/web-ui/app/components/plugins/rendering.js +3 -0
  184. package/dist/src/web-ui/app/components/reasoning-override-prompt.js +82 -0
  185. package/dist/src/web-ui/app/components/runtime-config-activation.js +22 -8
  186. package/dist/src/web-ui/app/components/runtime-setup/optional-steps.js +7 -4
  187. package/dist/src/web-ui/app/components/runtime-setup/plugins.js +3 -1
  188. package/dist/src/web-ui/app/components/runtime-setup/rendering.js +6 -4
  189. package/dist/src/web-ui/app/components/runtime-setup-guide.d.ts +1 -0
  190. package/dist/src/web-ui/app/components/schedules/form.js +10 -8
  191. package/dist/src/web-ui/app/components/schedules/workspace.js +23 -4
  192. package/dist/src/web-ui/app/components/session-sidebar-sections.js +2 -2
  193. package/dist/src/web-ui/app/components/spark-chat/handoff-actions.js +9 -3
  194. package/dist/src/web-ui/app/components/spark-chat/placement.js +4 -7
  195. package/dist/src/web-ui/app/components/spark-chat/settings.js +7 -3
  196. package/dist/src/web-ui/app/components/system-host/macos-permissions.js +2 -0
  197. package/dist/src/web-ui/app/components/system-host/native-windows-access.js +50 -0
  198. package/dist/src/web-ui/app/components/system-host/rendering.js +3 -0
  199. package/dist/src/web-ui/app/components/workspace-storage-notice.js +37 -0
  200. package/dist/src/web-ui/app/configuration-environment-refresh.js +27 -34
  201. package/dist/src/web-ui/app/configuration-feature.js +9 -1
  202. package/dist/src/web-ui/app/controllers/app-event-bindings.js +38 -105
  203. package/dist/src/web-ui/app/controllers/chat-request-controller.d.ts +28 -0
  204. package/dist/src/web-ui/app/controllers/chat-request-controller.js +34 -66
  205. package/dist/src/web-ui/app/controllers/composer-attachments-controller.d.ts +15 -40
  206. package/dist/src/web-ui/app/controllers/composer-attachments-controller.js +26 -69
  207. package/dist/src/web-ui/app/controllers/composer-draft-view.d.ts +27 -0
  208. package/dist/src/web-ui/app/controllers/composer-draft-view.js +48 -0
  209. package/dist/src/web-ui/app/controllers/composer-drafts.d.ts +55 -0
  210. package/dist/src/web-ui/app/controllers/composer-drafts.js +120 -0
  211. package/dist/src/web-ui/app/controllers/composer-feature.d.ts +65 -0
  212. package/dist/src/web-ui/app/controllers/composer-feature.js +124 -0
  213. package/dist/src/web-ui/app/controllers/composer-queue-controller.d.ts +33 -94
  214. package/dist/src/web-ui/app/controllers/composer-queue-controller.js +185 -251
  215. package/dist/src/web-ui/app/controllers/composer-submission-lifecycle.d.ts +48 -0
  216. package/dist/src/web-ui/app/controllers/composer-submission-lifecycle.js +97 -0
  217. package/dist/src/web-ui/app/controllers/composer-submit-controller.d.ts +30 -61
  218. package/dist/src/web-ui/app/controllers/composer-submit-controller.js +56 -138
  219. package/dist/src/web-ui/app/controllers/composer-surface-controller.js +6 -0
  220. package/dist/src/web-ui/app/controllers/composer-workspace-controller.d.ts +22 -40
  221. package/dist/src/web-ui/app/controllers/composer-workspace-controller.js +49 -165
  222. package/dist/src/web-ui/app/controllers/conversation-navigation-intent.js +15 -0
  223. package/dist/src/web-ui/app/controllers/conversation-request-hydration.js +20 -17
  224. package/dist/src/web-ui/app/controllers/conversation-session-controller.d.ts +1 -2
  225. package/dist/src/web-ui/app/controllers/conversation-session-controller.js +49 -22
  226. package/dist/src/web-ui/app/controllers/conversation-workspace-activation.js +27 -0
  227. package/dist/src/web-ui/app/controllers/daily-memory-review.js +15 -16
  228. package/dist/src/web-ui/app/controllers/environment-transition.js +126 -0
  229. package/dist/src/web-ui/app/controllers/environment-workspace-preparation.js +18 -0
  230. package/dist/src/web-ui/app/controllers/home-composer-feature.d.ts +14 -36
  231. package/dist/src/web-ui/app/controllers/home-composer-feature.js +17 -114
  232. package/dist/src/web-ui/app/controllers/home-conversation-activation.js +6 -8
  233. package/dist/src/web-ui/app/controllers/passive-learning-controller.js +56 -0
  234. package/dist/src/web-ui/app/controllers/projects-controller.d.ts +1 -1
  235. package/dist/src/web-ui/app/controllers/projects-controller.js +6 -1
  236. package/dist/src/web-ui/app/controllers/reasoning-mode-controller.js +174 -0
  237. package/dist/src/web-ui/app/controllers/runtime-selection-controller.d.ts +7 -0
  238. package/dist/src/web-ui/app/controllers/runtime-selection-controller.js +20 -155
  239. package/dist/src/web-ui/app/controllers/session-controller.js +33 -17
  240. package/dist/src/web-ui/app/controllers/session-pin-updates.js +14 -0
  241. package/dist/src/web-ui/app/controllers/session-sidebar-controller.js +12 -14
  242. package/dist/src/web-ui/app/controllers/spark-chat-sync.js +2 -2
  243. package/dist/src/web-ui/app/controllers/steer-controller.js +9 -7
  244. package/dist/src/web-ui/app/controllers/tool-permission-mode-controller.js +1 -1
  245. package/dist/src/web-ui/app/controllers/workspace-conversation-opener.js +34 -0
  246. package/dist/src/web-ui/app/dashboard-feature.js +3 -2
  247. package/dist/src/web-ui/app/lib/reasoning-controls.js +35 -0
  248. package/dist/src/web-ui/app/lib/session-composer-queue-ownership.js +58 -0
  249. package/dist/src/web-ui/app/lib/session-composer-queue.d.ts +12 -0
  250. package/dist/src/web-ui/app/lib/session-composer-queue.js +25 -6
  251. package/dist/src/web-ui/app/passive-learning-feature.js +16 -3
  252. package/dist/src/web-ui/app/schedules-feature.js +5 -3
  253. package/dist/src/web-ui/app/services/client-preferences.d.ts +18 -10
  254. package/dist/src/web-ui/app/services/client-preferences.js +25 -16
  255. package/dist/src/web-ui/app/services/home-guidance-preferences.js +13 -13
  256. package/dist/src/web-ui/app/services/reasoning-override.js +12 -0
  257. package/dist/src/web-ui/app/services/runtime-web-client/automations.js +10 -2
  258. package/dist/src/web-ui/app/services/runtime-web-client/memory.js +7 -2
  259. package/dist/src/web-ui/app/services/runtime-web-client/system-host.js +2 -0
  260. package/dist/src/web-ui/app/services/runtime-web-client.d.ts +2 -0
  261. package/dist/src/web-ui/app/services/runtime-web-client.js +2 -0
  262. package/dist/src/web-ui/app/services/server-composer-queue.js +32 -0
  263. package/dist/src/web-ui/app/services/session-sidebar-preferences.js +5 -5
  264. package/dist/src/web-ui/app/services/workspace-state-storage.js +116 -0
  265. package/dist/src/web-ui/app/services/workspace-state.js +27 -0
  266. package/dist/src/web-ui/app/spark-chat-conversation.js +34 -45
  267. package/dist/src/web-ui/app/spark-chat-feature.js +10 -4
  268. package/dist/src/web-ui/app/styles/21-composer-controls.css +16 -0
  269. package/dist/src/web-ui/app/styles/41-plugin-management.css +8 -0
  270. package/dist/src/web-ui/app/styles/42-model-plugin-permissions.css +1 -0
  271. package/dist/src/web-ui/app/styles/49-collection-consent.css +30 -0
  272. package/dist/src/web-ui/app/styles/64-workspace-storage.css +23 -0
  273. package/dist/src/web-ui/app/styles.css +2 -0
  274. package/dist/src/web-ui/client-state/contracts.d.ts +15 -0
  275. package/dist/src/web-ui/client-state/contracts.js +13 -0
  276. package/dist/src/web-ui/client-state/preference-shapes.d.ts +2 -0
  277. package/dist/src/web-ui/client-state/preference-shapes.js +80 -0
  278. package/dist/src/web-ui/client-state/preferences.d.ts +3 -0
  279. package/dist/src/web-ui/client-state/preferences.js +84 -0
  280. package/dist/src/web-ui/client-state/queue.d.ts +3 -0
  281. package/dist/src/web-ui/client-state/queue.js +43 -0
  282. package/dist/src/web-ui/client-state/routes.d.ts +7 -0
  283. package/dist/src/web-ui/client-state/routes.js +58 -0
  284. package/dist/src/web-ui/client-state/store.d.ts +14 -0
  285. package/dist/src/web-ui/client-state/store.js +88 -0
  286. package/dist/src/web-ui/local-runtime/configuration-activation-source.js +2 -0
  287. package/dist/src/web-ui/local-runtime/http.js +11 -2
  288. package/dist/src/web-ui/local-runtime/model-context-capacity-error.d.ts +14 -0
  289. package/dist/src/web-ui/local-runtime/model-context-capacity-error.js +28 -0
  290. package/dist/src/web-ui/local-runtime/model-setup-context-window.d.ts +15 -0
  291. package/dist/src/web-ui/local-runtime/model-setup-context-window.js +25 -0
  292. package/dist/src/web-ui/local-runtime/model-setup-routes.js +2 -0
  293. package/dist/src/web-ui/local-runtime/model-setup-service.js +5 -2
  294. package/dist/src/web-ui/local-runtime/model-setup-validation.d.ts +1 -0
  295. package/dist/src/web-ui/local-runtime/model-setup-validation.js +14 -7
  296. package/dist/src/web-ui/local-runtime/request-body-error.d.ts +11 -0
  297. package/dist/src/web-ui/local-runtime/request-body-error.js +14 -0
  298. package/dist/src/web-ui/local-runtime/request-control-observation.js +2 -2
  299. package/dist/src/web-ui/local-runtime/request-execution.js +18 -18
  300. package/dist/src/web-ui/local-runtime/runtime-setup-connection-edit.d.ts +2 -0
  301. package/dist/src/web-ui/local-runtime/runtime-setup-connection-edit.js +35 -22
  302. package/dist/src/web-ui/local-runtime/runtime-setup-context-window.d.ts +2 -9
  303. package/dist/src/web-ui/local-runtime/runtime-setup-context-window.js +4 -27
  304. package/dist/src/web-ui/local-runtime/runtime-setup-credentials.d.ts +15 -1
  305. package/dist/src/web-ui/local-runtime/runtime-setup-credentials.js +30 -11
  306. package/dist/src/web-ui/local-runtime/runtime-setup-edit-files.d.ts +20 -0
  307. package/dist/src/web-ui/local-runtime/runtime-setup-edit-files.js +104 -0
  308. package/dist/src/web-ui/local-runtime/runtime-setup-edit-journal.d.ts +29 -0
  309. package/dist/src/web-ui/local-runtime/runtime-setup-edit-journal.js +151 -0
  310. package/dist/src/web-ui/local-runtime/runtime-setup-edit-recovery.d.ts +7 -0
  311. package/dist/src/web-ui/local-runtime/runtime-setup-edit-recovery.js +87 -0
  312. package/dist/src/web-ui/local-runtime/runtime-setup-edit-transaction.d.ts +3 -0
  313. package/dist/src/web-ui/local-runtime/runtime-setup-edit-transaction.js +37 -0
  314. package/dist/src/web-ui/local-runtime/runtime-setup-service.js +4 -0
  315. package/dist/src/web-ui/local-runtime-backend.js +14 -0
  316. package/dist/src/web-ui/plugin-management-catalog.d.ts +3 -1
  317. package/dist/src/web-ui/plugin-management-catalog.js +3 -1
  318. package/dist/src/web-ui/plugin-management-service.d.ts +1 -0
  319. package/dist/src/web-ui/plugin-removal-service.d.ts +1 -0
  320. package/dist/src/web-ui/server-readiness.d.ts +3 -0
  321. package/dist/src/web-ui/server-readiness.js +36 -0
  322. package/dist/src/web-ui/server.d.ts +2 -0
  323. package/dist/src/web-ui/server.js +23 -1
  324. package/dist/src/web-ui/system-host-service.js +13 -2
  325. package/dist/src/web-ui/system-host-setup/collection-consent-route.d.ts +3 -0
  326. package/dist/src/web-ui/system-host-setup/collection-consent-route.js +30 -0
  327. package/docs/installation.md +44 -5
  328. package/docs/plugins.md +145 -4
  329. package/docs/tool-execution-result-evidence-contract.md +57 -0
  330. package/docs/windows-companion-store.md +5 -0
  331. package/package.json +4 -2
  332. package/plugins/capability-brief/plugin.json +4 -0
  333. package/plugins/code-outline/README.md +20 -0
  334. package/plugins/code-outline/plugin.json +1 -0
  335. package/plugins/code-outline/source/index.ts +16 -20
  336. package/plugins/code-outline/source/read-failure.ts +40 -0
  337. package/plugins/code-outline/src/index.cjs +614 -29
  338. package/plugins/document-reader/README.md +33 -0
  339. package/plugins/document-reader/plugin.json +1 -0
  340. package/plugins/document-reader/source/pdf-contract.ts +57 -0
  341. package/plugins/document-reader/source/pdf-parser.ts +139 -0
  342. package/plugins/document-reader/source/pdf-process-main.ts +56 -0
  343. package/plugins/document-reader/source/pdf-process.ts +207 -0
  344. package/plugins/document-reader/source/pdf-result.ts +79 -0
  345. package/plugins/document-reader/source/pdf-worker.ts +39 -303
  346. package/plugins/document-reader/source/pdf.ts +4 -1
  347. package/plugins/document-reader/source/read-failure.ts +37 -0
  348. package/plugins/document-reader/source/reader.ts +3 -19
  349. package/plugins/document-reader/src/index.cjs +995 -211
  350. package/plugins/exec/README.md +19 -0
  351. package/plugins/exec/plugin.json +4 -3
  352. package/plugins/exec/skills/exec_skill/SKILL.md +3 -2
  353. package/plugins/exec/source/filesystem-file-observer.ts +98 -0
  354. package/plugins/exec/source/filesystem-observer.ts +8 -79
  355. package/plugins/exec/source/output-files.ts +12 -6
  356. package/plugins/exec/source/paths.ts +3 -1
  357. package/plugins/exec/source/process-manager.ts +8 -24
  358. package/plugins/exec/source/shell-platform.ts +19 -3
  359. package/plugins/exec/source/shell-process.ts +55 -0
  360. package/plugins/exec/source/windows-job-source.ts +1 -0
  361. package/plugins/exec/source/windows-shell-bootstrap.ts +20 -0
  362. package/plugins/exec/src/index.cjs +252 -96
  363. package/plugins/filesystem/README.md +65 -0
  364. package/plugins/filesystem/plugin.json +6 -2
  365. package/plugins/filesystem/source/atomic-write.ts +2 -0
  366. package/plugins/filesystem/source/bounded-io.ts +80 -306
  367. package/plugins/filesystem/source/directory-sample.ts +2 -0
  368. package/plugins/filesystem/source/errors.ts +14 -0
  369. package/plugins/filesystem/source/file-observation.ts +151 -0
  370. package/plugins/filesystem/source/file-version.ts +41 -0
  371. package/plugins/filesystem/source/index.ts +6 -0
  372. package/plugins/filesystem/source/mutation-coordinator.ts +1 -0
  373. package/plugins/filesystem/source/windows/authority-script.ts +1 -0
  374. package/plugins/filesystem/source/windows/native-script.ts +1 -0
  375. package/plugins/filesystem/source/windows/operations.ts +197 -0
  376. package/plugins/filesystem/source/windows/process.ts +214 -0
  377. package/plugins/filesystem/source/windows/publication-script.ts +29 -0
  378. package/plugins/filesystem/source/windows/read-script.ts +63 -0
  379. package/plugins/filesystem/source/windows/request-availability.ts +67 -0
  380. package/plugins/filesystem/source/windows/source.ts +42 -0
  381. package/plugins/filesystem/source/windows/storage-script.ts +11 -0
  382. package/plugins/filesystem/source/windows/streams-script.ts +24 -0
  383. package/plugins/filesystem/source/windows/write-script.ts +86 -0
  384. package/plugins/filesystem/src/index.cjs +1208 -322
  385. package/plugins/json-inspector/README.md +18 -0
  386. package/plugins/json-inspector/plugin.json +1 -0
  387. package/plugins/json-inspector/source/index.ts +16 -19
  388. package/plugins/json-inspector/source/read-failure.ts +42 -0
  389. package/plugins/json-inspector/src/index.cjs +612 -27
  390. package/plugins/local-search/README.md +29 -0
  391. package/plugins/local-search/plugin.json +1 -0
  392. package/plugins/local-search/source/errors.ts +2 -0
  393. package/plugins/local-search/source/paths.ts +3 -0
  394. package/plugins/local-search/source/ripgrep-process.ts +31 -5
  395. package/plugins/local-search/source/ripgrep.ts +3 -3
  396. package/plugins/local-search/source/windows-authority.ts +99 -0
  397. package/plugins/local-search/source/windows-search-lease.ts +49 -0
  398. package/plugins/local-search/source/windows-search-process.ts +91 -0
  399. package/plugins/local-search/source/windows-search-script.ts +52 -0
  400. package/plugins/local-search/src/index.cjs +595 -26
  401. package/plugins/memory/plugin.json +4 -0
  402. package/plugins/memory/source/lock-directory-claim.ts +56 -0
  403. package/plugins/memory/source/lock-owner-file.ts +71 -0
  404. package/plugins/memory/source/lock-path-observation.ts +26 -0
  405. package/plugins/memory/source/prepared-memory-replacement.ts +40 -0
  406. package/plugins/memory/source/store-lock.ts +12 -7
  407. package/plugins/memory/source/store.ts +3 -2
  408. package/plugins/memory/src/index.cjs +174 -25
  409. package/plugins/project-orientation/README.md +23 -0
  410. package/plugins/project-orientation/plugin.json +1 -0
  411. package/plugins/project-orientation/source/index.ts +12 -9
  412. package/plugins/project-orientation/source/inspection-failure.ts +70 -0
  413. package/plugins/project-orientation/source/manifest-summary.ts +9 -2
  414. package/plugins/project-orientation/source/tree.ts +6 -0
  415. package/plugins/project-orientation/src/index.cjs +647 -31
  416. package/plugins/system/README.md +51 -15
  417. package/plugins/system/plugin.json +5 -1
  418. package/plugins/system/skills/system_actions/SKILL.md +1 -1
  419. package/plugins/system/source/command-working-directory.ts +47 -0
  420. package/plugins/system/source/computer/handlers.ts +13 -9
  421. package/plugins/system/source/computer/observation-result.ts +10 -5
  422. package/plugins/system/source/computer/request-computers.ts +10 -3
  423. package/plugins/system/source/computer/request-modules.ts +3 -6
  424. package/plugins/system/source/computer/runtime-platform.ts +18 -0
  425. package/plugins/system/source/host-dispatch.ts +18 -2
  426. package/plugins/system/source/index.ts +5 -3
  427. package/plugins/system/source/local-command-output-retention.ts +16 -0
  428. package/plugins/system/source/local-command-output.ts +16 -8
  429. package/plugins/system/source/request-system-modules.ts +12 -2
  430. package/plugins/system/source/request-target-snapshot.ts +2 -1
  431. package/plugins/system/source/security/desktop-result.ts +177 -0
  432. package/plugins/system/source/security/observed-error.ts +10 -0
  433. package/plugins/system/source/security/secret-text.ts +118 -0
  434. package/plugins/system/source/security/system-results.ts +62 -0
  435. package/plugins/system/source/security/windows-output-directory.ts +82 -0
  436. package/plugins/system/src/index.cjs +837 -151
  437. package/plugins/system-probe/plugin.json +8 -2
  438. package/plugins/system-probe/source/disk-path.ts +8 -0
  439. package/plugins/system-probe/source/index.ts +10 -5
  440. package/plugins/system-probe/source/machine-load.ts +33 -0
  441. package/plugins/system-probe/source/metrics.ts +6 -8
  442. package/plugins/system-probe/src/index.cjs +49 -16
  443. package/plugins/web/plugin.json +4 -0
@@ -1,3 +1,5 @@
1
+ import { commitRuntimeSetupEdit } from "./runtime-setup-edit-transaction.js";
2
+ import { withPlannedRuntimeSetupCredentials, } from "./runtime-setup-credentials.js";
1
3
  import { randomUUID } from "node:crypto";
2
4
  import { dirname, join, resolve } from "node:path";
3
5
  import { isDeepStrictEqual } from "node:util";
@@ -80,30 +82,41 @@ export async function editRuntimeSetupConnection(params) {
80
82
  modelConfig,
81
83
  ownedProviders: retained.ownedProviders,
82
84
  };
83
- let modelWritten = false;
84
- let configWritten = false;
85
- try {
86
- await modelTransaction.write(modelConfig, {
87
- expectedConfig: params.draft.modelConfig,
88
- });
89
- modelWritten = true;
90
- await configTransaction.write(config, {
91
- expectedConfig: source.config,
92
- });
93
- configWritten = true;
94
- await writeRuntimeSetupDraft(nextDraft);
95
- }
96
- catch (error) {
97
- if (configWritten)
98
- await configTransaction.write(source.config, {
99
- expectedConfig: config,
85
+ await withPlannedRuntimeSetupCredentials(params.credentialWrite, async (credentials) => {
86
+ const json = (value) => JSON.stringify(value, null, 2) + "\n";
87
+ await commitRuntimeSetupEdit(params.rootDir, [
88
+ {
89
+ role: "model",
90
+ path: modelTransaction.path,
91
+ text: json(modelConfig),
92
+ },
93
+ {
94
+ role: "config",
95
+ path: configTransaction.path,
96
+ text: json(config),
97
+ },
98
+ {
99
+ role: "receipt",
100
+ path: configTransaction.path + ".web-setup.json",
101
+ text: json(nextDraft),
102
+ },
103
+ {
104
+ role: "credentials",
105
+ path: credentials.path,
106
+ text: credentials.text,
107
+ mode: 0o600,
108
+ },
109
+ ], async () => {
110
+ await modelTransaction.write(modelConfig, {
111
+ expectedConfig: params.draft.modelConfig,
100
112
  });
101
- if (modelWritten)
102
- await modelTransaction.write(params.draft.modelConfig, {
103
- expectedConfig: modelConfig,
113
+ await configTransaction.write(config, {
114
+ expectedConfig: source.config,
104
115
  });
105
- throw error;
106
- }
116
+ await writeRuntimeSetupDraft(nextDraft);
117
+ await credentials.write();
118
+ }, credentials.publish);
119
+ });
107
120
  return { draft: nextDraft, embeddingInvalidated };
108
121
  });
109
122
  });
@@ -1,14 +1,7 @@
1
1
  import type { ModelContextCapacityIssue } from "../../runtime/config/model-context-capacity.js";
2
2
  import { RuntimeSetupError } from "./runtime-setup-input.js";
3
- export type RuntimeSetupContextWindowIssue = Readonly<{
4
- field: "contextWindowTokens";
5
- declaredTokens: number;
6
- effectiveTokens: number;
7
- reservedTokens: number;
8
- minimumTokens: number;
9
- allocationTokens?: number;
10
- environmentId?: string;
11
- }>;
3
+ import { type PublicContextWindowIssue } from "./model-context-capacity-error.js";
4
+ export type RuntimeSetupContextWindowIssue = PublicContextWindowIssue;
12
5
  export declare class RuntimeSetupContextWindowError extends RuntimeSetupError {
13
6
  readonly contextWindow: RuntimeSetupContextWindowIssue;
14
7
  constructor(issue: ModelContextCapacityIssue, environmentId?: string);
@@ -1,38 +1,15 @@
1
- import { RuntimeConfigValidationError } from "../../runtime/config/validation.js";
2
1
  import { RuntimeSetupError } from "./runtime-setup-input.js";
3
- function setupContextWindowMessage(issue) {
4
- const capacity = `The effective context window is ${issue.effectiveTokens} tokens, but the configured reserves require more than ${issue.reservedTokens} tokens. Use a model-supported context window of at least ${issue.minimumTokens} tokens or adjust the configured reserves.`;
5
- if (issue.allocationTokens === undefined)
6
- return capacity;
7
- if (issue.allocationTokens >= issue.minimumTokens)
8
- return capacity;
9
- return `${capacity} The Ollama num_ctx allocation of ${issue.allocationTokens} tokens must also support that window.`;
10
- }
2
+ import { modelContextCapacityMessage, publicContextWindowIssue, readModelContextCapacityIssue, } from "./model-context-capacity-error.js";
11
3
  export class RuntimeSetupContextWindowError extends RuntimeSetupError {
12
4
  contextWindow;
13
5
  constructor(issue, environmentId) {
14
- super("context_window_too_small", setupContextWindowMessage(issue));
15
- this.contextWindow = {
16
- field: "contextWindowTokens",
17
- declaredTokens: issue.declaredTokens,
18
- effectiveTokens: issue.effectiveTokens,
19
- reservedTokens: issue.reservedTokens,
20
- minimumTokens: issue.minimumTokens,
21
- ...(issue.allocationTokens === undefined
22
- ? {}
23
- : { allocationTokens: issue.allocationTokens }),
24
- ...(environmentId === undefined ? {} : { environmentId }),
25
- };
6
+ super("context_window_too_small", modelContextCapacityMessage(issue));
7
+ this.contextWindow = publicContextWindowIssue(issue, environmentId);
26
8
  }
27
9
  }
28
- function readSetupContextCapacityIssue(error) {
29
- if (!(error instanceof RuntimeConfigValidationError))
30
- return undefined;
31
- return error.capacityIssues.find((issue) => issue.profileId === "default");
32
- }
33
10
  /** Project only known capacity evidence; other exceptions keep their redaction. */
34
11
  export function throwRuntimeSetupValidationError(error, environmentId) {
35
- const issue = readSetupContextCapacityIssue(error);
12
+ const issue = readModelContextCapacityIssue(error, "default");
36
13
  if (!issue)
37
14
  throw error;
38
15
  throw new RuntimeSetupContextWindowError(issue, environmentId);
@@ -1,4 +1,8 @@
1
- type RuntimeSetupCredentialWrite = {
1
+ type CredentialFileSnapshot = {
2
+ raw?: string;
3
+ mode: number;
4
+ };
5
+ export type RuntimeSetupCredentialWrite = {
2
6
  rootDir: string;
3
7
  configPath: string;
4
8
  apiKey?: string;
@@ -9,6 +13,16 @@ export declare function readRuntimeSetupCredential(rootDir: string, apiKeyEnv?:
9
13
  export declare function assertRuntimeSetupCredentialFile(rootDir: string): Promise<void>;
10
14
  export declare function hasRuntimeSetupCredential(rootDir: string, apiKeyEnv?: string): Promise<boolean>;
11
15
  export declare function persistRuntimeSetupCredentials(params: RuntimeSetupCredentialWrite): Promise<void>;
16
+ export type RuntimeSetupCredentialPlan = Readonly<{
17
+ rootDir: string;
18
+ path: string;
19
+ text: string;
20
+ previous: CredentialFileSnapshot;
21
+ write: () => Promise<void>;
22
+ publish: () => void;
23
+ }>;
24
+ /** Publish process credentials only after the caller's complete transaction commits. */
25
+ export declare function withPlannedRuntimeSetupCredentials<T>(params: RuntimeSetupCredentialWrite, operation: (plan: RuntimeSetupCredentialPlan) => Promise<T>): Promise<T>;
12
26
  /** Keep the credential private and locked until the related setup commit settles. */
13
27
  export declare function commitRuntimeSetupCredentials<T>(params: RuntimeSetupCredentialWrite, commit: () => Promise<T>): Promise<T>;
14
28
  export {};
@@ -108,10 +108,36 @@ export async function hasRuntimeSetupCredential(rootDir, apiKeyEnv = "OPENAI_API
108
108
  export async function persistRuntimeSetupCredentials(params) {
109
109
  await commitRuntimeSetupCredentials(params, async () => undefined);
110
110
  }
111
+ /** Publish process credentials only after the caller's complete transaction commits. */
112
+ export async function withPlannedRuntimeSetupCredentials(params, operation) {
113
+ const rootDir = await realpath(params.rootDir);
114
+ return withFileLock(join(rootDir, ".env.credentials.lock"), async () => {
115
+ const plan = await planCredentialAssignments({ ...params, rootDir });
116
+ const publish = () => {
117
+ const key = params.apiKey ||
118
+ process.env[plan.apiKeyEnv] ||
119
+ readSavedApiKey(plan.previousFile.raw ?? "", plan.apiKeyEnv);
120
+ if (key)
121
+ process.env[plan.apiKeyEnv] = key;
122
+ };
123
+ const result = await operation({
124
+ rootDir,
125
+ path: join(rootDir, ".env"),
126
+ text: plan.next,
127
+ previous: plan.previousFile,
128
+ write: () => replaceCredentialFile(rootDir, plan.previousFile.raw, plan.next),
129
+ publish,
130
+ });
131
+ publish();
132
+ return result;
133
+ });
134
+ }
111
135
  /** Keep the credential private and locked until the related setup commit settles. */
112
136
  export async function commitRuntimeSetupCredentials(params, commit) {
113
- const rootDir = await realpath(params.rootDir);
114
- return withFileLock(join(rootDir, ".env.credentials.lock"), () => saveCredentialAssignments({ ...params, rootDir }, commit));
137
+ return withPlannedRuntimeSetupCredentials(params, async (plan) => {
138
+ await plan.write();
139
+ return commitOrRestoreCredentials(plan.rootDir, plan.previous, plan.text, commit);
140
+ });
115
141
  }
116
142
  function wouldReplaceConfiguredCredential(preserveExistingCredential, incomingKey, configuredKeys) {
117
143
  if (!preserveExistingCredential)
@@ -124,7 +150,7 @@ function wouldReplaceConfiguredCredential(preserveExistingCredential, incomingKe
124
150
  return configuredKey !== incomingKey;
125
151
  });
126
152
  }
127
- async function saveCredentialAssignments(params, commit) {
153
+ async function planCredentialAssignments(params) {
128
154
  const apiKeyEnv = params.apiKeyEnv ?? "OPENAI_API_KEY";
129
155
  const previousFile = await readCredentialFileSnapshot(params.rootDir);
130
156
  const previous = previousFile.raw ?? "";
@@ -137,12 +163,5 @@ async function saveCredentialAssignments(params, commit) {
137
163
  let next = replaceRuntimeSetupEnvironmentAssignment(previous, "LLM_RUNTIME_CONFIG_FILE", params.configPath);
138
164
  if (params.apiKey)
139
165
  next = replaceRuntimeSetupEnvironmentAssignment(next, apiKeyEnv, params.apiKey);
140
- await replaceCredentialFile(params.rootDir, previousFile.raw, next);
141
- const result = await commitOrRestoreCredentials(params.rootDir, previousFile, next, commit);
142
- const key = params.apiKey ||
143
- process.env[apiKeyEnv] ||
144
- readSavedApiKey(previous, apiKeyEnv);
145
- if (key)
146
- process.env[apiKeyEnv] = key;
147
- return result;
166
+ return { previousFile, next, apiKeyEnv };
148
167
  }
@@ -0,0 +1,20 @@
1
+ import { RuntimeSetupError } from "./runtime-setup-input.js";
2
+ export type SetupEditFileSnapshot = Readonly<{
3
+ bytes: string | null;
4
+ mode: number;
5
+ }>;
6
+ export declare function setupEditRecoveryRequired(): RuntimeSetupError;
7
+ export declare function isMissingSetupEditFile(error: unknown): boolean;
8
+ /** Snapshots preserve bytes, existence and mode; linked or special targets are not owned. */
9
+ export declare function readSetupEditFile(path: string): Promise<SetupEditFileSnapshot>;
10
+ export declare function setupEditFileMatches(actual: SetupEditFileSnapshot, expected: SetupEditFileSnapshot): boolean;
11
+ export declare function setupEditTextSnapshot(text: string, mode: number): SetupEditFileSnapshot;
12
+ export declare function setupEditSnapshotText(snapshot: SetupEditFileSnapshot): string;
13
+ /** Directory sync is available on Unix; Windows does not expose it through Node. */
14
+ export declare function syncSetupEditDirectory(path: string): Promise<void>;
15
+ export declare function syncSetupEditFile(path: string): Promise<void>;
16
+ export declare function requireSetupEditFileSnapshot(path: string, expected: SetupEditFileSnapshot): Promise<void>;
17
+ /** Cooperative locks are held by the caller; recheck immediately before replacement. */
18
+ export declare function restoreSetupEditFile(path: string, expected: SetupEditFileSnapshot, replacement: SetupEditFileSnapshot): Promise<void>;
19
+ /** Publish the marker itself atomically; private mode also protects credential snapshots. */
20
+ export declare function publishSetupEditJournal(path: string, text: string, expected: SetupEditFileSnapshot): Promise<void>;
@@ -0,0 +1,104 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { chmod, lstat, open, readFile, rename, rm } from "node:fs/promises";
3
+ import { dirname } from "node:path";
4
+ import { canonicalConfigFilePath } from "../../runtime/adapters/config-file-transaction.js";
5
+ import { RuntimeSetupError } from "./runtime-setup-input.js";
6
+ export function setupEditRecoveryRequired() {
7
+ return new RuntimeSetupError("setup_edit_recovery_required", "An interrupted connection edit needs recovery. Restart this Runtime before applying configuration. If recovery reports a conflict, preserve the transaction and review the changed files.", 409);
8
+ }
9
+ export function isMissingSetupEditFile(error) {
10
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
11
+ }
12
+ /** Snapshots preserve bytes, existence and mode; linked or special targets are not owned. */
13
+ export async function readSetupEditFile(path) {
14
+ if ((await canonicalConfigFilePath(path)) !== path)
15
+ throw setupEditRecoveryRequired();
16
+ try {
17
+ const info = await lstat(path);
18
+ if (!info.isFile() || info.isSymbolicLink())
19
+ throw setupEditRecoveryRequired();
20
+ return {
21
+ bytes: (await readFile(path)).toString("base64"),
22
+ mode: info.mode & 0o777,
23
+ };
24
+ }
25
+ catch (error) {
26
+ if (isMissingSetupEditFile(error))
27
+ return { bytes: null, mode: 0 };
28
+ throw error;
29
+ }
30
+ }
31
+ export function setupEditFileMatches(actual, expected) {
32
+ if (actual.bytes !== expected.bytes)
33
+ return false;
34
+ // Node's Windows chmod only implements the writable bit, unlike POSIX modes.
35
+ const mask = process.platform === "win32" ? 0o200 : 0o777;
36
+ return (actual.mode & mask) === (expected.mode & mask);
37
+ }
38
+ export function setupEditTextSnapshot(text, mode) {
39
+ return { bytes: Buffer.from(text, "utf8").toString("base64"), mode };
40
+ }
41
+ export function setupEditSnapshotText(snapshot) {
42
+ if (snapshot.bytes === null)
43
+ throw setupEditRecoveryRequired();
44
+ return Buffer.from(snapshot.bytes, "base64").toString("utf8");
45
+ }
46
+ /** Directory sync is available on Unix; Windows does not expose it through Node. */
47
+ export async function syncSetupEditDirectory(path) {
48
+ if (process.platform === "win32")
49
+ return;
50
+ const handle = await open(path, "r");
51
+ try {
52
+ await handle.sync();
53
+ }
54
+ finally {
55
+ await handle.close();
56
+ }
57
+ }
58
+ export async function syncSetupEditFile(path) {
59
+ // Windows FlushFileBuffers requires a handle opened for writing.
60
+ const handle = await open(path, process.platform === "win32" ? "r+" : "r");
61
+ try {
62
+ await handle.sync();
63
+ }
64
+ finally {
65
+ await handle.close();
66
+ }
67
+ await syncSetupEditDirectory(dirname(path));
68
+ }
69
+ export async function requireSetupEditFileSnapshot(path, expected) {
70
+ if (!setupEditFileMatches(await readSetupEditFile(path), expected))
71
+ throw setupEditRecoveryRequired();
72
+ }
73
+ /** Cooperative locks are held by the caller; recheck immediately before replacement. */
74
+ export async function restoreSetupEditFile(path, expected, replacement) {
75
+ await requireSetupEditFileSnapshot(path, expected);
76
+ if (replacement.bytes === null) {
77
+ await rm(path);
78
+ await syncSetupEditDirectory(dirname(path));
79
+ return;
80
+ }
81
+ const temporary = `${path}.${randomUUID()}.setup-edit.tmp`;
82
+ try {
83
+ const handle = await open(temporary, "wx", replacement.mode);
84
+ try {
85
+ await handle.writeFile(Buffer.from(replacement.bytes, "base64"));
86
+ await handle.chmod(replacement.mode);
87
+ await handle.sync();
88
+ }
89
+ finally {
90
+ await handle.close();
91
+ }
92
+ await requireSetupEditFileSnapshot(path, expected);
93
+ await rename(temporary, path);
94
+ await syncSetupEditDirectory(dirname(path));
95
+ }
96
+ finally {
97
+ await rm(temporary, { force: true });
98
+ }
99
+ }
100
+ /** Publish the marker itself atomically; private mode also protects credential snapshots. */
101
+ export async function publishSetupEditJournal(path, text, expected) {
102
+ await restoreSetupEditFile(path, expected, setupEditTextSnapshot(text, 0o600));
103
+ await chmod(path, 0o600);
104
+ }
@@ -0,0 +1,29 @@
1
+ import { type SetupEditFileSnapshot } from "./runtime-setup-edit-files.js";
2
+ export declare const SETUP_EDIT_JOURNAL_NAME = ".runtime-setup-edit.json";
3
+ declare const FILE_ROLES: readonly ["model", "config", "receipt", "credentials"];
4
+ type SetupEditFileRole = (typeof FILE_ROLES)[number];
5
+ export type SetupEditJournalFile = Readonly<{
6
+ role: SetupEditFileRole;
7
+ path: string;
8
+ before: SetupEditFileSnapshot;
9
+ after: SetupEditFileSnapshot;
10
+ }>;
11
+ export type SetupEditJournal = Readonly<{
12
+ version: 1;
13
+ id: string;
14
+ rootDir: string;
15
+ phase: "pending" | "committed";
16
+ files: readonly SetupEditJournalFile[];
17
+ }>;
18
+ export type SetupEditFilePlan = Readonly<{
19
+ role: SetupEditFileRole;
20
+ path: string;
21
+ text: string;
22
+ mode?: number;
23
+ }>;
24
+ export declare function setupEditJournalPath(rootDir: string): string;
25
+ export declare function validateSetupEditJournal(value: unknown, rootDir: string): Promise<SetupEditJournal>;
26
+ export declare function readSetupEditJournal(rootDir: string): Promise<SetupEditJournal | undefined>;
27
+ export declare function createSetupEditJournal(rootDir: string, plans: readonly SetupEditFilePlan[]): Promise<SetupEditJournal>;
28
+ export declare function writeSetupEditJournal(journal: SetupEditJournal, previous?: SetupEditJournal): Promise<void>;
29
+ export {};
@@ -0,0 +1,151 @@
1
+ import { parse } from "dotenv";
2
+ import { isDeepStrictEqual } from "node:util";
3
+ import { randomUUID } from "node:crypto";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { isRecord } from "../../runtime/config/utils.js";
6
+ import { canonicalConfigFilePath } from "../../runtime/adapters/config-file-transaction.js";
7
+ import { readSetupEditFile, setupEditRecoveryRequired, setupEditSnapshotText, setupEditTextSnapshot, publishSetupEditJournal, } from "./runtime-setup-edit-files.js";
8
+ export const SETUP_EDIT_JOURNAL_NAME = ".runtime-setup-edit.json";
9
+ const FILE_ROLES = ["model", "config", "receipt", "credentials"];
10
+ export function setupEditJournalPath(rootDir) {
11
+ return join(rootDir, SETUP_EDIT_JOURNAL_NAME);
12
+ }
13
+ function isSetupEditSnapshot(value) {
14
+ if (!isRecord(value))
15
+ return false;
16
+ if (!Number.isInteger(value.mode))
17
+ return false;
18
+ if (typeof value.mode !== "number" || value.mode < 0 || value.mode > 0o777)
19
+ return false;
20
+ if (value.bytes === null)
21
+ return value.mode === 0;
22
+ if (typeof value.bytes !== "string")
23
+ return false;
24
+ return Buffer.from(value.bytes, "base64").toString("base64") === value.bytes;
25
+ }
26
+ function isSetupEditJournalFile(value, index) {
27
+ if (!isRecord(value))
28
+ return false;
29
+ if (value.role !== FILE_ROLES[index])
30
+ return false;
31
+ if (typeof value.path !== "string" || value.path !== resolve(value.path))
32
+ return false;
33
+ if (!isSetupEditSnapshot(value.before))
34
+ return false;
35
+ if (!isSetupEditSnapshot(value.after))
36
+ return false;
37
+ if (value.after.bytes === null)
38
+ return false;
39
+ if (value.role !== "credentials" && value.before.bytes === null)
40
+ return false;
41
+ return true;
42
+ }
43
+ function parseSetupEditObject(snapshot) {
44
+ const value = JSON.parse(setupEditSnapshotText(snapshot));
45
+ if (!isRecord(value))
46
+ throw setupEditRecoveryRequired();
47
+ return value;
48
+ }
49
+ async function requireSetupEditFileBindings(journal) {
50
+ const [model, config, receipt, credentials] = journal.files;
51
+ if (receipt.path !== config.path + ".web-setup.json")
52
+ throw setupEditRecoveryRequired();
53
+ if (credentials.path !== join(journal.rootDir, ".env"))
54
+ throw setupEditRecoveryRequired();
55
+ if (new Set(journal.files.map((file) => file.path)).size !== FILE_ROLES.length)
56
+ throw setupEditRecoveryRequired();
57
+ for (const state of ["before", "after"]) {
58
+ const draft = parseSetupEditObject(receipt[state]);
59
+ if (draft.version !== 1 || typeof draft.revision !== "string")
60
+ throw setupEditRecoveryRequired();
61
+ if (draft.configPath !== config.path || draft.modelPath !== model.path)
62
+ throw setupEditRecoveryRequired();
63
+ if (!isDeepStrictEqual(draft.modelConfig, parseSetupEditObject(model[state])))
64
+ throw setupEditRecoveryRequired();
65
+ const saved = parseSetupEditObject(config[state]);
66
+ const models = isRecord(saved.models) ? saved.models : {};
67
+ const profiles = isRecord(models.profiles) ? models.profiles : {};
68
+ if (!isDeepStrictEqual(draft.profileReferences, profiles))
69
+ throw setupEditRecoveryRequired();
70
+ if (!isRecord(draft.ownedProviders))
71
+ throw setupEditRecoveryRequired();
72
+ const providers = isRecord(models.providers) ? models.providers : {};
73
+ for (const [id, provider] of Object.entries(draft.ownedProviders)) {
74
+ if (!isDeepStrictEqual(providers[id], provider))
75
+ throw setupEditRecoveryRequired();
76
+ }
77
+ const profile = isRecord(profiles.default) ? profiles.default : {};
78
+ if (typeof profile.configRef !== "string")
79
+ throw setupEditRecoveryRequired();
80
+ const referenced = await canonicalConfigFilePath(resolve(dirname(config.path), profile.configRef));
81
+ if (referenced !== model.path)
82
+ throw setupEditRecoveryRequired();
83
+ }
84
+ const env = parse(setupEditSnapshotText(credentials.after));
85
+ if (typeof env.LLM_RUNTIME_CONFIG_FILE !== "string")
86
+ throw setupEditRecoveryRequired();
87
+ const configured = await canonicalConfigFilePath(resolve(journal.rootDir, env.LLM_RUNTIME_CONFIG_FILE));
88
+ if (configured !== config.path)
89
+ throw setupEditRecoveryRequired();
90
+ }
91
+ export async function validateSetupEditJournal(value, rootDir) {
92
+ try {
93
+ if (!isRecord(value))
94
+ throw setupEditRecoveryRequired();
95
+ if (value.version !== 1 || typeof value.id !== "string")
96
+ throw setupEditRecoveryRequired();
97
+ if (value.rootDir !== rootDir)
98
+ throw setupEditRecoveryRequired();
99
+ if (value.phase !== "pending" && value.phase !== "committed")
100
+ throw setupEditRecoveryRequired();
101
+ if (!Array.isArray(value.files) || value.files.length !== FILE_ROLES.length)
102
+ throw setupEditRecoveryRequired();
103
+ if (!value.files.every(isSetupEditJournalFile))
104
+ throw setupEditRecoveryRequired();
105
+ const journal = value;
106
+ await requireSetupEditFileBindings(journal);
107
+ return journal;
108
+ }
109
+ catch {
110
+ throw setupEditRecoveryRequired();
111
+ }
112
+ }
113
+ export async function readSetupEditJournal(rootDir) {
114
+ const snapshot = await readSetupEditFile(setupEditJournalPath(rootDir));
115
+ if (snapshot.bytes === null)
116
+ return undefined;
117
+ let value;
118
+ try {
119
+ value = JSON.parse(setupEditSnapshotText(snapshot));
120
+ }
121
+ catch {
122
+ throw setupEditRecoveryRequired();
123
+ }
124
+ return validateSetupEditJournal(value, rootDir);
125
+ }
126
+ export async function createSetupEditJournal(rootDir, plans) {
127
+ const files = [];
128
+ for (const plan of plans) {
129
+ const before = await readSetupEditFile(plan.path);
130
+ files.push({
131
+ role: plan.role,
132
+ path: plan.path,
133
+ before,
134
+ after: setupEditTextSnapshot(plan.text, plan.mode ?? before.mode),
135
+ });
136
+ }
137
+ return validateSetupEditJournal({
138
+ version: 1,
139
+ id: randomUUID(),
140
+ rootDir,
141
+ phase: "pending",
142
+ files,
143
+ }, rootDir);
144
+ }
145
+ export async function writeSetupEditJournal(journal, previous) {
146
+ const path = setupEditJournalPath(journal.rootDir);
147
+ const expected = previous
148
+ ? setupEditTextSnapshot(JSON.stringify(previous) + "\n", 0o600)
149
+ : { bytes: null, mode: 0 };
150
+ await publishSetupEditJournal(path, JSON.stringify(journal) + "\n", expected);
151
+ }
@@ -0,0 +1,7 @@
1
+ import { type SetupEditJournal } from "./runtime-setup-edit-journal.js";
2
+ /** Synchronous consumers must not observe any part of an unresolved edit. */
3
+ export declare function requireRuntimeSetupEditSettled(rootDir: string): void;
4
+ /** Caller holds every participant lock; repeatable after interruption at any restore. */
5
+ export declare function reconcileSetupEditJournal(journal: SetupEditJournal): Promise<void>;
6
+ /** Runs before dotenv/configuration loading. No journal means no speculative repair. */
7
+ export declare function recoverRuntimeSetupEdit(rootDir: string): Promise<void>;
@@ -0,0 +1,87 @@
1
+ import { lstatSync, realpathSync } from "node:fs";
2
+ import { realpath, rm } from "node:fs/promises";
3
+ import { join, resolve } from "node:path";
4
+ import { withFileLock } from "../../runtime/adapters/long-term-memory/file-lock.js";
5
+ import { CONFIG_FILE_LOCK_OPTIONS } from "../../runtime/adapters/config-file-transaction.js";
6
+ import { isMissingSetupEditFile, readSetupEditFile, requireSetupEditFileSnapshot, restoreSetupEditFile, setupEditFileMatches, setupEditRecoveryRequired, setupEditTextSnapshot, syncSetupEditDirectory, } from "./runtime-setup-edit-files.js";
7
+ import { readSetupEditJournal, setupEditJournalPath, } from "./runtime-setup-edit-journal.js";
8
+ /** Synchronous consumers must not observe any part of an unresolved edit. */
9
+ export function requireRuntimeSetupEditSettled(rootDir) {
10
+ let path = resolve(rootDir);
11
+ try {
12
+ path = realpathSync(path);
13
+ lstatSync(setupEditJournalPath(path));
14
+ }
15
+ catch (error) {
16
+ if (isMissingSetupEditFile(error))
17
+ return;
18
+ throw setupEditRecoveryRequired();
19
+ }
20
+ throw setupEditRecoveryRequired();
21
+ }
22
+ async function requireRecoverableSetupEditFiles(journal) {
23
+ for (const file of journal.files) {
24
+ const current = await readSetupEditFile(file.path);
25
+ if (setupEditFileMatches(current, file.after))
26
+ continue;
27
+ if (journal.phase === "pending" &&
28
+ setupEditFileMatches(current, file.before))
29
+ continue;
30
+ throw setupEditRecoveryRequired();
31
+ }
32
+ }
33
+ /** Caller holds every participant lock; repeatable after interruption at any restore. */
34
+ export async function reconcileSetupEditJournal(journal) {
35
+ await requireRecoverableSetupEditFiles(journal);
36
+ if (journal.phase === "pending") {
37
+ for (const file of [...journal.files].reverse()) {
38
+ const current = await readSetupEditFile(file.path);
39
+ if (setupEditFileMatches(current, file.before))
40
+ continue;
41
+ if (!setupEditFileMatches(current, file.after))
42
+ throw setupEditRecoveryRequired();
43
+ await restoreSetupEditFile(file.path, file.after, file.before);
44
+ }
45
+ }
46
+ const path = setupEditJournalPath(journal.rootDir);
47
+ await requireSetupEditFileSnapshot(path, setupEditTextSnapshot(JSON.stringify(journal) + "\n", 0o600));
48
+ await rm(path);
49
+ await syncSetupEditDirectory(journal.rootDir);
50
+ }
51
+ async function withSetupEditRecoveryLocks(journal, operation) {
52
+ const [model, config, receipt] = journal.files;
53
+ const locks = [
54
+ config.path + ".config.lock",
55
+ model.path + ".config.lock",
56
+ join(journal.rootDir, ".env.credentials.lock"),
57
+ receipt.path + ".config.lock",
58
+ ];
59
+ const acquire = (index) => {
60
+ if (index === locks.length)
61
+ return operation();
62
+ return withFileLock(locks[index], () => acquire(index + 1), CONFIG_FILE_LOCK_OPTIONS);
63
+ };
64
+ return acquire(0);
65
+ }
66
+ /** Runs before dotenv/configuration loading. No journal means no speculative repair. */
67
+ export async function recoverRuntimeSetupEdit(rootDir) {
68
+ try {
69
+ requireRuntimeSetupEditSettled(rootDir);
70
+ return;
71
+ }
72
+ catch {
73
+ // Parsing and lock acquisition below decide whether recovery is safe.
74
+ }
75
+ const root = await realpath(rootDir);
76
+ await withFileLock(join(root, ".runtime-setup.lock"), async () => {
77
+ const journal = await readSetupEditJournal(root);
78
+ if (!journal)
79
+ return;
80
+ await withSetupEditRecoveryLocks(journal, async () => {
81
+ const current = await readSetupEditJournal(root);
82
+ if (!current || JSON.stringify(current) !== JSON.stringify(journal))
83
+ throw setupEditRecoveryRequired();
84
+ await reconcileSetupEditJournal(journal);
85
+ });
86
+ }, CONFIG_FILE_LOCK_OPTIONS);
87
+ }
@@ -0,0 +1,3 @@
1
+ import { type SetupEditFilePlan } from "./runtime-setup-edit-journal.js";
2
+ /** Setup, config, model and credential locks enclose this complete transaction. */
3
+ export declare function commitRuntimeSetupEdit(rootDir: string, files: readonly SetupEditFilePlan[], commit: () => Promise<void>, publishCommittedCredentials: () => void): Promise<void>;