@timurproko/a1 0.1.8-dev.21b95d6 → 0.1.8-dev.224

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 (461) hide show
  1. package/README.md +107 -67
  2. package/bin/cli.js +28 -10
  3. package/bin/guardian.js +4 -1
  4. package/bin/module-identity.js +69 -35
  5. package/bin/pi-tui.d.ts +6 -0
  6. package/bin/pi-tui.js +28 -0
  7. package/bin/release-cleanup.js +8 -0
  8. package/bin/supervisor.js +1 -1
  9. package/bin/sync-pi-tui-proxy.js +97 -0
  10. package/bin/ui.js +25 -6
  11. package/bin/warmup.js +18 -0
  12. package/dist/cli/capabilities.d.ts +6 -0
  13. package/dist/{src/cli → cli}/capabilities.js +1 -1
  14. package/dist/{src/cli → cli}/dispatch.d.ts +6 -0
  15. package/dist/cli/dispatch.js +202 -0
  16. package/dist/{src/cli → cli}/packages.d.ts +10 -2
  17. package/dist/{src/cli → cli}/packages.js +24 -20
  18. package/dist/{src/cli → cli}/version-stats.d.ts +6 -0
  19. package/dist/cli/version-stats.js +112 -0
  20. package/dist/composition/agent-engine-bridge.d.ts +3 -0
  21. package/dist/composition/agent-engine-bridge.js +108 -0
  22. package/dist/composition/index.d.ts +3 -0
  23. package/dist/composition/index.js +3 -0
  24. package/dist/composition/owned-ui.d.ts +28 -0
  25. package/dist/composition/owned-ui.js +64 -0
  26. package/dist/composition/process.d.ts +16 -0
  27. package/dist/composition/process.js +45 -0
  28. package/dist/composition/settings-route-host.d.ts +8 -0
  29. package/dist/composition/settings-route-host.js +75 -0
  30. package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.d.ts +2 -2
  31. package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.js +22 -4
  32. package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.d.ts +17 -0
  33. package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.d.ts +36 -0
  34. package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.js +25 -0
  35. package/dist/{src/features → features}/launch/development-launch.js +11 -3
  36. package/dist/{src/features → features}/launch/index.d.ts +0 -1
  37. package/dist/{src/features → features}/launch/index.js +0 -1
  38. package/dist/{src/features → features}/launch/intent.d.ts +3 -2
  39. package/dist/features/launch/intent.js +3 -0
  40. package/dist/{src/features → features}/launch/prepare-launch.d.ts +0 -2
  41. package/dist/{src/features → features}/launch/prepare-launch.js +2 -9
  42. package/dist/{src/features → features}/launch/profile-paths.d.ts +1 -2
  43. package/dist/{src/features → features}/launch/profile-paths.js +2 -8
  44. package/dist/{src/features → features}/launch/runtime-selection.d.ts +2 -5
  45. package/dist/{src/features → features}/owned-ui/customization.d.ts +3 -1
  46. package/dist/{src/features → features}/owned-ui/customization.js +3 -1
  47. package/dist/{src/features → features}/owned-ui/diagnostics.d.ts +2 -1
  48. package/dist/{src/features → features}/owned-ui/diagnostics.js +1 -0
  49. package/dist/{src/features → features}/owned-ui/index.d.ts +1 -0
  50. package/dist/{src/features → features}/owned-ui/index.js +1 -0
  51. package/dist/features/owned-ui/project-trust-prompt.d.ts +25 -0
  52. package/dist/features/owned-ui/project-trust-prompt.js +149 -0
  53. package/dist/{src/features → features}/owned-ui/run.d.ts +2 -2
  54. package/dist/{src/features → features}/owned-ui/run.js +2 -0
  55. package/dist/{src/features → features}/owned-ui/settings-app.d.ts +3 -3
  56. package/dist/{src/features → features}/owned-ui/settings-app.js +103 -54
  57. package/dist/{src/features → features}/workspace/capabilities.d.ts +1 -1
  58. package/dist/{src/features → features}/workspace/reducer.d.ts +2 -1
  59. package/dist/{src/features → features}/workspace/reducer.js +2 -1
  60. package/dist/{src/features → features}/workspace/router.d.ts +2 -1
  61. package/dist/{src/features → features}/workspace/router.js +1 -0
  62. package/dist/{src/features → features}/workspace/store.d.ts +2 -1
  63. package/dist/{src/features → features}/workspace/store.js +1 -0
  64. package/dist/{src/foundation → foundation}/launch-guardian/main.js +10 -2
  65. package/dist/{src/foundation → foundation}/lifecycle/model.d.ts +1 -1
  66. package/dist/{src/foundation → foundation}/lifecycle/model.js +1 -1
  67. package/dist/foundation/lifecycle/paths.d.ts +28 -0
  68. package/dist/{src/foundation → foundation}/lifecycle/paths.js +21 -0
  69. package/dist/{src/foundation → foundation}/native-host-protocol/codec.d.ts +2 -0
  70. package/dist/{src/foundation → foundation}/native-host-protocol/codec.js +2 -0
  71. package/dist/{src/foundation → foundation}/native-host-protocol/messages.d.ts +1 -1
  72. package/dist/{src/foundation → foundation}/native-host-protocol/messages.js +1 -1
  73. package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.d.ts +1 -0
  74. package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.js +1 -0
  75. package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.d.ts +1 -0
  76. package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.js +1 -0
  77. package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.d.ts +1 -0
  78. package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.js +1 -0
  79. package/dist/{src/foundation → foundation}/protocol/client.d.ts +1 -0
  80. package/dist/{src/foundation → foundation}/protocol/client.js +1 -0
  81. package/dist/{src/foundation → foundation}/protocol/messages.d.ts +1 -0
  82. package/dist/{src/foundation → foundation}/protocol/messages.js +1 -0
  83. package/dist/{src/foundation → foundation}/release/bootstrap.d.ts +14 -4
  84. package/dist/{src/foundation → foundation}/release/bootstrap.js +66 -13
  85. package/dist/foundation/release/cohort-state.d.ts +131 -0
  86. package/dist/foundation/release/cohort-state.js +384 -0
  87. package/dist/foundation/release/dependency-layer.d.ts +78 -0
  88. package/dist/foundation/release/dependency-layer.js +487 -0
  89. package/dist/foundation/release/endpoints.d.ts +20 -0
  90. package/dist/foundation/release/endpoints.js +50 -0
  91. package/dist/{src/foundation → foundation}/release/index.d.ts +3 -0
  92. package/dist/{src/foundation → foundation}/release/index.js +3 -0
  93. package/dist/foundation/release/release-gc.d.ts +60 -0
  94. package/dist/foundation/release/release-gc.js +538 -0
  95. package/dist/{src/foundation → foundation}/release/release-store.d.ts +3 -1
  96. package/dist/{src/foundation → foundation}/release/release-store.js +60 -10
  97. package/dist/{src/foundation → foundation}/release/release.d.ts +4 -1
  98. package/dist/{src/foundation → foundation}/release/release.js +10 -3
  99. package/dist/{src/foundation → foundation}/release/update-transaction.d.ts +1 -0
  100. package/dist/{src/foundation → foundation}/release/update-transaction.js +1 -0
  101. package/dist/{src/foundation → foundation}/release/update.d.ts +19 -3
  102. package/dist/{src/foundation → foundation}/release/update.js +114 -54
  103. package/dist/foundation/release/warmup.d.ts +3 -0
  104. package/dist/foundation/release/warmup.js +35 -0
  105. package/dist/foundation/startup/index.d.ts +1 -0
  106. package/dist/foundation/startup/index.js +1 -0
  107. package/dist/foundation/startup/startup-runtime.d.ts +36 -0
  108. package/dist/foundation/startup/startup-runtime.js +140 -0
  109. package/dist/{src/foundation → foundation}/storage/control-store.d.ts +2 -1
  110. package/dist/{src/foundation → foundation}/storage/control-store.js +39 -4
  111. package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.d.ts +2 -1
  112. package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.js +2 -1
  113. package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.d.ts +2 -1
  114. package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.js +2 -1
  115. package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.d.ts +1 -1
  116. package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.js +1 -1
  117. package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.d.ts +2 -1
  118. package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.js +2 -1
  119. package/dist/{src/foundation → foundation}/structured-agent-runtime/state.d.ts +2 -1
  120. package/dist/{src/foundation → foundation}/structured-agent-runtime/state.js +2 -1
  121. package/dist/foundation/supervision/index.d.ts +3 -0
  122. package/dist/foundation/supervision/index.js +3 -0
  123. package/dist/{src/foundation → foundation}/supervision/main.js +11 -5
  124. package/dist/foundation/supervision/paths.d.ts +1 -0
  125. package/dist/foundation/supervision/paths.js +1 -0
  126. package/dist/{src/foundation → foundation}/supervision/server.d.ts +19 -1
  127. package/dist/{src/foundation → foundation}/supervision/server.js +51 -2
  128. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.d.ts +1 -1
  129. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.d.ts +1 -0
  130. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.js +3 -2
  131. package/dist/integrations/pi/components/owned-editor-ux.d.ts +55 -0
  132. package/dist/integrations/pi/components/owned-editor-ux.js +778 -0
  133. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.d.ts +1 -0
  134. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.js +1 -0
  135. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-editor-autocomplete.js +54 -6
  136. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.d.ts +1 -1
  137. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.d.ts +3 -3
  138. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.js +32 -17
  139. package/dist/integrations/pi/components/shell-presenters-info.d.ts +36 -0
  140. package/dist/integrations/pi/components/shell-presenters-info.js +78 -0
  141. package/dist/integrations/pi/components/shell-presenters-transcript.d.ts +25 -0
  142. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-presenters-transcript.js +92 -131
  143. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.d.ts +1 -1
  144. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.d.ts +52 -8
  145. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.js +4 -2
  146. package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +13 -0
  147. package/dist/integrations/pi/components/submitted-prompt-adapter.js +27 -0
  148. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.d.ts +10 -2
  149. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.js +36 -3
  150. package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.d.ts +1 -1
  151. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.d.ts +22 -4
  152. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.js +289 -68
  153. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.d.ts +2 -0
  154. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.js +4 -2
  155. package/dist/integrations/pi/engine/http-dispatcher.d.ts +4 -0
  156. package/dist/integrations/pi/engine/http-dispatcher.js +25 -0
  157. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.d.ts +3 -0
  158. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.js +3 -0
  159. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.d.ts +2 -1
  160. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.js +1 -0
  161. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.d.ts +1 -1
  162. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.js +2 -2
  163. package/dist/integrations/pi/engine/project-trust-preflight.d.ts +22 -0
  164. package/dist/integrations/pi/engine/project-trust-preflight.js +50 -0
  165. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.d.ts +2 -1
  166. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.js +1 -0
  167. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.d.ts +16 -1
  168. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.js +39 -4
  169. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.d.ts +4 -2
  170. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.js +19 -4
  171. package/dist/integrations/pi/engine/settings-effects.d.ts +66 -0
  172. package/dist/integrations/pi/engine/settings-effects.js +249 -0
  173. package/dist/integrations/pi/engine/settings-integration.d.ts +43 -0
  174. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/settings-integration.js +102 -108
  175. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.d.ts +3 -2
  176. package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.js +1 -0
  177. package/dist/integrations/pi/session-ui/clipboard-image.d.ts +11 -0
  178. package/dist/integrations/pi/session-ui/clipboard-image.js +29 -0
  179. package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/index.d.ts +1 -0
  180. package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/index.js +1 -0
  181. package/dist/integrations/pi/session-ui/prompt-chips.d.ts +23 -0
  182. package/dist/integrations/pi/session-ui/prompt-chips.js +246 -0
  183. package/dist/integrations/pi/session-ui/route-host.d.ts +5 -0
  184. package/dist/integrations/pi/session-ui/session-shell-root.d.ts +137 -0
  185. package/dist/integrations/pi/session-ui/session-shell-root.js +1106 -0
  186. package/dist/integrations/pi/session-ui/session-shell.d.ts +55 -0
  187. package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/session-shell.js +415 -775
  188. package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +44 -0
  189. package/dist/integrations/pi/session-ui/session-viewport-controller.js +434 -0
  190. package/dist/integrations/pi/session-ui/stream-presentation-coalescer.d.ts +29 -0
  191. package/dist/integrations/pi/session-ui/stream-presentation-coalescer.js +79 -0
  192. package/dist/integrations/pi/session-ui/system-clipboard.d.ts +20 -0
  193. package/dist/integrations/pi/session-ui/system-clipboard.js +130 -0
  194. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.d.ts +8 -1
  195. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.js +216 -9
  196. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/contracts.d.ts +29 -6
  197. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +63 -0
  198. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +240 -0
  199. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/index.d.ts +2 -0
  200. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/index.js +2 -0
  201. package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +39 -0
  202. package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.js +139 -0
  203. package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.d.ts +1 -1
  204. package/dist/native/darwin-arm64/manifest.json +1 -1
  205. package/dist/native/linux-x64/manifest.json +3 -3
  206. package/dist/native/linux-x64/process-guardian +0 -0
  207. package/dist/native/win32-x64/manifest.json +3 -3
  208. package/dist/native/win32-x64/process-guardian.exe +0 -0
  209. package/dist/{src/product-identity.d.ts → product-identity.d.ts} +3 -3
  210. package/dist/{src/product-identity.js → product-identity.js} +7 -5
  211. package/dist/{src/product-identity.json → product-identity.json} +11 -6
  212. package/dist/runtime-payload-inventory.json +122328 -0
  213. package/dist/{src/foundation/ui-apps → ui/apps}/contracts.d.ts +23 -1
  214. package/dist/{src/foundation/ui-apps → ui/apps}/host.d.ts +1 -1
  215. package/dist/{src/foundation/ui-apps → ui/apps}/host.js +14 -10
  216. package/dist/{src/foundation/ui-apps → ui/apps}/registry.d.ts +1 -0
  217. package/dist/{src/foundation/ui-apps → ui/apps}/registry.js +1 -0
  218. package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.js +5 -3
  219. package/dist/{src/foundation/ui-components → ui/components}/frame.d.ts +1 -0
  220. package/dist/{src/foundation/ui-components → ui/components}/frame.js +1 -0
  221. package/dist/{src/foundation/ui-components → ui/components}/index.d.ts +4 -0
  222. package/dist/{src/foundation/ui-components → ui/components}/index.js +4 -0
  223. package/dist/{src/foundation/ui-components → ui/components}/line-input.d.ts +1 -6
  224. package/dist/{src/foundation/ui-components → ui/components}/line-input.js +4 -9
  225. package/dist/{src/foundation/ui-components → ui/components}/list-view.d.ts +0 -6
  226. package/dist/{src/foundation/ui-components → ui/components}/list-view.js +14 -7
  227. package/dist/{src/foundation/ui-components → ui/components}/mouse.d.ts +10 -0
  228. package/dist/{src/foundation/ui-components → ui/components}/mouse.js +23 -0
  229. package/dist/ui/components/progress-status.d.ts +2 -0
  230. package/dist/ui/components/progress-status.js +4 -0
  231. package/dist/ui/components/prompt-row.d.ts +14 -0
  232. package/dist/ui/components/prompt-row.js +20 -0
  233. package/dist/{src/foundation/ui-components → ui/components}/scrollbar.d.ts +26 -0
  234. package/dist/{src/foundation/ui-components → ui/components}/scrollbar.js +35 -0
  235. package/dist/{src/foundation/ui-components → ui/components}/shortcuts.d.ts +1 -0
  236. package/dist/{src/foundation/ui-components → ui/components}/shortcuts.js +1 -0
  237. package/dist/ui/components/spans.d.ts +25 -0
  238. package/dist/ui/components/spans.js +257 -0
  239. package/dist/ui/components/submitted-prompt.d.ts +23 -0
  240. package/dist/ui/components/submitted-prompt.js +50 -0
  241. package/dist/{src/foundation/ui-components → ui/components}/surface.d.ts +0 -5
  242. package/dist/{src/foundation/ui-components → ui/components}/surface.js +1 -5
  243. package/dist/ui/components/text-selection.d.ts +62 -0
  244. package/dist/ui/components/text-selection.js +235 -0
  245. package/dist/{src/foundation/ui-components → ui/components}/text.d.ts +14 -0
  246. package/dist/{src/foundation/ui-components → ui/components}/text.js +66 -4
  247. package/dist/ui/components/transcript-viewport.d.ts +146 -0
  248. package/dist/ui/components/transcript-viewport.js +629 -0
  249. package/dist/{src/foundation/owned-ui-settings → ui/settings}/declarations.d.ts +8 -1
  250. package/dist/{src/foundation/owned-ui-settings → ui/settings}/declarations.js +33 -5
  251. package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.d.ts +1 -1
  252. package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.js +21 -2
  253. package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.d.ts +6 -19
  254. package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.js +32 -23
  255. package/dist/{src/foundation/owned-ui-settings → ui/settings}/session.d.ts +9 -17
  256. package/dist/{src/foundation/owned-ui-settings → ui/settings}/session.js +65 -55
  257. package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.d.ts +1 -0
  258. package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.js +2 -1
  259. package/docs/architecture/boundaries.md +9 -9
  260. package/docs/architecture/code-documentation.md +77 -0
  261. package/docs/architecture/project-structure.md +67 -30
  262. package/docs/architecture/resource-and-data-policy.md +1 -1
  263. package/docs/architecture/toolchain.md +10 -10
  264. package/docs/architecture/ui-reference-provenance.md +34 -5
  265. package/docs/ci-release-runbook.md +186 -79
  266. package/docs/features/launch-profiles.md +10 -19
  267. package/docs/manual-launch-instance-acceptance.md +12 -35
  268. package/docs/manual-owned-ui-checkpoint.md +78 -0
  269. package/docs/manual-pi-boundary-candidate.md +4 -5
  270. package/docs/manual-terminal-colour-check.md +4 -3
  271. package/docs/repository-governance-live-acceptance.md +77 -0
  272. package/package.json +37 -27
  273. package/dist/src/cli/capabilities.d.ts +0 -15
  274. package/dist/src/cli/dispatch.js +0 -177
  275. package/dist/src/cli/version-stats.js +0 -72
  276. package/dist/src/composition/index.d.ts +0 -48
  277. package/dist/src/composition/index.js +0 -258
  278. package/dist/src/features/launch/intent.js +0 -4
  279. package/dist/src/features/launch/profiles.d.ts +0 -12
  280. package/dist/src/features/launch/profiles.js +0 -26
  281. package/dist/src/foundation/lifecycle/paths.d.ts +0 -10
  282. package/dist/src/foundation/pi-component-adapter/shell-presenters-transcript.d.ts +0 -57
  283. package/dist/src/foundation/pi-engine-adapter/settings-integration.d.ts +0 -55
  284. package/dist/src/foundation/pi-owned-ui-integration/route-host.d.ts +0 -29
  285. package/dist/src/foundation/pi-owned-ui-integration/session-shell.d.ts +0 -112
  286. package/dist/src/foundation/release/cohort-state.d.ts +0 -70
  287. package/dist/src/foundation/release/cohort-state.js +0 -202
  288. package/dist/src/foundation/release/release-gc.d.ts +0 -5
  289. package/dist/src/foundation/release/release-gc.js +0 -16
  290. package/dist/src/foundation/supervision/index.d.ts +0 -3
  291. package/dist/src/foundation/supervision/index.js +0 -3
  292. package/dist/src/foundation/supervision/paths.d.ts +0 -1
  293. package/dist/src/foundation/supervision/paths.js +0 -1
  294. package/dist/src/foundation/ui-components/spans.d.ts +0 -7
  295. package/dist/src/foundation/ui-components/spans.js +0 -59
  296. package/docs/manual-transparent-checkpoint.md +0 -53
  297. /package/dist/{src/cli → cli}/index.d.ts +0 -0
  298. /package/dist/{src/cli → cli}/index.js +0 -0
  299. /package/dist/{src/cli → cli}/version.d.ts +0 -0
  300. /package/dist/{src/cli → cli}/version.js +0 -0
  301. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.js +0 -0
  302. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.d.ts +0 -0
  303. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.js +0 -0
  304. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.d.ts +0 -0
  305. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.js +0 -0
  306. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.d.ts +0 -0
  307. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.js +0 -0
  308. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.d.ts +0 -0
  309. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.js +0 -0
  310. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.d.ts +0 -0
  311. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.js +0 -0
  312. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.d.ts +0 -0
  313. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.js +0 -0
  314. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.d.ts +0 -0
  315. /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.js +0 -0
  316. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.d.ts +0 -0
  317. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.js +0 -0
  318. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/index.d.ts +0 -0
  319. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/index.js +0 -0
  320. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.js +0 -0
  321. /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.d.ts +0 -0
  322. /package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.d.ts +0 -0
  323. /package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.js +0 -0
  324. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.d.ts +0 -0
  325. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.js +0 -0
  326. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.d.ts +0 -0
  327. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.js +0 -0
  328. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.d.ts +0 -0
  329. /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.js +0 -0
  330. /package/dist/{src/features → features}/launch/development-launch.d.ts +0 -0
  331. /package/dist/{src/features → features}/launch/initialize-profile.d.ts +0 -0
  332. /package/dist/{src/features → features}/launch/initialize-profile.js +0 -0
  333. /package/dist/{src/features → features}/launch/runtime-selection.js +0 -0
  334. /package/dist/{src/features → features}/workspace/capabilities.js +0 -0
  335. /package/dist/{src/features → features}/workspace/index.d.ts +0 -0
  336. /package/dist/{src/features → features}/workspace/index.js +0 -0
  337. /package/dist/{src/features → features}/workspace/presentation.d.ts +0 -0
  338. /package/dist/{src/features → features}/workspace/presentation.js +0 -0
  339. /package/dist/{src/features → features}/workspace/reconciliation.d.ts +0 -0
  340. /package/dist/{src/features → features}/workspace/reconciliation.js +0 -0
  341. /package/dist/{src/foundation → foundation}/launch-guardian/index.d.ts +0 -0
  342. /package/dist/{src/foundation → foundation}/launch-guardian/index.js +0 -0
  343. /package/dist/{src/foundation → foundation}/launch-guardian/main.d.ts +0 -0
  344. /package/dist/{src/foundation → foundation}/lifecycle/commands.d.ts +0 -0
  345. /package/dist/{src/foundation → foundation}/lifecycle/commands.js +0 -0
  346. /package/dist/{src/foundation → foundation}/lifecycle/index.d.ts +0 -0
  347. /package/dist/{src/foundation → foundation}/lifecycle/index.js +0 -0
  348. /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.d.ts +0 -0
  349. /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.js +0 -0
  350. /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.d.ts +0 -0
  351. /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.js +0 -0
  352. /package/dist/{src/foundation → foundation}/native-host-protocol/index.d.ts +0 -0
  353. /package/dist/{src/foundation → foundation}/native-host-protocol/index.js +0 -0
  354. /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.d.ts +0 -0
  355. /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.js +0 -0
  356. /package/dist/{src/foundation → foundation}/process-containment/artifact.d.ts +0 -0
  357. /package/dist/{src/foundation → foundation}/process-containment/artifact.js +0 -0
  358. /package/dist/{src/foundation → foundation}/process-containment/contracts.d.ts +0 -0
  359. /package/dist/{src/foundation → foundation}/process-containment/contracts.js +0 -0
  360. /package/dist/{src/foundation → foundation}/process-containment/index.d.ts +0 -0
  361. /package/dist/{src/foundation → foundation}/process-containment/index.js +0 -0
  362. /package/dist/{src/foundation → foundation}/protocol/index.d.ts +0 -0
  363. /package/dist/{src/foundation → foundation}/protocol/index.js +0 -0
  364. /package/dist/{src/foundation → foundation}/release/cohort-selection.d.ts +0 -0
  365. /package/dist/{src/foundation → foundation}/release/cohort-selection.js +0 -0
  366. /package/dist/{src/foundation → foundation}/release/concurrency.d.ts +0 -0
  367. /package/dist/{src/foundation → foundation}/release/concurrency.js +0 -0
  368. /package/dist/{src/foundation → foundation}/release/process-cleanup.d.ts +0 -0
  369. /package/dist/{src/foundation → foundation}/release/process-cleanup.js +0 -0
  370. /package/dist/{src/foundation → foundation}/release/stable-release.d.ts +0 -0
  371. /package/dist/{src/foundation → foundation}/release/stable-release.js +0 -0
  372. /package/dist/{src/foundation → foundation}/storage/index.d.ts +0 -0
  373. /package/dist/{src/foundation → foundation}/storage/index.js +0 -0
  374. /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.d.ts +0 -0
  375. /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.js +0 -0
  376. /package/dist/{src/foundation → foundation}/supervision/main.d.ts +0 -0
  377. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.js +0 -0
  378. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.d.ts +0 -0
  379. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.js +0 -0
  380. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.d.ts +0 -0
  381. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.js +0 -0
  382. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-editor-autocomplete.d.ts +0 -0
  383. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.js +0 -0
  384. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.js +0 -0
  385. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.d.ts +0 -0
  386. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.js +0 -0
  387. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.d.ts +0 -0
  388. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.js +0 -0
  389. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.d.ts +0 -0
  390. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.js +0 -0
  391. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.d.ts +0 -0
  392. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.js +0 -0
  393. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/earendil-announcement.d.ts +0 -0
  394. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/earendil-announcement.js +0 -0
  395. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.d.ts +0 -0
  396. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.js +0 -0
  397. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.d.ts +0 -0
  398. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.js +0 -0
  399. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.d.ts +0 -0
  400. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.js +0 -0
  401. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.d.ts +0 -0
  402. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.js +0 -0
  403. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/owned-editor.d.ts +0 -0
  404. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/owned-editor.js +0 -0
  405. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.d.ts +0 -0
  406. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.js +0 -0
  407. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.js +0 -0
  408. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.d.ts +0 -0
  409. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.js +0 -0
  410. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.d.ts +0 -0
  411. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.js +0 -0
  412. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.d.ts +0 -0
  413. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.js +0 -0
  414. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.d.ts +0 -0
  415. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.js +0 -0
  416. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.d.ts +0 -0
  417. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.js +0 -0
  418. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.d.ts +0 -0
  419. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.js +0 -0
  420. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.d.ts +0 -0
  421. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.js +0 -0
  422. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.d.ts +0 -0
  423. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.js +0 -0
  424. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.d.ts +0 -0
  425. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.js +0 -0
  426. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.d.ts +0 -0
  427. /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.js +0 -0
  428. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/pi-settings-metadata.json +0 -0
  429. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.d.ts +0 -0
  430. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.js +0 -0
  431. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.d.ts +0 -0
  432. /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.js +0 -0
  433. /package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/route-host.js +0 -0
  434. /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.d.ts +0 -0
  435. /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.js +0 -0
  436. /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/contracts.js +0 -0
  437. /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.js +0 -0
  438. /package/dist/{src/foundation/ui-apps → ui/apps}/contracts.js +0 -0
  439. /package/dist/{src/foundation/ui-apps → ui/apps}/index.d.ts +0 -0
  440. /package/dist/{src/foundation/ui-apps → ui/apps}/index.js +0 -0
  441. /package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.d.ts +0 -0
  442. /package/dist/{src/foundation/ui-components → ui/components}/label.d.ts +0 -0
  443. /package/dist/{src/foundation/ui-components → ui/components}/label.js +0 -0
  444. /package/dist/{src/foundation/ui-components → ui/components}/list-block.d.ts +0 -0
  445. /package/dist/{src/foundation/ui-components → ui/components}/list-block.js +0 -0
  446. /package/dist/{src/foundation/ui-components → ui/components}/pane.d.ts +0 -0
  447. /package/dist/{src/foundation/ui-components → ui/components}/pane.js +0 -0
  448. /package/dist/{src/foundation/ui-components → ui/components}/revision.d.ts +0 -0
  449. /package/dist/{src/foundation/ui-components → ui/components}/revision.js +0 -0
  450. /package/dist/{src/foundation/ui-components → ui/components}/status-line.d.ts +0 -0
  451. /package/dist/{src/foundation/ui-components → ui/components}/status-line.js +0 -0
  452. /package/dist/{src/foundation/ui-components → ui/components}/stepper.d.ts +0 -0
  453. /package/dist/{src/foundation/ui-components → ui/components}/stepper.js +0 -0
  454. /package/dist/{src/foundation/ui-components → ui/components}/theme.d.ts +0 -0
  455. /package/dist/{src/foundation/ui-components → ui/components}/theme.js +0 -0
  456. /package/dist/{src/foundation/ui-components → ui/components}/value-menu.d.ts +0 -0
  457. /package/dist/{src/foundation/ui-components → ui/components}/value-menu.js +0 -0
  458. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.d.ts +0 -0
  459. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.js +0 -0
  460. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.d.ts +0 -0
  461. /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.js +0 -0
@@ -1,9 +1,10 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
- import { chmod, lstat, mkdir, readFile, realpath, rename, rm, writeFile } from "node:fs/promises";
2
+ import { chmod, lstat, mkdir, readFile, realpath, rename, rm, symlink, writeFile } from "node:fs/promises";
3
3
  import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
4
- import { PRODUCT_PACKAGE_NAME, createReleaseIdentity, digestManifestFiles, discoverReleasePayload, releaseFileIdentity, resolveWithin, } from "./release.js";
4
+ import { PRODUCT_PACKAGE_NAME, createReleaseIdentity, discoverReleasePayload, releaseFileIdentity, resolveWithin, } from "./release.js";
5
5
  import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../../product-identity.js";
6
6
  import { mapWithConcurrency } from "./concurrency.js";
7
+ import { dependencyReference, materializeDependencyLayer, readCertifiedDependencyLayer, selectPublishedDependencyRuntimePayload, verifyDependencyLayer, } from "./dependency-layer.js";
7
8
  const RELEASE_FILE_IO_CONCURRENCY = 32;
8
9
  const certificationReady = new WeakSet();
9
10
  export const RELEASE_MANIFEST_FILENAME = PRODUCT_IDENTITY.manifest.releaseFilename;
@@ -13,15 +14,32 @@ export async function materializeRelease(packageRoot, dataDir, options = {}) {
13
14
  });
14
15
  const storeRoot = resolve(dataDir, "releases");
15
16
  await mkdir(storeRoot, { recursive: true, mode: 0o700 });
16
- options.onProgress?.({ phase: "copying", fileCount: payload.paths.length });
17
+ const dependencyPaths = payload.paths.filter(path => path.startsWith("node_modules/"));
18
+ const productPaths = payload.paths.filter(path => !path.startsWith("node_modules/"));
19
+ const selectedDependencies = await selectPublishedDependencyRuntimePayload(payload.packageRoot, dependencyPaths);
20
+ options.onRuntimeInventory?.(selectedDependencies.inventory);
21
+ const layerOperations = [];
22
+ const layer = await materializeDependencyLayer(payload.packageRoot, dataDir, selectedDependencies.paths, {
23
+ inventory: selectedDependencies.inventory,
24
+ cachedFiles: payload.cachedFiles,
25
+ onOperation: event => layerOperations.push(event),
26
+ ...(options.writeCandidateFile === undefined ? {} : { writeCandidateFile: options.writeCandidateFile }),
27
+ });
28
+ const layerReferences = layer === null ? [] : [dependencyReference(layer)];
29
+ options.onProgress?.({
30
+ phase: "copying",
31
+ fileCount: productPaths.length + (layer?.reused === false ? layer.files.length : 0),
32
+ });
33
+ for (const event of layerOperations)
34
+ options.onOperation?.(event);
17
35
  const candidate = resolveWithin(storeRoot, `.candidate-${randomUUID()}`);
18
36
  await mkdir(candidate, { recursive: false, mode: 0o700 });
19
37
  try {
20
- const directories = [...new Set(payload.paths.map(path => dirname(resolveWithin(candidate, path))))];
38
+ const directories = [...new Set(productPaths.map(path => dirname(resolveWithin(candidate, path))))];
21
39
  await mapWithConcurrency(directories, RELEASE_FILE_IO_CONCURRENCY, async (directory) => {
22
40
  await mkdir(directory, { recursive: true, mode: 0o700 });
23
41
  });
24
- const files = await mapWithConcurrency(payload.paths, RELEASE_FILE_IO_CONCURRENCY, async (path) => {
42
+ const files = await mapWithConcurrency(productPaths, RELEASE_FILE_IO_CONCURRENCY, async (path) => {
25
43
  const source = resolveWithin(payload.packageRoot, path);
26
44
  const destination = resolveWithin(candidate, path);
27
45
  const metadata = await lstat(source);
@@ -41,7 +59,12 @@ export async function materializeRelease(packageRoot, dataDir, options = {}) {
41
59
  options.onOperation?.({ operation: "candidate-write", path, bytes: bytes.length });
42
60
  return releaseFileIdentity(path, bytes, (metadata.mode & 0o111) !== 0);
43
61
  });
44
- const identity = createReleaseIdentity(payload.packageRoot, payload.packageVersion, files);
62
+ const identity = createReleaseIdentity(payload.packageRoot, payload.packageVersion, files, layerReferences);
63
+ if (layer !== null) {
64
+ const binding = resolveWithin(candidate, "node_modules");
65
+ const target = resolveWithin(layer.layerRoot, "node_modules");
66
+ await symlink(target, binding, process.platform === "win32" ? "junction" : "dir");
67
+ }
45
68
  const releaseRoot = resolveWithin(storeRoot, identity.releaseId);
46
69
  if (await lstat(releaseRoot).catch(() => null)) {
47
70
  await rm(candidate, { recursive: true, force: true });
@@ -84,7 +107,8 @@ export async function readMaterializedRelease(releaseRoot) {
84
107
  */
85
108
  export async function readCertifiedReleaseManifest(record, selectedStoreRoot) {
86
109
  const canonical = await realpath(record.releaseRoot);
87
- assertContained(await realpath(selectedStoreRoot), canonical, "release root is outside the selected release store");
110
+ const canonicalStoreRoot = await realpath(selectedStoreRoot);
111
+ assertContained(canonicalStoreRoot, canonical, "release root is outside the selected release store");
88
112
  const manifest = JSON.parse(await readFile(resolveWithin(canonical, RELEASE_MANIFEST_FILENAME), "utf8"));
89
113
  validateManifest(manifest);
90
114
  if (manifest.releaseId !== record.releaseId || manifest.contentDigest !== record.contentDigest
@@ -93,12 +117,13 @@ export async function readCertifiedReleaseManifest(record, selectedStoreRoot) {
93
117
  }
94
118
  if (canonical.split(sep).at(-1) !== manifest.releaseId)
95
119
  throw new Error(`release directory does not match identity ${manifest.releaseId}`);
120
+ await verifyReleaseDependencies(canonical, canonicalStoreRoot, manifest.dependencyLayers ?? [], false);
96
121
  return { ...manifest, releaseRoot: canonical };
97
122
  }
98
123
  export async function verifyMaterializedRelease(releaseRoot, expected, selectedStoreRoot, options = {}) {
99
124
  const canonical = await realpath(releaseRoot);
100
- if (selectedStoreRoot)
101
- assertContained(await realpath(selectedStoreRoot), canonical, "release root is outside the selected release store");
125
+ const canonicalStoreRoot = selectedStoreRoot ? await realpath(selectedStoreRoot) : await realpath(dirname(canonical));
126
+ assertContained(canonicalStoreRoot, canonical, "release root is outside the selected release store");
102
127
  const manifestPath = resolveWithin(canonical, RELEASE_MANIFEST_FILENAME);
103
128
  const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
104
129
  validateManifest(manifest);
@@ -111,9 +136,10 @@ export async function verifyMaterializedRelease(releaseRoot, expected, selectedS
111
136
  await mapWithConcurrency(manifest.files, RELEASE_FILE_IO_CONCURRENCY, async (file) => {
112
137
  await verifyFile(canonical, file, options);
113
138
  });
114
- const recomputed = digestManifestFiles(manifest.files);
139
+ const recomputed = createReleaseIdentity(manifest.packageRoot, manifest.packageVersion, manifest.files, manifest.dependencyLayers ?? []).contentDigest;
115
140
  if (recomputed !== manifest.contentDigest)
116
141
  throw new Error(`release content digest mismatch for ${manifest.releaseId}`);
142
+ await verifyReleaseDependencies(canonical, canonicalStoreRoot, manifest.dependencyLayers ?? [], true, options);
117
143
  return { ...manifest, releaseRoot: canonical };
118
144
  }
119
145
  export async function assertImmutableExecutionRoot(release, dataDir) {
@@ -135,6 +161,25 @@ export async function resolveReleaseEntryPoint(release, entryPoint) {
135
161
  assertContained(release.releaseRoot, canonical, "entry point resolves outside the selected release root");
136
162
  return canonical;
137
163
  }
164
+ async function verifyReleaseDependencies(releaseRoot, storeRoot, references, fullVerification, options = {}) {
165
+ if (references.length === 0)
166
+ return;
167
+ if (references.length !== 1)
168
+ throw new Error("release currently supports exactly one dependency layer");
169
+ const dataDir = dirname(storeRoot);
170
+ const reference = references[0];
171
+ const layer = fullVerification
172
+ ? await verifyDependencyLayer(dataDir, reference, event => options.onOperation?.({ operation: event.operation, path: event.path, bytes: event.bytes }))
173
+ : await readCertifiedDependencyLayer(dataDir, reference.layerId, reference);
174
+ const binding = resolveWithin(releaseRoot, reference.binding);
175
+ const metadata = await lstat(binding);
176
+ if (!metadata.isSymbolicLink())
177
+ throw new Error(`release dependency binding is not managed: ${binding}`);
178
+ const target = await realpath(binding);
179
+ const expected = await realpath(resolveWithin(layer.layerRoot, "node_modules"));
180
+ if (target !== expected)
181
+ throw new Error(`release dependency binding targets unexpected content: ${target}`);
182
+ }
138
183
  async function verifyFile(root, file, options) {
139
184
  const path = resolveWithin(root, file.path);
140
185
  const metadata = await lstat(path).catch(() => null);
@@ -159,6 +204,11 @@ function validateManifest(value) {
159
204
  throw new Error(PRODUCT_TEXT.diagnostic("release identity is invalid"));
160
205
  if (!Array.isArray(value.files) || value.files.length === 0)
161
206
  throw new Error("release manifest contains no files");
207
+ if (value.dependencyLayers !== undefined && (!Array.isArray(value.dependencyLayers) || value.dependencyLayers.length === 0
208
+ || value.dependencyLayers.some(layer => !/^dependencies-[a-f0-9]{32}$/.test(layer.layerId)
209
+ || !/^[a-f0-9]{64}$/.test(layer.contentDigest) || layer.binding !== "node_modules"))) {
210
+ throw new Error("release dependency-layer references are invalid");
211
+ }
162
212
  for (const file of value.files) {
163
213
  if (typeof file.path !== "string" || file.path.length === 0 || file.path.includes("\\") || file.path.startsWith("/") || file.path.split("/").includes("..")) {
164
214
  throw new Error(`invalid release manifest path: ${String(file.path)}`);
@@ -1,3 +1,4 @@
1
+ import type { DependencyLayerReference } from "./dependency-layer.js";
1
2
  export declare const PRODUCT_PACKAGE_NAME: string;
2
3
  export interface ReleaseFileIdentity {
3
4
  readonly path: string;
@@ -12,6 +13,8 @@ export interface ReleaseIdentity {
12
13
  readonly releaseId: string;
13
14
  readonly packageRoot: string;
14
15
  readonly files: readonly ReleaseFileIdentity[];
16
+ /** Absent for legacy full-copy releases. */
17
+ readonly dependencyLayers?: readonly DependencyLayerReference[];
15
18
  }
16
19
  export interface DiscoveredReleasePayload {
17
20
  readonly packageRoot: string;
@@ -31,7 +34,7 @@ export declare function discoverReleasePayload(packageRoot: string, options?: Di
31
34
  * content.
32
35
  */
33
36
  export declare function deriveReleaseIdentity(packageRoot: string): Promise<ReleaseIdentity>;
34
- export declare function createReleaseIdentity(packageRoot: string, packageVersion: string, files: readonly ReleaseFileIdentity[]): ReleaseIdentity;
37
+ export declare function createReleaseIdentity(packageRoot: string, packageVersion: string, files: readonly ReleaseFileIdentity[], dependencyLayers?: readonly DependencyLayerReference[]): ReleaseIdentity;
35
38
  export declare function releaseFileIdentity(path: string, bytes: Uint8Array, executable: boolean): ReleaseFileIdentity;
36
39
  export declare function digestManifestFiles(files: readonly ReleaseFileIdentity[]): string;
37
40
  export declare function resolveWithin(root: string, candidate: string): string;
@@ -51,8 +51,14 @@ export async function deriveReleaseIdentity(packageRoot) {
51
51
  });
52
52
  return createReleaseIdentity(payload.packageRoot, payload.packageVersion, files);
53
53
  }
54
- export function createReleaseIdentity(packageRoot, packageVersion, files) {
55
- const contentDigest = digestManifestFiles(files);
54
+ export function createReleaseIdentity(packageRoot, packageVersion, files, dependencyLayers = []) {
55
+ const productDigest = digestManifestFiles(files);
56
+ const contentDigest = dependencyLayers.length === 0
57
+ ? productDigest
58
+ : createHash("sha256")
59
+ .update(`product\0${productDigest}\n`)
60
+ .update(dependencyLayers.map(layer => `${layer.layerId}\0${layer.contentDigest}\0${layer.binding}\n`).join(""))
61
+ .digest("hex");
56
62
  return {
57
63
  packageName: PRODUCT_PACKAGE_NAME,
58
64
  packageVersion,
@@ -60,6 +66,7 @@ export function createReleaseIdentity(packageRoot, packageVersion, files) {
60
66
  releaseId: `${packageVersion}-${contentDigest.slice(0, 20)}`,
61
67
  packageRoot,
62
68
  files: [...files].sort(compareReleaseFiles),
69
+ ...(dependencyLayers.length === 0 ? {} : { dependencyLayers: [...dependencyLayers] }),
63
70
  };
64
71
  }
65
72
  export function releaseFileIdentity(path, bytes, executable) {
@@ -143,7 +150,7 @@ async function findInstalledDependency(root, requesterRoot, name) {
143
150
  const metadata = await lstat(candidate).catch(() => null);
144
151
  if (metadata?.isDirectory() && !metadata.isSymbolicLink())
145
152
  return candidate;
146
- // A linked dependency directory is how this installation unifies a module
153
+ // Invariant: a linked dependency directory is how this installation unifies a module
147
154
  // that would otherwise be present twice, and the link is made by A1 itself
148
155
  // at install and at every launch. Follow it to the directory it names and
149
156
  // collect from there, so the payload still reads only real files — but
@@ -14,6 +14,7 @@ export interface UpdateTransaction {
14
14
  readonly startedAt: string;
15
15
  readonly updatedAt: string;
16
16
  }
17
+ /** Persists the durable update journal and permits only validated forward transaction phases. */
17
18
  export declare class UpdateTransactionStore {
18
19
  #private;
19
20
  readonly path: string;
@@ -3,6 +3,7 @@ import { mkdir, open, readFile, rename, rm } from "node:fs/promises";
3
3
  import { dirname, resolve } from "node:path";
4
4
  import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../../product-identity.js";
5
5
  export const UPDATE_JOURNAL_SCHEMA = PRODUCT_IDENTITY.protocol.updateJournalSchema;
6
+ /** Persists the durable update journal and permits only validated forward transaction phases. */
6
7
  export class UpdateTransactionStore {
7
8
  path;
8
9
  constructor(dataDir) { this.path = resolve(dataDir, "update-transaction.json"); }
@@ -18,7 +18,7 @@ export interface UpdateOutput {
18
18
  stdout(message: string): void;
19
19
  stderr(message: string): void;
20
20
  }
21
- export type UpdateMeasuredPhase = "package-version" | "target-resolution" | "global-root" | "ownership-release" | "npm-install" | "materialized" | "certified" | "active-reference-committed" | "supervisor-verified" | "transaction-complete";
21
+ export type UpdateMeasuredPhase = "package-version" | "target-resolution" | "global-root" | "ownership-release" | "npm-install" | "materialized" | "certified" | "active-reference-committed" | "warmup" | "supervisor-verified" | "transaction-complete";
22
22
  export interface UpdatePhaseTimingEvent {
23
23
  readonly phase: UpdateMeasuredPhase;
24
24
  readonly durationMs: number;
@@ -28,12 +28,18 @@ export interface UpdatePerformanceEvidence {
28
28
  readonly sourceReads: number;
29
29
  readonly candidateWrites: number;
30
30
  readonly verificationReads: number;
31
+ readonly layerWrites?: number;
32
+ readonly layerReusedFiles?: number;
33
+ readonly layerReusedBytes?: number;
34
+ readonly payloadExcludedFiles?: number;
35
+ readonly payloadExcludedBytes?: number;
36
+ readonly warmupDurationMs?: number;
31
37
  readonly postNpmDurationMs: number;
32
38
  }
33
39
  export interface SelfUpdateOptions {
34
40
  packageRoot: string;
35
41
  channel?: UpdateChannel;
36
- /** A specific preview to install, named by its commit or its full version. */
42
+ /** A specific preview to install, named by its development number or full version. */
37
43
  target?: string;
38
44
  environment?: NodeJS.ProcessEnv;
39
45
  fileSystem?: UpdateFileSystem;
@@ -41,6 +47,8 @@ export interface SelfUpdateOptions {
41
47
  runner?: UpdateProcessRunner;
42
48
  lifecycle?: UpdateLifecycleCoordinator;
43
49
  transactionStore?: UpdateTransactionJournal;
50
+ /** Test or embedding seam for post-activation release maintenance. */
51
+ maintenance?: () => Promise<void>;
44
52
  progress?: boolean;
45
53
  onPhaseTiming?: (event: UpdatePhaseTimingEvent) => void;
46
54
  now?: () => number;
@@ -61,7 +69,7 @@ export interface UpdateLifecycleCoordinator {
61
69
  priorActiveVersion: string | null;
62
70
  }>;
63
71
  verifyPackageUnlocked(packageRoot: string): Promise<void>;
64
- activateInstalled(packageRoot: string, targetVersion: string, phase: (phase: UpdateActivationPhase) => Promise<void>, onMaterializing?: (progress: UpdateMaterializationProgress) => void): Promise<void>;
72
+ activateInstalled(packageRoot: string, targetVersion: string, phase: (phase: UpdateActivationPhase) => Promise<void>, onMaterializing?: (progress: UpdateMaterializationProgress) => void, onWarmup?: (state: "started" | "completed") => void): Promise<void>;
65
73
  }
66
74
  export interface UpdateTransactionJournal {
67
75
  readonly path: string;
@@ -77,6 +85,14 @@ export interface UpdateTransactionJournal {
77
85
  clearCompleted(): Promise<void>;
78
86
  }
79
87
  export declare function createNpmProcessRunner(platform?: NodeJS.Platform): UpdateProcessRunner;
88
+ export type UpdateOwnershipAction = "clean-dead-record" | "leave-running" | "end-session";
89
+ /**
90
+ * What an update does about the owner it found. A cohort running from retained immutable
91
+ * content keeps its work: the installation replaces files it does not read, and it listens on
92
+ * its own endpoint. A cohort running from the mutable installation is the one exception,
93
+ * because that installation is exactly what is about to be replaced under it.
94
+ */
95
+ export declare function planUpdateOwnership(ownership: "live-verified" | "dead", runsFromRetainedRelease: boolean): UpdateOwnershipAction;
80
96
  export declare function createUpdateLifecycleCoordinator(environment?: NodeJS.ProcessEnv, fileSystem?: UpdateFileSystem, output?: UpdateOutput): UpdateLifecycleCoordinator;
81
97
  export declare function runSelfUpdate(options: SelfUpdateOptions): Promise<number>;
82
98
  export declare function assertUpdatePerformanceBudget(evidence: UpdatePerformanceEvidence, maximumPostNpmDurationMs?: number): void;
@@ -6,21 +6,16 @@ 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
8
  import { certifyMaterializedRelease, probeOwnership, readEndpointMetadata, removeEndpointArtifacts, startSupervisor, waitForProcessExit, waitForVerifiedEndpoint, } from "./bootstrap.js";
9
- import { resolveProductPaths } from "../lifecycle/index.js";
9
+ import { resolveCohortEndpoint, resolveProductPaths } from "../lifecycle/index.js";
10
10
  import { encodeFrame, LineFrameDecoder } from "../protocol/index.js";
11
11
  import { CohortStateStore } from "./cohort-state.js";
12
12
  import { cleanupVerifiedOwner, processIsAlive } from "./process-cleanup.js";
13
13
  import { materializeRelease, readMaterializedRelease } from "./release-store.js";
14
+ import { scheduleReleaseCleanup } from "./release-gc.js";
15
+ import { warmMaterializedRelease } from "./warmup.js";
14
16
  import { UpdateTransactionStore } from "./update-transaction.js";
15
17
  export const PRODUCT_PACKAGE = PRODUCT_TEXT.packageName;
16
18
  const UPDATE_DIST_TAGS = { stable: "latest", next: "next" };
17
- /**
18
- * What each channel is called when A1 says it out loud. The internal name stays
19
- * `stable` because that is what the channel is, but what a reader is moving to is
20
- * a release, and that is the word the repository, its tags, and its GitHub
21
- * releases all use.
22
- */
23
- const UPDATE_CHANNEL_LABELS = { stable: "release", next: "next" };
24
19
  const defaultFileSystem = {
25
20
  async readFile(path) { return await readFile(path, "utf8"); },
26
21
  realpath,
@@ -47,6 +42,33 @@ export function createNpmProcessRunner(platform = process.platform) {
47
42
  } });
48
43
  });
49
44
  }
45
+ /**
46
+ * What an update does about the owner it found. A cohort running from retained immutable
47
+ * content keeps its work: the installation replaces files it does not read, and it listens on
48
+ * its own endpoint. A cohort running from the mutable installation is the one exception,
49
+ * because that installation is exactly what is about to be replaced under it.
50
+ */
51
+ export function planUpdateOwnership(ownership, runsFromRetainedRelease) {
52
+ if (ownership === "dead")
53
+ return "clean-dead-record";
54
+ return runsFromRetainedRelease ? "leave-running" : "end-session";
55
+ }
56
+ /**
57
+ * The endpoint of the active cohort, together with where it is recorded, so a caller that
58
+ * finds it can also clean it up. A release that predates cohort-scoped endpoints published
59
+ * one endpoint for the runtime directory, and that one is recognized too.
60
+ */
61
+ async function readActiveEndpoint(paths, activeReleaseId, environment) {
62
+ if (activeReleaseId !== null) {
63
+ const cohort = resolveCohortEndpoint(paths, activeReleaseId, environment);
64
+ const metadata = await readEndpointMetadata(cohort.endpointMetadataPath);
65
+ if (metadata)
66
+ return { metadata, paths: cohort };
67
+ }
68
+ const legacyPaths = { endpoint: paths.endpoint, endpointMetadataPath: paths.endpointMetadataPath };
69
+ const legacy = await readEndpointMetadata(legacyPaths.endpointMetadataPath);
70
+ return legacy ? { metadata: legacy, paths: legacyPaths } : null;
71
+ }
50
72
  export function createUpdateLifecycleCoordinator(environment = process.env, fileSystem = defaultFileSystem, output = defaultOutput) {
51
73
  const paths = resolveProductPaths(environment);
52
74
  const stateStore = new CohortStateStore(paths.dataDir);
@@ -56,45 +78,51 @@ export function createUpdateLifecycleCoordinator(environment = process.env, file
56
78
  const activeId = state.references.active;
57
79
  if (!activeId || state.releases[activeId]?.packageVersion !== targetVersion)
58
80
  return false;
59
- const endpoint = await readEndpointMetadata(paths.endpointMetadataPath);
60
- return endpoint?.releaseId === activeId && await probeOwnership(endpoint) === "live-verified";
81
+ const endpoint = await readActiveEndpoint(paths, activeId, environment);
82
+ return endpoint?.metadata.releaseId === activeId && await probeOwnership(endpoint.metadata) === "live-verified";
61
83
  },
62
84
  async shutdownVerifiedOwners(targetVersion) {
63
85
  const state = await stateStore.read();
64
- const priorActiveVersion = state.references.active ? state.releases[state.references.active]?.packageVersion ?? null : null;
65
- const endpoint = await readEndpointMetadata(paths.endpointMetadataPath);
66
- if (!endpoint)
86
+ const activeId = state.references.active;
87
+ const priorActiveVersion = activeId ? state.releases[activeId]?.packageVersion ?? null : null;
88
+ const owner = await readActiveEndpoint(paths, activeId, environment);
89
+ if (!owner)
67
90
  return { priorActiveVersion };
91
+ const endpoint = owner.metadata;
68
92
  const ownership = await probeOwnership(endpoint);
69
93
  if (ownership !== "live-verified" && ownership !== "dead") {
70
94
  throw new Error(PRODUCT_TEXT.diagnostic(`refused update shutdown because supervisor ownership is ${ownership}`));
71
95
  }
72
- const immutableRoot = await canonicalImmutableRoot(paths.dataDir, endpoint.releaseRoot);
73
- const legacyMutableInstall = ownership === "live-verified" && !immutableRoot;
74
- const identity = ownership === "dead"
75
- ? { accepted: false, reason: "recorded owner is dead" }
76
- : await requestUpdateShutdown(endpoint, targetVersion, 2_000);
96
+ const plan = planUpdateOwnership(ownership, await canonicalImmutableRoot(paths.dataDir, endpoint.releaseRoot));
97
+ if (plan === "clean-dead-record") {
98
+ await removeEndpointArtifacts(owner.paths.endpointMetadataPath, owner.paths.endpoint);
99
+ return { priorActiveVersion };
100
+ }
101
+ // Rationale: leaving sessions alone is the expected outcome, and saying so mid-update tears
102
+ // the progress bar; only ending a session (below) is worth interrupting it for.
103
+ if (plan === "leave-running")
104
+ return { priorActiveVersion };
105
+ // Rationale: say whose work is ending before it ends.
106
+ const live = endpoint.ownership.liveInstanceIds.length;
107
+ if (live > 0) {
108
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`ending ${live === 1 ? "one session" : `${live} sessions`} that run from the installation being replaced; a session started by an installed release would have been left alone.`)}\n`);
109
+ }
110
+ const identity = await requestUpdateShutdown(endpoint, targetVersion, 2_000);
77
111
  if (!identity.accepted && processIsAlive(endpoint.pid)) {
78
- // Explicit update consent permits bounded cleanup of an authenticated
112
+ // Security: explicit update consent permits bounded cleanup of an authenticated
79
113
  // older owner that predates the update-shutdown message.
80
- const cleanup = await cleanupVerifiedOwner(endpoint, {
81
- allowLiveInstances: true,
82
- reason: legacyMutableInstall ? "legacy-mutable-install" : "explicit-update",
83
- });
114
+ const cleanup = await cleanupVerifiedOwner(endpoint, { allowLiveInstances: true, reason: "legacy-mutable-install" });
84
115
  if (!cleanup.terminated)
85
116
  throw new Error(`verified ${PRODUCT_TEXT.displayName} owner ${endpoint.pid} rejected shutdown and could not be terminated: ${identity.reason}`);
86
117
  }
87
118
  else if (identity.accepted) {
88
119
  await waitForProcessExit(endpoint.pid, 3_000).catch(async () => {
89
- const cleanup = await cleanupVerifiedOwner(endpoint, {
90
- allowLiveInstances: true,
91
- reason: legacyMutableInstall ? "legacy-mutable-install" : "explicit-update",
92
- });
120
+ const cleanup = await cleanupVerifiedOwner(endpoint, { allowLiveInstances: true, reason: "legacy-mutable-install" });
93
121
  if (!cleanup.terminated)
94
122
  throw new Error(`verified ${PRODUCT_TEXT.displayName} owner ${endpoint.pid} did not terminate`);
95
123
  });
96
124
  }
97
- await removeEndpointArtifacts(paths.endpointMetadataPath, paths.endpoint);
125
+ await removeEndpointArtifacts(owner.paths.endpointMetadataPath, owner.paths.endpoint);
98
126
  return { priorActiveVersion };
99
127
  },
100
128
  async verifyPackageUnlocked(packageRoot) {
@@ -107,12 +135,12 @@ export function createUpdateLifecycleCoordinator(environment = process.env, file
107
135
  await rename(probe, packageRoot);
108
136
  }
109
137
  catch (error) {
110
- // Best-effort rollback if the first rename succeeded and the second did not.
138
+ // Invariant: best-effort rollback runs if the first rename succeeded and the second did not.
111
139
  await rename(probe, packageRoot).catch(() => { });
112
140
  throw new Error(PRODUCT_TEXT.diagnostic(`package remains locked after verified shutdown: ${errorMessage(error)}`));
113
141
  }
114
142
  },
115
- async activateInstalled(packageRoot, targetVersion, phase, onMaterializing) {
143
+ async activateInstalled(packageRoot, targetVersion, phase, onMaterializing, onWarmup) {
116
144
  let total = 0;
117
145
  let completed = 0;
118
146
  const candidate = await materializeRelease(packageRoot, paths.dataDir, {
@@ -121,7 +149,7 @@ export function createUpdateLifecycleCoordinator(environment = process.env, file
121
149
  onMaterializing?.({ completed, total });
122
150
  },
123
151
  onOperation: event => {
124
- if (event.operation !== "candidate-write")
152
+ if (event.operation !== "candidate-write" && event.operation !== "layer-write")
125
153
  return;
126
154
  completed += 1;
127
155
  onMaterializing?.({ completed, total });
@@ -136,8 +164,11 @@ export function createUpdateLifecycleCoordinator(environment = process.env, file
136
164
  await phase("certified");
137
165
  await stateStore.activate(candidate.releaseId);
138
166
  await phase("active-reference-committed");
167
+ onWarmup?.("started");
168
+ await warmMaterializedRelease(candidate, environment);
169
+ onWarmup?.("completed");
139
170
  await startSupervisor(candidate, environment);
140
- await waitForVerifiedEndpoint(paths.endpointMetadataPath, candidate, 8_000);
171
+ await waitForVerifiedEndpoint(resolveCohortEndpoint(paths, candidate.releaseId, environment).endpointMetadataPath, candidate, 8_000);
141
172
  },
142
173
  };
143
174
  }
@@ -188,7 +219,7 @@ function createUpdateProgress(output, enabled) {
188
219
  draw();
189
220
  if (creepTo <= current)
190
221
  return;
191
- // Creep asymptotically toward (but never reach) the next milestone so
222
+ // Rationale: creep asymptotically toward (but never reach) the next milestone so
192
223
  // long opaque phases such as npm install still show visible motion. The
193
224
  // ceiling stays a whole point below the milestone: settling on `creepTo`
194
225
  // itself would render as that milestone and make arriving at it invisible,
@@ -199,7 +230,7 @@ function createUpdateProgress(output, enabled) {
199
230
  }, PROGRESS_TICK_MS);
200
231
  timer.unref?.();
201
232
  },
202
- // The bar exists to say the update is still moving. Once it has finished
233
+ // Rationale: the bar exists to say the update is still moving. Once it has finished
203
234
  // there is a better line to occupy that row — the one naming what is now
204
235
  // installed — so the bar gives the row back rather than leaving a full
205
236
  // meter above a message that already implies it.
@@ -223,12 +254,13 @@ function createUpdateProgress(output, enabled) {
223
254
  }
224
255
  /** The newest version the channel points at, which is what an unqualified update takes. */
225
256
  async function resolveChannelHead(runner, distTag, output) {
226
- const lookup = await runNpm(runner, ["view", `${PRODUCT_PACKAGE}@${distTag}`, "version"], true, output, `query the npm ${distTag} channel`);
257
+ const publicChannel = distTag === "next" ? "development" : "release";
258
+ const lookup = await runNpm(runner, ["view", `${PRODUCT_PACKAGE}@${distTag}`, "version"], true, output, `query the npm ${publicChannel} channel`);
227
259
  if (lookup.result === null)
228
260
  return { version: null, exitCode: lookup.exitCode };
229
261
  const version = validSemver(lookup.result.stdout.trim());
230
262
  if (version === null) {
231
- output.stderr(`${PRODUCT_TEXT.diagnostic(`received a malformed ${distTag} version from npm: ${JSON.stringify(lookup.result.stdout.trim())}.`)}\n`);
263
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`received a malformed ${publicChannel} channel version from npm: ${JSON.stringify(lookup.result.stdout.trim())}.`)}\n`);
232
264
  return { version: null, exitCode: 1 };
233
265
  }
234
266
  return { version, exitCode: 0 };
@@ -236,14 +268,10 @@ async function resolveChannelHead(runner, distTag, output) {
236
268
  /**
237
269
  * Resolve a preview the caller named.
238
270
  *
239
- * A preview is published as `<version>-dev.<commit>`, so its commit is enough to
240
- * say which one is wanted the version in front of it is not something anyone
241
- * should have to remember. A full version is accepted too, for anyone reading one
242
- * back from `a1 version` or a changelog.
243
- *
244
- * The published list is the authority: naming a commit that was never published,
245
- * or one published more than once under different versions, is an error rather
246
- * than a guess.
271
+ * A preview is published as `<version>-dev.<pull-request-number>`, so its decimal
272
+ * development number is enough to identify it. A full version is accepted too.
273
+ * The published list remains authoritative: nothing is constructed from the
274
+ * installed package's base version.
247
275
  */
248
276
  async function resolveRequestedPreview(runner, requested, output) {
249
277
  const lookup = await runNpm(runner, ["view", PRODUCT_PACKAGE, "versions", "--json"], true, output, "list the published versions");
@@ -260,9 +288,8 @@ async function resolveRequestedPreview(runner, requested, output) {
260
288
  const versions = (Array.isArray(published) ? published : [published]).filter((value) => typeof value === "string");
261
289
  const exact = versions.find(version => version === requested);
262
290
  if (exact !== undefined) {
263
- // Naming a release here would install it through the preview path, which is a
264
- // different command with a different meaning. The commit form cannot express
265
- // one, so only the fuller spelling of a preview reaches this.
291
+ // Rationale: naming a release here would install it through the preview path, which is a
292
+ // different command with a different meaning.
266
293
  if (!exact.includes("-dev.")) {
267
294
  output.stderr(`${PRODUCT_TEXT.diagnostic(`${exact} is a release, not a preview; run ${PRODUCT_TEXT.commandName} update to move to the current release.`)}\n`);
268
295
  return { version: null, exitCode: 1 };
@@ -314,9 +341,9 @@ export async function runSelfUpdate(options) {
314
341
  if (resolved.version === null)
315
342
  return resolved.exitCode;
316
343
  const targetVersion = resolved.version;
317
- // No full stop after a version: it already ends in a dot-separated identifier,
344
+ // Rationale: no full stop after a version: it already ends in a dot-separated identifier,
318
345
  // and a trailing one reads as part of the version rather than as punctuation.
319
- output.stdout(`${PRODUCT_TEXT.commandName} update (${UPDATE_CHANNEL_LABELS[channel]}): ${runningVersion} → ${targetVersion}\n`);
346
+ output.stdout(`${PRODUCT_TEXT.commandName} update: ${runningVersion} → ${targetVersion}\n`);
320
347
  const progress = createUpdateProgress(output, options.progress ?? (options.output === undefined && process.stdout.isTTY === true));
321
348
  const rootLookup = await measure("global-root", async () => await runNpm(runner, ["root", "--global"], true, output, "resolve npm's global package root"));
322
349
  if (rootLookup.result === null)
@@ -342,6 +369,9 @@ export async function runSelfUpdate(options) {
342
369
  const paths = resolveProductPaths(environment);
343
370
  const lifecycle = options.lifecycle ?? createUpdateLifecycleCoordinator(environment, fileSystem, output);
344
371
  const transactionStore = options.transactionStore ?? new UpdateTransactionStore(paths.dataDir);
372
+ const maintenance = options.maintenance ?? (options.lifecycle
373
+ ? async () => { }
374
+ : async () => await scheduleReleaseCleanup(paths.dataDir, paths));
345
375
  let transaction = await transactionStore.read();
346
376
  try {
347
377
  if (await lifecycle.targetIsActive(targetVersion)) {
@@ -349,11 +379,12 @@ export async function runSelfUpdate(options) {
349
379
  await transactionStore.advance("supervisor-verified");
350
380
  await transactionStore.finish("completed");
351
381
  }
382
+ await maintenance();
352
383
  await transactionStore.clearCompleted();
353
384
  output.stdout(`${PRODUCT_TEXT.commandName} is up to date — no update needed.\n`);
354
385
  return 0;
355
386
  }
356
- // The bar first appears here so a no-change run never flashes it.
387
+ // Rationale: the bar first appears here so a no-change run never flashes it.
357
388
  progress.set(3, 15);
358
389
  const cohortState = await new CohortStateStore(paths.dataDir).read();
359
390
  transaction = await transactionStore.begin({
@@ -381,8 +412,21 @@ export async function runSelfUpdate(options) {
381
412
  }
382
413
  transaction = await transactionStore.advance("package-installed");
383
414
  }
415
+ // Compatibility: npm 12 blocks install scripts unless allowScripts covers the package, so
416
+ // the postinstall that points the #pi-tui proxy at the tree npm just built
417
+ // may never have run. Run the shipped script directly: the proxy must be
418
+ // correct before the release store copies this tree. A failure is reported
419
+ // and left to the launch-time self-heal rather than failing the update.
420
+ try {
421
+ const proxySync = await runner(process.execPath, [resolve(packageRoot, "bin", "sync-pi-tui-proxy.js")], { captureStdout: true });
422
+ if (proxySync.code !== 0)
423
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`could not point the #pi-tui proxy at the installed tree (exited ${formatExitCode(proxySync.code)}).`)}\n`);
424
+ }
425
+ catch (error) {
426
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`could not point the #pi-tui proxy at the installed tree: ${errorMessage(error)}`)}\n`);
427
+ }
384
428
  progress.set(70, 75);
385
- // Ownership can be reacquired after an interrupted installation (for
429
+ // Concurrency: ownership can be reacquired after an interrupted installation (for
386
430
  // example, if bare A1 is launched before the update is resumed). Recheck
387
431
  // immediately before activation so recovery cannot start a second cohort.
388
432
  await measure("ownership-release", async () => { await lifecycle.shutdownVerifiedOwners(targetVersion); });
@@ -397,11 +441,24 @@ export async function runSelfUpdate(options) {
397
441
  const span = MATERIALIZE_PROGRESS.to - MATERIALIZE_PROGRESS.from;
398
442
  const done = total > 0 ? Math.min(1, completed / total) : 0;
399
443
  progress.set(MATERIALIZE_PROGRESS.from + span * done);
444
+ }, state => {
445
+ if (state === "started") {
446
+ activationPhaseStartedAt = now();
447
+ progress.set(98, 99);
448
+ }
449
+ else {
450
+ options.onPhaseTiming?.({ phase: "warmup", durationMs: Math.max(0, now() - activationPhaseStartedAt) });
451
+ activationPhaseStartedAt = now();
452
+ progress.set(99);
453
+ }
400
454
  });
401
455
  options.onPhaseTiming?.({ phase: "supervisor-verified", durationMs: Math.max(0, now() - activationPhaseStartedAt) });
402
456
  const transactionStartedAt = now();
403
457
  await transactionStore.advance("supervisor-verified");
404
458
  await transactionStore.finish("completed");
459
+ // Invariant: successful output follows the durable cleanup disposition. Slow recursive
460
+ // removal belongs to the detached worker started by this maintenance coordinator.
461
+ await maintenance();
405
462
  await transactionStore.clearCompleted();
406
463
  options.onPhaseTiming?.({ phase: "transaction-complete", durationMs: Math.max(0, now() - transactionStartedAt) });
407
464
  progress.finish();
@@ -426,8 +483,9 @@ export function assertUpdatePerformanceBudget(evidence, maximumPostNpmDurationMs
426
483
  failures.push("fixture contains no payload files");
427
484
  if (evidence.sourceReads !== evidence.fileCount)
428
485
  failures.push(`source payload read count is ${evidence.sourceReads} for ${evidence.fileCount} files`);
429
- if (evidence.candidateWrites !== evidence.fileCount)
430
- failures.push(`candidate payload write count is ${evidence.candidateWrites} for ${evidence.fileCount} files`);
486
+ const totalWrites = evidence.candidateWrites + (evidence.layerWrites ?? 0);
487
+ if (totalWrites !== evidence.fileCount)
488
+ failures.push(`runtime payload write count is ${totalWrites} for ${evidence.fileCount} files`);
431
489
  if (evidence.verificationReads > 0)
432
490
  failures.push(`fresh certification reread ${evidence.verificationReads} candidate files`);
433
491
  if (evidence.postNpmDurationMs > maximumPostNpmDurationMs)
@@ -495,8 +553,10 @@ async function rollbackPriorCohort(dataDir, environment, priorReleaseId) {
495
553
  }
496
554
  const release = await readMaterializedRelease(prior.releaseRoot);
497
555
  const paths = resolveProductPaths(environment);
556
+ // Invariant: rollback re-points the active reference and starts the prior cohort on its own endpoint;
557
+ // a cohort that survived the update keeps serving the work it already had.
498
558
  await startSupervisor(release, environment);
499
- await waitForVerifiedEndpoint(paths.endpointMetadataPath, release, 8_000);
559
+ await waitForVerifiedEndpoint(resolveCohortEndpoint(paths, release.releaseId, environment).endpointMetadataPath, release, 8_000);
500
560
  return "rolled back";
501
561
  }
502
562
  function phaseBefore(current, target) {
@@ -0,0 +1,3 @@
1
+ import type { MaterializedRelease } from "./release-store.js";
2
+ /** Import the exact immutable startup graph in a terminal-free bounded child process. */
3
+ export declare function warmMaterializedRelease(release: MaterializedRelease, environment: NodeJS.ProcessEnv, timeoutMs?: number): Promise<void>;