@timurproko/a1 0.2.6 → 0.2.7-dev.1221

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 (410) hide show
  1. package/README.md +41 -3
  2. package/bin/automatic-update.js +7 -0
  3. package/bin/cli.js +4 -0
  4. package/bin/guardian.js +5 -0
  5. package/bin/tab-launch-context.d.ts +27 -0
  6. package/bin/tab-launch-context.js +94 -0
  7. package/bin/ui.js +107 -59
  8. package/dist/app/session-shell/clipboard-diagnostics.js +1 -1
  9. package/dist/app/session-shell/dialog-coordinator.d.ts +42 -0
  10. package/dist/app/session-shell/dialog-coordinator.js +133 -0
  11. package/dist/app/session-shell/dock-chrome.d.ts +34 -0
  12. package/dist/app/session-shell/dock-chrome.js +109 -0
  13. package/dist/app/session-shell/exit-notice.d.ts +1 -1
  14. package/dist/app/session-shell/exit-notice.js +1 -1
  15. package/dist/app/session-shell/extension-surface.d.ts +30 -0
  16. package/dist/app/session-shell/extension-surface.js +105 -0
  17. package/dist/app/session-shell/helper-pool.d.ts +3 -5
  18. package/dist/app/session-shell/helper-pool.js +3 -5
  19. package/dist/app/session-shell/input-surface-switch.d.ts +36 -0
  20. package/dist/app/session-shell/input-surface-switch.js +85 -0
  21. package/dist/app/session-shell/login-interaction.d.ts +27 -0
  22. package/dist/app/session-shell/login-interaction.js +91 -0
  23. package/dist/app/session-shell/prompt-submission.d.ts +48 -0
  24. package/dist/app/session-shell/prompt-submission.js +276 -0
  25. package/dist/app/session-shell/resident-tab-coordinator.d.ts +38 -0
  26. package/dist/app/session-shell/resident-tab-coordinator.js +77 -0
  27. package/dist/app/session-shell/response-copy-helper.js +21 -6
  28. package/dist/app/session-shell/response-copy-protocol.d.ts +1 -1
  29. package/dist/app/session-shell/response-copy-transport.d.ts +16 -6
  30. package/dist/app/session-shell/response-copy-transport.js +69 -17
  31. package/dist/app/session-shell/session-concern.d.ts +22 -0
  32. package/dist/app/session-shell/session-concern.js +29 -0
  33. package/dist/app/session-shell/session-lifecycle.d.ts +29 -0
  34. package/dist/app/session-shell/session-lifecycle.js +49 -0
  35. package/dist/app/session-shell/session-shell-root.d.ts +42 -6
  36. package/dist/app/session-shell/session-shell-root.js +196 -908
  37. package/dist/app/session-shell/session-shell.d.ts +3 -8
  38. package/dist/app/session-shell/session-shell.js +324 -835
  39. package/dist/app/session-shell/session-viewport-controller.d.ts +2 -2
  40. package/dist/app/session-shell/session-viewport-controller.js +29 -15
  41. package/dist/app/session-shell/settings-bindings.d.ts +17 -0
  42. package/dist/app/session-shell/settings-bindings.js +91 -0
  43. package/dist/app/session-shell/shell-editor-factory.d.ts +27 -0
  44. package/dist/app/session-shell/shell-editor-factory.js +102 -0
  45. package/dist/app/session-shell/shell-host.d.ts +6 -0
  46. package/dist/app/session-shell/shell-host.js +34 -7
  47. package/dist/app/session-shell/shell-layout.d.ts +64 -0
  48. package/dist/app/session-shell/shell-layout.js +18 -0
  49. package/dist/app/session-shell/suggestion-surface.d.ts +25 -0
  50. package/dist/app/session-shell/suggestion-surface.js +63 -0
  51. package/dist/app/session-shell/transcript-document.d.ts +78 -0
  52. package/dist/app/session-shell/transcript-document.js +365 -0
  53. package/dist/app/session-shell/viewport-layout.d.ts +31 -0
  54. package/dist/app/session-shell/viewport-layout.js +160 -0
  55. package/dist/app/session-shell/workflow-output.d.ts +33 -0
  56. package/dist/app/session-shell/workflow-output.js +174 -0
  57. package/dist/app/session-shell/workflow-router.d.ts +25 -0
  58. package/dist/app/session-shell/workflow-router.js +39 -0
  59. package/dist/cli/dispatch.d.ts +11 -1
  60. package/dist/cli/dispatch.js +79 -5
  61. package/dist/cli/tabs-request.d.ts +7 -0
  62. package/dist/cli/tabs-request.js +1 -0
  63. package/dist/cli/tabs.d.ts +14 -0
  64. package/dist/cli/tabs.js +151 -0
  65. package/dist/cli/version-stats.js +38 -3
  66. package/dist/composition/owned-settings.d.ts +12 -0
  67. package/dist/composition/owned-settings.js +36 -0
  68. package/dist/composition/owned-ui.d.ts +27 -28
  69. package/dist/composition/owned-ui.js +205 -153
  70. package/dist/composition/resident-tab-bridge.d.ts +25 -0
  71. package/dist/composition/resident-tab-bridge.js +180 -0
  72. package/dist/composition/session-backend.d.ts +19 -0
  73. package/dist/composition/session-backend.js +1 -0
  74. package/dist/composition/session-runtime-registry.d.ts +20 -0
  75. package/dist/composition/session-runtime-registry.js +85 -0
  76. package/dist/composition/settings-route-host.d.ts +16 -1
  77. package/dist/composition/settings-route-host.js +29 -10
  78. package/dist/composition/settings-search-input.d.ts +9 -0
  79. package/dist/composition/settings-search-input.js +58 -0
  80. package/dist/composition/startup-route.d.ts +32 -0
  81. package/dist/composition/startup-route.js +72 -0
  82. package/dist/composition/utility-tab.d.ts +28 -0
  83. package/dist/composition/utility-tab.js +242 -0
  84. package/dist/contracts/owned-ui/index.d.ts +1 -1
  85. package/dist/contracts/owned-ui/model.d.ts +3 -0
  86. package/dist/contracts/owned-ui/session-backend.d.ts +3 -0
  87. package/dist/contracts/owned-ui/session-workflows.d.ts +11 -4
  88. package/dist/contracts/presentation/index.d.ts +11 -0
  89. package/dist/contracts/presentation/index.js +12 -0
  90. package/dist/features/launch/development-launch.js +6 -0
  91. package/dist/features/launch/index.d.ts +1 -1
  92. package/dist/features/launch/intent.d.ts +3 -1
  93. package/dist/features/launch/intent.js +7 -4
  94. package/dist/features/launch/profile-paths.js +4 -0
  95. package/dist/features/owned-ui/plus-menu-dialog.d.ts +22 -0
  96. package/dist/features/owned-ui/plus-menu-dialog.js +76 -0
  97. package/dist/features/owned-ui/project-trust-dialog.d.ts +1 -1
  98. package/dist/features/owned-ui/project-trust-dialog.js +6 -8
  99. package/dist/features/owned-ui/project-trust-prompt.d.ts +1 -0
  100. package/dist/features/owned-ui/project-trust-prompt.js +7 -3
  101. package/dist/features/owned-ui/reference-screen-app.d.ts +2 -0
  102. package/dist/features/owned-ui/reference-screen-app.js +12 -2
  103. package/dist/features/owned-ui/settings-app.d.ts +12 -2
  104. package/dist/features/owned-ui/settings-app.js +116 -81
  105. package/dist/features/owned-ui/settings-search-input.d.ts +29 -0
  106. package/dist/features/owned-ui/settings-search-input.js +1 -0
  107. package/dist/features/prompt-history/index.d.ts +1 -1
  108. package/dist/features/prompt-history/paths.d.ts +2 -1
  109. package/dist/features/prompt-history/paths.js +10 -2
  110. package/dist/features/prompt-history/service.d.ts +5 -0
  111. package/dist/features/prompt-history/service.js +1 -1
  112. package/dist/features/resident-tab/auto-name.d.ts +11 -0
  113. package/dist/features/resident-tab/auto-name.js +44 -0
  114. package/dist/features/resident-tab/index.d.ts +5 -0
  115. package/dist/features/resident-tab/index.js +7 -0
  116. package/dist/features/resident-tab/shortcut-bindings-file.d.ts +8 -0
  117. package/dist/features/resident-tab/shortcut-bindings-file.js +40 -0
  118. package/dist/features/resident-tab/shortcut-declarations.d.ts +13 -0
  119. package/dist/features/resident-tab/shortcut-declarations.js +26 -0
  120. package/dist/features/resident-tab/shortcut-projection.d.ts +29 -0
  121. package/dist/features/resident-tab/shortcut-projection.js +64 -0
  122. package/dist/features/resident-tab/status-deriver.d.ts +10 -0
  123. package/dist/features/resident-tab/status-deriver.js +12 -0
  124. package/dist/foundation/launch-context/index.d.ts +12 -0
  125. package/dist/foundation/launch-context/index.js +26 -0
  126. package/dist/foundation/launch-guardian/exit-watcher.d.ts +14 -0
  127. package/dist/foundation/launch-guardian/exit-watcher.js +94 -0
  128. package/dist/foundation/launch-guardian/main.d.ts +7 -1
  129. package/dist/foundation/launch-guardian/main.js +60 -7
  130. package/dist/foundation/lifecycle/session-repository-context.js +16 -2
  131. package/dist/foundation/process-containment/{native-guardian-containment.d.ts → addon-containment.d.ts} +7 -5
  132. package/dist/foundation/process-containment/addon-containment.js +139 -0
  133. package/dist/foundation/process-containment/addon-process-inspector.d.ts +11 -0
  134. package/dist/foundation/process-containment/addon-process-inspector.js +36 -0
  135. package/dist/foundation/process-containment/addon.d.ts +42 -0
  136. package/dist/foundation/process-containment/addon.js +57 -0
  137. package/dist/foundation/process-containment/artifact.d.ts +1 -1
  138. package/dist/foundation/process-containment/artifact.js +6 -5
  139. package/dist/foundation/process-containment/contracts.d.ts +2 -0
  140. package/dist/foundation/process-containment/index.d.ts +4 -4
  141. package/dist/foundation/process-containment/index.js +3 -3
  142. package/dist/foundation/process-containment/native-process-inspector.d.ts +2 -1
  143. package/dist/foundation/process-containment/native-process-inspector.js +10 -10
  144. package/dist/foundation/release/automatic-update.d.ts +37 -0
  145. package/dist/foundation/release/automatic-update.js +265 -0
  146. package/dist/foundation/release/bootstrap.d.ts +7 -9
  147. package/dist/foundation/release/bootstrap.js +107 -24
  148. package/dist/foundation/release/cohort-state.d.ts +1 -1
  149. package/dist/foundation/release/cohort-state.js +1 -1
  150. package/dist/foundation/release/dependency-certification.js +54 -19
  151. package/dist/foundation/release/early-accent.d.ts +12 -0
  152. package/dist/foundation/release/early-accent.js +59 -0
  153. package/dist/foundation/release/index.d.ts +2 -2
  154. package/dist/foundation/release/index.js +2 -2
  155. package/dist/foundation/release/latest-release.d.ts +24 -2
  156. package/dist/foundation/release/latest-release.js +51 -1
  157. package/dist/foundation/release/progress-palette.generated.d.ts +137 -3
  158. package/dist/foundation/release/progress-palette.generated.js +137 -3
  159. package/dist/foundation/release/release-gc.d.ts +3 -0
  160. package/dist/foundation/release/release-gc.js +59 -8
  161. package/dist/foundation/release/release-store.d.ts +12 -0
  162. package/dist/foundation/release/release-store.js +124 -2
  163. package/dist/foundation/release/update-execution-lease.d.ts +48 -0
  164. package/dist/foundation/release/update-execution-lease.js +161 -0
  165. package/dist/foundation/release/update.d.ts +12 -7
  166. package/dist/foundation/release/update.js +281 -196
  167. package/dist/foundation/resident-tabs/bounded-host-command.d.ts +18 -0
  168. package/dist/foundation/resident-tabs/bounded-host-command.js +39 -0
  169. package/dist/foundation/resident-tabs/bridge-client.d.ts +70 -0
  170. package/dist/foundation/resident-tabs/bridge-client.js +321 -0
  171. package/dist/foundation/resident-tabs/doctor.d.ts +28 -0
  172. package/dist/foundation/resident-tabs/doctor.js +166 -0
  173. package/dist/foundation/resident-tabs/draft-checkpoint.d.ts +27 -0
  174. package/dist/foundation/resident-tabs/draft-checkpoint.js +145 -0
  175. package/dist/foundation/resident-tabs/ensure-terminal-host.d.ts +36 -0
  176. package/dist/foundation/resident-tabs/ensure-terminal-host.js +151 -0
  177. package/dist/foundation/resident-tabs/fault-injection.d.ts +8 -0
  178. package/dist/foundation/resident-tabs/fault-injection.js +26 -0
  179. package/dist/foundation/resident-tabs/fixture-control.d.ts +7 -0
  180. package/dist/foundation/resident-tabs/fixture-control.js +35 -0
  181. package/dist/foundation/resident-tabs/host-entry.d.ts +1 -0
  182. package/dist/foundation/resident-tabs/host-entry.js +17 -0
  183. package/dist/foundation/resident-tabs/index.d.ts +12 -0
  184. package/dist/foundation/resident-tabs/index.js +6 -0
  185. package/dist/foundation/resident-tabs/maintenance.d.ts +39 -0
  186. package/dist/foundation/resident-tabs/maintenance.js +75 -0
  187. package/dist/foundation/resident-tabs/progress-observation-schema.d.ts +34 -0
  188. package/dist/foundation/resident-tabs/progress-observation-schema.js +1 -0
  189. package/dist/foundation/resident-tabs/progress-observation.d.ts +4 -0
  190. package/dist/foundation/resident-tabs/progress-observation.js +150 -0
  191. package/dist/foundation/resident-tabs/prompt-journal.d.ts +63 -0
  192. package/dist/foundation/resident-tabs/prompt-journal.js +213 -0
  193. package/dist/foundation/resident-tabs/protocol.d.ts +12 -0
  194. package/dist/foundation/resident-tabs/protocol.js +195 -0
  195. package/dist/foundation/resident-tabs/recovery.d.ts +26 -0
  196. package/dist/foundation/resident-tabs/recovery.js +205 -0
  197. package/dist/foundation/resident-tabs/release-holds.d.ts +28 -0
  198. package/dist/foundation/resident-tabs/release-holds.js +75 -0
  199. package/dist/foundation/resident-tabs/routes.d.ts +5 -0
  200. package/dist/foundation/resident-tabs/routes.js +5 -0
  201. package/dist/foundation/resident-tabs/routing.d.ts +11 -0
  202. package/dist/foundation/resident-tabs/routing.js +10 -0
  203. package/dist/foundation/resident-tabs/session-sync.d.ts +14 -0
  204. package/dist/foundation/resident-tabs/session-sync.js +37 -0
  205. package/dist/foundation/resident-tabs/settings.d.ts +12 -0
  206. package/dist/foundation/resident-tabs/settings.js +58 -0
  207. package/dist/foundation/resident-tabs/terminal-host-artifact.d.ts +14 -0
  208. package/dist/foundation/resident-tabs/terminal-host-artifact.js +78 -0
  209. package/dist/foundation/resident-tabs/zip-archive.d.ts +9 -0
  210. package/dist/foundation/resident-tabs/zip-archive.js +56 -0
  211. package/dist/foundation/session-writer-lock/index.d.ts +30 -0
  212. package/dist/foundation/session-writer-lock/index.js +203 -0
  213. package/dist/foundation/startup/startup-descriptor.js +2 -2
  214. package/dist/foundation/terminal-cleanup/index.d.ts +1 -1
  215. package/dist/foundation/terminal-cleanup/index.js +1 -1
  216. package/dist/foundation/terminal-cleanup/terminal-reset.d.ts +6 -0
  217. package/dist/foundation/terminal-cleanup/terminal-reset.js +6 -0
  218. package/dist/integrations/pi/components/editor-interaction.d.ts +2 -0
  219. package/dist/integrations/pi/components/modal-frame.d.ts +17 -1
  220. package/dist/integrations/pi/components/modal-frame.js +48 -9
  221. package/dist/integrations/pi/components/models-dialog.js +4 -52
  222. package/dist/integrations/pi/components/owned-editor-ux.d.ts +6 -1
  223. package/dist/integrations/pi/components/owned-editor-ux.js +90 -6
  224. package/dist/integrations/pi/components/resources/builtin-themes.d.ts +4 -4
  225. package/dist/integrations/pi/components/resources/builtin-themes.js +4 -4
  226. package/dist/integrations/pi/components/share-operation-dialog.d.ts +2 -0
  227. package/dist/integrations/pi/components/share-operation-dialog.js +2 -1
  228. package/dist/integrations/pi/components/shell-editor-autocomplete.js +58 -36
  229. package/dist/integrations/pi/components/shell-extension-ui.js +79 -60
  230. package/dist/integrations/pi/components/shell-footer-status.d.ts +1 -1
  231. package/dist/integrations/pi/components/shell-footer-status.js +21 -5
  232. package/dist/integrations/pi/components/shell-hotkey-sections.js +1 -1
  233. package/dist/integrations/pi/components/shell-presenters-info.d.ts +5 -2
  234. package/dist/integrations/pi/components/shell-presenters-info.js +18 -4
  235. package/dist/integrations/pi/components/shell-presenters-transcript.js +4 -1
  236. package/dist/integrations/pi/components/shell-selectors-dialogs.js +5 -1
  237. package/dist/integrations/pi/components/shell-shared-facade.d.ts +12 -1
  238. package/dist/integrations/pi/components/skills-dialog.js +2 -2
  239. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
  240. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +17 -4
  241. package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
  242. package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
  243. package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
  244. package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
  245. package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
  246. package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
  247. package/dist/integrations/pi/components/upstream/components/extension-selector.js +1 -1
  248. package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
  249. package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +8 -6
  250. package/dist/integrations/pi/components/upstream/components/owned-editor.js +16 -9
  251. package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
  252. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +4 -4
  253. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +2 -2
  254. package/dist/integrations/pi/components/upstream/components/session-footer.d.ts +2 -1
  255. package/dist/integrations/pi/components/upstream/components/session-footer.js +31 -25
  256. package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
  257. package/dist/integrations/pi/components/upstream/components/session-selector.js +8 -7
  258. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +1 -1
  259. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +1 -1
  260. package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +2 -2
  261. package/dist/integrations/pi/components/upstream/components/status-indicator.js +3 -3
  262. package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
  263. package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
  264. package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +8 -7
  265. package/dist/integrations/pi/components/upstream/components/thinking-selector.js +10 -9
  266. package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +2 -6
  267. package/dist/integrations/pi/components/upstream/components/tool-execution.js +103 -101
  268. package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +9 -9
  269. package/dist/integrations/pi/components/upstream/components/tree-selector.js +13 -21
  270. package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
  271. package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
  272. package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +2 -2
  273. package/dist/integrations/pi/components/upstream/history/editor-core.js +7 -5
  274. package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
  275. package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
  276. package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
  277. package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
  278. package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
  279. package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
  280. package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
  281. package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
  282. package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +1 -1
  283. package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
  284. package/dist/integrations/pi/components/upstream/theme/theme.d.ts +5 -0
  285. package/dist/integrations/pi/components/upstream/theme/theme.js +29 -2
  286. package/dist/integrations/pi/engine/adapter.d.ts +5 -77
  287. package/dist/integrations/pi/engine/adapter.js +95 -394
  288. package/dist/integrations/pi/engine/command-dispatch.d.ts +13 -0
  289. package/dist/integrations/pi/engine/command-dispatch.js +57 -0
  290. package/dist/integrations/pi/engine/host.js +2 -2
  291. package/dist/integrations/pi/engine/offline-settings-port.d.ts +23 -0
  292. package/dist/integrations/pi/engine/offline-settings-port.js +53 -0
  293. package/dist/integrations/pi/engine/pi-settings-metadata.json +14 -2
  294. package/dist/integrations/pi/engine/ports.d.ts +56 -0
  295. package/dist/integrations/pi/engine/ports.js +93 -0
  296. package/dist/integrations/pi/engine/prompt-suggestions.d.ts +1 -0
  297. package/dist/integrations/pi/engine/prompt-suggestions.js +40 -0
  298. package/dist/integrations/pi/engine/resources/changelog.json +4 -4
  299. package/dist/integrations/pi/engine/runtime-integration.js +102 -29
  300. package/dist/integrations/pi/engine/session-runtime.d.ts +0 -6
  301. package/dist/integrations/pi/engine/session-runtime.js +13 -5
  302. package/dist/integrations/pi/engine/session-selection.d.ts +3 -0
  303. package/dist/integrations/pi/engine/session-selection.js +45 -9
  304. package/dist/integrations/pi/engine/settings-bridge.d.ts +5 -0
  305. package/dist/integrations/pi/engine/settings-bridge.js +15 -0
  306. package/dist/integrations/pi/engine/settings-port.js +11 -15
  307. package/dist/integrations/pi/engine/view-state.d.ts +42 -0
  308. package/dist/integrations/pi/engine/view-state.js +126 -0
  309. package/dist/integrations/pi/engine/workflow-contexts.js +10 -1
  310. package/dist/integrations/pi/engine/workflow-runner.js +73 -4
  311. package/dist/integrations/pi/engine/workflow-support.d.ts +12 -0
  312. package/dist/integrations/pi/engine/workflow-support.js +36 -0
  313. package/dist/integrations/pi/engine/workflows.d.ts +3 -1
  314. package/dist/integrations/pi/engine/workflows.js +1 -0
  315. package/dist/integrations/pi/startup-public.js +257 -310
  316. package/dist/integrations/pi/startup-public.manifest.json +564 -440
  317. package/dist/integrations/pi/tui-runtime/adapter.d.ts +6 -0
  318. package/dist/integrations/pi/tui-runtime/adapter.js +32 -1
  319. package/dist/integrations/pi/tui-runtime/contracts.d.ts +5 -0
  320. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +12 -1
  321. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +31 -2
  322. package/dist/native/darwin-arm64/manifest.json +10 -7
  323. package/dist/native/darwin-arm64/process-guardian.node +0 -0
  324. package/dist/native/darwin-arm64/terminal-host-THIRD-PARTY-NOTICES.txt +10500 -0
  325. package/dist/native/darwin-arm64/terminal-host.manifest.json +46 -0
  326. package/dist/native/darwin-arm64/terminal-host.node +0 -0
  327. package/dist/native/darwin-x64/manifest.json +23 -0
  328. package/dist/native/darwin-x64/process-guardian.node +0 -0
  329. package/dist/native/darwin-x64/terminal-host-THIRD-PARTY-NOTICES.txt +10737 -0
  330. package/dist/native/darwin-x64/terminal-host.manifest.json +46 -0
  331. package/dist/native/darwin-x64/terminal-host.node +0 -0
  332. package/dist/native/linux-x64/manifest.json +10 -7
  333. package/dist/native/linux-x64/process-guardian.node +0 -0
  334. package/dist/native/linux-x64/terminal-host-THIRD-PARTY-NOTICES.txt +11226 -0
  335. package/dist/native/linux-x64/terminal-host.manifest.json +46 -0
  336. package/dist/native/linux-x64/terminal-host.node +0 -0
  337. package/dist/native/win32-x64/manifest.json +10 -7
  338. package/dist/native/win32-x64/process-guardian.node +0 -0
  339. package/dist/native/win32-x64/terminal-host-THIRD-PARTY-NOTICES.txt +10757 -0
  340. package/dist/native/win32-x64/terminal-host.manifest.json +46 -0
  341. package/dist/native/win32-x64/terminal-host.node +0 -0
  342. package/dist/product-identity.d.ts +3 -3
  343. package/dist/product-identity.js +4 -4
  344. package/dist/product-identity.json +16 -2
  345. package/dist/runtime-payload-inventory.json +6330 -6677
  346. package/dist/ui/apps/host.d.ts +2 -0
  347. package/dist/ui/apps/host.js +7 -1
  348. package/dist/ui/components/dialog-panel.js +35 -30
  349. package/dist/ui/components/index.d.ts +2 -2
  350. package/dist/ui/components/index.js +1 -1
  351. package/dist/ui/components/line-input.d.ts +4 -1
  352. package/dist/ui/components/line-input.js +3 -1
  353. package/dist/ui/components/prompt-input.d.ts +11 -8
  354. package/dist/ui/components/prompt-input.js +15 -13
  355. package/dist/ui/components/selection-copy.d.ts +2 -0
  356. package/dist/ui/components/selection-copy.js +13 -0
  357. package/dist/ui/components/spans.js +2 -2
  358. package/dist/ui/components/submitted-prompt.d.ts +9 -6
  359. package/dist/ui/components/submitted-prompt.js +20 -12
  360. package/dist/ui/components/surface.js +4 -2
  361. package/dist/ui/components/text.d.ts +3 -6
  362. package/dist/ui/components/text.js +6 -8
  363. package/dist/ui/components/transcript-viewport.d.ts +9 -2
  364. package/dist/ui/components/transcript-viewport.js +176 -55
  365. package/dist/ui/settings/declarations.d.ts +90 -16
  366. package/dist/ui/settings/declarations.js +67 -14
  367. package/dist/ui/settings/early-accent.d.ts +81 -0
  368. package/dist/ui/settings/early-accent.js +50 -0
  369. package/dist/ui/settings/index.d.ts +4 -2
  370. package/dist/ui/settings/index.js +2 -1
  371. package/dist/ui/settings/manager.d.ts +16 -3
  372. package/dist/ui/settings/manager.js +122 -33
  373. package/dist/ui/settings/migrations.d.ts +6 -0
  374. package/dist/ui/settings/migrations.js +73 -0
  375. package/dist/ui/settings/profile-document.d.ts +26 -0
  376. package/dist/ui/settings/profile-document.js +164 -0
  377. package/dist/ui/settings/progress-palette.generated.d.ts +139 -0
  378. package/dist/ui/settings/progress-palette.generated.js +139 -0
  379. package/dist/ui/settings/sections.d.ts +4 -0
  380. package/dist/ui/settings/sections.js +9 -3
  381. package/docs/architecture/boundaries.md +24 -9
  382. package/docs/architecture/evidence/resident-tabs/linux-x64.md +37 -0
  383. package/docs/architecture/evidence/resident-tabs/macos-arm64.md +36 -0
  384. package/docs/architecture/evidence/resident-tabs/macos-x64.md +35 -0
  385. package/docs/architecture/evidence/resident-tabs/windows-x64.md +36 -0
  386. package/docs/architecture/internal-naming.md +3 -1
  387. package/docs/architecture/process-guardian-provenance.md +18 -10
  388. package/docs/architecture/project-structure.md +8 -0
  389. package/docs/architecture/resident-tabs-requirements.md +18 -0
  390. package/docs/architecture/resident-tabs.md +648 -0
  391. package/docs/architecture/response-copy-delivery.md +1 -1
  392. package/docs/architecture/terminal-host-proof-gate.md +2 -0
  393. package/docs/architecture/terminal-host-provenance.md +16 -4
  394. package/docs/architecture/tool-image-presentation.md +2 -1
  395. package/docs/architecture/toolchain.md +11 -9
  396. package/docs/ci-release-runbook.md +14 -7
  397. package/docs/features/launch-profiles.md +11 -8
  398. package/docs/features/prompt-history.md +41 -20
  399. package/docs/manual-resident-tabs-acceptance.md +51 -0
  400. package/docs/openspec-archive-automation.md +49 -22
  401. package/docs/validation.md +49 -9
  402. package/package.json +19 -6
  403. package/dist/foundation/process-containment/darwin-process-inspector.d.ts +0 -5
  404. package/dist/foundation/process-containment/darwin-process-inspector.js +0 -7
  405. package/dist/foundation/process-containment/native-guardian-containment.js +0 -152
  406. package/dist/foundation/process-containment/windows-process-inspector.d.ts +0 -19
  407. package/dist/foundation/process-containment/windows-process-inspector.js +0 -56
  408. package/dist/native/darwin-arm64/process-guardian +0 -0
  409. package/dist/native/linux-x64/process-guardian +0 -0
  410. package/dist/native/win32-x64/process-guardian.exe +0 -0
@@ -5,8 +5,9 @@ import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
5
5
  import crossSpawn from "cross-spawn";
6
6
  import { valid as validSemver } from "semver";
7
7
  import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../../product-identity.js";
8
+ import { earlyAccentPalette, earlyTerminalAppearance, earlyTerminalColorMode, resolveEarlyAccentColor } from "./early-accent.js";
8
9
  import { SHARED_PROGRESS_ACCENT_ANSI } from "./progress-palette.generated.js";
9
- import { isNewerRelease, releaseChannelOf } from "./latest-release.js";
10
+ import { createRegistryFetcher, invalidateReleaseCheckCache, isNewerRelease, queryPublishedVersions, releaseChannelOf, } from "./latest-release.js";
10
11
  import { certifyMaterializedRelease, ensureSupervisor, waitForProcessExit, } from "./bootstrap.js";
11
12
  import { probeOwnership, readEndpointMetadata, removeEndpointArtifacts } from "./endpoints.js";
12
13
  import { resolveCohortEndpoint, resolveProductPaths } from "../lifecycle/index.js";
@@ -17,6 +18,7 @@ import { materializeRelease, readMaterializedRelease } from "./release-store.js"
17
18
  import { scheduleReleaseCleanup } from "./release-gc.js";
18
19
  import { UPDATE_ACTIVATION_CONTRACT, activateInstalledRelease, delegateActivation, readActivationContracts, } from "./update-activation.js";
19
20
  import { UpdateTransactionStore } from "./update-transaction.js";
21
+ import { acquireUpdateExecutionLease, reclaimDeadLease } from "./update-execution-lease.js";
20
22
  import { npmPrefixForGlobalRoot, removeUpdateRecoveryCapsule, resolveNpmCli, runProtectedPackageReplacement, updateLauncherPaths, updateNpmInstallArguments, } from "./update-recovery.js";
21
23
  export const PRODUCT_PACKAGE = PRODUCT_TEXT.packageName;
22
24
  const UPDATE_DIST_TAGS = { stable: "latest", next: "next" };
@@ -34,6 +36,9 @@ const defaultFileSystem = {
34
36
  * The update therefore keeps checking for this long before it calls the package locked.
35
37
  */
36
38
  export const PACKAGE_UNLOCK_PATIENCE_MS = 15_000;
39
+ export const UPDATE_ALREADY_RUNNING_EXIT_CODE = 75;
40
+ /** A named preview reads the registry's whole package document, which is larger than a dist-tag lookup. */
41
+ const PREVIEW_LOOKUP_TIMEOUT_MS = 30_000;
37
42
  const PACKAGE_UNLOCK_INITIAL_DELAY_MS = 100;
38
43
  const PACKAGE_UNLOCK_MAX_DELAY_MS = 1_000;
39
44
  // Platform: Windows reports a held directory as EPERM or EBUSY; EACCES and ENOTEMPTY are the other
@@ -85,6 +90,21 @@ export function createNpmProcessRunner(platform = process.platform) {
85
90
  * its own endpoint. A cohort running from the mutable installation is the one exception,
86
91
  * because that installation is exactly what is about to be replaced under it.
87
92
  */
93
+ async function verifyAutomaticUpdateSafety(paths, stateStore, environment) {
94
+ const state = await stateStore.read();
95
+ const owner = await readActiveEndpoint(paths, state.references.active, environment);
96
+ if (!owner)
97
+ return;
98
+ const ownership = await probeOwnership(owner.metadata);
99
+ if (ownership === "dead")
100
+ return;
101
+ if (ownership !== "live-verified") {
102
+ throw new UpdateAutomaticDeferred(PRODUCT_TEXT.diagnostic(`automatic update deferred because supervisor ownership is ${ownership}`));
103
+ }
104
+ if (!await canonicalImmutableRoot(paths.dataDir, owner.metadata.releaseRoot)) {
105
+ throw new UpdateAutomaticDeferred(PRODUCT_TEXT.diagnostic("automatic update deferred because the running session is not using a retained immutable release; run the update command manually"));
106
+ }
107
+ }
88
108
  export function planUpdateOwnership(ownership, runsFromRetainedRelease) {
89
109
  if (ownership === "dead")
90
110
  return "clean-dead-record";
@@ -111,13 +131,13 @@ export function createUpdateLifecycleCoordinator(environment = process.env, file
111
131
  const stateStore = new CohortStateStore(paths.dataDir);
112
132
  return {
113
133
  async targetIsActive(targetVersion) {
114
- const state = await stateStore.read();
115
- const activeId = state.references.active;
134
+ const state = await stateStore.read(), activeId = state.references.active;
116
135
  if (!activeId || state.releases[activeId]?.packageVersion !== targetVersion)
117
136
  return false;
118
137
  const endpoint = await readActiveEndpoint(paths, activeId, environment);
119
138
  return endpoint?.metadata.releaseId === activeId && await probeOwnership(endpoint.metadata) === "live-verified";
120
139
  },
140
+ async verifyAutomaticSafety() { await verifyAutomaticUpdateSafety(paths, stateStore, environment); },
121
141
  async shutdownVerifiedOwners(targetVersion) {
122
142
  const state = await stateStore.read();
123
143
  const activeId = state.references.active;
@@ -233,16 +253,19 @@ const ACTIVATION_PROGRESS = {
233
253
  "active-reference-committed": { at: 96, creepTo: 99 },
234
254
  };
235
255
  /** Renders the terminal-only update meter; the visual preview shares this exact frame. */
236
- export function renderUpdateProgressBar(percent) {
256
+ export function renderUpdateProgressBar(percent, accent = SHARED_PROGRESS_ACCENT_ANSI) {
237
257
  const bounded = Math.min(100, Math.max(0, Math.round(percent)));
238
258
  const filled = Math.round((bounded / 100) * PROGRESS_BAR_WIDTH);
239
- // Rationale: the completed run follows the pinned Pi controls' semantic accent,
240
- // while the track and percentage retain the update meter's neutral treatment.
259
+ // Rationale: the completed run follows the A1 profile accent; the track and
260
+ // percentage retain the update meter's neutral treatment.
241
261
  const gray = "\u001b[38;2;128;128;128m";
242
262
  const track = "\u001b[38;2;102;102;102m";
243
- return `${SHARED_PROGRESS_ACCENT_ANSI}${"━".repeat(filled)}${track}${"─".repeat(PROGRESS_BAR_WIDTH - filled)}${gray} ${bounded}%\u001b[39m`;
263
+ return `${accent}${"━".repeat(filled)}${track}${"─".repeat(PROGRESS_BAR_WIDTH - filled)}${gray} ${bounded}%\u001b[39m`;
264
+ }
265
+ function updateProgressAccent(environment) {
266
+ return earlyAccentPalette(resolveEarlyAccentColor(environment), earlyTerminalAppearance(environment), earlyTerminalColorMode(environment)).accent;
244
267
  }
245
- function createUpdateProgress(output, enabled) {
268
+ function createUpdateProgress(output, enabled, accent = SHARED_PROGRESS_ACCENT_ANSI) {
246
269
  let visible = false;
247
270
  let current = 0;
248
271
  let shown = -1;
@@ -253,7 +276,7 @@ function createUpdateProgress(output, enabled) {
253
276
  return;
254
277
  shown = rounded;
255
278
  visible = true;
256
- output.stdout(`\r${renderUpdateProgressBar(rounded)}`);
279
+ output.stdout(`\r${renderUpdateProgressBar(rounded, accent)}`);
257
280
  };
258
281
  const stopCreep = () => {
259
282
  if (timer !== null) {
@@ -320,35 +343,28 @@ async function resolveChannelHead(runner, distTag, output) {
320
343
  /**
321
344
  * Resolve a preview the caller named.
322
345
  *
323
- * A preview is published as `<version>-dev.<pull-request-number>`, so its decimal
324
- * development number is enough to identify it. A full version is accepted too.
325
- * The published list remains authoritative: nothing is constructed from the
326
- * installed package's base version.
346
+ * A decimal names the pull request a published preview records in its manifest, or the trailing
347
+ * number of a preview published as `<version>-dev.<pull-request>` before pull requests were
348
+ * recorded; a full version is accepted too. The registry's published manifests remain
349
+ * authoritative: nothing is constructed from the installed package's base version.
327
350
  */
328
- async function resolveRequestedPreview(runner, requested, output) {
329
- const lookup = await runNpm(runner, ["view", PRODUCT_PACKAGE, "versions", "--json"], true, output, "list the published versions");
330
- if (lookup.result === null)
331
- return { version: null, exitCode: lookup.exitCode };
332
- let published;
333
- try {
334
- published = JSON.parse(lookup.result.stdout.trim() || "[]");
335
- }
336
- catch {
337
- output.stderr(`${PRODUCT_TEXT.diagnostic(`received a malformed version list from npm: ${JSON.stringify(lookup.result.stdout.trim())}.`)}\n`);
351
+ async function resolveRequestedPreview(fetcher, registry, requested, output) {
352
+ const published = await queryPublishedVersions(fetcher, registry);
353
+ if (published.error !== null) {
354
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`could not list the published versions: ${published.error}.`)}\n`);
338
355
  return { version: null, exitCode: 1 };
339
356
  }
340
- const versions = (Array.isArray(published) ? published : [published]).filter((value) => typeof value === "string");
341
- const exact = versions.find(version => version === requested);
357
+ const exact = published.versions.find(entry => entry.version === requested);
342
358
  if (exact !== undefined) {
343
359
  // Rationale: naming a release here would install it through the preview path, which is a
344
360
  // different command with a different meaning.
345
- if (!exact.includes("-dev.")) {
346
- output.stderr(`${PRODUCT_TEXT.diagnostic(`${exact} is a release, not a preview; run ${PRODUCT_TEXT.commandName} update to move to the current release.`)}\n`);
361
+ if (!exact.version.includes("-dev.")) {
362
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`${exact.version} is a release, not a preview; run ${PRODUCT_TEXT.commandName} update to move to the current release.`)}\n`);
347
363
  return { version: null, exitCode: 1 };
348
364
  }
349
- return { version: exact, exitCode: 0 };
365
+ return { version: exact.version, exitCode: 0 };
350
366
  }
351
- const matches = versions.filter(version => version.endsWith(`-dev.${requested}`));
367
+ const matches = previewsNumbered(published.versions, requested);
352
368
  if (matches.length === 1)
353
369
  return { version: matches[0], exitCode: 0 };
354
370
  if (matches.length > 1) {
@@ -358,6 +374,13 @@ async function resolveRequestedPreview(runner, requested, output) {
358
374
  output.stderr(`${PRODUCT_TEXT.diagnostic(`published no preview for ${requested}.`)}\n`);
359
375
  return { version: null, exitCode: 1 };
360
376
  }
377
+ /** The published versions a preview number names: by recorded pull request, or by trailing identifier. */
378
+ function previewsNumbered(versions, requested) {
379
+ const number = Number(requested);
380
+ return versions
381
+ .filter(entry => entry.pullRequest === number || entry.version.endsWith(`-dev.${requested}`))
382
+ .map(entry => entry.version);
383
+ }
361
384
  async function resolveManagedNpmInstallation(requestedPackageRoot, fileSystem, runner, output) {
362
385
  const rootLookup = await runNpm(runner, ["root", "--global"], true, output, "resolve npm's global package root");
363
386
  if (rootLookup.result === null)
@@ -455,9 +478,72 @@ async function launchersOwnPackage(globalRoot, fileSystem) {
455
478
  return false;
456
479
  }
457
480
  }
481
+ async function resolveSelfUpdateTarget(input) {
482
+ if (input.exactTarget !== undefined && input.exactTarget.length > 0) {
483
+ return resolveExactAutomaticTarget(input.exactTarget, input.channel, input.output);
484
+ }
485
+ return input.requested === undefined || input.requested.length === 0
486
+ ? await resolveChannelHead(input.runner, input.distTag, input.output)
487
+ : await resolveRequestedPreview(input.fetcher ?? createRegistryFetcher(PREVIEW_LOOKUP_TIMEOUT_MS), input.registry?.trim() || undefined, input.requested, input.output);
488
+ }
489
+ function resolveExactAutomaticTarget(target, channel, output) {
490
+ const version = validSemver(target);
491
+ const expected = channel === "stable" ? "stable" : "development";
492
+ if (version === null || releaseChannelOf(version) !== expected) {
493
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`refused invalid automatic ${expected} update target ${JSON.stringify(target)}`)}\n`);
494
+ return { version: null, exitCode: 1 };
495
+ }
496
+ return { version, exitCode: 0 };
497
+ }
458
498
  function reportUnmanagedInstallation(output, packageRoot, activeGlobalRoot) {
459
499
  output.stderr(`${PRODUCT_TEXT.diagnostic(`refused to update automatically because ${packageRoot} could not be verified as an npm-managed ${PRODUCT_PACKAGE} installation; npm's active global package root is ${activeGlobalRoot}. Run npm install --global ${PRODUCT_PACKAGE} to install it manually.`)}\n`);
460
500
  }
501
+ async function withUpdateExecutionLease(input, options, output, operation) {
502
+ let lease = await acquireUpdateExecutionLease(input);
503
+ if (lease.status === "interrupted") {
504
+ // Rationale: the owner that targeted another version is gone. Its durable transaction is rolled
505
+ // back to the cohort that ran before it, so this request proceeds as an ordinary update of its
506
+ // own target instead of reporting a dead attempt as in progress.
507
+ const interrupted = lease.owner.targetVersion;
508
+ const rollback = await rollbackPriorCohort(input.dataDir, options.environment ?? process.env, lease.transaction.priorActiveReleaseId)
509
+ .catch(error => `rollback failed: ${errorMessage(error)}`);
510
+ const store = new UpdateTransactionStore(input.dataDir);
511
+ await store.finish("rolled-back", `interrupted ${interrupted} update settled by ${input.targetVersion}; ${rollback}`);
512
+ await store.clearCompleted().catch(() => undefined);
513
+ await reclaimDeadLease(input.dataDir, lease.owner);
514
+ output.stdout(`${PRODUCT_TEXT.commandName} rolled back the interrupted ${interrupted} update: ${rollback}\n`);
515
+ lease = await acquireUpdateExecutionLease(input);
516
+ }
517
+ if (lease.status !== "acquired") {
518
+ options.onLeaseBusy?.(lease.owner);
519
+ if ((options.mode ?? "manual") === "manual") {
520
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`update already in progress for ${lease.owner.targetVersion}`)}\n`);
521
+ }
522
+ return UPDATE_ALREADY_RUNNING_EXIT_CODE;
523
+ }
524
+ try {
525
+ options.onLeaseAcquired?.(lease.owner);
526
+ return await operation();
527
+ }
528
+ finally {
529
+ await lease.release();
530
+ }
531
+ }
532
+ async function readRunningPackageVersion(packageRoot, fileSystem, output) {
533
+ try {
534
+ const packageJson = JSON.parse(await fileSystem.readFile(resolve(packageRoot, "package.json")));
535
+ const version = typeof packageJson.version === "string" ? validSemver(packageJson.version) : null;
536
+ if (packageJson.name !== PRODUCT_PACKAGE)
537
+ throw new Error(`package.json does not identify ${PRODUCT_PACKAGE}`);
538
+ if (version === null)
539
+ throw new Error("package.json does not contain a valid semantic version");
540
+ return version;
541
+ }
542
+ catch (error) {
543
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`could not read its running package version: ${errorMessage(error)}`)}\n`);
544
+ return null;
545
+ }
546
+ }
461
547
  export async function runSelfUpdate(options) {
462
548
  const fileSystem = options.fileSystem ?? defaultFileSystem;
463
549
  const output = options.output ?? defaultOutput;
@@ -474,24 +560,15 @@ export async function runSelfUpdate(options) {
474
560
  options.onPhaseTiming?.({ phase, durationMs: Math.max(0, now() - startedAt) });
475
561
  }
476
562
  };
477
- let runningVersion;
478
- try {
479
- const packageJson = JSON.parse(await measure("package-version", async () => await fileSystem.readFile(resolve(options.packageRoot, "package.json"))));
480
- const parsedVersion = typeof packageJson.version === "string" ? validSemver(packageJson.version) : null;
481
- if (packageJson.name !== PRODUCT_PACKAGE)
482
- throw new Error(`package.json does not identify ${PRODUCT_PACKAGE}`);
483
- if (parsedVersion === null)
484
- throw new Error("package.json does not contain a valid semantic version");
485
- runningVersion = parsedVersion;
486
- }
487
- catch (error) {
488
- output.stderr(`${PRODUCT_TEXT.diagnostic(`could not read its running package version: ${errorMessage(error)}`)}\n`);
563
+ const runningVersion = await measure("package-version", async () => await readRunningPackageVersion(options.packageRoot, fileSystem, output));
564
+ if (runningVersion === null)
489
565
  return 1;
490
- }
491
566
  const requested = options.target?.trim();
492
- const resolved = await measure("target-resolution", async () => requested === undefined || requested.length === 0
493
- ? await resolveChannelHead(runner, distTag, output)
494
- : await resolveRequestedPreview(runner, requested, output));
567
+ const exactTarget = options.resolvedTarget?.trim();
568
+ const environment = options.environment ?? process.env;
569
+ const resolved = await measure("target-resolution", async () => await resolveSelfUpdateTarget({
570
+ runner, output, channel, distTag, requested, exactTarget, fetcher: options.fetcher, registry: environment.npm_config_registry,
571
+ }));
495
572
  if (resolved.version === null)
496
573
  return resolved.exitCode;
497
574
  const targetVersion = resolved.version;
@@ -506,178 +583,184 @@ export async function runSelfUpdate(options) {
506
583
  // Rationale: no full stop after a version: it already ends in a dot-separated identifier,
507
584
  // and a trailing one reads as part of the version rather than as punctuation.
508
585
  output.stdout(`${PRODUCT_TEXT.commandName} update: ${runningVersion} → ${targetVersion}\n`);
509
- const progress = createUpdateProgress(output, options.progress ?? (options.output === undefined && process.stdout.isTTY === true));
586
+ const progress = createUpdateProgress(output, options.progress ?? (options.output === undefined && process.stdout.isTTY === true), updateProgressAccent(environment));
510
587
  const managed = await measure("global-root", async () => await resolveManagedNpmInstallation(options.packageRoot, fileSystem, runner, output));
511
588
  if (managed.installation === null)
512
589
  return managed.exitCode;
513
590
  const { packageRoot, globalRoot, npmCliRoot } = managed.installation;
514
- const environment = options.environment ?? process.env;
515
591
  const paths = resolveProductPaths(environment);
516
592
  const lifecycle = options.lifecycle ?? createUpdateLifecycleCoordinator(environment, fileSystem, output);
517
593
  const transactionStore = options.transactionStore ?? new UpdateTransactionStore(paths.dataDir);
594
+ const mode = options.mode ?? "manual";
518
595
  const maintenance = options.maintenance ?? (options.lifecycle
519
596
  ? async () => { }
520
597
  : async () => await scheduleReleaseCleanup(paths.dataDir, paths));
521
- let transaction = await transactionStore.read();
522
- let npmCli;
523
- try {
524
- if ((!transaction || transaction.status === "completed") && await lifecycle.targetIsActive(targetVersion)) {
525
- await maintenance();
526
- await transactionStore.clearCompleted();
527
- output.stdout(`${PRODUCT_TEXT.commandName} is up to date — no update needed.\n`);
528
- return 0;
529
- }
530
- const preflightRequired = options.npmCliResolver !== undefined
531
- || options.packageReplacement === undefined && options.runner === undefined;
532
- if (preflightRequired) {
533
- try {
534
- npmCli = await (options.npmCliResolver ?? resolveNpmCli)(npmCliRoot, environment);
598
+ return await withUpdateExecutionLease({ dataDir: paths.dataDir, packageRoot, channel, targetVersion, mode }, options, output, async () => {
599
+ let transaction = await transactionStore.read();
600
+ let npmCli;
601
+ try {
602
+ if (mode === "automatic")
603
+ await lifecycle.verifyAutomaticSafety?.();
604
+ if ((!transaction || transaction.status === "completed") && await lifecycle.targetIsActive(targetVersion)) {
605
+ await maintenance();
606
+ await transactionStore.clearCompleted();
607
+ output.stdout(`${PRODUCT_TEXT.commandName} is up to date — no update needed.\n`);
608
+ return 0;
535
609
  }
536
- catch (error) {
537
- throw new UpdatePreflightFailure(errorMessage(error));
610
+ const preflightRequired = options.npmCliResolver !== undefined
611
+ || options.packageReplacement === undefined && options.runner === undefined;
612
+ if (preflightRequired) {
613
+ try {
614
+ npmCli = await (options.npmCliResolver ?? resolveNpmCli)(npmCliRoot, environment);
615
+ }
616
+ catch (error) {
617
+ throw new UpdatePreflightFailure(errorMessage(error));
618
+ }
538
619
  }
539
- }
540
- // Rationale: the bar first appears only after every non-mutating replacement prerequisite passes.
541
- progress.set(3, 15);
542
- const cohortStore = new CohortStateStore(paths.dataDir);
543
- let cohortState = await cohortStore.read();
544
- let priorActiveReleaseId = cohortState.references.active;
545
- if (options.runner === undefined && (priorActiveReleaseId === null || cohortState.releases[priorActiveReleaseId]?.approval !== "approved")) {
546
- // Invariant: protected replacement needs an immutable launch authority that npm cannot rename.
547
- const recoveryRelease = await materializeRelease(packageRoot, paths.dataDir);
548
- await cohortStore.recordCandidate(recoveryRelease);
549
- const diagnostics = await certifyMaterializedRelease(recoveryRelease, paths.dataDir);
550
- await cohortStore.approve(recoveryRelease.releaseId, diagnostics);
551
- await cohortStore.activate(recoveryRelease.releaseId);
552
- cohortState = await cohortStore.read();
553
- priorActiveReleaseId = recoveryRelease.releaseId;
554
- }
555
- transaction = await transactionStore.begin({
556
- channel,
557
- targetVersion,
558
- packageRoot,
559
- priorActiveReleaseId,
560
- });
561
- if (phaseBefore(transaction.phase, "ownership-released")) {
562
- await measure("ownership-release", async () => {
563
- await lifecycle.shutdownVerifiedOwners(targetVersion);
564
- await lifecycle.verifyPackageUnlocked(packageRoot);
620
+ // Rationale: the bar first appears only after every non-mutating replacement prerequisite passes.
621
+ progress.set(3, 15);
622
+ const cohortStore = new CohortStateStore(paths.dataDir);
623
+ let cohortState = await cohortStore.read();
624
+ let priorActiveReleaseId = cohortState.references.active;
625
+ if (options.runner === undefined && (priorActiveReleaseId === null || cohortState.releases[priorActiveReleaseId]?.approval !== "approved")) {
626
+ // Invariant: protected replacement needs an immutable launch authority that npm cannot rename.
627
+ const recoveryRelease = await materializeRelease(packageRoot, paths.dataDir);
628
+ await cohortStore.recordCandidate(recoveryRelease);
629
+ const diagnostics = await certifyMaterializedRelease(recoveryRelease, paths.dataDir);
630
+ await cohortStore.approve(recoveryRelease.releaseId, diagnostics);
631
+ await cohortStore.activate(recoveryRelease.releaseId);
632
+ cohortState = await cohortStore.read();
633
+ priorActiveReleaseId = recoveryRelease.releaseId;
634
+ }
635
+ transaction = await transactionStore.begin({
636
+ channel,
637
+ targetVersion,
638
+ packageRoot,
639
+ priorActiveReleaseId,
565
640
  });
566
- transaction = await transactionStore.advance("ownership-released");
567
- }
568
- progress.set(15, 70);
569
- if (phaseBefore(transaction.phase, "package-installed")) {
570
- if (options.packageReplacement || options.runner === undefined) {
571
- const priorReleaseId = transaction.priorActiveReleaseId ?? priorActiveReleaseId;
572
- const recordedPrior = priorReleaseId === null ? undefined : cohortState.releases[priorReleaseId];
573
- if ((!recordedPrior || recordedPrior.approval !== "approved") && !options.packageReplacement) {
574
- throw new Error(PRODUCT_TEXT.diagnostic("cannot protect package replacement because no approved prior release is available"));
641
+ if (phaseBefore(transaction.phase, "ownership-released")) {
642
+ await measure("ownership-release", async () => {
643
+ await lifecycle.shutdownVerifiedOwners(targetVersion);
644
+ await lifecycle.verifyPackageUnlocked(packageRoot);
645
+ });
646
+ transaction = await transactionStore.advance("ownership-released");
647
+ }
648
+ progress.set(15, 70);
649
+ if (phaseBefore(transaction.phase, "package-installed")) {
650
+ if (options.packageReplacement || options.runner === undefined) {
651
+ const priorReleaseId = transaction.priorActiveReleaseId ?? priorActiveReleaseId;
652
+ const recordedPrior = priorReleaseId === null ? undefined : cohortState.releases[priorReleaseId];
653
+ if ((!recordedPrior || recordedPrior.approval !== "approved") && !options.packageReplacement) {
654
+ throw new Error(PRODUCT_TEXT.diagnostic("cannot protect package replacement because no approved prior release is available"));
655
+ }
656
+ const priorRelease = recordedPrior ?? {
657
+ releaseId: priorReleaseId ?? "injected-prior-release",
658
+ releaseRoot: packageRoot,
659
+ contentDigest: "0".repeat(64),
660
+ };
661
+ const replacementTransaction = transaction;
662
+ const replacement = await measure("npm-install", async () => await (options.packageReplacement ?? runProtectedPackageReplacement)({
663
+ dataDir: paths.dataDir,
664
+ globalRoot,
665
+ npmCliRoot,
666
+ ...(npmCli === undefined ? {} : { npmCli }),
667
+ packageRoot,
668
+ transaction: replacementTransaction,
669
+ priorRelease,
670
+ output,
671
+ environment,
672
+ onRecoveryState: async (recovery) => {
673
+ if (transactionStore.setRecovery)
674
+ transaction = await transactionStore.setRecovery(recovery) ?? transaction;
675
+ },
676
+ }));
677
+ // Rationale: npm's own text explains a failed replacement and says nothing about a
678
+ // successful one, so it reaches the terminal only when the installation did not happen.
679
+ if (replacement.outcome !== "installed")
680
+ reportChildDiagnostics(output, replacement);
681
+ if (replacement.outcome === "installed")
682
+ transaction = await transactionStore.advance("package-installed");
683
+ if (replacement.cancelled) {
684
+ progress.clear();
685
+ output.stderr(`${PRODUCT_TEXT.diagnostic("update cancelled safely; the launcher is available and the transaction can be resumed.")}\n`);
686
+ return 130;
687
+ }
688
+ if (replacement.outcome !== "installed") {
689
+ throw new UpdateFailure(unsuccessfulCode(replacement.npmExitCode), `npm exited with status ${formatExitCode(replacement.npmExitCode)}`);
690
+ }
575
691
  }
576
- const priorRelease = recordedPrior ?? {
577
- releaseId: priorReleaseId ?? "injected-prior-release",
578
- releaseRoot: packageRoot,
579
- contentDigest: "0".repeat(64),
580
- };
581
- const replacementTransaction = transaction;
582
- const replacement = await measure("npm-install", async () => await (options.packageReplacement ?? runProtectedPackageReplacement)({
583
- dataDir: paths.dataDir,
584
- globalRoot,
585
- npmCliRoot,
586
- ...(npmCli === undefined ? {} : { npmCli }),
587
- packageRoot,
588
- transaction: replacementTransaction,
589
- priorRelease,
590
- output,
591
- environment,
592
- onRecoveryState: async (recovery) => {
593
- if (transactionStore.setRecovery)
594
- transaction = await transactionStore.setRecovery(recovery) ?? transaction;
595
- },
596
- }));
597
- // Rationale: npm's own text explains a failed replacement and says nothing about a
598
- // successful one, so it reaches the terminal only when the installation did not happen.
599
- if (replacement.outcome !== "installed")
600
- reportChildDiagnostics(output, replacement);
601
- if (replacement.outcome === "installed")
692
+ else {
693
+ const installation = await measure("npm-install", async () => await runNpm(runner, updateNpmInstallArguments(globalRoot, targetVersion), true, output, "start the global npm installation", false));
694
+ if (installation.result === null)
695
+ throw new UpdateFailure(installation.exitCode, "npm process failed");
696
+ if (installation.result.code !== 0) {
697
+ reportChildDiagnostics(output, installation.result);
698
+ throw new UpdateFailure(unsuccessfulCode(installation.result.code), `npm exited with status ${formatExitCode(installation.result.code)}`);
699
+ }
602
700
  transaction = await transactionStore.advance("package-installed");
603
- if (replacement.cancelled) {
604
- progress.clear();
605
- output.stderr(`${PRODUCT_TEXT.diagnostic("update cancelled safely; the launcher is available and the transaction can be resumed.")}\n`);
606
- return 130;
607
- }
608
- if (replacement.outcome !== "installed") {
609
- throw new UpdateFailure(unsuccessfulCode(replacement.npmExitCode), `npm exited with status ${formatExitCode(replacement.npmExitCode)}`);
610
701
  }
611
702
  }
612
- else {
613
- const installation = await measure("npm-install", async () => await runNpm(runner, updateNpmInstallArguments(globalRoot, targetVersion), true, output, "start the global npm installation", false));
614
- if (installation.result === null)
615
- throw new UpdateFailure(installation.exitCode, "npm process failed");
616
- if (installation.result.code !== 0) {
617
- reportChildDiagnostics(output, installation.result);
618
- throw new UpdateFailure(unsuccessfulCode(installation.result.code), `npm exited with status ${formatExitCode(installation.result.code)}`);
703
+ progress.set(70, 75);
704
+ // Concurrency: ownership can be reacquired after an interrupted installation (for
705
+ // example, if bare A1 is launched before the update is resumed). Recheck
706
+ // immediately before activation so recovery cannot start a second cohort.
707
+ await measure("ownership-release", async () => { await lifecycle.shutdownVerifiedOwners(targetVersion); });
708
+ progress.set(75, MATERIALIZE_PROGRESS.from);
709
+ let activationPhaseStartedAt = now();
710
+ await lifecycle.activateInstalled(packageRoot, targetVersion, async (phase) => {
711
+ options.onPhaseTiming?.({ phase, durationMs: Math.max(0, now() - activationPhaseStartedAt) });
712
+ transaction = await transactionStore.advance(phase);
713
+ progress.set(ACTIVATION_PROGRESS[phase].at, ACTIVATION_PROGRESS[phase].creepTo);
714
+ activationPhaseStartedAt = now();
715
+ }, ({ completed, total }) => {
716
+ const span = MATERIALIZE_PROGRESS.to - MATERIALIZE_PROGRESS.from;
717
+ const done = total > 0 ? Math.min(1, completed / total) : 0;
718
+ progress.set(MATERIALIZE_PROGRESS.from + span * done);
719
+ }, state => {
720
+ if (state === "started") {
721
+ activationPhaseStartedAt = now();
722
+ progress.set(98, 99);
619
723
  }
620
- transaction = await transactionStore.advance("package-installed");
621
- }
724
+ else {
725
+ options.onPhaseTiming?.({ phase: "warmup", durationMs: Math.max(0, now() - activationPhaseStartedAt) });
726
+ activationPhaseStartedAt = now();
727
+ progress.set(99);
728
+ }
729
+ });
730
+ options.onPhaseTiming?.({ phase: "supervisor-verified", durationMs: Math.max(0, now() - activationPhaseStartedAt) });
731
+ const transactionStartedAt = now();
732
+ await transactionStore.advance("supervisor-verified");
733
+ if (transaction.recovery?.capsulePath)
734
+ await removeUpdateRecoveryCapsule(paths.dataDir, transaction.transactionId);
735
+ // Invariant: successful output follows the durable cleanup disposition. Slow recursive
736
+ // removal belongs to the detached worker started by this maintenance coordinator.
737
+ await maintenance();
738
+ // Concurrency: this is the launch cutover. No failure-prone update work follows success.
739
+ await transactionStore.finish("completed");
740
+ await Promise.all([transactionStore.clearCompleted(), invalidateReleaseCheckCache(paths.configDir)]).catch(() => undefined);
741
+ options.onPhaseTiming?.({ phase: "transaction-complete", durationMs: Math.max(0, now() - transactionStartedAt) });
742
+ progress.finish();
743
+ output.stdout(`${PRODUCT_TEXT.commandName} updated successfully to ${targetVersion}\n`);
744
+ return 0;
622
745
  }
623
- progress.set(70, 75);
624
- // Concurrency: ownership can be reacquired after an interrupted installation (for
625
- // example, if bare A1 is launched before the update is resumed). Recheck
626
- // immediately before activation so recovery cannot start a second cohort.
627
- await measure("ownership-release", async () => { await lifecycle.shutdownVerifiedOwners(targetVersion); });
628
- progress.set(75, MATERIALIZE_PROGRESS.from);
629
- let activationPhaseStartedAt = now();
630
- await lifecycle.activateInstalled(packageRoot, targetVersion, async (phase) => {
631
- options.onPhaseTiming?.({ phase, durationMs: Math.max(0, now() - activationPhaseStartedAt) });
632
- transaction = await transactionStore.advance(phase);
633
- progress.set(ACTIVATION_PROGRESS[phase].at, ACTIVATION_PROGRESS[phase].creepTo);
634
- activationPhaseStartedAt = now();
635
- }, ({ completed, total }) => {
636
- const span = MATERIALIZE_PROGRESS.to - MATERIALIZE_PROGRESS.from;
637
- const done = total > 0 ? Math.min(1, completed / total) : 0;
638
- progress.set(MATERIALIZE_PROGRESS.from + span * done);
639
- }, state => {
640
- if (state === "started") {
641
- activationPhaseStartedAt = now();
642
- progress.set(98, 99);
643
- }
644
- else {
645
- options.onPhaseTiming?.({ phase: "warmup", durationMs: Math.max(0, now() - activationPhaseStartedAt) });
646
- activationPhaseStartedAt = now();
647
- progress.set(99);
746
+ catch (error) {
747
+ progress.clear();
748
+ const message = errorMessage(error);
749
+ if (error instanceof UpdateAutomaticDeferred)
750
+ return 1;
751
+ if (error instanceof UpdatePreflightFailure) {
752
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`update could not start safely: ${message}. Nothing was changed. Retry with npm x -y -- ${PRODUCT_PACKAGE}-install`)}\n`);
753
+ return 1;
648
754
  }
649
- });
650
- options.onPhaseTiming?.({ phase: "supervisor-verified", durationMs: Math.max(0, now() - activationPhaseStartedAt) });
651
- const transactionStartedAt = now();
652
- await transactionStore.advance("supervisor-verified");
653
- if (transaction.recovery?.capsulePath)
654
- await removeUpdateRecoveryCapsule(paths.dataDir, transaction.transactionId);
655
- // Invariant: successful output follows the durable cleanup disposition. Slow recursive
656
- // removal belongs to the detached worker started by this maintenance coordinator.
657
- await maintenance();
658
- // Concurrency: this is the launch cutover. No failure-prone update work follows success.
659
- await transactionStore.finish("completed");
660
- await transactionStore.clearCompleted().catch(() => undefined);
661
- options.onPhaseTiming?.({ phase: "transaction-complete", durationMs: Math.max(0, now() - transactionStartedAt) });
662
- progress.finish();
663
- output.stdout(`${PRODUCT_TEXT.commandName} updated successfully to ${targetVersion}\n`);
664
- return 0;
665
- }
666
- catch (error) {
667
- progress.clear();
668
- const message = errorMessage(error);
669
- if (error instanceof UpdatePreflightFailure) {
670
- output.stderr(`${PRODUCT_TEXT.diagnostic(`update could not start safely: ${message}. Nothing was changed. Retry with npm x -y -- ${PRODUCT_PACKAGE}-install`)}\n`);
671
- return 1;
755
+ const rollback = options.lifecycle
756
+ ? "previous test lifecycle retained"
757
+ : await rollbackPriorCohort(paths.dataDir, environment, transaction?.priorActiveReleaseId ?? null).catch(rollbackError => `rollback failed: ${errorMessage(rollbackError)}`);
758
+ if (transaction)
759
+ await transactionStore.finish(rollback === "rolled back" ? "rolled-back" : "failed", `${message}; ${rollback}`);
760
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`update failed: ${message}. ${rollback}. Diagnostics: ${transactionStore.path}`)}\n`);
761
+ return error instanceof UpdateFailure ? error.exitCode : 1;
672
762
  }
673
- const rollback = options.lifecycle
674
- ? "previous test lifecycle retained"
675
- : await rollbackPriorCohort(paths.dataDir, environment, transaction?.priorActiveReleaseId ?? null).catch(rollbackError => `rollback failed: ${errorMessage(rollbackError)}`);
676
- if (transaction)
677
- await transactionStore.finish(rollback === "rolled back" ? "rolled-back" : "failed", `${message}; ${rollback}`);
678
- output.stderr(`${PRODUCT_TEXT.diagnostic(`update failed: ${message}. ${rollback}. Diagnostics: ${transactionStore.path}`)}\n`);
679
- return error instanceof UpdateFailure ? error.exitCode : 1;
680
- }
763
+ });
681
764
  }
682
765
  export function assertUpdatePerformanceBudget(evidence, maximumPostNpmDurationMs = 30_000) {
683
766
  const failures = [];
@@ -777,6 +860,8 @@ class UpdateFailure extends Error {
777
860
  }
778
861
  class UpdatePreflightFailure extends Error {
779
862
  }
863
+ class UpdateAutomaticDeferred extends Error {
864
+ }
780
865
  async function canonicalImmutableRoot(dataDir, releaseRoot) {
781
866
  try {
782
867
  const [store, selected] = await Promise.all([realpath(resolve(dataDir, "releases")), realpath(releaseRoot)]);
@@ -0,0 +1,18 @@
1
+ import type { TerminalHostCommand } from "./ensure-terminal-host.js";
2
+ export interface BoundedHostCommandResult {
3
+ readonly code: number;
4
+ readonly stdout: string;
5
+ }
6
+ export interface BoundedHostCommandLimits {
7
+ /** Output beyond this many bytes fails the exchange instead of being parsed. */
8
+ readonly maxStdoutBytes: number;
9
+ readonly timeoutMs: number;
10
+ /** Names the exchange in the timeout error. */
11
+ readonly label: string;
12
+ readonly environment?: NodeJS.ProcessEnv;
13
+ }
14
+ /**
15
+ * Runs one terminal-host command whose report is small. An oversized report kills the command and
16
+ * reports a failed exchange; a command that outlives its deadline is killed and rejected.
17
+ */
18
+ export declare function runBoundedHostCommand(command: TerminalHostCommand, arguments_: readonly string[], limits: BoundedHostCommandLimits): Promise<BoundedHostCommandResult>;