@timurproko/a1 0.2.6 → 0.2.7-dev.1221
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -3
- package/bin/automatic-update.js +7 -0
- package/bin/cli.js +4 -0
- package/bin/guardian.js +5 -0
- package/bin/tab-launch-context.d.ts +27 -0
- package/bin/tab-launch-context.js +94 -0
- package/bin/ui.js +107 -59
- package/dist/app/session-shell/clipboard-diagnostics.js +1 -1
- package/dist/app/session-shell/dialog-coordinator.d.ts +42 -0
- package/dist/app/session-shell/dialog-coordinator.js +133 -0
- package/dist/app/session-shell/dock-chrome.d.ts +34 -0
- package/dist/app/session-shell/dock-chrome.js +109 -0
- package/dist/app/session-shell/exit-notice.d.ts +1 -1
- package/dist/app/session-shell/exit-notice.js +1 -1
- package/dist/app/session-shell/extension-surface.d.ts +30 -0
- package/dist/app/session-shell/extension-surface.js +105 -0
- package/dist/app/session-shell/helper-pool.d.ts +3 -5
- package/dist/app/session-shell/helper-pool.js +3 -5
- package/dist/app/session-shell/input-surface-switch.d.ts +36 -0
- package/dist/app/session-shell/input-surface-switch.js +85 -0
- package/dist/app/session-shell/login-interaction.d.ts +27 -0
- package/dist/app/session-shell/login-interaction.js +91 -0
- package/dist/app/session-shell/prompt-submission.d.ts +48 -0
- package/dist/app/session-shell/prompt-submission.js +276 -0
- package/dist/app/session-shell/resident-tab-coordinator.d.ts +38 -0
- package/dist/app/session-shell/resident-tab-coordinator.js +77 -0
- package/dist/app/session-shell/response-copy-helper.js +21 -6
- package/dist/app/session-shell/response-copy-protocol.d.ts +1 -1
- package/dist/app/session-shell/response-copy-transport.d.ts +16 -6
- package/dist/app/session-shell/response-copy-transport.js +69 -17
- package/dist/app/session-shell/session-concern.d.ts +22 -0
- package/dist/app/session-shell/session-concern.js +29 -0
- package/dist/app/session-shell/session-lifecycle.d.ts +29 -0
- package/dist/app/session-shell/session-lifecycle.js +49 -0
- package/dist/app/session-shell/session-shell-root.d.ts +42 -6
- package/dist/app/session-shell/session-shell-root.js +196 -908
- package/dist/app/session-shell/session-shell.d.ts +3 -8
- package/dist/app/session-shell/session-shell.js +324 -835
- package/dist/app/session-shell/session-viewport-controller.d.ts +2 -2
- package/dist/app/session-shell/session-viewport-controller.js +29 -15
- package/dist/app/session-shell/settings-bindings.d.ts +17 -0
- package/dist/app/session-shell/settings-bindings.js +91 -0
- package/dist/app/session-shell/shell-editor-factory.d.ts +27 -0
- package/dist/app/session-shell/shell-editor-factory.js +102 -0
- package/dist/app/session-shell/shell-host.d.ts +6 -0
- package/dist/app/session-shell/shell-host.js +34 -7
- package/dist/app/session-shell/shell-layout.d.ts +64 -0
- package/dist/app/session-shell/shell-layout.js +18 -0
- package/dist/app/session-shell/suggestion-surface.d.ts +25 -0
- package/dist/app/session-shell/suggestion-surface.js +63 -0
- package/dist/app/session-shell/transcript-document.d.ts +78 -0
- package/dist/app/session-shell/transcript-document.js +365 -0
- package/dist/app/session-shell/viewport-layout.d.ts +31 -0
- package/dist/app/session-shell/viewport-layout.js +160 -0
- package/dist/app/session-shell/workflow-output.d.ts +33 -0
- package/dist/app/session-shell/workflow-output.js +174 -0
- package/dist/app/session-shell/workflow-router.d.ts +25 -0
- package/dist/app/session-shell/workflow-router.js +39 -0
- package/dist/cli/dispatch.d.ts +11 -1
- package/dist/cli/dispatch.js +79 -5
- package/dist/cli/tabs-request.d.ts +7 -0
- package/dist/cli/tabs-request.js +1 -0
- package/dist/cli/tabs.d.ts +14 -0
- package/dist/cli/tabs.js +151 -0
- package/dist/cli/version-stats.js +38 -3
- package/dist/composition/owned-settings.d.ts +12 -0
- package/dist/composition/owned-settings.js +36 -0
- package/dist/composition/owned-ui.d.ts +27 -28
- package/dist/composition/owned-ui.js +205 -153
- package/dist/composition/resident-tab-bridge.d.ts +25 -0
- package/dist/composition/resident-tab-bridge.js +180 -0
- package/dist/composition/session-backend.d.ts +19 -0
- package/dist/composition/session-backend.js +1 -0
- package/dist/composition/session-runtime-registry.d.ts +20 -0
- package/dist/composition/session-runtime-registry.js +85 -0
- package/dist/composition/settings-route-host.d.ts +16 -1
- package/dist/composition/settings-route-host.js +29 -10
- package/dist/composition/settings-search-input.d.ts +9 -0
- package/dist/composition/settings-search-input.js +58 -0
- package/dist/composition/startup-route.d.ts +32 -0
- package/dist/composition/startup-route.js +72 -0
- package/dist/composition/utility-tab.d.ts +28 -0
- package/dist/composition/utility-tab.js +242 -0
- package/dist/contracts/owned-ui/index.d.ts +1 -1
- package/dist/contracts/owned-ui/model.d.ts +3 -0
- package/dist/contracts/owned-ui/session-backend.d.ts +3 -0
- package/dist/contracts/owned-ui/session-workflows.d.ts +11 -4
- package/dist/contracts/presentation/index.d.ts +11 -0
- package/dist/contracts/presentation/index.js +12 -0
- package/dist/features/launch/development-launch.js +6 -0
- package/dist/features/launch/index.d.ts +1 -1
- package/dist/features/launch/intent.d.ts +3 -1
- package/dist/features/launch/intent.js +7 -4
- package/dist/features/launch/profile-paths.js +4 -0
- package/dist/features/owned-ui/plus-menu-dialog.d.ts +22 -0
- package/dist/features/owned-ui/plus-menu-dialog.js +76 -0
- package/dist/features/owned-ui/project-trust-dialog.d.ts +1 -1
- package/dist/features/owned-ui/project-trust-dialog.js +6 -8
- package/dist/features/owned-ui/project-trust-prompt.d.ts +1 -0
- package/dist/features/owned-ui/project-trust-prompt.js +7 -3
- package/dist/features/owned-ui/reference-screen-app.d.ts +2 -0
- package/dist/features/owned-ui/reference-screen-app.js +12 -2
- package/dist/features/owned-ui/settings-app.d.ts +12 -2
- package/dist/features/owned-ui/settings-app.js +116 -81
- package/dist/features/owned-ui/settings-search-input.d.ts +29 -0
- package/dist/features/owned-ui/settings-search-input.js +1 -0
- package/dist/features/prompt-history/index.d.ts +1 -1
- package/dist/features/prompt-history/paths.d.ts +2 -1
- package/dist/features/prompt-history/paths.js +10 -2
- package/dist/features/prompt-history/service.d.ts +5 -0
- package/dist/features/prompt-history/service.js +1 -1
- package/dist/features/resident-tab/auto-name.d.ts +11 -0
- package/dist/features/resident-tab/auto-name.js +44 -0
- package/dist/features/resident-tab/index.d.ts +5 -0
- package/dist/features/resident-tab/index.js +7 -0
- package/dist/features/resident-tab/shortcut-bindings-file.d.ts +8 -0
- package/dist/features/resident-tab/shortcut-bindings-file.js +40 -0
- package/dist/features/resident-tab/shortcut-declarations.d.ts +13 -0
- package/dist/features/resident-tab/shortcut-declarations.js +26 -0
- package/dist/features/resident-tab/shortcut-projection.d.ts +29 -0
- package/dist/features/resident-tab/shortcut-projection.js +64 -0
- package/dist/features/resident-tab/status-deriver.d.ts +10 -0
- package/dist/features/resident-tab/status-deriver.js +12 -0
- package/dist/foundation/launch-context/index.d.ts +12 -0
- package/dist/foundation/launch-context/index.js +26 -0
- package/dist/foundation/launch-guardian/exit-watcher.d.ts +14 -0
- package/dist/foundation/launch-guardian/exit-watcher.js +94 -0
- package/dist/foundation/launch-guardian/main.d.ts +7 -1
- package/dist/foundation/launch-guardian/main.js +60 -7
- package/dist/foundation/lifecycle/session-repository-context.js +16 -2
- package/dist/foundation/process-containment/{native-guardian-containment.d.ts → addon-containment.d.ts} +7 -5
- package/dist/foundation/process-containment/addon-containment.js +139 -0
- package/dist/foundation/process-containment/addon-process-inspector.d.ts +11 -0
- package/dist/foundation/process-containment/addon-process-inspector.js +36 -0
- package/dist/foundation/process-containment/addon.d.ts +42 -0
- package/dist/foundation/process-containment/addon.js +57 -0
- package/dist/foundation/process-containment/artifact.d.ts +1 -1
- package/dist/foundation/process-containment/artifact.js +6 -5
- package/dist/foundation/process-containment/contracts.d.ts +2 -0
- package/dist/foundation/process-containment/index.d.ts +4 -4
- package/dist/foundation/process-containment/index.js +3 -3
- package/dist/foundation/process-containment/native-process-inspector.d.ts +2 -1
- package/dist/foundation/process-containment/native-process-inspector.js +10 -10
- package/dist/foundation/release/automatic-update.d.ts +37 -0
- package/dist/foundation/release/automatic-update.js +265 -0
- package/dist/foundation/release/bootstrap.d.ts +7 -9
- package/dist/foundation/release/bootstrap.js +107 -24
- package/dist/foundation/release/cohort-state.d.ts +1 -1
- package/dist/foundation/release/cohort-state.js +1 -1
- package/dist/foundation/release/dependency-certification.js +54 -19
- package/dist/foundation/release/early-accent.d.ts +12 -0
- package/dist/foundation/release/early-accent.js +59 -0
- package/dist/foundation/release/index.d.ts +2 -2
- package/dist/foundation/release/index.js +2 -2
- package/dist/foundation/release/latest-release.d.ts +24 -2
- package/dist/foundation/release/latest-release.js +51 -1
- package/dist/foundation/release/progress-palette.generated.d.ts +137 -3
- package/dist/foundation/release/progress-palette.generated.js +137 -3
- package/dist/foundation/release/release-gc.d.ts +3 -0
- package/dist/foundation/release/release-gc.js +59 -8
- package/dist/foundation/release/release-store.d.ts +12 -0
- package/dist/foundation/release/release-store.js +124 -2
- package/dist/foundation/release/update-execution-lease.d.ts +48 -0
- package/dist/foundation/release/update-execution-lease.js +161 -0
- package/dist/foundation/release/update.d.ts +12 -7
- package/dist/foundation/release/update.js +281 -196
- package/dist/foundation/resident-tabs/bounded-host-command.d.ts +18 -0
- package/dist/foundation/resident-tabs/bounded-host-command.js +39 -0
- package/dist/foundation/resident-tabs/bridge-client.d.ts +70 -0
- package/dist/foundation/resident-tabs/bridge-client.js +321 -0
- package/dist/foundation/resident-tabs/doctor.d.ts +28 -0
- package/dist/foundation/resident-tabs/doctor.js +166 -0
- package/dist/foundation/resident-tabs/draft-checkpoint.d.ts +27 -0
- package/dist/foundation/resident-tabs/draft-checkpoint.js +145 -0
- package/dist/foundation/resident-tabs/ensure-terminal-host.d.ts +36 -0
- package/dist/foundation/resident-tabs/ensure-terminal-host.js +151 -0
- package/dist/foundation/resident-tabs/fault-injection.d.ts +8 -0
- package/dist/foundation/resident-tabs/fault-injection.js +26 -0
- package/dist/foundation/resident-tabs/fixture-control.d.ts +7 -0
- package/dist/foundation/resident-tabs/fixture-control.js +35 -0
- package/dist/foundation/resident-tabs/host-entry.d.ts +1 -0
- package/dist/foundation/resident-tabs/host-entry.js +17 -0
- package/dist/foundation/resident-tabs/index.d.ts +12 -0
- package/dist/foundation/resident-tabs/index.js +6 -0
- package/dist/foundation/resident-tabs/maintenance.d.ts +39 -0
- package/dist/foundation/resident-tabs/maintenance.js +75 -0
- package/dist/foundation/resident-tabs/progress-observation-schema.d.ts +34 -0
- package/dist/foundation/resident-tabs/progress-observation-schema.js +1 -0
- package/dist/foundation/resident-tabs/progress-observation.d.ts +4 -0
- package/dist/foundation/resident-tabs/progress-observation.js +150 -0
- package/dist/foundation/resident-tabs/prompt-journal.d.ts +63 -0
- package/dist/foundation/resident-tabs/prompt-journal.js +213 -0
- package/dist/foundation/resident-tabs/protocol.d.ts +12 -0
- package/dist/foundation/resident-tabs/protocol.js +195 -0
- package/dist/foundation/resident-tabs/recovery.d.ts +26 -0
- package/dist/foundation/resident-tabs/recovery.js +205 -0
- package/dist/foundation/resident-tabs/release-holds.d.ts +28 -0
- package/dist/foundation/resident-tabs/release-holds.js +75 -0
- package/dist/foundation/resident-tabs/routes.d.ts +5 -0
- package/dist/foundation/resident-tabs/routes.js +5 -0
- package/dist/foundation/resident-tabs/routing.d.ts +11 -0
- package/dist/foundation/resident-tabs/routing.js +10 -0
- package/dist/foundation/resident-tabs/session-sync.d.ts +14 -0
- package/dist/foundation/resident-tabs/session-sync.js +37 -0
- package/dist/foundation/resident-tabs/settings.d.ts +12 -0
- package/dist/foundation/resident-tabs/settings.js +58 -0
- package/dist/foundation/resident-tabs/terminal-host-artifact.d.ts +14 -0
- package/dist/foundation/resident-tabs/terminal-host-artifact.js +78 -0
- package/dist/foundation/resident-tabs/zip-archive.d.ts +9 -0
- package/dist/foundation/resident-tabs/zip-archive.js +56 -0
- package/dist/foundation/session-writer-lock/index.d.ts +30 -0
- package/dist/foundation/session-writer-lock/index.js +203 -0
- package/dist/foundation/startup/startup-descriptor.js +2 -2
- package/dist/foundation/terminal-cleanup/index.d.ts +1 -1
- package/dist/foundation/terminal-cleanup/index.js +1 -1
- package/dist/foundation/terminal-cleanup/terminal-reset.d.ts +6 -0
- package/dist/foundation/terminal-cleanup/terminal-reset.js +6 -0
- package/dist/integrations/pi/components/editor-interaction.d.ts +2 -0
- package/dist/integrations/pi/components/modal-frame.d.ts +17 -1
- package/dist/integrations/pi/components/modal-frame.js +48 -9
- package/dist/integrations/pi/components/models-dialog.js +4 -52
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +6 -1
- package/dist/integrations/pi/components/owned-editor-ux.js +90 -6
- package/dist/integrations/pi/components/resources/builtin-themes.d.ts +4 -4
- package/dist/integrations/pi/components/resources/builtin-themes.js +4 -4
- package/dist/integrations/pi/components/share-operation-dialog.d.ts +2 -0
- package/dist/integrations/pi/components/share-operation-dialog.js +2 -1
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +58 -36
- package/dist/integrations/pi/components/shell-extension-ui.js +79 -60
- package/dist/integrations/pi/components/shell-footer-status.d.ts +1 -1
- package/dist/integrations/pi/components/shell-footer-status.js +21 -5
- package/dist/integrations/pi/components/shell-hotkey-sections.js +1 -1
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +5 -2
- package/dist/integrations/pi/components/shell-presenters-info.js +18 -4
- package/dist/integrations/pi/components/shell-presenters-transcript.js +4 -1
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +5 -1
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +12 -1
- package/dist/integrations/pi/components/skills-dialog.js +2 -2
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +17 -4
- package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
- package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +8 -6
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +16 -9
- package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +4 -4
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +2 -2
- package/dist/integrations/pi/components/upstream/components/session-footer.d.ts +2 -1
- package/dist/integrations/pi/components/upstream/components/session-footer.js +31 -25
- package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector.js +8 -7
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +2 -2
- package/dist/integrations/pi/components/upstream/components/status-indicator.js +3 -3
- package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +8 -7
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +10 -9
- package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +2 -6
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +103 -101
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +9 -9
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +13 -21
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +2 -2
- package/dist/integrations/pi/components/upstream/history/editor-core.js +7 -5
- package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
- package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
- package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
- package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
- package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme.d.ts +5 -0
- package/dist/integrations/pi/components/upstream/theme/theme.js +29 -2
- package/dist/integrations/pi/engine/adapter.d.ts +5 -77
- package/dist/integrations/pi/engine/adapter.js +95 -394
- package/dist/integrations/pi/engine/command-dispatch.d.ts +13 -0
- package/dist/integrations/pi/engine/command-dispatch.js +57 -0
- package/dist/integrations/pi/engine/host.js +2 -2
- package/dist/integrations/pi/engine/offline-settings-port.d.ts +23 -0
- package/dist/integrations/pi/engine/offline-settings-port.js +53 -0
- package/dist/integrations/pi/engine/pi-settings-metadata.json +14 -2
- package/dist/integrations/pi/engine/ports.d.ts +56 -0
- package/dist/integrations/pi/engine/ports.js +93 -0
- package/dist/integrations/pi/engine/prompt-suggestions.d.ts +1 -0
- package/dist/integrations/pi/engine/prompt-suggestions.js +40 -0
- package/dist/integrations/pi/engine/resources/changelog.json +4 -4
- package/dist/integrations/pi/engine/runtime-integration.js +102 -29
- package/dist/integrations/pi/engine/session-runtime.d.ts +0 -6
- package/dist/integrations/pi/engine/session-runtime.js +13 -5
- package/dist/integrations/pi/engine/session-selection.d.ts +3 -0
- package/dist/integrations/pi/engine/session-selection.js +45 -9
- package/dist/integrations/pi/engine/settings-bridge.d.ts +5 -0
- package/dist/integrations/pi/engine/settings-bridge.js +15 -0
- package/dist/integrations/pi/engine/settings-port.js +11 -15
- package/dist/integrations/pi/engine/view-state.d.ts +42 -0
- package/dist/integrations/pi/engine/view-state.js +126 -0
- package/dist/integrations/pi/engine/workflow-contexts.js +10 -1
- package/dist/integrations/pi/engine/workflow-runner.js +73 -4
- package/dist/integrations/pi/engine/workflow-support.d.ts +12 -0
- package/dist/integrations/pi/engine/workflow-support.js +36 -0
- package/dist/integrations/pi/engine/workflows.d.ts +3 -1
- package/dist/integrations/pi/engine/workflows.js +1 -0
- package/dist/integrations/pi/startup-public.js +257 -310
- package/dist/integrations/pi/startup-public.manifest.json +564 -440
- package/dist/integrations/pi/tui-runtime/adapter.d.ts +6 -0
- package/dist/integrations/pi/tui-runtime/adapter.js +32 -1
- package/dist/integrations/pi/tui-runtime/contracts.d.ts +5 -0
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +12 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +31 -2
- package/dist/native/darwin-arm64/manifest.json +10 -7
- package/dist/native/darwin-arm64/process-guardian.node +0 -0
- package/dist/native/darwin-arm64/terminal-host-THIRD-PARTY-NOTICES.txt +10500 -0
- package/dist/native/darwin-arm64/terminal-host.manifest.json +46 -0
- package/dist/native/darwin-arm64/terminal-host.node +0 -0
- package/dist/native/darwin-x64/manifest.json +23 -0
- package/dist/native/darwin-x64/process-guardian.node +0 -0
- package/dist/native/darwin-x64/terminal-host-THIRD-PARTY-NOTICES.txt +10737 -0
- package/dist/native/darwin-x64/terminal-host.manifest.json +46 -0
- package/dist/native/darwin-x64/terminal-host.node +0 -0
- package/dist/native/linux-x64/manifest.json +10 -7
- package/dist/native/linux-x64/process-guardian.node +0 -0
- package/dist/native/linux-x64/terminal-host-THIRD-PARTY-NOTICES.txt +11226 -0
- package/dist/native/linux-x64/terminal-host.manifest.json +46 -0
- package/dist/native/linux-x64/terminal-host.node +0 -0
- package/dist/native/win32-x64/manifest.json +10 -7
- package/dist/native/win32-x64/process-guardian.node +0 -0
- package/dist/native/win32-x64/terminal-host-THIRD-PARTY-NOTICES.txt +10757 -0
- package/dist/native/win32-x64/terminal-host.manifest.json +46 -0
- package/dist/native/win32-x64/terminal-host.node +0 -0
- package/dist/product-identity.d.ts +3 -3
- package/dist/product-identity.js +4 -4
- package/dist/product-identity.json +16 -2
- package/dist/runtime-payload-inventory.json +6330 -6677
- package/dist/ui/apps/host.d.ts +2 -0
- package/dist/ui/apps/host.js +7 -1
- package/dist/ui/components/dialog-panel.js +35 -30
- package/dist/ui/components/index.d.ts +2 -2
- package/dist/ui/components/index.js +1 -1
- package/dist/ui/components/line-input.d.ts +4 -1
- package/dist/ui/components/line-input.js +3 -1
- package/dist/ui/components/prompt-input.d.ts +11 -8
- package/dist/ui/components/prompt-input.js +15 -13
- package/dist/ui/components/selection-copy.d.ts +2 -0
- package/dist/ui/components/selection-copy.js +13 -0
- package/dist/ui/components/spans.js +2 -2
- package/dist/ui/components/submitted-prompt.d.ts +9 -6
- package/dist/ui/components/submitted-prompt.js +20 -12
- package/dist/ui/components/surface.js +4 -2
- package/dist/ui/components/text.d.ts +3 -6
- package/dist/ui/components/text.js +6 -8
- package/dist/ui/components/transcript-viewport.d.ts +9 -2
- package/dist/ui/components/transcript-viewport.js +176 -55
- package/dist/ui/settings/declarations.d.ts +90 -16
- package/dist/ui/settings/declarations.js +67 -14
- package/dist/ui/settings/early-accent.d.ts +81 -0
- package/dist/ui/settings/early-accent.js +50 -0
- package/dist/ui/settings/index.d.ts +4 -2
- package/dist/ui/settings/index.js +2 -1
- package/dist/ui/settings/manager.d.ts +16 -3
- package/dist/ui/settings/manager.js +122 -33
- package/dist/ui/settings/migrations.d.ts +6 -0
- package/dist/ui/settings/migrations.js +73 -0
- package/dist/ui/settings/profile-document.d.ts +26 -0
- package/dist/ui/settings/profile-document.js +164 -0
- package/dist/ui/settings/progress-palette.generated.d.ts +139 -0
- package/dist/ui/settings/progress-palette.generated.js +139 -0
- package/dist/ui/settings/sections.d.ts +4 -0
- package/dist/ui/settings/sections.js +9 -3
- package/docs/architecture/boundaries.md +24 -9
- package/docs/architecture/evidence/resident-tabs/linux-x64.md +37 -0
- package/docs/architecture/evidence/resident-tabs/macos-arm64.md +36 -0
- package/docs/architecture/evidence/resident-tabs/macos-x64.md +35 -0
- package/docs/architecture/evidence/resident-tabs/windows-x64.md +36 -0
- package/docs/architecture/internal-naming.md +3 -1
- package/docs/architecture/process-guardian-provenance.md +18 -10
- package/docs/architecture/project-structure.md +8 -0
- package/docs/architecture/resident-tabs-requirements.md +18 -0
- package/docs/architecture/resident-tabs.md +648 -0
- package/docs/architecture/response-copy-delivery.md +1 -1
- package/docs/architecture/terminal-host-proof-gate.md +2 -0
- package/docs/architecture/terminal-host-provenance.md +16 -4
- package/docs/architecture/tool-image-presentation.md +2 -1
- package/docs/architecture/toolchain.md +11 -9
- package/docs/ci-release-runbook.md +14 -7
- package/docs/features/launch-profiles.md +11 -8
- package/docs/features/prompt-history.md +41 -20
- package/docs/manual-resident-tabs-acceptance.md +51 -0
- package/docs/openspec-archive-automation.md +49 -22
- package/docs/validation.md +49 -9
- package/package.json +19 -6
- package/dist/foundation/process-containment/darwin-process-inspector.d.ts +0 -5
- package/dist/foundation/process-containment/darwin-process-inspector.js +0 -7
- package/dist/foundation/process-containment/native-guardian-containment.js +0 -152
- package/dist/foundation/process-containment/windows-process-inspector.d.ts +0 -19
- package/dist/foundation/process-containment/windows-process-inspector.js +0 -56
- package/dist/native/darwin-arm64/process-guardian +0 -0
- package/dist/native/linux-x64/process-guardian +0 -0
- package/dist/native/win32-x64/process-guardian.exe +0 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { DraftCheckpointer } from "./draft-checkpoint.js";
|
|
4
|
+
import { ResidentTabFaultInjection } from "./fault-injection.js";
|
|
5
|
+
import { PromptJournal } from "./prompt-journal.js";
|
|
6
|
+
import { SettledTurnSynchronizer, synchronizeSessionFile } from "./session-sync.js";
|
|
7
|
+
export class ResidentTabRecovery {
|
|
8
|
+
#journal;
|
|
9
|
+
#draft;
|
|
10
|
+
#synchronizer;
|
|
11
|
+
#faults;
|
|
12
|
+
#onDegraded;
|
|
13
|
+
#active = [];
|
|
14
|
+
#recovered = { prompts: [], draft: null };
|
|
15
|
+
constructor(dataDir, options = {}) {
|
|
16
|
+
const faults = options.faults ?? new ResidentTabFaultInjection();
|
|
17
|
+
this.#faults = faults;
|
|
18
|
+
this.#onDegraded = options.onDegraded ?? (() => { });
|
|
19
|
+
this.#journal = new PromptJournal(join(dataDir, "journal.jsonl"), { faults });
|
|
20
|
+
this.#draft = new DraftCheckpointer(join(dataDir, "draft.json"), { faults, onDegraded: this.#onDegraded });
|
|
21
|
+
this.#synchronizer = new SettledTurnSynchronizer(this.#journal, faults);
|
|
22
|
+
}
|
|
23
|
+
get recovered() { return this.#recovered; }
|
|
24
|
+
async initialize(currentSessionFile = null, currentSessionId = null) {
|
|
25
|
+
await this.#journal.initialize();
|
|
26
|
+
await adoptHistoricalJournals(dirname(dirname(this.#journal.path)), this.#journal, currentSessionFile, currentSessionId);
|
|
27
|
+
const records = await this.#journal.read();
|
|
28
|
+
const sessionFiles = new Set(records.flatMap(record => record.type === "submitted" && record.sessionFile !== null ? [record.sessionFile] : []));
|
|
29
|
+
if (currentSessionFile !== null)
|
|
30
|
+
sessionFiles.add(currentSessionFile);
|
|
31
|
+
const sessionEntries = (await Promise.all([...sessionFiles].map(readSessionJournal))).flat();
|
|
32
|
+
const [pending, draft] = await Promise.all([
|
|
33
|
+
this.#journal.pending(sessionEntries),
|
|
34
|
+
this.#draft.restore(),
|
|
35
|
+
]);
|
|
36
|
+
this.#recovered = { prompts: pending.map(value => value.submitted), draft: draft?.text ?? null };
|
|
37
|
+
return this.#recovered;
|
|
38
|
+
}
|
|
39
|
+
async admit(input, timeoutMs = 2_000) {
|
|
40
|
+
const fileExisted = input.sessionFile === null ? false : await stat(input.sessionFile).then(() => true, error => {
|
|
41
|
+
if (error.code === "ENOENT")
|
|
42
|
+
return false;
|
|
43
|
+
throw error;
|
|
44
|
+
});
|
|
45
|
+
let timer;
|
|
46
|
+
try {
|
|
47
|
+
return await Promise.race([
|
|
48
|
+
this.#journal.submit({ ...input, fileExisted }),
|
|
49
|
+
new Promise((_, reject) => {
|
|
50
|
+
timer = setTimeout(() => reject(new Error("resident prompt journal admission timed out")), timeoutMs);
|
|
51
|
+
timer.unref();
|
|
52
|
+
}),
|
|
53
|
+
]);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
if (timer !== undefined)
|
|
57
|
+
clearTimeout(timer);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
dispatched() { this.#faults.at("journal-after-dispatch"); }
|
|
61
|
+
async correlated(submissionId, entryId) {
|
|
62
|
+
await this.#journal.correlate(submissionId, entryId);
|
|
63
|
+
this.#active.push({ id: submissionId, entryId });
|
|
64
|
+
}
|
|
65
|
+
checkpoint(text) { this.#draft.change(text); }
|
|
66
|
+
async settled(sessionFile) {
|
|
67
|
+
const active = this.#active.splice(0);
|
|
68
|
+
if (active.length === 0 || sessionFile === null)
|
|
69
|
+
return;
|
|
70
|
+
await this.#synchronizer.settleMany(sessionFile, active);
|
|
71
|
+
for (const entry of active)
|
|
72
|
+
await this.#journal.retire(entry.id);
|
|
73
|
+
await this.#journal.compactIfRetired();
|
|
74
|
+
}
|
|
75
|
+
async gracefulStop(sessionFile) {
|
|
76
|
+
await this.#draft.flush();
|
|
77
|
+
if (sessionFile !== null)
|
|
78
|
+
await synchronizeSessionFile(sessionFile);
|
|
79
|
+
await this.#synchronizer.flush();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const MAX_SESSION_RECONCILE_BYTES = 64 * 1024 * 1024;
|
|
83
|
+
const MAX_ADOPTION_AGE_MS = 7 * 24 * 60 * 60 * 1_000;
|
|
84
|
+
async function adoptHistoricalJournals(profileTabsRoot, target, currentSessionFile, currentSessionId) {
|
|
85
|
+
if (currentSessionFile === null && currentSessionId === null)
|
|
86
|
+
return;
|
|
87
|
+
const history = join(profileTabsRoot, "registry-history");
|
|
88
|
+
const names = await readdir(history).catch(() => []);
|
|
89
|
+
for (const name of names.filter(value => /^tabset-.+\.json$/.test(value)).sort().reverse()) {
|
|
90
|
+
const path = join(history, name);
|
|
91
|
+
const metadata = await stat(path).catch(() => null);
|
|
92
|
+
if (metadata === null || Date.now() - metadata.mtimeMs > MAX_ADOPTION_AGE_MS)
|
|
93
|
+
continue;
|
|
94
|
+
let document;
|
|
95
|
+
try {
|
|
96
|
+
document = JSON.parse(await readFile(path, "utf8"));
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const tabs = typeof document === "object" && document !== null && Array.isArray(document.tabs)
|
|
102
|
+
? document.tabs : [];
|
|
103
|
+
for (const value of tabs) {
|
|
104
|
+
if (typeof value !== "object" || value === null)
|
|
105
|
+
continue;
|
|
106
|
+
const tab = value;
|
|
107
|
+
if (typeof tab.tabId !== "string")
|
|
108
|
+
continue;
|
|
109
|
+
const fileMatches = currentSessionFile !== null && typeof tab.sessionFile === "string"
|
|
110
|
+
&& resolve(tab.sessionFile) === resolve(currentSessionFile);
|
|
111
|
+
const sourcePath = join(profileTabsRoot, tab.tabId, "journal.jsonl");
|
|
112
|
+
if (resolve(sourcePath) === resolve(target.path))
|
|
113
|
+
continue;
|
|
114
|
+
if (!await stat(sourcePath).then(() => true, () => false))
|
|
115
|
+
continue;
|
|
116
|
+
const source = new PromptJournal(sourcePath);
|
|
117
|
+
await source.initialize();
|
|
118
|
+
const records = await source.read();
|
|
119
|
+
const submitted = records.filter((record) => record.type === "submitted");
|
|
120
|
+
const idMatches = currentSessionId !== null && submitted.some(record => record.sessionId === currentSessionId);
|
|
121
|
+
if (!fileMatches && !idMatches)
|
|
122
|
+
continue;
|
|
123
|
+
const pending = await source.pending(currentSessionFile === null ? [] : await readSessionJournal(currentSessionFile));
|
|
124
|
+
for (const entry of pending) {
|
|
125
|
+
await target.adopt(entry.submitted);
|
|
126
|
+
await source.retire(entry.submitted.id);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** Reconcile only durable user/assistant ancestry; a torn final JSONL record is not authority. */
|
|
132
|
+
export async function readSessionJournal(path) {
|
|
133
|
+
let text;
|
|
134
|
+
try {
|
|
135
|
+
const metadata = await stat(path);
|
|
136
|
+
if (metadata.size > MAX_SESSION_RECONCILE_BYTES)
|
|
137
|
+
throw new Error("resident session exceeds the recovery scan limit");
|
|
138
|
+
text = await readFile(path, "utf8");
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (error.code === "ENOENT")
|
|
142
|
+
return [];
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
const raw = [];
|
|
146
|
+
const lines = text.split("\n");
|
|
147
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
148
|
+
const line = lines[index];
|
|
149
|
+
if (line.length === 0)
|
|
150
|
+
continue;
|
|
151
|
+
let value;
|
|
152
|
+
try {
|
|
153
|
+
value = JSON.parse(line);
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (index === lines.length - 1 && !text.endsWith("\n"))
|
|
157
|
+
break;
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
if (typeof value !== "object" || value === null)
|
|
161
|
+
continue;
|
|
162
|
+
const record = value;
|
|
163
|
+
const message = typeof record.message === "object" && record.message !== null
|
|
164
|
+
? record.message
|
|
165
|
+
: null;
|
|
166
|
+
if (record.type !== "message" || typeof record.id !== "string" || message === null
|
|
167
|
+
|| typeof message.role !== "string")
|
|
168
|
+
continue;
|
|
169
|
+
const content = message.content;
|
|
170
|
+
const promptText = typeof content === "string" ? content : Array.isArray(content)
|
|
171
|
+
? content.flatMap(part => typeof part === "object" && part !== null
|
|
172
|
+
&& part.type === "text"
|
|
173
|
+
&& typeof part.text === "string"
|
|
174
|
+
? [part.text] : []).join("")
|
|
175
|
+
: "";
|
|
176
|
+
raw.push({
|
|
177
|
+
id: record.id,
|
|
178
|
+
parentId: typeof record.parentId === "string" ? record.parentId : null,
|
|
179
|
+
role: message.role,
|
|
180
|
+
text: promptText,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
const byId = new Map(raw.map(record => [record.id, record]));
|
|
184
|
+
const settled = new Set();
|
|
185
|
+
for (const record of raw) {
|
|
186
|
+
if (record.role !== "assistant")
|
|
187
|
+
continue;
|
|
188
|
+
let parent = record.parentId;
|
|
189
|
+
const visited = new Set();
|
|
190
|
+
while (parent !== null && !visited.has(parent)) {
|
|
191
|
+
visited.add(parent);
|
|
192
|
+
const ancestor = byId.get(parent);
|
|
193
|
+
if (ancestor === undefined)
|
|
194
|
+
break;
|
|
195
|
+
if (ancestor.role === "user") {
|
|
196
|
+
settled.add(ancestor.id);
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
parent = ancestor.parentId;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return raw
|
|
203
|
+
.filter(record => record.role === "user")
|
|
204
|
+
.map(record => ({ entryId: record.id, text: record.text, settled: settled.has(record.id) }));
|
|
205
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type TerminalHostCommand } from "./ensure-terminal-host.js";
|
|
2
|
+
export interface ResidentReleaseHoldReport {
|
|
3
|
+
/** False when any resident record or identity could not be verified; callers then keep every release. */
|
|
4
|
+
readonly complete: boolean;
|
|
5
|
+
readonly releaseRoots: readonly string[];
|
|
6
|
+
readonly uncertain: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
export interface ResidentReleaseHoldOptions {
|
|
9
|
+
readonly dataDir: string;
|
|
10
|
+
/** Installed release roots whose terminal host may answer, in preference order. */
|
|
11
|
+
readonly releaseRoots: readonly string[];
|
|
12
|
+
readonly platform?: NodeJS.Platform;
|
|
13
|
+
readonly architecture?: string;
|
|
14
|
+
readonly timeoutMs?: number;
|
|
15
|
+
readonly verify?: (addon: string, platform: NodeJS.Platform, architecture: string) => Promise<unknown>;
|
|
16
|
+
readonly run?: (command: TerminalHostCommand, arguments_: readonly string[], timeoutMs: number) => Promise<{
|
|
17
|
+
readonly code: number;
|
|
18
|
+
readonly stdout: string;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Reports the releases that live resident processes run from, read-only. The verified terminal
|
|
23
|
+
* host inspects its own records, so pid reuse and identity formats are judged exactly as the
|
|
24
|
+
* server judges them. No records means nothing to hold; any doubt yields an incomplete report.
|
|
25
|
+
*/
|
|
26
|
+
export declare function readResidentReleaseHolds(options: ResidentReleaseHoldOptions): Promise<ResidentReleaseHoldReport>;
|
|
27
|
+
/** The largest release-hold report accepted from the terminal host. */
|
|
28
|
+
export declare const MAX_RELEASE_HOLD_REPORT_BYTES: number;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { PRODUCT_IDENTITY } from "../../product-identity.js";
|
|
4
|
+
import { runBoundedHostCommand } from "./bounded-host-command.js";
|
|
5
|
+
import { resolveTerminalHostEntryPath, resolveTerminalHostPath } from "./ensure-terminal-host.js";
|
|
6
|
+
import { verifyTerminalHostArtifact } from "./terminal-host-artifact.js";
|
|
7
|
+
const COMPLETE_EMPTY = Object.freeze({ complete: true, releaseRoots: Object.freeze([]), uncertain: Object.freeze([]) });
|
|
8
|
+
/**
|
|
9
|
+
* Reports the releases that live resident processes run from, read-only. The verified terminal
|
|
10
|
+
* host inspects its own records, so pid reuse and identity formats are judged exactly as the
|
|
11
|
+
* server judges them. No records means nothing to hold; any doubt yields an incomplete report.
|
|
12
|
+
*/
|
|
13
|
+
export async function readResidentReleaseHolds(options) {
|
|
14
|
+
if (!await hasResidentRecords(options.dataDir))
|
|
15
|
+
return COMPLETE_EMPTY;
|
|
16
|
+
const platform = options.platform ?? process.platform;
|
|
17
|
+
const architecture = options.architecture ?? process.arch;
|
|
18
|
+
const verify = options.verify ?? verifyTerminalHostArtifact;
|
|
19
|
+
let command;
|
|
20
|
+
for (const root of options.releaseRoots) {
|
|
21
|
+
const candidate = resolveTerminalHostPath(root, {}, platform, architecture);
|
|
22
|
+
try {
|
|
23
|
+
await verify(candidate, platform, architecture);
|
|
24
|
+
command = { executable: process.execPath, entry: resolveTerminalHostEntryPath(root) };
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Rationale: an older release may predate the packaged host; another retained release may still carry it.
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (!command)
|
|
32
|
+
return incomplete("no verified terminal host is installed to inspect resident records");
|
|
33
|
+
try {
|
|
34
|
+
const result = await (options.run ?? runHost)(command, ["release-holds", "--data-dir", options.dataDir], options.timeoutMs ?? 5_000);
|
|
35
|
+
const report = JSON.parse(result.stdout.trim().split(/\r?\n/u).at(-1) ?? "");
|
|
36
|
+
if (result.code !== 0 || report.schema !== "a1-resident-release-holds-v1" || typeof report.complete !== "boolean"
|
|
37
|
+
|| !isStringArray(report.releaseRoots) || !isStringArray(report.uncertain)) {
|
|
38
|
+
return incomplete("terminal host returned no valid release-hold report");
|
|
39
|
+
}
|
|
40
|
+
return { complete: report.complete, releaseRoots: report.releaseRoots, uncertain: report.uncertain };
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return incomplete("terminal host release-hold inspection failed");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function hasResidentRecords(dataDir) {
|
|
47
|
+
let profiles;
|
|
48
|
+
try {
|
|
49
|
+
profiles = await readdir(resolve(dataDir, "tabs"));
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return !(error instanceof Error && "code" in error && error.code === "ENOENT");
|
|
53
|
+
}
|
|
54
|
+
// Invariant: native inspection, not a following stat, judges unknown or linked namespace entries.
|
|
55
|
+
return profiles.length > 0;
|
|
56
|
+
}
|
|
57
|
+
function incomplete(reason) {
|
|
58
|
+
return { complete: false, releaseRoots: [], uncertain: [reason] };
|
|
59
|
+
}
|
|
60
|
+
function isStringArray(value) {
|
|
61
|
+
return Array.isArray(value) && value.every(item => typeof item === "string");
|
|
62
|
+
}
|
|
63
|
+
/** The largest release-hold report accepted from the terminal host. */
|
|
64
|
+
export const MAX_RELEASE_HOLD_REPORT_BYTES = 1024 * 1024;
|
|
65
|
+
async function runHost(command, arguments_, timeoutMs) {
|
|
66
|
+
const environment = { ...process.env };
|
|
67
|
+
delete environment[PRODUCT_IDENTITY.environment.developmentInstanceId];
|
|
68
|
+
delete environment[PRODUCT_IDENTITY.environment.terminalHostPath];
|
|
69
|
+
return await runBoundedHostCommand(command, arguments_, {
|
|
70
|
+
environment,
|
|
71
|
+
maxStdoutBytes: MAX_RELEASE_HOLD_REPORT_BYTES,
|
|
72
|
+
timeoutMs,
|
|
73
|
+
label: "terminal host release-hold inspection",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The owned screens the server opens in a utility tab; each names its tab id stem, `<route>-…`. */
|
|
2
|
+
export type ResidentTabRoute = "settings" | "changelog";
|
|
3
|
+
export declare const RESIDENT_TAB_ROUTES: readonly ResidentTabRoute[];
|
|
4
|
+
/** The utility route whose screen is the resident tab `tabId`, or `null` for an Agent tab. */
|
|
5
|
+
export declare function residentUtilityRoute(tabId: string): ResidentTabRoute | null;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const RESIDENT_TAB_ROUTES = ["settings", "changelog"];
|
|
2
|
+
/** The utility route whose screen is the resident tab `tabId`, or `null` for an Agent tab. */
|
|
3
|
+
export function residentUtilityRoute(tabId) {
|
|
4
|
+
return RESIDENT_TAB_ROUTES.find(route => tabId.startsWith(`${route}-`)) ?? null;
|
|
5
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { EnsureTerminalHostResult } from "./ensure-terminal-host.js";
|
|
2
|
+
export interface ResidentHostSelectionOptions {
|
|
3
|
+
readonly profileId: "a1" | "pi";
|
|
4
|
+
readonly currentLaunchContract: boolean;
|
|
5
|
+
readonly solo: boolean;
|
|
6
|
+
/** Both standard input and standard output are terminals the attach client can own. */
|
|
7
|
+
readonly interactive: boolean;
|
|
8
|
+
readonly ensureHost: () => Promise<EnsureTerminalHostResult>;
|
|
9
|
+
}
|
|
10
|
+
/** Invariant: comparison, solo, and superseded launches stay outside resident discovery and startup. */
|
|
11
|
+
export declare function selectResidentHost(options: ResidentHostSelectionOptions): Promise<EnsureTerminalHostResult | null>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Invariant: comparison, solo, and superseded launches stay outside resident discovery and startup. */
|
|
2
|
+
export async function selectResidentHost(options) {
|
|
3
|
+
if (options.profileId !== "a1" || options.solo || !options.currentLaunchContract)
|
|
4
|
+
return null;
|
|
5
|
+
// Platform: the attach client reads the outer terminal's size and owns its raw input, so piped
|
|
6
|
+
// or redirected launches run the direct UI, which already serves non-terminal streams.
|
|
7
|
+
if (!options.interactive)
|
|
8
|
+
return { status: "fallback", reason: "no interactive terminal" };
|
|
9
|
+
return await options.ensureHost();
|
|
10
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PromptJournal } from "./prompt-journal.js";
|
|
2
|
+
import { ResidentTabFaultInjection } from "./fault-injection.js";
|
|
3
|
+
export declare function synchronizeSessionFile(path: string, faults?: ResidentTabFaultInjection): Promise<void>;
|
|
4
|
+
/** Serializes settled-turn sync and journal ordering off the input path. */
|
|
5
|
+
export declare class SettledTurnSynchronizer {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(journal: PromptJournal, faults?: ResidentTabFaultInjection);
|
|
8
|
+
settle(sessionFile: string, submissionId: string, entryId: string): Promise<void>;
|
|
9
|
+
settleMany(sessionFile: string, entries: readonly {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly entryId: string;
|
|
12
|
+
}[]): Promise<void>;
|
|
13
|
+
flush(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { open } from "node:fs/promises";
|
|
2
|
+
import { ResidentTabFaultInjection } from "./fault-injection.js";
|
|
3
|
+
export async function synchronizeSessionFile(path, faults = new ResidentTabFaultInjection()) {
|
|
4
|
+
const handle = await open(path, "r+");
|
|
5
|
+
try {
|
|
6
|
+
faults.at("session-before-sync");
|
|
7
|
+
await handle.sync();
|
|
8
|
+
faults.at("session-after-sync");
|
|
9
|
+
}
|
|
10
|
+
finally {
|
|
11
|
+
await handle.close();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** Serializes settled-turn sync and journal ordering off the input path. */
|
|
15
|
+
export class SettledTurnSynchronizer {
|
|
16
|
+
#journal;
|
|
17
|
+
#faults;
|
|
18
|
+
#queue = Promise.resolve();
|
|
19
|
+
constructor(journal, faults = new ResidentTabFaultInjection()) {
|
|
20
|
+
this.#journal = journal;
|
|
21
|
+
this.#faults = faults;
|
|
22
|
+
}
|
|
23
|
+
settle(sessionFile, submissionId, entryId) {
|
|
24
|
+
return this.settleMany(sessionFile, [{ id: submissionId, entryId }]);
|
|
25
|
+
}
|
|
26
|
+
settleMany(sessionFile, entries) {
|
|
27
|
+
const operation = this.#queue.then(async () => {
|
|
28
|
+
await synchronizeSessionFile(sessionFile, this.#faults);
|
|
29
|
+
this.#faults.at("journal-after-settle-sync");
|
|
30
|
+
for (const entry of entries)
|
|
31
|
+
await this.#journal.settle(entry.id, entry.entryId);
|
|
32
|
+
});
|
|
33
|
+
this.#queue = operation.catch(() => undefined);
|
|
34
|
+
return operation;
|
|
35
|
+
}
|
|
36
|
+
flush() { return this.#queue; }
|
|
37
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const RESIDENT_TABS_MAX_CONCURRENT_STARTS = 2;
|
|
2
|
+
export declare const RESIDENT_TABS_MAX_CONCURRENT_STARTS_CAP = 8;
|
|
3
|
+
export declare const RESIDENT_TABS_PREWARM_COUNT = 1;
|
|
4
|
+
export declare const RESIDENT_TABS_PREWARM_CAP = 1;
|
|
5
|
+
export interface ResidentTabLaunchSettings {
|
|
6
|
+
readonly tabsAutoName: boolean;
|
|
7
|
+
readonly maxConcurrentStarts: number;
|
|
8
|
+
readonly prewarmCount: number;
|
|
9
|
+
readonly unresponsiveRestartSeconds: number;
|
|
10
|
+
}
|
|
11
|
+
/** Read only resident-launch values before any UI or extension module is loaded. */
|
|
12
|
+
export declare function readResidentTabLaunchSettings(profileDir: string, namespace?: string, legacyConfigDir?: string, profileId?: string): Promise<ResidentTabLaunchSettings>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { OWNED_SETTING_DECLARATIONS, OWNED_UI_SETTINGS_MIGRATIONS, OWNED_UI_SETTINGS_VERSION, normalizeOwnedUiSettingsValues, parseOwnedUiSettingsDocument, readProfileSettingsNamespace, repairProfileSettingsDocument, resolveOwnedUiSettings, settingValue, } from "../../ui/settings/index.js";
|
|
4
|
+
const MAX_SETTINGS_BYTES = 256 * 1024;
|
|
5
|
+
export const RESIDENT_TABS_MAX_CONCURRENT_STARTS = 2;
|
|
6
|
+
export const RESIDENT_TABS_MAX_CONCURRENT_STARTS_CAP = 8;
|
|
7
|
+
export const RESIDENT_TABS_PREWARM_COUNT = 1;
|
|
8
|
+
export const RESIDENT_TABS_PREWARM_CAP = 1;
|
|
9
|
+
const DEFAULTS = Object.freeze({
|
|
10
|
+
tabsAutoName: true,
|
|
11
|
+
maxConcurrentStarts: RESIDENT_TABS_MAX_CONCURRENT_STARTS,
|
|
12
|
+
prewarmCount: RESIDENT_TABS_PREWARM_COUNT,
|
|
13
|
+
unresponsiveRestartSeconds: 120,
|
|
14
|
+
});
|
|
15
|
+
/** Read only resident-launch values before any UI or extension module is loaded. */
|
|
16
|
+
export async function readResidentTabLaunchSettings(profileDir, namespace = "a1", legacyConfigDir, profileId = namespace) {
|
|
17
|
+
const sharedFile = resolve(profileDir, "settings.json");
|
|
18
|
+
try {
|
|
19
|
+
repairProfileSettingsDocument(sharedFile);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Compatibility: recovery is opportunistic; resident launch falls back when bytes stay invalid.
|
|
23
|
+
}
|
|
24
|
+
const shared = readProfileSettingsNamespace(sharedFile, namespace);
|
|
25
|
+
if (shared.status === "invalid")
|
|
26
|
+
return DEFAULTS;
|
|
27
|
+
if (shared.status === "available") {
|
|
28
|
+
const compatibility = normalizeOwnedUiSettingsValues(shared.value);
|
|
29
|
+
return compatibility.values === null
|
|
30
|
+
? DEFAULTS
|
|
31
|
+
: resolveLaunchValues({ version: OWNED_UI_SETTINGS_VERSION, values: compatibility.values }, []);
|
|
32
|
+
}
|
|
33
|
+
const file = resolve(legacyConfigDir ?? profileDir, "settings", `${profileId}.json`);
|
|
34
|
+
try {
|
|
35
|
+
const raw = await readFile(file, "utf8");
|
|
36
|
+
if (Buffer.byteLength(raw, "utf8") > MAX_SETTINGS_BYTES)
|
|
37
|
+
return DEFAULTS;
|
|
38
|
+
const document = parseOwnedUiSettingsDocument(raw);
|
|
39
|
+
return document === null ? DEFAULTS : resolveLaunchValues(document, OWNED_UI_SETTINGS_MIGRATIONS);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return DEFAULTS;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function resolveLaunchValues(document, migrations) {
|
|
46
|
+
const resolution = resolveOwnedUiSettings({
|
|
47
|
+
declarations: [OWNED_SETTING_DECLARATIONS.tabsAutoName],
|
|
48
|
+
migrations,
|
|
49
|
+
document,
|
|
50
|
+
currentVersion: OWNED_UI_SETTINGS_VERSION,
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
tabsAutoName: settingValue(resolution, "tabsAutoName") === true,
|
|
54
|
+
maxConcurrentStarts: RESIDENT_TABS_MAX_CONCURRENT_STARTS,
|
|
55
|
+
prewarmCount: RESIDENT_TABS_PREWARM_COUNT,
|
|
56
|
+
unresponsiveRestartSeconds: DEFAULTS.unresponsiveRestartSeconds,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const TERMINAL_HOST_MANIFEST_FILENAME = "terminal-host.manifest.json";
|
|
2
|
+
export type TerminalHostArtifactErrorCode = "TERMINAL_HOST_ARTIFACT_MISSING" | "TERMINAL_HOST_ARTIFACT_TAMPERED" | "TERMINAL_HOST_ARTIFACT_INCOMPATIBLE" | "TERMINAL_HOST_ARTIFACT_UNSUPPORTED";
|
|
3
|
+
export declare class TerminalHostArtifactError extends Error {
|
|
4
|
+
readonly code: TerminalHostArtifactErrorCode;
|
|
5
|
+
readonly manifestPath: string;
|
|
6
|
+
constructor(code: TerminalHostArtifactErrorCode, manifestPath: string, message: string);
|
|
7
|
+
}
|
|
8
|
+
export interface VerifiedTerminalHostArtifact {
|
|
9
|
+
readonly addon: string;
|
|
10
|
+
readonly entry: string;
|
|
11
|
+
readonly generation: 1;
|
|
12
|
+
}
|
|
13
|
+
/** Verifies every runtime file certified by the terminal-host v2 manifest before Node loads it. */
|
|
14
|
+
export declare function verifyTerminalHostArtifact(addonPath: string, platform?: NodeJS.Platform, architecture?: string): Promise<VerifiedTerminalHostArtifact>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, resolve } from "node:path";
|
|
4
|
+
import { PRODUCT_IDENTITY } from "../../product-identity.js";
|
|
5
|
+
export const TERMINAL_HOST_MANIFEST_FILENAME = "terminal-host.manifest.json";
|
|
6
|
+
const SCHEMA = "a1-terminal-host-artifact-v2";
|
|
7
|
+
const GENERATION = 1;
|
|
8
|
+
const NODE_API = 9;
|
|
9
|
+
const NOTICES_NAME = "terminal-host-THIRD-PARTY-NOTICES.txt";
|
|
10
|
+
export class TerminalHostArtifactError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
manifestPath;
|
|
13
|
+
constructor(code, manifestPath, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "TerminalHostArtifactError";
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.manifestPath = manifestPath;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Verifies every runtime file certified by the terminal-host v2 manifest before Node loads it. */
|
|
21
|
+
export async function verifyTerminalHostArtifact(addonPath, platform = process.platform, architecture = process.arch) {
|
|
22
|
+
const directory = dirname(addonPath);
|
|
23
|
+
const releaseRoot = resolve(directory, "../../..");
|
|
24
|
+
const manifestPath = resolve(directory, TERMINAL_HOST_MANIFEST_FILENAME);
|
|
25
|
+
let manifest;
|
|
26
|
+
try {
|
|
27
|
+
const parsed = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
28
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
29
|
+
throw new TypeError("terminal host manifest is not an object");
|
|
30
|
+
manifest = parsed;
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
const code = error instanceof Error && "code" in error && error.code === "ENOENT"
|
|
34
|
+
? "TERMINAL_HOST_ARTIFACT_MISSING"
|
|
35
|
+
: "TERMINAL_HOST_ARTIFACT_INCOMPATIBLE";
|
|
36
|
+
throw new TerminalHostArtifactError(code, manifestPath, "terminal host manifest is missing or invalid");
|
|
37
|
+
}
|
|
38
|
+
if (manifest.capability === "unsupported") {
|
|
39
|
+
throw new TerminalHostArtifactError("TERMINAL_HOST_ARTIFACT_UNSUPPORTED", manifestPath, "terminal host is unsupported on this platform");
|
|
40
|
+
}
|
|
41
|
+
if (manifest.schema !== SCHEMA || manifest.kind !== "node-addon" || manifest.nodeApi !== NODE_API
|
|
42
|
+
|| manifest.protocolVersion !== 1 || manifest.generation !== GENERATION
|
|
43
|
+
|| manifest.platform !== platform || manifest.architecture !== architecture || manifest.capability !== "supported"
|
|
44
|
+
|| !validRecord(manifest.artifact) || !validRecord(manifest.entry) || !validRecord(manifest.notices)
|
|
45
|
+
|| manifest.artifact.filename !== `${PRODUCT_IDENTITY.artifacts.terminalHostAddon}.node`
|
|
46
|
+
|| manifest.entry.filename !== `dist/foundation/resident-tabs/${PRODUCT_IDENTITY.artifacts.terminalHostEntry}.js`
|
|
47
|
+
|| manifest.notices.filename !== NOTICES_NAME
|
|
48
|
+
|| basename(addonPath) !== manifest.artifact.filename) {
|
|
49
|
+
throw new TerminalHostArtifactError("TERMINAL_HOST_ARTIFACT_INCOMPATIBLE", manifestPath, "terminal host manifest is incompatible");
|
|
50
|
+
}
|
|
51
|
+
const entry = resolve(releaseRoot, manifest.entry.filename);
|
|
52
|
+
await verifyFile(addonPath, manifest.artifact, manifestPath);
|
|
53
|
+
await verifyFile(entry, manifest.entry, manifestPath);
|
|
54
|
+
await verifyFile(resolve(directory, manifest.notices.filename), manifest.notices, manifestPath);
|
|
55
|
+
return { addon: addonPath, entry, generation: 1 };
|
|
56
|
+
}
|
|
57
|
+
function validRecord(value) {
|
|
58
|
+
return typeof value === "object" && value !== null
|
|
59
|
+
&& typeof value.filename === "string"
|
|
60
|
+
&& /^[a-f0-9]{64}$/u.test(value.sha256)
|
|
61
|
+
&& Number.isSafeInteger(value.size) && value.size >= 0;
|
|
62
|
+
}
|
|
63
|
+
async function verifyFile(path, record, manifestPath) {
|
|
64
|
+
let bytes;
|
|
65
|
+
let metadata;
|
|
66
|
+
try {
|
|
67
|
+
[bytes, metadata] = await Promise.all([readFile(path), stat(path)]);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
71
|
+
throw new TerminalHostArtifactError("TERMINAL_HOST_ARTIFACT_MISSING", manifestPath, `certified terminal host file is missing: ${record.filename}`);
|
|
72
|
+
}
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
if (!metadata.isFile() || bytes.byteLength !== record.size || createHash("sha256").update(bytes).digest("hex") !== record.sha256) {
|
|
76
|
+
throw new TerminalHostArtifactError("TERMINAL_HOST_ARTIFACT_TAMPERED", manifestPath, `certified terminal host file failed verification: ${record.filename}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface ZipEntry {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly data: Buffer;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Encodes a small deflated zip archive. Names are forward-slash relative paths; there are no
|
|
7
|
+
* directories, extra fields, or encryption, so any standard unzip tool reads it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function encodeZip(entries: readonly ZipEntry[], modified?: Date): Buffer;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { crc32, deflateRawSync } from "node:zlib";
|
|
2
|
+
/**
|
|
3
|
+
* Encodes a small deflated zip archive. Names are forward-slash relative paths; there are no
|
|
4
|
+
* directories, extra fields, or encryption, so any standard unzip tool reads it.
|
|
5
|
+
*/
|
|
6
|
+
export function encodeZip(entries, modified = new Date()) {
|
|
7
|
+
const time = ((modified.getHours() << 11) | (modified.getMinutes() << 5) | Math.floor(modified.getSeconds() / 2)) & 0xffff;
|
|
8
|
+
const date = (((modified.getFullYear() - 1980) << 9) | ((modified.getMonth() + 1) << 5) | modified.getDate()) & 0xffff;
|
|
9
|
+
const locals = [];
|
|
10
|
+
const centrals = [];
|
|
11
|
+
let offset = 0;
|
|
12
|
+
for (const entry of entries) {
|
|
13
|
+
const segments = entry.name.split("/");
|
|
14
|
+
if (segments.some(segment => !/^[A-Za-z0-9._-]+$/u.test(segment) || segment === "." || segment === "..")) {
|
|
15
|
+
throw new Error(`zip entry name is unsafe: ${entry.name}`);
|
|
16
|
+
}
|
|
17
|
+
const name = Buffer.from(entry.name, "utf8");
|
|
18
|
+
const compressed = deflateRawSync(entry.data);
|
|
19
|
+
const checksum = crc32(entry.data);
|
|
20
|
+
const local = Buffer.alloc(30);
|
|
21
|
+
local.writeUInt32LE(0x04034b50, 0);
|
|
22
|
+
local.writeUInt16LE(20, 4);
|
|
23
|
+
local.writeUInt16LE(0x0800, 6);
|
|
24
|
+
local.writeUInt16LE(8, 8);
|
|
25
|
+
local.writeUInt16LE(time, 10);
|
|
26
|
+
local.writeUInt16LE(date, 12);
|
|
27
|
+
local.writeUInt32LE(checksum, 14);
|
|
28
|
+
local.writeUInt32LE(compressed.length, 18);
|
|
29
|
+
local.writeUInt32LE(entry.data.length, 22);
|
|
30
|
+
local.writeUInt16LE(name.length, 26);
|
|
31
|
+
locals.push(local, name, compressed);
|
|
32
|
+
const central = Buffer.alloc(46);
|
|
33
|
+
central.writeUInt32LE(0x02014b50, 0);
|
|
34
|
+
central.writeUInt16LE(20, 4);
|
|
35
|
+
central.writeUInt16LE(20, 6);
|
|
36
|
+
central.writeUInt16LE(0x0800, 8);
|
|
37
|
+
central.writeUInt16LE(8, 10);
|
|
38
|
+
central.writeUInt16LE(time, 12);
|
|
39
|
+
central.writeUInt16LE(date, 14);
|
|
40
|
+
central.writeUInt32LE(checksum, 16);
|
|
41
|
+
central.writeUInt32LE(compressed.length, 20);
|
|
42
|
+
central.writeUInt32LE(entry.data.length, 24);
|
|
43
|
+
central.writeUInt16LE(name.length, 28);
|
|
44
|
+
central.writeUInt32LE(offset, 42);
|
|
45
|
+
centrals.push(central, name);
|
|
46
|
+
offset += local.length + name.length + compressed.length;
|
|
47
|
+
}
|
|
48
|
+
const directory = Buffer.concat(centrals);
|
|
49
|
+
const end = Buffer.alloc(22);
|
|
50
|
+
end.writeUInt32LE(0x06054b50, 0);
|
|
51
|
+
end.writeUInt16LE(entries.length, 8);
|
|
52
|
+
end.writeUInt16LE(entries.length, 10);
|
|
53
|
+
end.writeUInt32LE(directory.length, 12);
|
|
54
|
+
end.writeUInt32LE(offset, 16);
|
|
55
|
+
return Buffer.concat([...locals, directory, end]);
|
|
56
|
+
}
|