@timurproko/a1 0.1.8-dev.235df0e → 0.1.8-dev.260
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.
- package/README.md +107 -67
- package/bin/cli.js +28 -10
- package/bin/guardian.js +8 -3
- package/bin/module-identity.js +69 -35
- package/bin/pi-tui.d.ts +6 -0
- package/bin/pi-tui.js +28 -0
- package/bin/release-cleanup.js +8 -0
- package/bin/supervisor.js +2 -2
- package/bin/sync-pi-tui-proxy.js +97 -0
- package/bin/ui.js +47 -20
- package/bin/warmup.js +27 -0
- package/dist/cli/capabilities.d.ts +6 -0
- package/dist/{src/cli → cli}/capabilities.js +1 -1
- package/dist/{src/cli → cli}/dispatch.d.ts +15 -1
- package/dist/cli/dispatch.js +261 -0
- package/dist/cli/package-messages.d.ts +26 -0
- package/dist/cli/package-messages.js +71 -0
- package/dist/{src/cli → cli}/packages.d.ts +11 -2
- package/dist/{src/cli → cli}/packages.js +24 -27
- package/dist/{src/cli → cli}/version-stats.d.ts +6 -0
- package/dist/cli/version-stats.js +112 -0
- package/dist/composition/agent-engine-bridge.d.ts +3 -0
- package/dist/composition/agent-engine-bridge.js +108 -0
- package/dist/composition/index.d.ts +3 -0
- package/dist/composition/index.js +3 -0
- package/dist/composition/owned-ui.d.ts +31 -0
- package/dist/composition/owned-ui.js +66 -0
- package/dist/composition/process.d.ts +16 -0
- package/dist/composition/process.js +45 -0
- package/dist/composition/settings-route-host.d.ts +8 -0
- package/dist/composition/settings-route-host.js +75 -0
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.d.ts +2 -2
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.js +22 -4
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.d.ts +17 -0
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.d.ts +6 -0
- package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.d.ts +36 -0
- package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.js +25 -0
- package/dist/{src/features → features}/launch/development-launch.js +11 -3
- package/dist/{src/features → features}/launch/index.d.ts +0 -1
- package/dist/{src/features → features}/launch/index.js +0 -1
- package/dist/features/launch/intent.d.ts +10 -0
- package/dist/features/launch/intent.js +8 -0
- package/dist/{src/features → features}/launch/prepare-launch.d.ts +0 -2
- package/dist/{src/features → features}/launch/prepare-launch.js +2 -9
- package/dist/{src/features → features}/launch/profile-paths.d.ts +1 -2
- package/dist/{src/features → features}/launch/profile-paths.js +2 -8
- package/dist/{src/features → features}/launch/runtime-selection.d.ts +2 -5
- package/dist/{src/features → features}/owned-ui/customization.d.ts +3 -1
- package/dist/{src/features → features}/owned-ui/customization.js +3 -1
- package/dist/{src/features → features}/owned-ui/diagnostics.d.ts +2 -1
- package/dist/{src/features → features}/owned-ui/diagnostics.js +1 -0
- package/dist/{src/features → features}/owned-ui/index.d.ts +2 -0
- package/dist/{src/features → features}/owned-ui/index.js +2 -0
- package/dist/features/owned-ui/project-trust-prompt.d.ts +25 -0
- package/dist/features/owned-ui/project-trust-prompt.js +149 -0
- package/dist/{src/features → features}/owned-ui/run.d.ts +2 -2
- package/dist/{src/features → features}/owned-ui/run.js +2 -0
- package/dist/features/owned-ui/session-fork-prompt.d.ts +8 -0
- package/dist/features/owned-ui/session-fork-prompt.js +34 -0
- package/dist/{src/features → features}/owned-ui/settings-app.d.ts +3 -3
- package/dist/{src/features → features}/owned-ui/settings-app.js +103 -54
- package/dist/{src/features → features}/workspace/capabilities.d.ts +1 -1
- package/dist/{src/features → features}/workspace/reducer.d.ts +2 -1
- package/dist/{src/features → features}/workspace/reducer.js +2 -1
- package/dist/{src/features → features}/workspace/router.d.ts +2 -1
- package/dist/{src/features → features}/workspace/router.js +1 -0
- package/dist/{src/features → features}/workspace/store.d.ts +2 -1
- package/dist/{src/features → features}/workspace/store.js +1 -0
- package/dist/{src/foundation → foundation}/launch-guardian/main.d.ts +2 -0
- package/dist/{src/foundation → foundation}/launch-guardian/main.js +18 -5
- package/dist/{src/foundation → foundation}/lifecycle/index.d.ts +2 -0
- package/dist/{src/foundation → foundation}/lifecycle/index.js +2 -0
- package/dist/{src/foundation → foundation}/lifecycle/model.d.ts +1 -1
- package/dist/{src/foundation → foundation}/lifecycle/model.js +1 -1
- package/dist/foundation/lifecycle/paths.d.ts +30 -0
- package/dist/{src/foundation → foundation}/lifecycle/paths.js +29 -1
- package/dist/foundation/lifecycle/session-selection.d.ts +9 -0
- package/dist/foundation/lifecycle/session-selection.js +39 -0
- package/dist/foundation/lifecycle/supervisor-startup.d.ts +30 -0
- package/dist/foundation/lifecycle/supervisor-startup.js +106 -0
- package/dist/{src/foundation → foundation}/native-host-protocol/codec.d.ts +2 -0
- package/dist/{src/foundation → foundation}/native-host-protocol/codec.js +2 -0
- package/dist/{src/foundation → foundation}/native-host-protocol/messages.d.ts +1 -1
- package/dist/{src/foundation → foundation}/native-host-protocol/messages.js +1 -1
- package/dist/foundation/process-containment/darwin-process-inspector.d.ts +5 -0
- package/dist/foundation/process-containment/darwin-process-inspector.js +7 -0
- package/dist/{src/foundation → foundation}/process-containment/index.d.ts +1 -0
- package/dist/{src/foundation → foundation}/process-containment/index.js +1 -0
- package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.d.ts +1 -0
- package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.js +1 -0
- package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.d.ts +1 -0
- package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.js +1 -0
- package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.d.ts +3 -1
- package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.js +5 -2
- package/dist/{src/foundation → foundation}/protocol/client.d.ts +1 -0
- package/dist/{src/foundation → foundation}/protocol/client.js +1 -0
- package/dist/{src/foundation → foundation}/protocol/messages.d.ts +1 -0
- package/dist/{src/foundation → foundation}/protocol/messages.js +1 -0
- package/dist/{src/foundation → foundation}/release/bootstrap.d.ts +25 -6
- package/dist/{src/foundation → foundation}/release/bootstrap.js +124 -34
- package/dist/foundation/release/cohort-state.d.ts +156 -0
- package/dist/foundation/release/cohort-state.js +471 -0
- package/dist/foundation/release/dependency-layer.d.ts +82 -0
- package/dist/foundation/release/dependency-layer.js +497 -0
- package/dist/foundation/release/endpoints.d.ts +20 -0
- package/dist/foundation/release/endpoints.js +50 -0
- package/dist/foundation/release/immutable-platform.d.ts +6 -0
- package/dist/foundation/release/immutable-platform.js +13 -0
- package/dist/{src/foundation → foundation}/release/index.d.ts +4 -0
- package/dist/{src/foundation → foundation}/release/index.js +4 -0
- package/dist/foundation/release/release-gc.d.ts +71 -0
- package/dist/foundation/release/release-gc.js +734 -0
- package/dist/{src/foundation → foundation}/release/release-store.d.ts +7 -3
- package/dist/{src/foundation → foundation}/release/release-store.js +65 -13
- package/dist/{src/foundation → foundation}/release/release.d.ts +4 -1
- package/dist/{src/foundation → foundation}/release/release.js +10 -3
- package/dist/foundation/release/restart-certification.d.ts +67 -0
- package/dist/foundation/release/restart-certification.js +211 -0
- package/dist/{src/foundation → foundation}/release/update-transaction.d.ts +1 -0
- package/dist/{src/foundation → foundation}/release/update-transaction.js +1 -0
- package/dist/{src/foundation → foundation}/release/update.d.ts +19 -3
- package/dist/{src/foundation → foundation}/release/update.js +116 -56
- package/dist/foundation/release/warmup.d.ts +3 -0
- package/dist/foundation/release/warmup.js +35 -0
- package/dist/foundation/startup/index.d.ts +1 -0
- package/dist/foundation/startup/index.js +1 -0
- package/dist/foundation/startup/startup-runtime.d.ts +36 -0
- package/dist/foundation/startup/startup-runtime.js +140 -0
- package/dist/{src/foundation → foundation}/storage/control-store.d.ts +2 -1
- package/dist/{src/foundation → foundation}/storage/control-store.js +39 -4
- package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.js +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.js +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.d.ts +1 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.js +1 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.js +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/state.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/state.js +2 -1
- package/dist/foundation/supervision/index.d.ts +3 -0
- package/dist/foundation/supervision/index.js +3 -0
- package/dist/foundation/supervision/main.d.ts +1 -0
- package/dist/foundation/supervision/main.js +80 -0
- package/dist/foundation/supervision/paths.d.ts +1 -0
- package/dist/foundation/supervision/paths.js +1 -0
- package/dist/{src/foundation → foundation}/supervision/server.d.ts +19 -1
- package/dist/{src/foundation → foundation}/supervision/server.js +65 -3
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.d.ts +1 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.d.ts +1 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.js +3 -2
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.d.ts +1 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.js +1 -1
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +55 -0
- package/dist/integrations/pi/components/owned-editor-ux.js +778 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.d.ts +1 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.js +1 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-editor-autocomplete.js +54 -6
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.d.ts +1 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.d.ts +3 -3
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.js +49 -18
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +36 -0
- package/dist/integrations/pi/components/shell-presenters-info.js +78 -0
- package/dist/integrations/pi/components/shell-presenters-transcript.d.ts +25 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-presenters-transcript.js +92 -131
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.d.ts +5 -2
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.js +2 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.d.ts +57 -8
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.js +4 -2
- package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +13 -0
- package/dist/integrations/pi/components/submitted-prompt-adapter.js +27 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.d.ts +10 -2
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.js +36 -3
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.d.ts +1 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.d.ts +28 -4
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.js +714 -127
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.d.ts +2 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.js +4 -2
- package/dist/integrations/pi/engine/http-dispatcher.d.ts +4 -0
- package/dist/integrations/pi/engine/http-dispatcher.js +25 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.d.ts +4 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.js +4 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.d.ts +2 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.js +1 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.d.ts +1 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.js +32 -26
- package/dist/integrations/pi/engine/project-trust-preflight.d.ts +22 -0
- package/dist/integrations/pi/engine/project-trust-preflight.js +50 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.d.ts +2 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.js +1 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.d.ts +19 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.js +47 -5
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.d.ts +4 -2
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.js +19 -4
- package/dist/integrations/pi/engine/session-selection.d.ts +28 -0
- package/dist/integrations/pi/engine/session-selection.js +90 -0
- package/dist/integrations/pi/engine/settings-effects.d.ts +66 -0
- package/dist/integrations/pi/engine/settings-effects.js +249 -0
- package/dist/integrations/pi/engine/settings-integration.d.ts +43 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/settings-integration.js +102 -108
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.d.ts +3 -2
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.js +1 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.d.ts +18 -1
- package/dist/integrations/pi/session-ui/clipboard-image.d.ts +11 -0
- package/dist/integrations/pi/session-ui/clipboard-image.js +29 -0
- package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/index.d.ts +1 -0
- package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/index.js +1 -0
- package/dist/integrations/pi/session-ui/prompt-chips.d.ts +23 -0
- package/dist/integrations/pi/session-ui/prompt-chips.js +246 -0
- package/dist/integrations/pi/session-ui/route-host.d.ts +5 -0
- package/dist/integrations/pi/session-ui/session-shell-root.d.ts +141 -0
- package/dist/integrations/pi/session-ui/session-shell-root.js +1158 -0
- package/dist/integrations/pi/session-ui/session-shell.d.ts +55 -0
- package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/session-shell.js +479 -719
- package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +45 -0
- package/dist/integrations/pi/session-ui/session-viewport-controller.js +463 -0
- package/dist/integrations/pi/session-ui/stream-presentation-coalescer.d.ts +29 -0
- package/dist/integrations/pi/session-ui/stream-presentation-coalescer.js +79 -0
- package/dist/integrations/pi/session-ui/system-clipboard.d.ts +20 -0
- package/dist/integrations/pi/session-ui/system-clipboard.js +130 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.d.ts +8 -1
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.js +216 -9
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/contracts.d.ts +29 -6
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +74 -0
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +380 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/index.d.ts +2 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/index.js +2 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +39 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.js +139 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.d.ts +1 -1
- package/dist/native/darwin-arm64/manifest.json +4 -4
- package/dist/native/darwin-arm64/process-guardian +0 -0
- package/dist/native/linux-x64/manifest.json +3 -3
- package/dist/native/linux-x64/process-guardian +0 -0
- package/dist/native/win32-x64/manifest.json +3 -3
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/{src/product-identity.d.ts → product-identity.d.ts} +3 -3
- package/dist/{src/product-identity.js → product-identity.js} +7 -5
- package/dist/{src/product-identity.json → product-identity.json} +11 -6
- package/dist/runtime-payload-inventory.json +122328 -0
- package/dist/{src/foundation/ui-apps → ui/apps}/contracts.d.ts +23 -1
- package/dist/{src/foundation/ui-apps → ui/apps}/host.d.ts +1 -1
- package/dist/{src/foundation/ui-apps → ui/apps}/host.js +14 -10
- package/dist/{src/foundation/ui-apps → ui/apps}/registry.d.ts +1 -0
- package/dist/{src/foundation/ui-apps → ui/apps}/registry.js +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.js +5 -3
- package/dist/{src/foundation/ui-components → ui/components}/frame.d.ts +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/frame.js +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/index.d.ts +5 -0
- package/dist/{src/foundation/ui-components → ui/components}/index.js +5 -0
- package/dist/{src/foundation/ui-components → ui/components}/line-input.d.ts +1 -6
- package/dist/{src/foundation/ui-components → ui/components}/line-input.js +4 -9
- package/dist/{src/foundation/ui-components → ui/components}/list-view.d.ts +0 -6
- package/dist/{src/foundation/ui-components → ui/components}/list-view.js +14 -7
- package/dist/{src/foundation/ui-components → ui/components}/mouse.d.ts +10 -0
- package/dist/{src/foundation/ui-components → ui/components}/mouse.js +23 -0
- package/dist/ui/components/progress-status.d.ts +2 -0
- package/dist/ui/components/progress-status.js +4 -0
- package/dist/ui/components/prompt-row.d.ts +14 -0
- package/dist/ui/components/prompt-row.js +20 -0
- package/dist/{src/foundation/ui-components → ui/components}/scrollbar.d.ts +26 -0
- package/dist/{src/foundation/ui-components → ui/components}/scrollbar.js +35 -0
- package/dist/{src/foundation/ui-components → ui/components}/shortcuts.d.ts +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/shortcuts.js +1 -0
- package/dist/ui/components/spans.d.ts +25 -0
- package/dist/ui/components/spans.js +257 -0
- package/dist/ui/components/submitted-prompt.d.ts +23 -0
- package/dist/ui/components/submitted-prompt.js +50 -0
- package/dist/{src/foundation/ui-components → ui/components}/surface.d.ts +0 -5
- package/dist/{src/foundation/ui-components → ui/components}/surface.js +1 -5
- package/dist/ui/components/text-selection.d.ts +62 -0
- package/dist/ui/components/text-selection.js +208 -0
- package/dist/{src/foundation/ui-components → ui/components}/text.d.ts +14 -0
- package/dist/{src/foundation/ui-components → ui/components}/text.js +66 -4
- package/dist/ui/components/transcript-viewport.d.ts +152 -0
- package/dist/ui/components/transcript-viewport.js +631 -0
- package/dist/ui/components/visible-hyperlinks.d.ts +19 -0
- package/dist/ui/components/visible-hyperlinks.js +64 -0
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/declarations.d.ts +8 -1
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/declarations.js +33 -5
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.d.ts +1 -1
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.js +21 -2
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.d.ts +6 -19
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.js +32 -23
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/session.d.ts +9 -17
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/session.js +65 -55
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.d.ts +1 -0
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.js +2 -1
- package/docs/architecture/boundaries.md +9 -9
- package/docs/architecture/code-documentation.md +77 -0
- package/docs/architecture/process-guardian-provenance.md +3 -1
- package/docs/architecture/project-structure.md +67 -30
- package/docs/architecture/resource-and-data-policy.md +1 -1
- package/docs/architecture/toolchain.md +10 -10
- package/docs/architecture/ui-reference-provenance.md +36 -5
- package/docs/ci-release-runbook.md +186 -79
- package/docs/features/launch-profiles.md +24 -17
- package/docs/manual-ghost-link-baseline.md +89 -0
- package/docs/manual-launch-instance-acceptance.md +12 -35
- package/docs/manual-owned-ui-checkpoint.md +78 -0
- package/docs/manual-pi-boundary-candidate.md +4 -5
- package/docs/manual-terminal-colour-check.md +4 -3
- package/docs/repository-governance-live-acceptance.md +77 -0
- package/package.json +37 -27
- package/dist/src/cli/capabilities.d.ts +0 -15
- package/dist/src/cli/dispatch.js +0 -177
- package/dist/src/cli/version-stats.js +0 -72
- package/dist/src/composition/index.d.ts +0 -48
- package/dist/src/composition/index.js +0 -258
- package/dist/src/features/launch/intent.d.ts +0 -7
- package/dist/src/features/launch/intent.js +0 -4
- package/dist/src/features/launch/profiles.d.ts +0 -12
- package/dist/src/features/launch/profiles.js +0 -26
- package/dist/src/foundation/lifecycle/paths.d.ts +0 -10
- package/dist/src/foundation/pi-component-adapter/shell-presenters-transcript.d.ts +0 -57
- package/dist/src/foundation/pi-engine-adapter/settings-integration.d.ts +0 -55
- package/dist/src/foundation/pi-owned-ui-integration/route-host.d.ts +0 -29
- package/dist/src/foundation/pi-owned-ui-integration/session-shell.d.ts +0 -106
- package/dist/src/foundation/release/cohort-state.d.ts +0 -70
- package/dist/src/foundation/release/cohort-state.js +0 -202
- package/dist/src/foundation/release/release-gc.d.ts +0 -5
- package/dist/src/foundation/release/release-gc.js +0 -16
- package/dist/src/foundation/supervision/index.d.ts +0 -3
- package/dist/src/foundation/supervision/index.js +0 -3
- package/dist/src/foundation/supervision/main.d.ts +0 -1
- package/dist/src/foundation/supervision/main.js +0 -41
- package/dist/src/foundation/supervision/paths.d.ts +0 -1
- package/dist/src/foundation/supervision/paths.js +0 -1
- package/dist/src/foundation/ui-components/spans.d.ts +0 -7
- package/dist/src/foundation/ui-components/spans.js +0 -59
- package/docs/manual-transparent-checkpoint.md +0 -53
- /package/dist/{src/cli → cli}/index.d.ts +0 -0
- /package/dist/{src/cli → cli}/index.js +0 -0
- /package/dist/{src/cli → cli}/version.d.ts +0 -0
- /package/dist/{src/cli → cli}/version.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/index.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/index.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.d.ts +0 -0
- /package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.d.ts +0 -0
- /package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.js +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.d.ts +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.js +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.d.ts +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.js +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.d.ts +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.js +0 -0
- /package/dist/{src/features → features}/launch/development-launch.d.ts +0 -0
- /package/dist/{src/features → features}/launch/initialize-profile.d.ts +0 -0
- /package/dist/{src/features → features}/launch/initialize-profile.js +0 -0
- /package/dist/{src/features → features}/launch/runtime-selection.js +0 -0
- /package/dist/{src/features → features}/workspace/capabilities.js +0 -0
- /package/dist/{src/features → features}/workspace/index.d.ts +0 -0
- /package/dist/{src/features → features}/workspace/index.js +0 -0
- /package/dist/{src/features → features}/workspace/presentation.d.ts +0 -0
- /package/dist/{src/features → features}/workspace/presentation.js +0 -0
- /package/dist/{src/features → features}/workspace/reconciliation.d.ts +0 -0
- /package/dist/{src/features → features}/workspace/reconciliation.js +0 -0
- /package/dist/{src/foundation → foundation}/launch-guardian/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/launch-guardian/index.js +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/commands.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/commands.js +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.js +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.js +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/index.js +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.js +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/artifact.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/artifact.js +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/contracts.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/contracts.js +0 -0
- /package/dist/{src/foundation → foundation}/protocol/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/protocol/index.js +0 -0
- /package/dist/{src/foundation → foundation}/release/cohort-selection.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/cohort-selection.js +0 -0
- /package/dist/{src/foundation → foundation}/release/concurrency.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/concurrency.js +0 -0
- /package/dist/{src/foundation → foundation}/release/process-cleanup.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/process-cleanup.js +0 -0
- /package/dist/{src/foundation → foundation}/release/stable-release.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/stable-release.js +0 -0
- /package/dist/{src/foundation → foundation}/storage/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/storage/index.js +0 -0
- /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-editor-autocomplete.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/earendil-announcement.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/earendil-announcement.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/owned-editor.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/owned-editor.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.js +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/pi-settings-metadata.json +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.d.ts +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.js +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.js +0 -0
- /package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/route-host.js +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.d.ts +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.js +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/contracts.js +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.js +0 -0
- /package/dist/{src/foundation/ui-apps → ui/apps}/contracts.js +0 -0
- /package/dist/{src/foundation/ui-apps → ui/apps}/index.d.ts +0 -0
- /package/dist/{src/foundation/ui-apps → ui/apps}/index.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/label.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/label.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/list-block.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/list-block.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/pane.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/pane.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/revision.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/revision.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/status-line.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/status-line.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/stepper.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/stepper.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/theme.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/theme.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/value-menu.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/value-menu.js +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.js +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.js +0 -0
|
@@ -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
|
|
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
|
|
65
|
-
const
|
|
66
|
-
|
|
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
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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");
|
|
139
|
-
|
|
140
|
-
await
|
|
167
|
+
onWarmup?.("started");
|
|
168
|
+
await warmMaterializedRelease(candidate, environment);
|
|
169
|
+
onWarmup?.("completed");
|
|
170
|
+
const startup = await startSupervisor(candidate, environment);
|
|
171
|
+
await waitForVerifiedEndpoint(resolveCohortEndpoint(paths, candidate.releaseId, environment).endpointMetadataPath, candidate, 8_000, startup);
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
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 ${
|
|
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.<
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
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
|
-
//
|
|
264
|
-
// different command with a different meaning.
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
|
|
430
|
-
|
|
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);
|
|
498
|
-
|
|
499
|
-
|
|
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.
|
|
558
|
+
const startup = await startSupervisor(release, environment);
|
|
559
|
+
await waitForVerifiedEndpoint(resolveCohortEndpoint(paths, release.releaseId, environment).endpointMetadataPath, release, 8_000, startup);
|
|
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>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { releaseEnvironment } from "./bootstrap.js";
|
|
4
|
+
import { PRODUCT_IDENTITY } from "../../product-identity.js";
|
|
5
|
+
/** Import the exact immutable startup graph in a terminal-free bounded child process. */
|
|
6
|
+
export async function warmMaterializedRelease(release, environment, timeoutMs = 30_000) {
|
|
7
|
+
const entry = resolve(release.releaseRoot, "bin", "warmup.js");
|
|
8
|
+
await new Promise((resolvePromise, rejectPromise) => {
|
|
9
|
+
const child = spawn(process.execPath, [entry], {
|
|
10
|
+
env: { ...releaseEnvironment(environment, release), [PRODUCT_IDENTITY.environment.immutableWarmup]: "1" },
|
|
11
|
+
stdio: "ignore",
|
|
12
|
+
windowsHide: true,
|
|
13
|
+
});
|
|
14
|
+
let settled = false;
|
|
15
|
+
const finish = (error) => {
|
|
16
|
+
if (settled)
|
|
17
|
+
return;
|
|
18
|
+
settled = true;
|
|
19
|
+
clearTimeout(timer);
|
|
20
|
+
if (error)
|
|
21
|
+
rejectPromise(error);
|
|
22
|
+
else
|
|
23
|
+
resolvePromise();
|
|
24
|
+
};
|
|
25
|
+
child.once("error", error => finish(error));
|
|
26
|
+
child.once("close", (code, signal) => finish(code === 0
|
|
27
|
+
? undefined
|
|
28
|
+
: new Error(`immutable startup warmup exited with ${code === null ? signal ?? "unknown status" : `status ${code}`}`)));
|
|
29
|
+
const timer = setTimeout(() => {
|
|
30
|
+
child.kill();
|
|
31
|
+
finish(new Error(`immutable startup warmup exceeded ${timeoutMs}ms`));
|
|
32
|
+
}, timeoutMs);
|
|
33
|
+
timer.unref?.();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./startup-runtime.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./startup-runtime.js";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { PRODUCT_IDENTITY } from "../../product-identity.js";
|
|
2
|
+
export type StartupPhase = "command-invoked" | "bootstrap-start" | "bootstrap-selected" | "durable-validation-start" | "durable-validation-complete" | "replacement-supervisor-start" | "replacement-supervisor-ready" | "guardian-start" | "guardian-connected" | "ui-entry" | "ui-modules-loaded" | "pi-services" | "resource-discovery" | "session-created" | "settings-loaded" | "first-input-ready-render";
|
|
3
|
+
export interface StartupPerformanceEvidence {
|
|
4
|
+
readonly profileId: "a1" | "pi";
|
|
5
|
+
readonly launchKind: "post-update" | "no-live-supervisor" | "warm";
|
|
6
|
+
readonly events: readonly StartupTraceEvent[];
|
|
7
|
+
}
|
|
8
|
+
export interface StartupTraceEvent {
|
|
9
|
+
readonly schema: typeof PRODUCT_IDENTITY.evidence.startupTraceSchema;
|
|
10
|
+
readonly traceId: string;
|
|
11
|
+
readonly phase: StartupPhase;
|
|
12
|
+
readonly elapsedMs: number;
|
|
13
|
+
readonly processId: number;
|
|
14
|
+
readonly profileId: string;
|
|
15
|
+
readonly releaseId: string | null;
|
|
16
|
+
readonly dependencyLayerIds: readonly string[];
|
|
17
|
+
readonly nodeVersion: string;
|
|
18
|
+
readonly fileReadOperations: number;
|
|
19
|
+
}
|
|
20
|
+
/** Initialize opt-in startup tracing from a caller-provided evidence path. */
|
|
21
|
+
export declare function initializeStartupTrace(environment: NodeJS.ProcessEnv, profileId: string, startedAtMs?: number): void;
|
|
22
|
+
/** Append one redacted phase event; ordinary launches without trace context perform no I/O. */
|
|
23
|
+
export declare function markStartupPhase(environment: NodeJS.ProcessEnv, phase: StartupPhase): Promise<void>;
|
|
24
|
+
export declare function assertImmutableWarmupEnvironment(environment: NodeJS.ProcessEnv): void;
|
|
25
|
+
/** Enable the compile cache directly from launch environment without loading profile services. */
|
|
26
|
+
export declare function enableEnvironmentCompileCache(environment: NodeJS.ProcessEnv): string | null;
|
|
27
|
+
/** Enable Node's supported persistent compile cache in an immutable-identity namespace. */
|
|
28
|
+
export declare function enableStartupCompileCache(dataDir: string, releaseId: string | null, dependencyLayerIds: readonly string[]): string | null;
|
|
29
|
+
export declare function startupCompileCachePath(dataDir: string, releaseId: string | null, dependencyLayerIds: readonly string[]): string;
|
|
30
|
+
/** Retain current compile namespaces plus a bounded number of recent fallbacks. */
|
|
31
|
+
export declare function collectCompileCaches(dataDir: string, protectedPaths: readonly string[], keepRecent?: number): Promise<void>;
|
|
32
|
+
export declare function assertStartupPerformanceBudget(evidence: StartupPerformanceEvidence, budgets?: {
|
|
33
|
+
readonly postUpdateMs: number;
|
|
34
|
+
readonly warmMs: number;
|
|
35
|
+
}): void;
|
|
36
|
+
export declare function parseStartupTrace(source: string): readonly StartupTraceEvent[];
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { appendFile, mkdir, readdir, rm } from "node:fs/promises";
|
|
3
|
+
import { constants as moduleConstants, enableCompileCache } from "node:module";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
5
|
+
import { homedir, platform } from "node:os";
|
|
6
|
+
import { performance } from "node:perf_hooks";
|
|
7
|
+
import { PRODUCT_IDENTITY } from "../../product-identity.js";
|
|
8
|
+
/** Initialize opt-in startup tracing from a caller-provided evidence path. */
|
|
9
|
+
export function initializeStartupTrace(environment, profileId, startedAtMs = performance.timeOrigin + performance.now()) {
|
|
10
|
+
const configured = environment[PRODUCT_IDENTITY.environment.startupTrace];
|
|
11
|
+
if (!configured || parseContext(configured) !== null)
|
|
12
|
+
return;
|
|
13
|
+
const context = {
|
|
14
|
+
path: resolve(configured),
|
|
15
|
+
traceId: randomUUID(),
|
|
16
|
+
startedAtMs,
|
|
17
|
+
profileId,
|
|
18
|
+
releaseId: environment[PRODUCT_IDENTITY.environment.releaseId] ?? null,
|
|
19
|
+
dependencyLayerIds: parseLayerIds(environment[PRODUCT_IDENTITY.environment.releaseLayers]),
|
|
20
|
+
};
|
|
21
|
+
environment[PRODUCT_IDENTITY.environment.startupTrace] = JSON.stringify(context);
|
|
22
|
+
}
|
|
23
|
+
/** Append one redacted phase event; ordinary launches without trace context perform no I/O. */
|
|
24
|
+
export async function markStartupPhase(environment, phase) {
|
|
25
|
+
const context = parseContext(environment[PRODUCT_IDENTITY.environment.startupTrace]);
|
|
26
|
+
if (context === null)
|
|
27
|
+
return;
|
|
28
|
+
const event = {
|
|
29
|
+
schema: PRODUCT_IDENTITY.evidence.startupTraceSchema,
|
|
30
|
+
traceId: context.traceId,
|
|
31
|
+
phase,
|
|
32
|
+
elapsedMs: Math.max(0, performance.timeOrigin + performance.now() - context.startedAtMs),
|
|
33
|
+
processId: process.pid,
|
|
34
|
+
profileId: context.profileId,
|
|
35
|
+
releaseId: environment[PRODUCT_IDENTITY.environment.releaseId] ?? context.releaseId,
|
|
36
|
+
dependencyLayerIds: parseLayerIds(environment[PRODUCT_IDENTITY.environment.releaseLayers]).length > 0
|
|
37
|
+
? parseLayerIds(environment[PRODUCT_IDENTITY.environment.releaseLayers])
|
|
38
|
+
: context.dependencyLayerIds,
|
|
39
|
+
nodeVersion: process.version,
|
|
40
|
+
fileReadOperations: process.resourceUsage().fsRead,
|
|
41
|
+
};
|
|
42
|
+
await mkdir(dirname(context.path), { recursive: true, mode: 0o700 });
|
|
43
|
+
await appendFile(context.path, `${JSON.stringify(event)}\n`, { encoding: "utf8", mode: 0o600 });
|
|
44
|
+
}
|
|
45
|
+
export function assertImmutableWarmupEnvironment(environment) {
|
|
46
|
+
if (environment[PRODUCT_IDENTITY.environment.immutableWarmup] !== "1") {
|
|
47
|
+
throw new Error("warmup entry is private to verified update activation");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Enable the compile cache directly from launch environment without loading profile services. */
|
|
51
|
+
export function enableEnvironmentCompileCache(environment) {
|
|
52
|
+
const home = environment.HOME ?? environment.USERPROFILE ?? homedir();
|
|
53
|
+
const dataDir = resolve(environment[PRODUCT_IDENTITY.environment.dataDir]
|
|
54
|
+
?? (platform() === "win32"
|
|
55
|
+
? resolve(environment.LOCALAPPDATA ?? home, PRODUCT_IDENTITY.state.windowsControlDirectory)
|
|
56
|
+
: resolve(environment.XDG_DATA_HOME ?? resolve(home, ".local", "share"), PRODUCT_IDENTITY.state.unixControlDirectory)));
|
|
57
|
+
return enableStartupCompileCache(dataDir, environment[PRODUCT_IDENTITY.environment.releaseId] ?? null, parseLayerIds(environment[PRODUCT_IDENTITY.environment.releaseLayers]));
|
|
58
|
+
}
|
|
59
|
+
/** Enable Node's supported persistent compile cache in an immutable-identity namespace. */
|
|
60
|
+
export function enableStartupCompileCache(dataDir, releaseId, dependencyLayerIds) {
|
|
61
|
+
try {
|
|
62
|
+
const path = startupCompileCachePath(dataDir, releaseId, dependencyLayerIds);
|
|
63
|
+
const result = enableCompileCache(path);
|
|
64
|
+
return result.status === moduleConstants.compileCacheStatus.FAILED ? null : result.directory ?? path;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export function startupCompileCachePath(dataDir, releaseId, dependencyLayerIds) {
|
|
71
|
+
const layers = createHash("sha256").update(dependencyLayerIds.join("\0")).digest("hex").slice(0, 20);
|
|
72
|
+
const content = dependencyLayerIds.length > 0
|
|
73
|
+
? `layers-${layers}`
|
|
74
|
+
: `release-${(releaseId ?? "mutable").replace(/[^0-9A-Za-z.+_-]/g, "_")}`;
|
|
75
|
+
// Performance: stable layer paths share compiled dependency entries across product releases;
|
|
76
|
+
// Node's own cache key still isolates each release-specific module path and source bytes.
|
|
77
|
+
return resolve(dataDir, "cache", "compile", `${process.versions.modules ?? "node"}-${process.version.replace(/[^0-9A-Za-z.-]/g, "_")}-${content}`);
|
|
78
|
+
}
|
|
79
|
+
/** Retain current compile namespaces plus a bounded number of recent fallbacks. */
|
|
80
|
+
export async function collectCompileCaches(dataDir, protectedPaths, keepRecent = 2) {
|
|
81
|
+
const root = resolve(dataDir, "cache", "compile");
|
|
82
|
+
const protectedSet = new Set(protectedPaths.map(path => resolve(path)));
|
|
83
|
+
const entries = await readdir(root, { withFileTypes: true }).catch(() => []);
|
|
84
|
+
const candidates = await Promise.all(entries.filter(entry => entry.isDirectory()).map(async (entry) => {
|
|
85
|
+
const path = resolve(root, entry.name);
|
|
86
|
+
const metadata = await import("node:fs/promises").then(fs => fs.stat(path));
|
|
87
|
+
return { path, mtimeMs: metadata.mtimeMs };
|
|
88
|
+
}));
|
|
89
|
+
const retainedRecent = new Set(candidates.filter(item => !protectedSet.has(item.path))
|
|
90
|
+
.sort((left, right) => right.mtimeMs - left.mtimeMs)
|
|
91
|
+
.slice(0, keepRecent)
|
|
92
|
+
.map(item => item.path));
|
|
93
|
+
for (const candidate of candidates) {
|
|
94
|
+
if (!protectedSet.has(candidate.path) && !retainedRecent.has(candidate.path))
|
|
95
|
+
await rm(candidate.path, { recursive: true, force: true });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export function assertStartupPerformanceBudget(evidence, budgets = { postUpdateMs: 5_000, warmMs: 3_000 }) {
|
|
99
|
+
const events = [...evidence.events].sort((left, right) => left.elapsedMs - right.elapsedMs);
|
|
100
|
+
const ready = events.findLast(event => event.phase === "first-input-ready-render");
|
|
101
|
+
if (!ready)
|
|
102
|
+
throw new Error(`startup budget failed for ${evidence.profileId}: first input-ready render was not recorded`);
|
|
103
|
+
const budget = evidence.launchKind === "warm" ? budgets.warmMs : budgets.postUpdateMs;
|
|
104
|
+
if (ready.elapsedMs <= budget)
|
|
105
|
+
return;
|
|
106
|
+
const intervals = events.map((event, index) => ({
|
|
107
|
+
phase: event.phase,
|
|
108
|
+
durationMs: event.elapsedMs - (events[index - 1]?.elapsedMs ?? 0),
|
|
109
|
+
})).sort((left, right) => right.durationMs - left.durationMs);
|
|
110
|
+
throw new Error(`startup budget failed for ${evidence.profileId} ${evidence.launchKind}: ${Math.round(ready.elapsedMs)}ms exceeds ${budget}ms; dominant phases: ${intervals.slice(0, 3).map(item => `${item.phase} ${Math.round(item.durationMs)}ms`).join(", ")}`);
|
|
111
|
+
}
|
|
112
|
+
export function parseStartupTrace(source) {
|
|
113
|
+
const events = source.split(/\r?\n/).filter(Boolean).map(line => JSON.parse(line));
|
|
114
|
+
for (const event of events) {
|
|
115
|
+
if (event.schema !== PRODUCT_IDENTITY.evidence.startupTraceSchema || typeof event.traceId !== "string"
|
|
116
|
+
|| typeof event.phase !== "string" || !Number.isFinite(event.elapsedMs) || !Array.isArray(event.dependencyLayerIds)) {
|
|
117
|
+
throw new Error("startup trace contains an invalid event");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return events.sort((left, right) => left.elapsedMs - right.elapsedMs);
|
|
121
|
+
}
|
|
122
|
+
function parseContext(value) {
|
|
123
|
+
if (!value?.startsWith("{"))
|
|
124
|
+
return null;
|
|
125
|
+
try {
|
|
126
|
+
const context = JSON.parse(value);
|
|
127
|
+
if (typeof context.path !== "string" || typeof context.traceId !== "string" || !Number.isFinite(context.startedAtMs)
|
|
128
|
+
|| typeof context.profileId !== "string" || !Array.isArray(context.dependencyLayerIds))
|
|
129
|
+
return null;
|
|
130
|
+
return context;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function parseLayerIds(value) {
|
|
137
|
+
if (!value)
|
|
138
|
+
return [];
|
|
139
|
+
return [...new Set(value.split(",").filter(id => /^dependencies-[a-f0-9]{32}$/.test(id)))].sort();
|
|
140
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DatabaseSync } from "node:sqlite";
|
|
2
|
-
import type { ManagedAgentDescriptor, PaneId, AgentRecoveryAuthority, RecoveryReferenceId, TerminalSessionLaunch, TerminalTopologySnapshot } from "
|
|
2
|
+
import type { ManagedAgentDescriptor, PaneId, AgentRecoveryAuthority, RecoveryReferenceId, TerminalSessionLaunch, TerminalTopologySnapshot } from "../../contracts/workspace/index.js";
|
|
3
3
|
import type { LaunchInstance, LaunchInstanceId, LaunchInstanceOutcome, NativeProcessIdentity, ProcessContainmentIdentity } from "../lifecycle/index.js";
|
|
4
4
|
export declare const DEFAULT_WORKSPACE_ID = "workspace-default";
|
|
5
5
|
export interface WorkspaceAgentPresentation {
|
|
@@ -14,6 +14,7 @@ export interface StoredWorkspaceAgent {
|
|
|
14
14
|
readonly agent: ManagedAgentDescriptor;
|
|
15
15
|
readonly presentation: WorkspaceAgentPresentation;
|
|
16
16
|
}
|
|
17
|
+
/** Owns WAL-backed control persistence and reconciles prior-boot records before current use. */
|
|
17
18
|
export declare class ControlStore {
|
|
18
19
|
#private;
|
|
19
20
|
readonly bootNonce: string | null;
|