@timurproko/a1 0.2.6 → 0.2.7-dev.1222
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 +197 -908
- package/dist/app/session-shell/session-shell.d.ts +3 -8
- package/dist/app/session-shell/session-shell.js +327 -835
- package/dist/app/session-shell/session-viewport-controller.d.ts +2 -1
- package/dist/app/session-shell/session-viewport-controller.js +41 -38
- 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 +105 -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 +207 -153
- package/dist/composition/reference-selection-options.d.ts +3 -0
- package/dist/composition/reference-selection-options.js +16 -0
- 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 -2
- package/dist/composition/settings-route-host.js +42 -17
- package/dist/composition/settings-search-input.d.ts +9 -0
- package/dist/composition/settings-search-input.js +61 -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 +244 -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 +84 -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-document-selection.d.ts +30 -0
- package/dist/features/owned-ui/reference-document-selection.js +179 -0
- package/dist/features/owned-ui/reference-screen-app.d.ts +6 -1
- package/dist/features/owned-ui/reference-screen-app.js +51 -10
- package/dist/features/owned-ui/settings-app.d.ts +13 -2
- package/dist/features/owned-ui/settings-app.js +136 -97
- 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 +138 -11
- 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 +74 -5
- 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.d.ts +17 -8
- package/dist/ui/components/dialog-panel.js +117 -41
- package/dist/ui/components/index.d.ts +5 -5
- package/dist/ui/components/index.js +4 -4
- 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/scrollbar.d.ts +1 -1
- package/dist/ui/components/scrollbar.js +1 -1
- package/dist/ui/components/selection-copy.d.ts +3 -3
- package/dist/ui/components/selection-copy.js +16 -1
- 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-selection.d.ts +1 -2
- package/dist/ui/components/text-selection.js +5 -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 +179 -58
- 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 +649 -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,276 @@
|
|
|
1
|
+
import { assertOwnedUiCommand, assertPromptImages, ImageAttachmentError, } from "../../contracts/owned-ui/index.js";
|
|
2
|
+
import { renderPiShellStatusText } from "../../integrations/pi/components/shell-presenters-info.js";
|
|
3
|
+
const rejected = (diagnostic) => ({ outcome: "rejected", diagnostic });
|
|
4
|
+
/**
|
|
5
|
+
* Turns editor input into engine commands: prompts, steering, follow-ups, and bash, each recorded
|
|
6
|
+
* in history first. It holds a submission whose image pastes are still preparing, journals prompts
|
|
7
|
+
* for resident tabs, and recovers the draft when a submission is rejected.
|
|
8
|
+
*/
|
|
9
|
+
export class PromptSubmission {
|
|
10
|
+
#ports;
|
|
11
|
+
#waiting = new Map();
|
|
12
|
+
#editorRevision = 0;
|
|
13
|
+
constructor(ports) {
|
|
14
|
+
this.#ports = ports;
|
|
15
|
+
}
|
|
16
|
+
/** True while a submission waits for its image pastes. */
|
|
17
|
+
get waiting() {
|
|
18
|
+
return this.#waiting.size > 0;
|
|
19
|
+
}
|
|
20
|
+
/** The editor changed; a later recovery never overwrites input typed after its submission. */
|
|
21
|
+
noteEditorChange() {
|
|
22
|
+
this.#editorRevision++;
|
|
23
|
+
}
|
|
24
|
+
submit(text) {
|
|
25
|
+
return this.#whenReady(text, () => this.#submit(text));
|
|
26
|
+
}
|
|
27
|
+
queueFollowUp(draft) {
|
|
28
|
+
return this.#whenReady(draft, () => this.#queueFollowUp(draft));
|
|
29
|
+
}
|
|
30
|
+
cancelWaiting() {
|
|
31
|
+
for (const item of this.#waiting.values())
|
|
32
|
+
item.controller.abort();
|
|
33
|
+
}
|
|
34
|
+
/** Puts waiting submissions and the engine's queued input back into the editor. */
|
|
35
|
+
restoreQueued() {
|
|
36
|
+
const queued = [...this.#waiting.keys(), ...this.#ports.backend.workflows.clearQueuedWorkflows()];
|
|
37
|
+
this.cancelWaiting();
|
|
38
|
+
if (queued.length === 0)
|
|
39
|
+
return;
|
|
40
|
+
this.#ports.root.editor.setText(queued.join("\n"));
|
|
41
|
+
this.#ports.terminal.requestRender();
|
|
42
|
+
}
|
|
43
|
+
/** Sends slash text the shell does not own as engine prompt input; history keeps what was typed. */
|
|
44
|
+
sendSlashPrompt(text, typed = text) {
|
|
45
|
+
this.#rememberInput(typed, "slash");
|
|
46
|
+
this.#ports.root.resumeViewportFollowing();
|
|
47
|
+
return this.execute({
|
|
48
|
+
type: this.#ports.lifecycle() === "busy" ? "steer" : "prompt",
|
|
49
|
+
correlationId: this.#ports.correlation("prompt-command"),
|
|
50
|
+
sessionId: this.#ports.backend.identity.sessionId,
|
|
51
|
+
text,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/** Executes a command; with a draft, a rejected or failed submission puts the draft back for recovery. */
|
|
55
|
+
async execute(command, draft) {
|
|
56
|
+
const { backend } = this.#ports;
|
|
57
|
+
if (draft === undefined)
|
|
58
|
+
return backend.session.execute(command);
|
|
59
|
+
const revision = this.#editorRevision;
|
|
60
|
+
try {
|
|
61
|
+
assertOwnedUiCommand(command);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
return this.#recover(draft, revision, error);
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const result = await backend.session.execute(command);
|
|
68
|
+
if (result.outcome === "rejected")
|
|
69
|
+
return this.#recover(draft, revision);
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Security: dispatch might already have reached the provider. Never retry automatically.
|
|
74
|
+
this.#ports.root.editor.addToHistory(draft);
|
|
75
|
+
this.#ports.promptHistory()?.rememberRecovery(draft);
|
|
76
|
+
this.reportError(undefined, "Submission failed; delivery is uncertain. Check the conversation before retrying. Press Up to recover the draft.");
|
|
77
|
+
return { outcome: "failed", diagnostic: "submission delivery is uncertain" };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
reportError(error, message) {
|
|
81
|
+
// Security: arbitrary provider/extension error messages can contain the entire request.
|
|
82
|
+
try {
|
|
83
|
+
this.#ports.root.appendWorkflowResult({ command: "debug", outcome: "failed", message: message
|
|
84
|
+
?? (error instanceof ImageAttachmentError ? error.message : "Submission failed. Check the prompt and try again.") }, error instanceof ImageAttachmentError ? error.code : undefined);
|
|
85
|
+
this.#ports.terminal.requestRender();
|
|
86
|
+
}
|
|
87
|
+
catch { /* Security: error presentation cannot create another rejected submission callback. */ }
|
|
88
|
+
}
|
|
89
|
+
onSessionReplaced() {
|
|
90
|
+
this.cancelWaiting();
|
|
91
|
+
}
|
|
92
|
+
dispose() {
|
|
93
|
+
this.cancelWaiting();
|
|
94
|
+
}
|
|
95
|
+
#whenReady(draft, action) {
|
|
96
|
+
const { root, backend } = this.#ports;
|
|
97
|
+
const previous = this.#waiting.get(draft);
|
|
98
|
+
if (previous !== undefined)
|
|
99
|
+
return previous.result;
|
|
100
|
+
if (!root.hasPendingPastes(draft))
|
|
101
|
+
return this.#guard(draft, action);
|
|
102
|
+
const controller = new AbortController();
|
|
103
|
+
const generation = backend.identity.sessionGeneration;
|
|
104
|
+
const result = this.#guard(draft, async () => {
|
|
105
|
+
await root.waitForPromptPastes(draft, controller.signal);
|
|
106
|
+
if (controller.signal.aborted || this.#ports.disposed() || backend.identity.sessionGeneration !== generation)
|
|
107
|
+
return rejected("image submission canceled");
|
|
108
|
+
return action();
|
|
109
|
+
}).finally(() => {
|
|
110
|
+
this.#waiting.delete(draft);
|
|
111
|
+
if (!this.#ports.disposed())
|
|
112
|
+
this.#showWaiting();
|
|
113
|
+
});
|
|
114
|
+
this.#waiting.set(draft, { controller, result });
|
|
115
|
+
if (root.editor.getText() === draft)
|
|
116
|
+
root.editor.setText("");
|
|
117
|
+
this.#showWaiting();
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
#showWaiting() {
|
|
121
|
+
const count = this.#waiting.size;
|
|
122
|
+
this.#ports.root.setExtensionWidget("owned-image-preparation", count === 0 ? null : {
|
|
123
|
+
render: width => [...renderPiShellStatusText(`Waiting for images (${count} submission${count === 1 ? "" : "s"}) — Esc cancels; dequeue restores`, width)],
|
|
124
|
+
invalidate: () => { },
|
|
125
|
+
}, "aboveEditor");
|
|
126
|
+
this.#ports.terminal.requestRender();
|
|
127
|
+
}
|
|
128
|
+
async #guard(draft, action) {
|
|
129
|
+
const revision = this.#editorRevision;
|
|
130
|
+
try {
|
|
131
|
+
return await action();
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
if (error instanceof ImageAttachmentError && error.code === "image-canceled")
|
|
135
|
+
return rejected("image submission canceled");
|
|
136
|
+
return this.#recover(draft, revision, error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
#recover(draft, revision, error) {
|
|
140
|
+
const { root } = this.#ports;
|
|
141
|
+
root.editor.addToHistory(draft);
|
|
142
|
+
this.#ports.promptHistory()?.rememberRecovery(draft);
|
|
143
|
+
// Concurrency: never overwrite input typed (even typed and cleared) after this submission.
|
|
144
|
+
if (revision === this.#editorRevision && root.editor.getText().length === 0)
|
|
145
|
+
root.editor.setText(draft);
|
|
146
|
+
const message = error instanceof ImageAttachmentError ? error.message : "Submission rejected. Check the prompt and attachments.";
|
|
147
|
+
this.reportError(error, error instanceof ImageAttachmentError && error.code === "image-count"
|
|
148
|
+
? message
|
|
149
|
+
: `${message} Press Up to recover the draft.`);
|
|
150
|
+
return rejected(message);
|
|
151
|
+
}
|
|
152
|
+
#rememberInput(text, kind) {
|
|
153
|
+
const { root } = this.#ports;
|
|
154
|
+
root.editor.addToHistory(text);
|
|
155
|
+
const history = this.#ports.promptHistory();
|
|
156
|
+
if (history === null)
|
|
157
|
+
return;
|
|
158
|
+
const reusable = root.prepareHistoryText(text);
|
|
159
|
+
if (reusable.length === 0) {
|
|
160
|
+
history.rememberRecovery(text);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
// Rationale: write the image chip payloads referenced by an editor draft to the sidecar
|
|
164
|
+
// directory before their history row commits. Missing sidecar dependency = silent skip; the
|
|
165
|
+
// recall path treats an absent sidecar the same as a corrupt one.
|
|
166
|
+
const sidecar = this.#ports.imageSidecar();
|
|
167
|
+
if (sidecar !== undefined) {
|
|
168
|
+
for (const record of root.imageChipAttachmentsFromEditor(text)) {
|
|
169
|
+
sidecar.write(record.id, { tag: record.tag, data: record.image.data, mimeType: record.image.mimeType, savedAt: new Date().toISOString() });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
history.capture(reusable, kind, this.#ports.cwd, this.#ports.backend.identity.sessionId);
|
|
173
|
+
}
|
|
174
|
+
async #submit(text) {
|
|
175
|
+
this.#ports.invalidateSuggestions();
|
|
176
|
+
const displayInput = text.trim();
|
|
177
|
+
if (!displayInput)
|
|
178
|
+
return { outcome: "completed", diagnostic: null };
|
|
179
|
+
if (displayInput.startsWith("/"))
|
|
180
|
+
return this.#ports.slashCommand(displayInput);
|
|
181
|
+
const { root, backend } = this.#ports;
|
|
182
|
+
const prepared = root.preparePromptSubmission(displayInput);
|
|
183
|
+
assertPromptImages(prepared.images);
|
|
184
|
+
const input = prepared.text.trim();
|
|
185
|
+
if (input.startsWith("!")) {
|
|
186
|
+
const bash = await this.#bash(input, displayInput);
|
|
187
|
+
if (bash !== undefined)
|
|
188
|
+
return bash;
|
|
189
|
+
}
|
|
190
|
+
// Compatibility: match interactive Pi: input during compaction is queued steering; the engine
|
|
191
|
+
// shows it in the pending rows and delivers it when compaction ends.
|
|
192
|
+
const type = this.#ports.lifecycle() === "busy" ? "steer" : "prompt";
|
|
193
|
+
this.#rememberInput(root.omitUnsentPromptImages(displayInput).trim(), type);
|
|
194
|
+
root.resumeViewportFollowing();
|
|
195
|
+
const command = {
|
|
196
|
+
type,
|
|
197
|
+
correlationId: this.#ports.correlation(type),
|
|
198
|
+
sessionId: backend.identity.sessionId,
|
|
199
|
+
text: input,
|
|
200
|
+
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
201
|
+
};
|
|
202
|
+
let submission;
|
|
203
|
+
try {
|
|
204
|
+
submission = await this.#ports.residentTab.admit({
|
|
205
|
+
sessionId: command.sessionId,
|
|
206
|
+
sessionFile: this.#ports.currentSessionFile(),
|
|
207
|
+
kind: type,
|
|
208
|
+
text: input,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
if (root.editor.getText().length === 0)
|
|
213
|
+
root.editor.setText(displayInput);
|
|
214
|
+
const message = "Prompt was not sent because its recovery journal could not be synchronized.";
|
|
215
|
+
this.reportError(undefined, message);
|
|
216
|
+
return rejected(message);
|
|
217
|
+
}
|
|
218
|
+
const finishSending = prepared.images.length === 0 ? () => { } : root.beginImageSubmissionStatus();
|
|
219
|
+
try {
|
|
220
|
+
const result = await this.execute(command, displayInput);
|
|
221
|
+
if (submission !== undefined && result.outcome !== "rejected") {
|
|
222
|
+
await this.#ports.residentTab.dispatched(submission.id, command.correlationId);
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
finishSending();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Protocol: `!command` runs bash with its output in context, `!!command` keeps it out; an empty command is prompt text.
|
|
231
|
+
async #bash(input, displayInput) {
|
|
232
|
+
const excludeFromContext = input.startsWith("!!");
|
|
233
|
+
const command = input.slice(excludeFromContext ? 2 : 1).trim();
|
|
234
|
+
if (!command)
|
|
235
|
+
return undefined;
|
|
236
|
+
this.#rememberInput(displayInput, "bash");
|
|
237
|
+
try {
|
|
238
|
+
const result = await this.#ports.backend.workflows.executeBashWorkflow(command, excludeFromContext);
|
|
239
|
+
const workflow = {
|
|
240
|
+
command: "debug",
|
|
241
|
+
outcome: result.cancelled ? "cancelled" : result.exitCode === 0 || result.exitCode === undefined ? "completed" : "failed",
|
|
242
|
+
message: result.cancelled ? "Bash command cancelled" : `Bash exited ${result.exitCode ?? 0}: ${command}`,
|
|
243
|
+
...(result.output ? { detail: result.output } : {}),
|
|
244
|
+
};
|
|
245
|
+
this.#ports.root.appendWorkflowResult(workflow);
|
|
246
|
+
this.#ports.terminal.requestRender();
|
|
247
|
+
return workflow.outcome === "failed" ? rejected(workflow.message) : { outcome: "completed", diagnostic: null };
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
const message = `Bash command failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
251
|
+
this.#ports.root.appendWorkflowResult({ command: "debug", outcome: "failed", message });
|
|
252
|
+
this.#ports.terminal.requestRender();
|
|
253
|
+
return rejected(message);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async #queueFollowUp(draft) {
|
|
257
|
+
const { root, backend } = this.#ports;
|
|
258
|
+
const displayInput = draft.trim();
|
|
259
|
+
if (!displayInput)
|
|
260
|
+
return rejected("nothing to queue");
|
|
261
|
+
const prepared = root.preparePromptSubmission(displayInput);
|
|
262
|
+
assertPromptImages(prepared.images);
|
|
263
|
+
const text = prepared.text.trim();
|
|
264
|
+
this.#rememberInput(displayInput, "follow-up");
|
|
265
|
+
if (root.editor.getText() === draft)
|
|
266
|
+
root.editor.setText("");
|
|
267
|
+
root.resumeViewportFollowing();
|
|
268
|
+
return this.execute({
|
|
269
|
+
type: "follow-up",
|
|
270
|
+
correlationId: this.#ports.correlation("follow-up"),
|
|
271
|
+
sessionId: backend.identity.sessionId,
|
|
272
|
+
text,
|
|
273
|
+
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
274
|
+
}, displayInput);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { OwnedUiEvent, PromptHistoryImageSidecarPort } from "../../contracts/owned-ui/index.js";
|
|
2
|
+
import type { SessionConcern } from "./session-concern.js";
|
|
3
|
+
import type { OwnedUiShellEngineOptions, OwnedUiSessionShellRoot } from "./session-shell-root.js";
|
|
4
|
+
export type ResidentTabOptions = NonNullable<OwnedUiShellEngineOptions["residentTab"]>;
|
|
5
|
+
export interface ResidentTabCoordinatorPorts {
|
|
6
|
+
readonly root: Pick<OwnedUiSessionShellRoot, "appendWorkflowStatus" | "rehydrateHistoryText" | "editor">;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The session presenter's side of a resident tab: recovered input, the idle status it reports to
|
|
10
|
+
* the strip, prompt admission and correlation through the recovery journal, draft checkpoints,
|
|
11
|
+
* detach on quit, and the graceful stop when the presenter is released. Outside a resident tab
|
|
12
|
+
* every operation is a no-op.
|
|
13
|
+
*/
|
|
14
|
+
export declare class ResidentTabCoordinator implements SessionConcern {
|
|
15
|
+
#private;
|
|
16
|
+
constructor(options: ResidentTabOptions | undefined, ports: ResidentTabCoordinatorPorts);
|
|
17
|
+
/** True inside a resident tab, where Settings and the session name live in the global strip. */
|
|
18
|
+
get active(): boolean;
|
|
19
|
+
checkpoint(text: string): void;
|
|
20
|
+
closeOwnedRoute(route: string): void;
|
|
21
|
+
/** Puts the prompts and draft a previous tab process left unfinished back into the editor. */
|
|
22
|
+
restoreInput(imageSidecar?: PromptHistoryImageSidecarPort): void;
|
|
23
|
+
/** Reports idle to the strip whenever the session leaves its busy lifecycle. */
|
|
24
|
+
observeLifecycle(event: OwnedUiEvent): void;
|
|
25
|
+
/** Journals a prompt before it is sent; undefined outside a resident tab. Rejects when the journal cannot sync. */
|
|
26
|
+
admit(input: Parameters<NonNullable<ResidentTabOptions["admit"]>>[0]): Promise<{
|
|
27
|
+
readonly id: string;
|
|
28
|
+
} | undefined>;
|
|
29
|
+
/** The admitted prompt reached the engine; its journal entry is correlated with the engine's entry. */
|
|
30
|
+
dispatched(submissionId: string, entryId: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Leaves the tab without stopping its engine. Returns undefined outside a resident tab, true when
|
|
33
|
+
* the client detached, or the notice to show when detaching is unavailable.
|
|
34
|
+
*/
|
|
35
|
+
detach(): Promise<true | string | undefined>;
|
|
36
|
+
gracefulStop(sessionFile: string | null): Promise<void>;
|
|
37
|
+
dispose(): void;
|
|
38
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The session presenter's side of a resident tab: recovered input, the idle status it reports to
|
|
3
|
+
* the strip, prompt admission and correlation through the recovery journal, draft checkpoints,
|
|
4
|
+
* detach on quit, and the graceful stop when the presenter is released. Outside a resident tab
|
|
5
|
+
* every operation is a no-op.
|
|
6
|
+
*/
|
|
7
|
+
export class ResidentTabCoordinator {
|
|
8
|
+
#options;
|
|
9
|
+
#ports;
|
|
10
|
+
constructor(options, ports) {
|
|
11
|
+
this.#options = options;
|
|
12
|
+
this.#ports = ports;
|
|
13
|
+
}
|
|
14
|
+
/** True inside a resident tab, where Settings and the session name live in the global strip. */
|
|
15
|
+
get active() {
|
|
16
|
+
return this.#options !== undefined;
|
|
17
|
+
}
|
|
18
|
+
checkpoint(text) {
|
|
19
|
+
this.#options?.checkpoint?.(text);
|
|
20
|
+
}
|
|
21
|
+
closeOwnedRoute(route) {
|
|
22
|
+
this.#options?.closeOwnedRoute?.(route);
|
|
23
|
+
}
|
|
24
|
+
/** Puts the prompts and draft a previous tab process left unfinished back into the editor. */
|
|
25
|
+
restoreInput(imageSidecar) {
|
|
26
|
+
const recovered = this.#options?.recovered;
|
|
27
|
+
if (recovered === undefined)
|
|
28
|
+
return;
|
|
29
|
+
const { root } = this.#ports;
|
|
30
|
+
const prompts = recovered.prompts
|
|
31
|
+
.map(prompt => root.rehydrateHistoryText(prompt.text, id => imageSidecar?.readAttachment(id) ?? null))
|
|
32
|
+
.filter(Boolean);
|
|
33
|
+
if (prompts.length > 0) {
|
|
34
|
+
root.editor.setText(prompts[0]);
|
|
35
|
+
if (recovered.draft)
|
|
36
|
+
root.editor.addToHistory(recovered.draft);
|
|
37
|
+
for (const additional of prompts.slice(1))
|
|
38
|
+
root.editor.addToHistory(additional);
|
|
39
|
+
root.appendWorkflowStatus(recovered.draft
|
|
40
|
+
? `Recovered an unfinished prompt; the prior draft and ${Math.max(0, prompts.length - 1)} additional prompt${prompts.length === 2 ? "" : "s"} are in editor history.`
|
|
41
|
+
: `Recovered an unfinished prompt${prompts.length > 1 ? `; ${prompts.length - 1} additional prompts are in editor history` : ""}.`);
|
|
42
|
+
}
|
|
43
|
+
else if (recovered.draft) {
|
|
44
|
+
root.editor.setText(recovered.draft);
|
|
45
|
+
root.appendWorkflowStatus("Recovered the editor draft from the previous tab process.");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** Reports idle to the strip whenever the session leaves its busy lifecycle. */
|
|
49
|
+
observeLifecycle(event) {
|
|
50
|
+
if (event.type === "session-lifecycle" && event.lifecycle !== "busy")
|
|
51
|
+
this.#options?.reportStatus?.("idle");
|
|
52
|
+
}
|
|
53
|
+
/** Journals a prompt before it is sent; undefined outside a resident tab. Rejects when the journal cannot sync. */
|
|
54
|
+
admit(input) {
|
|
55
|
+
return this.#options?.admit?.(input) ?? Promise.resolve(undefined);
|
|
56
|
+
}
|
|
57
|
+
/** The admitted prompt reached the engine; its journal entry is correlated with the engine's entry. */
|
|
58
|
+
async dispatched(submissionId, entryId) {
|
|
59
|
+
this.#options?.dispatched?.();
|
|
60
|
+
await this.#options?.correlated?.(submissionId, entryId).catch(() => undefined);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Leaves the tab without stopping its engine. Returns undefined outside a resident tab, true when
|
|
64
|
+
* the client detached, or the notice to show when detaching is unavailable.
|
|
65
|
+
*/
|
|
66
|
+
async detach() {
|
|
67
|
+
const resident = this.#options;
|
|
68
|
+
if (resident === undefined)
|
|
69
|
+
return undefined;
|
|
70
|
+
const detached = await resident.requestDetach().catch(() => false);
|
|
71
|
+
return detached ? true : resident.unavailableNotice ?? "Press Ctrl+C twice to leave; this agent keeps running.";
|
|
72
|
+
}
|
|
73
|
+
gracefulStop(sessionFile) {
|
|
74
|
+
return this.#options?.gracefulStop?.(sessionFile) ?? Promise.resolve();
|
|
75
|
+
}
|
|
76
|
+
dispose() { }
|
|
77
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MAX_COPY_ROWS, MAX_COPY_SOURCE_UNITS, selectionCopyRowText } from "../../ui/components/index.js";
|
|
2
2
|
import { COPY_CHUNK_UNITS, MAX_COPY_BYTES, MAX_COPY_CONTROL_BYTES } from "./response-copy-protocol.js";
|
|
3
|
+
const NATIVE_RETRY_DELAYS_MS = [20, 60];
|
|
3
4
|
// Security: this isolated executor never inherits the UI terminal and never logs clipboard contents.
|
|
4
5
|
let header;
|
|
5
6
|
let fragments = [];
|
|
@@ -24,6 +25,14 @@ function nextOutput() {
|
|
|
24
25
|
send({ kind: "data", text });
|
|
25
26
|
}
|
|
26
27
|
function send(message) { process.send?.(message); }
|
|
28
|
+
function transientClipboardError(error) {
|
|
29
|
+
const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "";
|
|
30
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
31
|
+
return /^(?:EAGAIN|EBUSY)$/iu.test(code) || /(?:busy|locked|contention|temporar|try again)/iu.test(message);
|
|
32
|
+
}
|
|
33
|
+
function delay(milliseconds) {
|
|
34
|
+
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
35
|
+
}
|
|
27
36
|
function finish(result, control) {
|
|
28
37
|
if (finished)
|
|
29
38
|
return;
|
|
@@ -97,13 +106,19 @@ async function receive(message) {
|
|
|
97
106
|
return;
|
|
98
107
|
}
|
|
99
108
|
send({ kind: "phase", phase: "submitting", bytes });
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
for (let attempt = 0; attempt <= NATIVE_RETRY_DELAYS_MS.length; attempt++) {
|
|
110
|
+
try {
|
|
111
|
+
await native.setText(text);
|
|
112
|
+
finish({ outcome: "delivered" });
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (!transientClipboardError(error) || attempt === NATIVE_RETRY_DELAYS_MS.length)
|
|
117
|
+
break;
|
|
118
|
+
await delay(NATIVE_RETRY_DELAYS_MS[attempt]);
|
|
119
|
+
}
|
|
106
120
|
}
|
|
121
|
+
finish({ outcome: "failed", failure: "denied" });
|
|
107
122
|
return;
|
|
108
123
|
}
|
|
109
124
|
else
|
|
@@ -19,7 +19,7 @@ export interface ResponseCopyEvent {
|
|
|
19
19
|
readonly pending: number;
|
|
20
20
|
readonly sourceUnits: number;
|
|
21
21
|
readonly bytes?: number;
|
|
22
|
-
readonly transport?: "native" | "terminal" | "injected";
|
|
22
|
+
readonly transport?: "native" | "terminal" | "platform" | "injected";
|
|
23
23
|
readonly outcome?: CopyOutcome;
|
|
24
24
|
}
|
|
25
25
|
/** One request per helper lifetime. Each source fragment is acknowledged before the next is sent. */
|
|
@@ -7,7 +7,7 @@ export interface ResponseCopyJob {
|
|
|
7
7
|
readonly stopped: Promise<void>;
|
|
8
8
|
cancel(): void;
|
|
9
9
|
}
|
|
10
|
-
export type CopyPhaseObserver = (phase: "extracted" | "encoded" | "submitting", bytes: number, transport: "native" | "terminal" | "injected") => void;
|
|
10
|
+
export type CopyPhaseObserver = (phase: "extracted" | "encoded" | "submitting", bytes: number, transport: "native" | "terminal" | "platform" | "injected") => void;
|
|
11
11
|
export type ResponseCopyExecutor = (snapshot: SelectionCopySnapshot, phase: CopyPhaseObserver) => ResponseCopyJob;
|
|
12
12
|
/** The production executor also holds a spare helper; the owner warms it at start and disposes it at shutdown unless the pool is shared. */
|
|
13
13
|
export interface OwnedResponseCopyExecutor extends ResponseCopyExecutor {
|
|
@@ -22,17 +22,27 @@ export interface ResponseCopyTerminal {
|
|
|
22
22
|
}
|
|
23
23
|
/** Never substitute a remote host's native clipboard for the terminal user's clipboard. */
|
|
24
24
|
export declare function responseCopyDestination(env: NodeJS.ProcessEnv): "native" | "terminal";
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Spawn options for one operating-system clipboard writer.
|
|
27
|
+
* Platform: on POSIX the writer is detached into its own process group, as pinned Pi 1.4 does, so a writer
|
|
28
|
+
* that daemonizes to keep serving the clipboard is not stopped when Ctrl+Z sends SIGTSTP to the shell's group.
|
|
29
|
+
*/
|
|
30
|
+
export declare function platformClipboardWriteOptions(signal: AbortSignal, platform?: NodeJS.Platform): {
|
|
31
|
+
signal: AbortSignal;
|
|
32
|
+
windowsHide: boolean;
|
|
33
|
+
timeout: number;
|
|
34
|
+
killSignal: "SIGKILL";
|
|
35
|
+
maxBuffer: number;
|
|
36
|
+
detached: boolean;
|
|
37
|
+
};
|
|
30
38
|
/** Isolates preparation and native clipboard access; only the owner may submit terminal controls. */
|
|
31
39
|
export declare function createResponseCopyExecutor(options?: {
|
|
32
40
|
readonly terminal?: ResponseCopyTerminal;
|
|
33
41
|
readonly destination?: "native" | "terminal";
|
|
34
42
|
/** Explicit host seam: must be non-blocking and honor cancellation, or its unresolved lifetime is quarantined. */
|
|
35
43
|
readonly writeText?: (text: string, signal: AbortSignal) => Promise<void>;
|
|
44
|
+
/** Platform/fault-test seam; production writes through the supported operating-system command. */
|
|
45
|
+
readonly platformWriteText?: (text: string, signal: AbortSignal) => Promise<boolean>;
|
|
36
46
|
/** Package/fault-test seam: the production helper is always an emitted sibling. */
|
|
37
47
|
readonly helper?: URL;
|
|
38
48
|
/** Idle bound for the spare helper; production keeps the default. */
|
|
@@ -1,25 +1,67 @@
|
|
|
1
|
-
import { fork } from "node:child_process";
|
|
2
|
-
import { fstatSync } from "node:fs";
|
|
1
|
+
import { execFile, fork } from "node:child_process";
|
|
3
2
|
import { HelperPool } from "./helper-pool.js";
|
|
3
|
+
import { PRODUCT_IDENTITY } from "../../product-identity.js";
|
|
4
4
|
import { COPY_CHUNK_UNITS, COPY_CLEANUP_MS, MAX_COPY_BYTES, MAX_COPY_CONTROL_BYTES } from "./response-copy-protocol.js";
|
|
5
|
+
const PLATFORM_WRITE_TIMEOUT_MS = 1_500;
|
|
5
6
|
/** Never substitute a remote host's native clipboard for the terminal user's clipboard. */
|
|
6
7
|
export function responseCopyDestination(env) {
|
|
7
|
-
return env.SSH_CONNECTION || env.SSH_CLIENT || env.SSH_TTY || env.TMUX || env.STY || env.WSL_DISTRO_NAME
|
|
8
|
+
return env[PRODUCT_IDENTITY.environment.tabId] || env.SSH_CONNECTION || env.SSH_CLIENT || env.SSH_TTY || env.TMUX || env.STY || env.WSL_DISTRO_NAME
|
|
8
9
|
? "terminal" : "native";
|
|
9
10
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
function platformClipboardCommands() {
|
|
12
|
+
if (process.platform === "win32")
|
|
13
|
+
return [{
|
|
14
|
+
command: "powershell.exe",
|
|
15
|
+
args: ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", "$value=[Console]::In.ReadToEnd(); Set-Clipboard -Value $value"],
|
|
16
|
+
}];
|
|
17
|
+
if (process.platform === "darwin")
|
|
18
|
+
return [{ command: "pbcopy", args: [] }];
|
|
19
|
+
return [
|
|
20
|
+
{ command: "wl-copy", args: ["--type", "text/plain;charset=utf-8"] },
|
|
21
|
+
{ command: "xclip", args: ["-selection", "clipboard", "-in"] },
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Spawn options for one operating-system clipboard writer.
|
|
26
|
+
* Platform: on POSIX the writer is detached into its own process group, as pinned Pi 1.4 does, so a writer
|
|
27
|
+
* that daemonizes to keep serving the clipboard is not stopped when Ctrl+Z sends SIGTSTP to the shell's group.
|
|
28
|
+
*/
|
|
29
|
+
export function platformClipboardWriteOptions(signal, platform = process.platform) {
|
|
30
|
+
return {
|
|
31
|
+
signal,
|
|
32
|
+
windowsHide: true,
|
|
33
|
+
timeout: PLATFORM_WRITE_TIMEOUT_MS,
|
|
34
|
+
killSignal: "SIGKILL",
|
|
35
|
+
maxBuffer: 1_024,
|
|
36
|
+
detached: platform !== "win32",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async function writePlatformClipboardText(text, signal) {
|
|
40
|
+
for (const route of platformClipboardCommands()) {
|
|
41
|
+
if (signal.aborted)
|
|
42
|
+
return false;
|
|
43
|
+
const delivered = await new Promise(resolve => {
|
|
44
|
+
let settled = false;
|
|
45
|
+
const done = (value) => {
|
|
46
|
+
if (settled)
|
|
47
|
+
return;
|
|
48
|
+
settled = true;
|
|
49
|
+
resolve(value);
|
|
50
|
+
};
|
|
51
|
+
const child = execFile(route.command, [...route.args], platformClipboardWriteOptions(signal), error => done(error === null));
|
|
52
|
+
child.once("error", () => done(false));
|
|
53
|
+
if (child.stdin === null) {
|
|
54
|
+
child.kill("SIGKILL");
|
|
55
|
+
done(false);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
child.stdin.once("error", () => { child.kill("SIGKILL"); done(false); });
|
|
59
|
+
child.stdin.end(text);
|
|
60
|
+
});
|
|
61
|
+
if (delivered)
|
|
62
|
+
return true;
|
|
22
63
|
}
|
|
64
|
+
return false;
|
|
23
65
|
}
|
|
24
66
|
/** Isolates preparation and native clipboard access; only the owner may submit terminal controls. */
|
|
25
67
|
export function createResponseCopyExecutor(options = {}) {
|
|
@@ -43,8 +85,18 @@ export function createResponseCopyExecutor(options = {}) {
|
|
|
43
85
|
};
|
|
44
86
|
let outcome = await execute(destination);
|
|
45
87
|
// Concurrency: helper results settle only after exit; fallback cannot race an older native write.
|
|
46
|
-
if (!controller.signal.aborted && destination === "native" && outcome.result.
|
|
47
|
-
|
|
88
|
+
if (!controller.signal.aborted && destination === "native" && outcome.result.outcome === "failed") {
|
|
89
|
+
const prepared = await execute("prepare");
|
|
90
|
+
if (prepared.result.outcome === "delivered" && prepared.text !== undefined) {
|
|
91
|
+
phase("submitting", prepared.bytes ?? 0, "platform");
|
|
92
|
+
const delivered = await (options.platformWriteText ?? writePlatformClipboardText)(prepared.text, controller.signal);
|
|
93
|
+
outcome = { kind: "result", result: delivered ? { outcome: "delivered" } : { outcome: "failed", failure: "unavailable" } };
|
|
94
|
+
}
|
|
95
|
+
else
|
|
96
|
+
outcome = { kind: "result", result: { outcome: "failed", failure: "transport" } };
|
|
97
|
+
if (!controller.signal.aborted && outcome.result.outcome === "failed" && options.terminal !== undefined) {
|
|
98
|
+
outcome = await execute("terminal");
|
|
99
|
+
}
|
|
48
100
|
}
|
|
49
101
|
if (controller.signal.aborted)
|
|
50
102
|
return { outcome: "canceled" };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One piece of a session presenter's state that resets itself when the backend replaces the
|
|
3
|
+
* session and releases itself when the presenter is released.
|
|
4
|
+
*/
|
|
5
|
+
export interface SessionConcern {
|
|
6
|
+
/** The backend replaced the session: drop the pending work, timers, and surfaces that belonged to it. */
|
|
7
|
+
onSessionReplaced?(): void;
|
|
8
|
+
/** Release everything this concern holds; called at most once. */
|
|
9
|
+
dispose?(): void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The presenter's concerns in their declared order. Session replacement and disposal fan out in
|
|
13
|
+
* that order, because later resets depend on earlier ones (copy intent before pastes before the
|
|
14
|
+
* input surface), and disposal is idempotent.
|
|
15
|
+
*/
|
|
16
|
+
export declare class SessionConcerns {
|
|
17
|
+
#private;
|
|
18
|
+
constructor(concerns: readonly SessionConcern[]);
|
|
19
|
+
replaceSession(): void;
|
|
20
|
+
/** Disposes each concern once, through `attempt` so one failure does not skip the rest. */
|
|
21
|
+
dispose(attempt?: (action: () => void) => void): void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The presenter's concerns in their declared order. Session replacement and disposal fan out in
|
|
3
|
+
* that order, because later resets depend on earlier ones (copy intent before pastes before the
|
|
4
|
+
* input surface), and disposal is idempotent.
|
|
5
|
+
*/
|
|
6
|
+
export class SessionConcerns {
|
|
7
|
+
#concerns;
|
|
8
|
+
#disposed = false;
|
|
9
|
+
constructor(concerns) {
|
|
10
|
+
this.#concerns = concerns;
|
|
11
|
+
}
|
|
12
|
+
replaceSession() {
|
|
13
|
+
if (this.#disposed)
|
|
14
|
+
return;
|
|
15
|
+
for (const concern of this.#concerns)
|
|
16
|
+
concern.onSessionReplaced?.();
|
|
17
|
+
}
|
|
18
|
+
/** Disposes each concern once, through `attempt` so one failure does not skip the rest. */
|
|
19
|
+
dispose(attempt = action => action()) {
|
|
20
|
+
if (this.#disposed)
|
|
21
|
+
return;
|
|
22
|
+
this.#disposed = true;
|
|
23
|
+
for (const concern of this.#concerns) {
|
|
24
|
+
const dispose = concern.dispose;
|
|
25
|
+
if (dispose !== undefined)
|
|
26
|
+
attempt(() => dispose.call(concern));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|