@timurproko/a1 0.1.8-dev.235df0e → 0.1.8-dev.259
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -67
- package/bin/cli.js +28 -10
- package/bin/guardian.js +8 -3
- package/bin/module-identity.js +69 -35
- package/bin/pi-tui.d.ts +6 -0
- package/bin/pi-tui.js +28 -0
- package/bin/release-cleanup.js +8 -0
- package/bin/supervisor.js +2 -2
- package/bin/sync-pi-tui-proxy.js +97 -0
- package/bin/ui.js +47 -20
- package/bin/warmup.js +27 -0
- package/dist/cli/capabilities.d.ts +6 -0
- package/dist/{src/cli → cli}/capabilities.js +1 -1
- package/dist/{src/cli → cli}/dispatch.d.ts +15 -1
- package/dist/cli/dispatch.js +261 -0
- package/dist/cli/package-messages.d.ts +26 -0
- package/dist/cli/package-messages.js +71 -0
- package/dist/{src/cli → cli}/packages.d.ts +11 -2
- package/dist/{src/cli → cli}/packages.js +24 -27
- package/dist/{src/cli → cli}/version-stats.d.ts +6 -0
- package/dist/cli/version-stats.js +112 -0
- package/dist/composition/agent-engine-bridge.d.ts +3 -0
- package/dist/composition/agent-engine-bridge.js +108 -0
- package/dist/composition/index.d.ts +3 -0
- package/dist/composition/index.js +3 -0
- package/dist/composition/owned-ui.d.ts +31 -0
- package/dist/composition/owned-ui.js +66 -0
- package/dist/composition/process.d.ts +16 -0
- package/dist/composition/process.js +45 -0
- package/dist/composition/settings-route-host.d.ts +8 -0
- package/dist/composition/settings-route-host.js +75 -0
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.d.ts +2 -2
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.js +22 -4
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.d.ts +17 -0
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.d.ts +6 -0
- package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.d.ts +36 -0
- package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.js +25 -0
- package/dist/{src/features → features}/launch/development-launch.js +11 -3
- package/dist/{src/features → features}/launch/index.d.ts +0 -1
- package/dist/{src/features → features}/launch/index.js +0 -1
- package/dist/features/launch/intent.d.ts +10 -0
- package/dist/features/launch/intent.js +8 -0
- package/dist/{src/features → features}/launch/prepare-launch.d.ts +0 -2
- package/dist/{src/features → features}/launch/prepare-launch.js +2 -9
- package/dist/{src/features → features}/launch/profile-paths.d.ts +1 -2
- package/dist/{src/features → features}/launch/profile-paths.js +2 -8
- package/dist/{src/features → features}/launch/runtime-selection.d.ts +2 -5
- package/dist/{src/features → features}/owned-ui/customization.d.ts +3 -1
- package/dist/{src/features → features}/owned-ui/customization.js +3 -1
- package/dist/{src/features → features}/owned-ui/diagnostics.d.ts +2 -1
- package/dist/{src/features → features}/owned-ui/diagnostics.js +1 -0
- package/dist/{src/features → features}/owned-ui/index.d.ts +2 -0
- package/dist/{src/features → features}/owned-ui/index.js +2 -0
- package/dist/features/owned-ui/project-trust-prompt.d.ts +25 -0
- package/dist/features/owned-ui/project-trust-prompt.js +149 -0
- package/dist/{src/features → features}/owned-ui/run.d.ts +2 -2
- package/dist/{src/features → features}/owned-ui/run.js +2 -0
- package/dist/features/owned-ui/session-fork-prompt.d.ts +8 -0
- package/dist/features/owned-ui/session-fork-prompt.js +34 -0
- package/dist/{src/features → features}/owned-ui/settings-app.d.ts +3 -3
- package/dist/{src/features → features}/owned-ui/settings-app.js +103 -54
- package/dist/{src/features → features}/workspace/capabilities.d.ts +1 -1
- package/dist/{src/features → features}/workspace/reducer.d.ts +2 -1
- package/dist/{src/features → features}/workspace/reducer.js +2 -1
- package/dist/{src/features → features}/workspace/router.d.ts +2 -1
- package/dist/{src/features → features}/workspace/router.js +1 -0
- package/dist/{src/features → features}/workspace/store.d.ts +2 -1
- package/dist/{src/features → features}/workspace/store.js +1 -0
- package/dist/{src/foundation → foundation}/launch-guardian/main.d.ts +2 -0
- package/dist/{src/foundation → foundation}/launch-guardian/main.js +18 -5
- package/dist/{src/foundation → foundation}/lifecycle/index.d.ts +2 -0
- package/dist/{src/foundation → foundation}/lifecycle/index.js +2 -0
- package/dist/{src/foundation → foundation}/lifecycle/model.d.ts +1 -1
- package/dist/{src/foundation → foundation}/lifecycle/model.js +1 -1
- package/dist/foundation/lifecycle/paths.d.ts +30 -0
- package/dist/{src/foundation → foundation}/lifecycle/paths.js +29 -1
- package/dist/foundation/lifecycle/session-selection.d.ts +9 -0
- package/dist/foundation/lifecycle/session-selection.js +39 -0
- package/dist/foundation/lifecycle/supervisor-startup.d.ts +30 -0
- package/dist/foundation/lifecycle/supervisor-startup.js +106 -0
- package/dist/{src/foundation → foundation}/native-host-protocol/codec.d.ts +2 -0
- package/dist/{src/foundation → foundation}/native-host-protocol/codec.js +2 -0
- package/dist/{src/foundation → foundation}/native-host-protocol/messages.d.ts +1 -1
- package/dist/{src/foundation → foundation}/native-host-protocol/messages.js +1 -1
- package/dist/foundation/process-containment/darwin-process-inspector.d.ts +5 -0
- package/dist/foundation/process-containment/darwin-process-inspector.js +7 -0
- package/dist/{src/foundation → foundation}/process-containment/index.d.ts +1 -0
- package/dist/{src/foundation → foundation}/process-containment/index.js +1 -0
- package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.d.ts +1 -0
- package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.js +1 -0
- package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.d.ts +1 -0
- package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.js +1 -0
- package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.d.ts +3 -1
- package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.js +5 -2
- package/dist/{src/foundation → foundation}/protocol/client.d.ts +1 -0
- package/dist/{src/foundation → foundation}/protocol/client.js +1 -0
- package/dist/{src/foundation → foundation}/protocol/messages.d.ts +1 -0
- package/dist/{src/foundation → foundation}/protocol/messages.js +1 -0
- package/dist/{src/foundation → foundation}/release/bootstrap.d.ts +23 -6
- package/dist/{src/foundation → foundation}/release/bootstrap.js +120 -34
- package/dist/foundation/release/cohort-state.d.ts +156 -0
- package/dist/foundation/release/cohort-state.js +471 -0
- package/dist/foundation/release/dependency-layer.d.ts +78 -0
- package/dist/foundation/release/dependency-layer.js +488 -0
- package/dist/foundation/release/endpoints.d.ts +20 -0
- package/dist/foundation/release/endpoints.js +50 -0
- package/dist/foundation/release/immutable-platform.d.ts +6 -0
- package/dist/foundation/release/immutable-platform.js +13 -0
- package/dist/{src/foundation → foundation}/release/index.d.ts +4 -0
- package/dist/{src/foundation → foundation}/release/index.js +4 -0
- package/dist/foundation/release/release-gc.d.ts +71 -0
- package/dist/foundation/release/release-gc.js +734 -0
- package/dist/{src/foundation → foundation}/release/release-store.d.ts +4 -2
- package/dist/{src/foundation → foundation}/release/release-store.js +64 -12
- package/dist/{src/foundation → foundation}/release/release.d.ts +4 -1
- package/dist/{src/foundation → foundation}/release/release.js +10 -3
- package/dist/foundation/release/restart-certification.d.ts +67 -0
- package/dist/foundation/release/restart-certification.js +211 -0
- package/dist/{src/foundation → foundation}/release/update-transaction.d.ts +1 -0
- package/dist/{src/foundation → foundation}/release/update-transaction.js +1 -0
- package/dist/{src/foundation → foundation}/release/update.d.ts +19 -3
- package/dist/{src/foundation → foundation}/release/update.js +116 -56
- package/dist/foundation/release/warmup.d.ts +3 -0
- package/dist/foundation/release/warmup.js +35 -0
- package/dist/foundation/startup/index.d.ts +1 -0
- package/dist/foundation/startup/index.js +1 -0
- package/dist/foundation/startup/startup-runtime.d.ts +36 -0
- package/dist/foundation/startup/startup-runtime.js +140 -0
- package/dist/{src/foundation → foundation}/storage/control-store.d.ts +2 -1
- package/dist/{src/foundation → foundation}/storage/control-store.js +39 -4
- package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.js +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.js +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.d.ts +1 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.js +1 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.js +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/state.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/state.js +2 -1
- package/dist/foundation/supervision/index.d.ts +3 -0
- package/dist/foundation/supervision/index.js +3 -0
- package/dist/foundation/supervision/main.d.ts +1 -0
- package/dist/foundation/supervision/main.js +77 -0
- package/dist/foundation/supervision/paths.d.ts +1 -0
- package/dist/foundation/supervision/paths.js +1 -0
- package/dist/{src/foundation → foundation}/supervision/server.d.ts +19 -1
- package/dist/{src/foundation → foundation}/supervision/server.js +65 -3
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.d.ts +1 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.d.ts +1 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.js +3 -2
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.d.ts +1 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.js +1 -1
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +55 -0
- package/dist/integrations/pi/components/owned-editor-ux.js +778 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.d.ts +1 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.js +1 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-editor-autocomplete.js +54 -6
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.d.ts +1 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.d.ts +3 -3
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.js +49 -18
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +36 -0
- package/dist/integrations/pi/components/shell-presenters-info.js +78 -0
- package/dist/integrations/pi/components/shell-presenters-transcript.d.ts +25 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-presenters-transcript.js +92 -131
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.d.ts +5 -2
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.js +2 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.d.ts +57 -8
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.js +4 -2
- package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +13 -0
- package/dist/integrations/pi/components/submitted-prompt-adapter.js +27 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.d.ts +10 -2
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.js +36 -3
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.d.ts +1 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.d.ts +28 -4
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.js +714 -127
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.d.ts +2 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.js +4 -2
- package/dist/integrations/pi/engine/http-dispatcher.d.ts +4 -0
- package/dist/integrations/pi/engine/http-dispatcher.js +25 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.d.ts +4 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.js +4 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.d.ts +2 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.js +1 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.d.ts +1 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.js +32 -26
- package/dist/integrations/pi/engine/project-trust-preflight.d.ts +22 -0
- package/dist/integrations/pi/engine/project-trust-preflight.js +50 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.d.ts +2 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.js +1 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.d.ts +19 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.js +47 -5
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.d.ts +4 -2
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.js +19 -4
- package/dist/integrations/pi/engine/session-selection.d.ts +28 -0
- package/dist/integrations/pi/engine/session-selection.js +90 -0
- package/dist/integrations/pi/engine/settings-effects.d.ts +66 -0
- package/dist/integrations/pi/engine/settings-effects.js +249 -0
- package/dist/integrations/pi/engine/settings-integration.d.ts +43 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/settings-integration.js +102 -108
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.d.ts +3 -2
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.js +1 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.d.ts +18 -1
- package/dist/integrations/pi/session-ui/clipboard-image.d.ts +11 -0
- package/dist/integrations/pi/session-ui/clipboard-image.js +29 -0
- package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/index.d.ts +1 -0
- package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/index.js +1 -0
- package/dist/integrations/pi/session-ui/prompt-chips.d.ts +23 -0
- package/dist/integrations/pi/session-ui/prompt-chips.js +246 -0
- package/dist/integrations/pi/session-ui/route-host.d.ts +5 -0
- package/dist/integrations/pi/session-ui/session-shell-root.d.ts +141 -0
- package/dist/integrations/pi/session-ui/session-shell-root.js +1158 -0
- package/dist/integrations/pi/session-ui/session-shell.d.ts +55 -0
- package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/session-shell.js +479 -719
- package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +45 -0
- package/dist/integrations/pi/session-ui/session-viewport-controller.js +463 -0
- package/dist/integrations/pi/session-ui/stream-presentation-coalescer.d.ts +29 -0
- package/dist/integrations/pi/session-ui/stream-presentation-coalescer.js +79 -0
- package/dist/integrations/pi/session-ui/system-clipboard.d.ts +20 -0
- package/dist/integrations/pi/session-ui/system-clipboard.js +130 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.d.ts +8 -1
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.js +216 -9
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/contracts.d.ts +29 -6
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +74 -0
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +380 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/index.d.ts +2 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/index.js +2 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +39 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.js +139 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.d.ts +1 -1
- package/dist/native/darwin-arm64/manifest.json +4 -4
- package/dist/native/darwin-arm64/process-guardian +0 -0
- package/dist/native/linux-x64/manifest.json +3 -3
- package/dist/native/linux-x64/process-guardian +0 -0
- package/dist/native/win32-x64/manifest.json +3 -3
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/{src/product-identity.d.ts → product-identity.d.ts} +3 -3
- package/dist/{src/product-identity.js → product-identity.js} +7 -5
- package/dist/{src/product-identity.json → product-identity.json} +11 -6
- package/dist/runtime-payload-inventory.json +122328 -0
- package/dist/{src/foundation/ui-apps → ui/apps}/contracts.d.ts +23 -1
- package/dist/{src/foundation/ui-apps → ui/apps}/host.d.ts +1 -1
- package/dist/{src/foundation/ui-apps → ui/apps}/host.js +14 -10
- package/dist/{src/foundation/ui-apps → ui/apps}/registry.d.ts +1 -0
- package/dist/{src/foundation/ui-apps → ui/apps}/registry.js +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.js +5 -3
- package/dist/{src/foundation/ui-components → ui/components}/frame.d.ts +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/frame.js +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/index.d.ts +5 -0
- package/dist/{src/foundation/ui-components → ui/components}/index.js +5 -0
- package/dist/{src/foundation/ui-components → ui/components}/line-input.d.ts +1 -6
- package/dist/{src/foundation/ui-components → ui/components}/line-input.js +4 -9
- package/dist/{src/foundation/ui-components → ui/components}/list-view.d.ts +0 -6
- package/dist/{src/foundation/ui-components → ui/components}/list-view.js +14 -7
- package/dist/{src/foundation/ui-components → ui/components}/mouse.d.ts +10 -0
- package/dist/{src/foundation/ui-components → ui/components}/mouse.js +23 -0
- package/dist/ui/components/progress-status.d.ts +2 -0
- package/dist/ui/components/progress-status.js +4 -0
- package/dist/ui/components/prompt-row.d.ts +14 -0
- package/dist/ui/components/prompt-row.js +20 -0
- package/dist/{src/foundation/ui-components → ui/components}/scrollbar.d.ts +26 -0
- package/dist/{src/foundation/ui-components → ui/components}/scrollbar.js +35 -0
- package/dist/{src/foundation/ui-components → ui/components}/shortcuts.d.ts +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/shortcuts.js +1 -0
- package/dist/ui/components/spans.d.ts +25 -0
- package/dist/ui/components/spans.js +257 -0
- package/dist/ui/components/submitted-prompt.d.ts +23 -0
- package/dist/ui/components/submitted-prompt.js +50 -0
- package/dist/{src/foundation/ui-components → ui/components}/surface.d.ts +0 -5
- package/dist/{src/foundation/ui-components → ui/components}/surface.js +1 -5
- package/dist/ui/components/text-selection.d.ts +62 -0
- package/dist/ui/components/text-selection.js +208 -0
- package/dist/{src/foundation/ui-components → ui/components}/text.d.ts +14 -0
- package/dist/{src/foundation/ui-components → ui/components}/text.js +66 -4
- package/dist/ui/components/transcript-viewport.d.ts +152 -0
- package/dist/ui/components/transcript-viewport.js +631 -0
- package/dist/ui/components/visible-hyperlinks.d.ts +19 -0
- package/dist/ui/components/visible-hyperlinks.js +64 -0
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/declarations.d.ts +8 -1
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/declarations.js +33 -5
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.d.ts +1 -1
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.js +21 -2
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.d.ts +6 -19
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.js +32 -23
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/session.d.ts +9 -17
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/session.js +65 -55
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.d.ts +1 -0
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.js +2 -1
- package/docs/architecture/boundaries.md +9 -9
- package/docs/architecture/code-documentation.md +77 -0
- package/docs/architecture/process-guardian-provenance.md +3 -1
- package/docs/architecture/project-structure.md +67 -30
- package/docs/architecture/resource-and-data-policy.md +1 -1
- package/docs/architecture/toolchain.md +10 -10
- package/docs/architecture/ui-reference-provenance.md +36 -5
- package/docs/ci-release-runbook.md +186 -79
- package/docs/features/launch-profiles.md +24 -17
- package/docs/manual-ghost-link-baseline.md +89 -0
- package/docs/manual-launch-instance-acceptance.md +12 -35
- package/docs/manual-owned-ui-checkpoint.md +78 -0
- package/docs/manual-pi-boundary-candidate.md +4 -5
- package/docs/manual-terminal-colour-check.md +4 -3
- package/docs/repository-governance-live-acceptance.md +77 -0
- package/package.json +37 -27
- package/dist/src/cli/capabilities.d.ts +0 -15
- package/dist/src/cli/dispatch.js +0 -177
- package/dist/src/cli/version-stats.js +0 -72
- package/dist/src/composition/index.d.ts +0 -48
- package/dist/src/composition/index.js +0 -258
- package/dist/src/features/launch/intent.d.ts +0 -7
- package/dist/src/features/launch/intent.js +0 -4
- package/dist/src/features/launch/profiles.d.ts +0 -12
- package/dist/src/features/launch/profiles.js +0 -26
- package/dist/src/foundation/lifecycle/paths.d.ts +0 -10
- package/dist/src/foundation/pi-component-adapter/shell-presenters-transcript.d.ts +0 -57
- package/dist/src/foundation/pi-engine-adapter/settings-integration.d.ts +0 -55
- package/dist/src/foundation/pi-owned-ui-integration/route-host.d.ts +0 -29
- package/dist/src/foundation/pi-owned-ui-integration/session-shell.d.ts +0 -106
- package/dist/src/foundation/release/cohort-state.d.ts +0 -70
- package/dist/src/foundation/release/cohort-state.js +0 -202
- package/dist/src/foundation/release/release-gc.d.ts +0 -5
- package/dist/src/foundation/release/release-gc.js +0 -16
- package/dist/src/foundation/supervision/index.d.ts +0 -3
- package/dist/src/foundation/supervision/index.js +0 -3
- package/dist/src/foundation/supervision/main.d.ts +0 -1
- package/dist/src/foundation/supervision/main.js +0 -41
- package/dist/src/foundation/supervision/paths.d.ts +0 -1
- package/dist/src/foundation/supervision/paths.js +0 -1
- package/dist/src/foundation/ui-components/spans.d.ts +0 -7
- package/dist/src/foundation/ui-components/spans.js +0 -59
- package/docs/manual-transparent-checkpoint.md +0 -53
- /package/dist/{src/cli → cli}/index.d.ts +0 -0
- /package/dist/{src/cli → cli}/index.js +0 -0
- /package/dist/{src/cli → cli}/version.d.ts +0 -0
- /package/dist/{src/cli → cli}/version.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/index.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/index.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.d.ts +0 -0
- /package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.d.ts +0 -0
- /package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.js +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.d.ts +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.js +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.d.ts +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.js +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.d.ts +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.js +0 -0
- /package/dist/{src/features → features}/launch/development-launch.d.ts +0 -0
- /package/dist/{src/features → features}/launch/initialize-profile.d.ts +0 -0
- /package/dist/{src/features → features}/launch/initialize-profile.js +0 -0
- /package/dist/{src/features → features}/launch/runtime-selection.js +0 -0
- /package/dist/{src/features → features}/workspace/capabilities.js +0 -0
- /package/dist/{src/features → features}/workspace/index.d.ts +0 -0
- /package/dist/{src/features → features}/workspace/index.js +0 -0
- /package/dist/{src/features → features}/workspace/presentation.d.ts +0 -0
- /package/dist/{src/features → features}/workspace/presentation.js +0 -0
- /package/dist/{src/features → features}/workspace/reconciliation.d.ts +0 -0
- /package/dist/{src/features → features}/workspace/reconciliation.js +0 -0
- /package/dist/{src/foundation → foundation}/launch-guardian/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/launch-guardian/index.js +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/commands.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/commands.js +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.js +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.js +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/index.js +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.js +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/artifact.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/artifact.js +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/contracts.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/contracts.js +0 -0
- /package/dist/{src/foundation → foundation}/protocol/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/protocol/index.js +0 -0
- /package/dist/{src/foundation → foundation}/release/cohort-selection.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/cohort-selection.js +0 -0
- /package/dist/{src/foundation → foundation}/release/concurrency.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/concurrency.js +0 -0
- /package/dist/{src/foundation → foundation}/release/process-cleanup.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/process-cleanup.js +0 -0
- /package/dist/{src/foundation → foundation}/release/stable-release.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/stable-release.js +0 -0
- /package/dist/{src/foundation → foundation}/storage/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/storage/index.js +0 -0
- /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-editor-autocomplete.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/earendil-announcement.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/earendil-announcement.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/owned-editor.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/owned-editor.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.js +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/pi-settings-metadata.json +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.d.ts +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.js +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.js +0 -0
- /package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/route-host.js +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.d.ts +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.js +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/contracts.js +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.js +0 -0
- /package/dist/{src/foundation/ui-apps → ui/apps}/contracts.js +0 -0
- /package/dist/{src/foundation/ui-apps → ui/apps}/index.d.ts +0 -0
- /package/dist/{src/foundation/ui-apps → ui/apps}/index.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/label.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/label.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/list-block.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/list-block.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/pane.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/pane.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/revision.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/revision.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/status-line.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/status-line.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/stepper.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/stepper.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/theme.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/theme.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/value-menu.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/value-menu.js +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.js +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.js +0 -0
package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/session-shell.js
RENAMED
|
@@ -1,668 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
#view;
|
|
13
|
-
#status;
|
|
14
|
-
#footer;
|
|
15
|
-
#queued;
|
|
16
|
-
#extensionRenderers;
|
|
17
|
-
#componentRuntime;
|
|
18
|
-
#toolsExpanded = false;
|
|
19
|
-
#thinkingVisible = true;
|
|
20
|
-
#workflowTranscriptSequence = 0;
|
|
21
|
-
#workflowStatusAnchors = new Map();
|
|
22
|
-
#workflowStatusMessages = new Map();
|
|
23
|
-
#lastWorkflowStatusId;
|
|
24
|
-
#inputSurface;
|
|
25
|
-
#extensionHeader = null;
|
|
26
|
-
#extensionFooter = null;
|
|
27
|
-
#extensionWidgets = new Map();
|
|
28
|
-
#extensionStatuses = new Map();
|
|
29
|
-
#extensionWorkingMessage;
|
|
30
|
-
#extensionWorkingVisible = true;
|
|
31
|
-
constructor(view, cwd, handlers, startup = {}, agentDir, extensionRenderers = {
|
|
32
|
-
getMessageRenderer: () => undefined,
|
|
33
|
-
getToolDefinition: () => undefined,
|
|
34
|
-
}) {
|
|
35
|
-
this.#view = view;
|
|
36
|
-
this.#cwd = cwd;
|
|
37
|
-
this.#extensionRenderers = extensionRenderers;
|
|
38
|
-
this.#componentRuntime = handlers;
|
|
39
|
-
this.header = createPiShellHeader(startup);
|
|
40
|
-
this.resources = createPiShellLoadedResources(startup.resources ?? [], startup.expanded ?? false);
|
|
41
|
-
this.#status = createPiShellStatus(view, handlers);
|
|
42
|
-
this.#footer = createPiShellFooter(this.#viewWithExtensionStatuses(view), cwd);
|
|
43
|
-
this.#queued = createPiQueuedInputStatus(view.editor.queuedSubmissions);
|
|
44
|
-
this.editor = createPiShellEditor({
|
|
45
|
-
...handlers,
|
|
46
|
-
cwd,
|
|
47
|
-
...(agentDir === undefined ? {} : { agentDir }),
|
|
48
|
-
onToolsExpand: () => this.#setToolsExpanded(!this.#toolsExpanded),
|
|
49
|
-
});
|
|
50
|
-
this.editor.setThinkingLevel(view.thinkingLevel);
|
|
51
|
-
this.#inputSurface = this.editor;
|
|
52
|
-
for (const block of view.transcript) {
|
|
53
|
-
if (block.kind === "user")
|
|
54
|
-
this.editor.addToHistory(block.text);
|
|
55
|
-
}
|
|
56
|
-
this.#syncTranscript(view.transcript);
|
|
57
|
-
}
|
|
58
|
-
update(view) {
|
|
59
|
-
this.#view = view;
|
|
60
|
-
this.#status.update(view);
|
|
61
|
-
this.#footer.update(this.#viewWithExtensionStatuses(view));
|
|
62
|
-
this.#queued.update(view.editor.queuedSubmissions);
|
|
63
|
-
this.#syncTranscript(view.transcript);
|
|
64
|
-
this.editor.setSubmitEnabled(view.lifecycle !== "stopping" && view.lifecycle !== "stopped" && view.lifecycle !== "failed");
|
|
65
|
-
this.editor.setThinkingLevel(view.thinkingLevel);
|
|
66
|
-
this.invalidate();
|
|
67
|
-
}
|
|
68
|
-
render(width) {
|
|
69
|
-
const queued = this.#view.editor.queuedSubmissions.length === 0 ? [] : this.#queued.render(width);
|
|
70
|
-
return [
|
|
71
|
-
...this.#renderDocument(width),
|
|
72
|
-
...queued,
|
|
73
|
-
...this.#renderStatus(width),
|
|
74
|
-
...this.#renderWidgets("aboveEditor", width),
|
|
75
|
-
...this.#inputSurface.render(width),
|
|
76
|
-
...this.#renderWidgets("belowEditor", width),
|
|
77
|
-
...this.#renderFooter(width),
|
|
78
|
-
];
|
|
79
|
-
}
|
|
80
|
-
layoutRoot() {
|
|
81
|
-
const document = layoutPort(width => this.#renderDocument(width), () => this.invalidate());
|
|
82
|
-
const queued = layoutPort(width => this.#view.editor.queuedSubmissions.length === 0 ? [] : this.#queued.render(width), () => this.#queued.invalidate());
|
|
83
|
-
const aboveWidgets = layoutPort(width => this.#renderWidgets("aboveEditor", width), () => this.#invalidateExtensions());
|
|
84
|
-
const status = layoutPort(width => this.#renderStatus(width), () => this.#status.invalidate());
|
|
85
|
-
const editor = layoutPort(width => this.#inputSurface.render(width), () => this.#inputSurface.invalidate(), data => this.#inputSurface.handleInput?.(data));
|
|
86
|
-
const belowWidgets = layoutPort(width => this.#renderWidgets("belowEditor", width), () => this.#invalidateExtensions());
|
|
87
|
-
const footer = layoutPort(width => this.#renderFooter(width), () => (this.#extensionFooter ?? this.#footer).invalidate());
|
|
88
|
-
return {
|
|
89
|
-
type: "stack",
|
|
90
|
-
direction: "vertical",
|
|
91
|
-
children: [
|
|
92
|
-
{
|
|
93
|
-
basis: 0,
|
|
94
|
-
grow: 1,
|
|
95
|
-
shrink: 1,
|
|
96
|
-
minSize: 1,
|
|
97
|
-
node: {
|
|
98
|
-
type: "scroll",
|
|
99
|
-
id: "transcript",
|
|
100
|
-
follow: "end",
|
|
101
|
-
primary: true,
|
|
102
|
-
overscroll: "chain",
|
|
103
|
-
scrollbar: "auto",
|
|
104
|
-
scrollbarStyle: text => piTheme().bg("scrollbarThumb", text),
|
|
105
|
-
child: { type: "component", component: document },
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
basis: "auto",
|
|
110
|
-
grow: 0,
|
|
111
|
-
shrink: 1,
|
|
112
|
-
minSize: 1,
|
|
113
|
-
node: {
|
|
114
|
-
type: "stack",
|
|
115
|
-
direction: "vertical",
|
|
116
|
-
children: [
|
|
117
|
-
{ shrink: 1, minSize: 0, node: { type: "component", component: queued } },
|
|
118
|
-
{ shrink: 1, minSize: 0, node: { type: "component", component: status } },
|
|
119
|
-
{ shrink: 1, minSize: 0, node: { type: "component", component: aboveWidgets } },
|
|
120
|
-
{ shrink: 1, minSize: 3, node: { type: "component", component: editor } },
|
|
121
|
-
{ shrink: 1, minSize: 0, node: { type: "component", component: belowWidgets } },
|
|
122
|
-
{ shrink: 1, minSize: 1, node: { type: "component", component: footer } },
|
|
123
|
-
],
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
],
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
#renderDocument(width) {
|
|
130
|
-
const transcript = this.#transcriptOrder.flatMap((id, index) => {
|
|
131
|
-
const block = this.#view.transcript.find(item => item.id === id);
|
|
132
|
-
if (!this.#thinkingVisible && block?.kind === "thinking")
|
|
133
|
-
return [];
|
|
134
|
-
const rows = this.#transcript.get(id)?.render(width) ?? [];
|
|
135
|
-
if (index > 0 && block?.kind === "user")
|
|
136
|
-
return ["", ...rows];
|
|
137
|
-
return rows;
|
|
138
|
-
});
|
|
139
|
-
const diagnostics = this.#view.diagnostics;
|
|
140
|
-
const startupRows = diagnostics
|
|
141
|
-
.filter(diagnostic => diagnostic.code === "engine-startup")
|
|
142
|
-
.flatMap(diagnostic => renderPiShellStartupDiagnostic(diagnostic, width));
|
|
143
|
-
const packageUpdateRows = diagnostics
|
|
144
|
-
.filter(diagnostic => diagnostic.code === "package-updates")
|
|
145
|
-
.flatMap(diagnostic => renderPiShellPackageUpdateNotice(diagnostic.message.split("\n").filter(line => line.startsWith("- ")).map(line => line.slice(2)), width));
|
|
146
|
-
const diagnosticRows = diagnostics
|
|
147
|
-
.filter(diagnostic => diagnostic.code !== "engine-startup" && diagnostic.code !== "package-updates")
|
|
148
|
-
.slice(-3)
|
|
149
|
-
.flatMap(diagnostic => renderPiShellTranscriptBlock({
|
|
150
|
-
id: `diagnostic-${diagnostic.sequence}`,
|
|
151
|
-
kind: diagnostic.severity === "error" ? "error" : "system",
|
|
152
|
-
status: "finalized",
|
|
153
|
-
revision: diagnostic.sequence,
|
|
154
|
-
title: diagnostic.code,
|
|
155
|
-
text: diagnostic.message,
|
|
156
|
-
payload: {},
|
|
157
|
-
}, width, this.#cwd));
|
|
158
|
-
const resourceRows = [...this.resources.render(width)];
|
|
159
|
-
if (resourceRows.at(-1) === "")
|
|
160
|
-
resourceRows.pop();
|
|
161
|
-
return [
|
|
162
|
-
...startupRows,
|
|
163
|
-
...(this.#extensionHeader ?? this.header).render(width),
|
|
164
|
-
...resourceRows,
|
|
165
|
-
...transcript,
|
|
166
|
-
...packageUpdateRows,
|
|
167
|
-
...diagnosticRows,
|
|
168
|
-
];
|
|
169
|
-
}
|
|
170
|
-
transcriptComponent(id) {
|
|
171
|
-
return this.#transcript.get(id);
|
|
172
|
-
}
|
|
173
|
-
appendWorkflowStatus(message) {
|
|
174
|
-
const previousId = this.#lastWorkflowStatusId;
|
|
175
|
-
if (previousId !== undefined
|
|
176
|
-
&& this.#transcriptOrder.at(-1) === previousId
|
|
177
|
-
&& this.#workflowStatusAnchors.get(previousId) === this.#view.transcript.length) {
|
|
178
|
-
this.#workflowStatusMessages.set(previousId, message);
|
|
179
|
-
this.invalidate();
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
const id = this.#appendAnchoredWorkflowComponent(width => [
|
|
183
|
-
"",
|
|
184
|
-
...renderPiShellStatusText(this.#workflowStatusMessages.get(id) ?? message, width),
|
|
185
|
-
]);
|
|
186
|
-
this.#workflowStatusMessages.set(id, message);
|
|
187
|
-
this.#lastWorkflowStatusId = id;
|
|
188
|
-
}
|
|
189
|
-
appendWorkflowResult(result) {
|
|
190
|
-
if (result.command === "reload" && result.outcome === "completed") {
|
|
191
|
-
this.appendWorkflowStatus(result.message);
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
if (result.command === "session" && result.outcome === "completed" && result.presentation?.kind === "session-info") {
|
|
195
|
-
this.#lastWorkflowStatusId = undefined;
|
|
196
|
-
const sessionInfo = createPiShellSessionInfo(result.presentation);
|
|
197
|
-
this.#appendAnchoredWorkflowComponent(width => sessionInfo.render(width), () => sessionInfo.dispose?.());
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
if (result.command === "hotkeys" && result.outcome === "completed") {
|
|
201
|
-
this.#lastWorkflowStatusId = undefined;
|
|
202
|
-
const hotkeys = createPiShellHotkeys();
|
|
203
|
-
this.#appendAnchoredWorkflowComponent(width => hotkeys.render(width), () => hotkeys.dispose?.());
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
if (result.command === "changelog" && result.outcome === "completed") {
|
|
207
|
-
this.#lastWorkflowStatusId = undefined;
|
|
208
|
-
const changelog = createPiShellChangelog(result.detail ?? "No changelog entries found.");
|
|
209
|
-
this.#appendAnchoredWorkflowComponent(width => changelog.render(width), () => changelog.dispose?.());
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
if (result.outcome === "failed") {
|
|
213
|
-
this.#lastWorkflowStatusId = undefined;
|
|
214
|
-
const warning = (result.command === "name" && result.message.startsWith("Usage:"))
|
|
215
|
-
|| (result.command === "reload" && result.message.startsWith("Wait for "));
|
|
216
|
-
const prefix = warning ? "Warning" : "Error";
|
|
217
|
-
const color = warning ? "warning" : "error";
|
|
218
|
-
this.#appendAnchoredWorkflowComponent(() => ["", ` ${piTheme().fg(color, `${prefix}: ${result.message}`)}`]);
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
if (result.outcome === "completed" && (result.command === "quit" || result.command === "compact"))
|
|
222
|
-
return;
|
|
223
|
-
if (result.command === "new" && result.outcome === "completed") {
|
|
224
|
-
this.#lastWorkflowStatusId = undefined;
|
|
225
|
-
this.#appendAnchoredWorkflowComponent(() => ["", ` ${piTheme().fg("accent", result.message)}`]);
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
if (result.command === "name" && result.outcome === "completed") {
|
|
229
|
-
this.#lastWorkflowStatusId = undefined;
|
|
230
|
-
this.#appendAnchoredWorkflowComponent(() => [
|
|
231
|
-
...(result.detail ? ["", ` ${piTheme().fg("warning", `Warning: ${result.detail}`)}`] : []),
|
|
232
|
-
"",
|
|
233
|
-
` ${piTheme().fg("dim", result.message)}`,
|
|
234
|
-
]);
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
if (result.command === "debug" && result.outcome === "completed") {
|
|
238
|
-
this.#lastWorkflowStatusId = undefined;
|
|
239
|
-
this.#appendAnchoredWorkflowComponent(() => [
|
|
240
|
-
"",
|
|
241
|
-
` ${piTheme().fg("accent", result.message)}`,
|
|
242
|
-
...(result.detail ? [` ${piTheme().fg("muted", result.detail)}`] : []),
|
|
243
|
-
]);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
if (result.command === "arminsayshi" && result.outcome === "completed") {
|
|
247
|
-
this.#lastWorkflowStatusId = undefined;
|
|
248
|
-
const armin = createPiShellArmin(this.#componentRuntime);
|
|
249
|
-
this.#appendAnchoredWorkflowComponent(width => ["", ...armin.render(width)], () => armin.dispose?.());
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
if (result.command === "dementedelves" && result.outcome === "completed") {
|
|
253
|
-
this.#lastWorkflowStatusId = undefined;
|
|
254
|
-
const announcement = createPiShellEarendilAnnouncement();
|
|
255
|
-
this.#appendAnchoredWorkflowComponent(width => ["", ...announcement.render(width)], () => announcement.dispose?.());
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
const message = result.command === "share" && result.detail
|
|
259
|
-
? `${result.message}\nGist: ${result.detail}`
|
|
260
|
-
: result.message;
|
|
261
|
-
this.appendWorkflowStatus(message);
|
|
262
|
-
}
|
|
263
|
-
appendDaxnuts() {
|
|
264
|
-
this.#lastWorkflowStatusId = undefined;
|
|
265
|
-
const daxnuts = createPiShellDaxnuts(this.#componentRuntime);
|
|
266
|
-
this.#appendAnchoredWorkflowComponent(width => ["", ...daxnuts.render(width)], () => daxnuts.dispose?.());
|
|
267
|
-
}
|
|
268
|
-
toggleThinkingVisibility() {
|
|
269
|
-
this.#thinkingVisible = !this.#thinkingVisible;
|
|
270
|
-
this.invalidate();
|
|
271
|
-
}
|
|
272
|
-
get toolsExpanded() {
|
|
273
|
-
return this.#toolsExpanded;
|
|
274
|
-
}
|
|
275
|
-
setToolsExpanded(expanded) {
|
|
276
|
-
this.#setToolsExpanded(expanded);
|
|
277
|
-
}
|
|
278
|
-
setExtensionWidget(key, component, placement) {
|
|
279
|
-
const previous = this.#extensionWidgets.get(key)?.component;
|
|
280
|
-
if (component === null)
|
|
281
|
-
this.#extensionWidgets.delete(key);
|
|
282
|
-
else
|
|
283
|
-
this.#extensionWidgets.set(key, { component, placement });
|
|
284
|
-
if (previous !== undefined && previous !== component)
|
|
285
|
-
previous.dispose?.();
|
|
286
|
-
this.invalidate();
|
|
287
|
-
}
|
|
288
|
-
setExtensionHeader(component) {
|
|
289
|
-
if (this.#extensionHeader !== component)
|
|
290
|
-
this.#extensionHeader?.dispose?.();
|
|
291
|
-
this.#extensionHeader = component;
|
|
292
|
-
this.invalidate();
|
|
293
|
-
}
|
|
294
|
-
setExtensionFooter(component) {
|
|
295
|
-
if (this.#extensionFooter !== component)
|
|
296
|
-
this.#extensionFooter?.dispose?.();
|
|
297
|
-
this.#extensionFooter = component;
|
|
298
|
-
this.invalidate();
|
|
299
|
-
}
|
|
300
|
-
setExtensionStatus(key, text) {
|
|
301
|
-
if (text === undefined)
|
|
302
|
-
this.#extensionStatuses.delete(key);
|
|
303
|
-
else
|
|
304
|
-
this.#extensionStatuses.set(key, text);
|
|
305
|
-
this.#footer.update(this.#viewWithExtensionStatuses(this.#view));
|
|
306
|
-
this.invalidate();
|
|
307
|
-
}
|
|
308
|
-
setExtensionWorking(message, visible = this.#extensionWorkingVisible) {
|
|
309
|
-
this.#extensionWorkingMessage = message;
|
|
310
|
-
this.#extensionWorkingVisible = visible;
|
|
311
|
-
this.#status.setWorkingOverride(visible ? message : undefined);
|
|
312
|
-
this.invalidate();
|
|
313
|
-
}
|
|
314
|
-
resetWorkflowPresentation() {
|
|
315
|
-
for (const id of this.#workflowStatusAnchors.keys()) {
|
|
316
|
-
this.#transcript.get(id)?.dispose?.();
|
|
317
|
-
this.#transcript.delete(id);
|
|
318
|
-
}
|
|
319
|
-
this.#workflowStatusAnchors.clear();
|
|
320
|
-
this.#workflowStatusMessages.clear();
|
|
321
|
-
this.#transcriptOrder = this.#transcriptOrder.filter(id => !id.startsWith("workflow-status-"));
|
|
322
|
-
this.#lastWorkflowStatusId = undefined;
|
|
323
|
-
this.invalidate();
|
|
324
|
-
}
|
|
325
|
-
resetExtensionUi() {
|
|
326
|
-
this.#extensionHeader?.dispose?.();
|
|
327
|
-
this.#extensionFooter?.dispose?.();
|
|
328
|
-
for (const { component } of this.#extensionWidgets.values())
|
|
329
|
-
component.dispose?.();
|
|
330
|
-
this.#extensionHeader = null;
|
|
331
|
-
this.#extensionFooter = null;
|
|
332
|
-
this.#extensionWidgets.clear();
|
|
333
|
-
this.#extensionStatuses.clear();
|
|
334
|
-
this.#extensionWorkingMessage = undefined;
|
|
335
|
-
this.#status.setWorkingOverride(undefined);
|
|
336
|
-
this.#footer.update(this.#viewWithExtensionStatuses(this.#view));
|
|
337
|
-
this.invalidate();
|
|
338
|
-
}
|
|
339
|
-
addExtensionNotification(message, type) {
|
|
340
|
-
if (type === "info") {
|
|
341
|
-
this.appendWorkflowStatus(message);
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
this.#lastWorkflowStatusId = undefined;
|
|
345
|
-
const prefix = type === "warning" ? "Warning" : "Error";
|
|
346
|
-
this.#appendAnchoredWorkflowComponent(() => ["", ` ${piTheme().fg(type, `${prefix}: ${message}`)}`]);
|
|
347
|
-
}
|
|
348
|
-
extensionFooterData() {
|
|
349
|
-
return {
|
|
350
|
-
getGitBranch: () => this.#view.status.footer?.branch ?? null,
|
|
351
|
-
getExtensionStatuses: () => new Map(this.#extensionStatuses),
|
|
352
|
-
getAvailableProviderCount: () => this.#view.status.footer?.availableProviderCount ?? 1,
|
|
353
|
-
onBranchChange: () => () => { },
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
setInputSurface(component, disposePrevious = true) {
|
|
357
|
-
const next = component ?? this.editor;
|
|
358
|
-
if (next === this.#inputSurface)
|
|
359
|
-
return;
|
|
360
|
-
this.#inputSurface.setFocused?.(false);
|
|
361
|
-
if (disposePrevious && this.#inputSurface !== this.editor)
|
|
362
|
-
this.#inputSurface.dispose?.();
|
|
363
|
-
this.#inputSurface = next;
|
|
364
|
-
this.#inputSurface.setFocused?.(true);
|
|
365
|
-
this.invalidate();
|
|
366
|
-
}
|
|
367
|
-
handleInput(data) {
|
|
368
|
-
this.#inputSurface.handleInput?.(data);
|
|
369
|
-
}
|
|
370
|
-
invalidate() {
|
|
371
|
-
this.header.invalidate();
|
|
372
|
-
this.resources.invalidate();
|
|
373
|
-
for (const component of this.#transcript.values())
|
|
374
|
-
component.invalidate();
|
|
375
|
-
this.editor.invalidate();
|
|
376
|
-
if (this.#inputSurface !== this.editor)
|
|
377
|
-
this.#inputSurface.invalidate();
|
|
378
|
-
this.#invalidateExtensions();
|
|
379
|
-
this.#status.invalidate();
|
|
380
|
-
this.#footer.invalidate();
|
|
381
|
-
this.#queued.invalidate();
|
|
382
|
-
}
|
|
383
|
-
setFocused(focused) {
|
|
384
|
-
this.#inputSurface.setFocused?.(focused);
|
|
385
|
-
}
|
|
386
|
-
dispose() {
|
|
387
|
-
this.header.dispose?.();
|
|
388
|
-
this.resources.dispose?.();
|
|
389
|
-
for (const component of this.#transcript.values())
|
|
390
|
-
component.dispose?.();
|
|
391
|
-
this.#transcript.clear();
|
|
392
|
-
if (this.#inputSurface !== this.editor)
|
|
393
|
-
this.#inputSurface.dispose?.();
|
|
394
|
-
this.#extensionHeader?.dispose?.();
|
|
395
|
-
this.#extensionFooter?.dispose?.();
|
|
396
|
-
for (const { component } of this.#extensionWidgets.values())
|
|
397
|
-
component.dispose?.();
|
|
398
|
-
this.#extensionWidgets.clear();
|
|
399
|
-
this.editor.dispose?.();
|
|
400
|
-
this.#status.dispose?.();
|
|
401
|
-
this.#footer.dispose?.();
|
|
402
|
-
this.#queued.dispose?.();
|
|
403
|
-
}
|
|
404
|
-
#syncTranscript(blocks) {
|
|
405
|
-
const nextIds = new Set(blocks.map(block => block.id));
|
|
406
|
-
for (const [id, component] of this.#transcript) {
|
|
407
|
-
if (id.startsWith("workflow-status-") || nextIds.has(id))
|
|
408
|
-
continue;
|
|
409
|
-
component.dispose?.();
|
|
410
|
-
this.#transcript.delete(id);
|
|
411
|
-
}
|
|
412
|
-
for (const block of blocks) {
|
|
413
|
-
const component = this.#transcript.get(block.id);
|
|
414
|
-
if (component === undefined) {
|
|
415
|
-
const created = createPiShellTranscriptComponent(block, this.#cwd, this.#extensionRenderers);
|
|
416
|
-
created.setExpanded(this.#toolsExpanded);
|
|
417
|
-
this.#transcript.set(block.id, created);
|
|
418
|
-
}
|
|
419
|
-
else if (component.revision !== block.revision) {
|
|
420
|
-
component.update(block);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
const statusIds = [...this.#workflowStatusAnchors.keys()];
|
|
424
|
-
const order = [];
|
|
425
|
-
for (let index = 0; index <= blocks.length; index += 1) {
|
|
426
|
-
for (const statusId of statusIds) {
|
|
427
|
-
if (this.#workflowStatusAnchors.get(statusId) === index)
|
|
428
|
-
order.push(statusId);
|
|
429
|
-
}
|
|
430
|
-
const block = blocks[index];
|
|
431
|
-
if (block !== undefined)
|
|
432
|
-
order.push(block.id);
|
|
433
|
-
}
|
|
434
|
-
for (const statusId of statusIds) {
|
|
435
|
-
if (!order.includes(statusId))
|
|
436
|
-
order.push(statusId);
|
|
437
|
-
}
|
|
438
|
-
this.#transcriptOrder = order;
|
|
439
|
-
}
|
|
440
|
-
#appendAnchoredWorkflowComponent(render, dispose) {
|
|
441
|
-
this.#workflowTranscriptSequence += 1;
|
|
442
|
-
const id = `workflow-status-${this.#workflowTranscriptSequence}`;
|
|
443
|
-
const component = {
|
|
444
|
-
id,
|
|
445
|
-
revision: 1,
|
|
446
|
-
render,
|
|
447
|
-
handleInput() { },
|
|
448
|
-
invalidate() { },
|
|
449
|
-
update() { },
|
|
450
|
-
setExpanded() { },
|
|
451
|
-
...(dispose === undefined ? {} : { dispose }),
|
|
452
|
-
};
|
|
453
|
-
this.#transcript.set(id, component);
|
|
454
|
-
this.#workflowStatusAnchors.set(id, this.#view.transcript.length);
|
|
455
|
-
this.#transcriptOrder.push(id);
|
|
456
|
-
this.invalidate();
|
|
457
|
-
return id;
|
|
458
|
-
}
|
|
459
|
-
#renderWidgets(placement, width) {
|
|
460
|
-
const rows = [...this.#extensionWidgets.values()]
|
|
461
|
-
.filter(widget => widget.placement === placement)
|
|
462
|
-
.flatMap(widget => widget.component.render(width));
|
|
463
|
-
return placement === "aboveEditor" ? ["", ...rows] : rows;
|
|
464
|
-
}
|
|
465
|
-
#renderStatus(width) {
|
|
466
|
-
return this.#status.render(width);
|
|
467
|
-
}
|
|
468
|
-
#renderFooter(width) {
|
|
469
|
-
return (this.#extensionFooter ?? this.#footer).render(width);
|
|
470
|
-
}
|
|
471
|
-
#viewWithExtensionStatuses(view) {
|
|
472
|
-
const footer = view.status.footer;
|
|
473
|
-
const statuses = new Map(footer?.extensionStatuses ?? []);
|
|
474
|
-
for (const [key, text] of this.#extensionStatuses)
|
|
475
|
-
statuses.set(key, text);
|
|
476
|
-
return {
|
|
477
|
-
...view,
|
|
478
|
-
status: {
|
|
479
|
-
...view.status,
|
|
480
|
-
footer: {
|
|
481
|
-
branch: footer?.branch ?? null,
|
|
482
|
-
sessionName: footer?.sessionName ?? null,
|
|
483
|
-
availableProviderCount: footer?.availableProviderCount ?? 1,
|
|
484
|
-
extensionStatuses: [...statuses],
|
|
485
|
-
},
|
|
486
|
-
},
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
#invalidateExtensions() {
|
|
490
|
-
this.#extensionHeader?.invalidate();
|
|
491
|
-
this.#extensionFooter?.invalidate();
|
|
492
|
-
for (const { component } of this.#extensionWidgets.values())
|
|
493
|
-
component.invalidate();
|
|
494
|
-
}
|
|
495
|
-
#setToolsExpanded(expanded) {
|
|
496
|
-
this.#toolsExpanded = expanded;
|
|
497
|
-
this.header.setExpanded(expanded);
|
|
498
|
-
this.resources.setExpanded(expanded);
|
|
499
|
-
for (const component of this.#transcript.values())
|
|
500
|
-
component.setExpanded(expanded);
|
|
501
|
-
this.invalidate();
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
function layoutPort(render, invalidate, handleInput) {
|
|
505
|
-
return {
|
|
506
|
-
render,
|
|
507
|
-
invalidate,
|
|
508
|
-
...(handleInput === undefined ? {} : { handleInput }),
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
function shellResourceEntries(backend) {
|
|
512
|
-
const resources = backend.nonVisualResources().map(resource => ({
|
|
513
|
-
section: resource.kind === "skill"
|
|
514
|
-
? "Skills"
|
|
515
|
-
: resource.kind === "prompt-template"
|
|
516
|
-
? "Prompts"
|
|
517
|
-
: resource.kind === "theme"
|
|
518
|
-
? "Themes"
|
|
519
|
-
: "Context",
|
|
520
|
-
label: resource.kind === "prompt-template"
|
|
521
|
-
? `/${resource.label}`
|
|
522
|
-
: resource.kind === "agent-context" || resource.kind === "system-prompt"
|
|
523
|
-
? compactResourceLabel(resource.sourcePath ?? resource.label)
|
|
524
|
-
: resource.label,
|
|
525
|
-
sourcePath: resource.sourcePath,
|
|
526
|
-
diagnostic: resource.diagnostic,
|
|
527
|
-
}));
|
|
528
|
-
const extensions = backend.extensionResources().filter(extension => !extension.hidden);
|
|
529
|
-
const loadedExtensions = extensions.filter(extension => extension.diagnostic === null);
|
|
530
|
-
const extensionLabels = compactExtensionLabels(loadedExtensions);
|
|
531
|
-
for (const extension of extensions) {
|
|
532
|
-
const labelIndex = loadedExtensions.indexOf(extension);
|
|
533
|
-
resources.push({
|
|
534
|
-
section: "Extensions",
|
|
535
|
-
label: extensionLabels[labelIndex] ?? compactResourceLabel(extension.sourcePath ?? extension.resolvedPath ?? "extension"),
|
|
536
|
-
sourcePath: extension.sourcePath ?? extension.resolvedPath,
|
|
537
|
-
diagnostic: extension.diagnostic,
|
|
538
|
-
});
|
|
539
|
-
}
|
|
540
|
-
return resources;
|
|
541
|
-
}
|
|
542
|
-
function compactResourceLabel(path) {
|
|
543
|
-
const segments = compactPathSegments(path);
|
|
544
|
-
const leaf = segments.at(-1) ?? path;
|
|
545
|
-
if ((leaf === "index.ts" || leaf === "index.js") && segments.length > 1)
|
|
546
|
-
return segments.at(-2) ?? leaf;
|
|
547
|
-
return leaf;
|
|
548
|
-
}
|
|
549
|
-
/**
|
|
550
|
-
* Pinned from InteractiveMode's compact extension-label helpers at Pi commit
|
|
551
|
-
* 914cf1472e715297caa30db4b9535d534a9eb718. The source metadata crosses an
|
|
552
|
-
* A1-owned boundary first; the owned shell never inspects Pi's private root.
|
|
553
|
-
*/
|
|
554
|
-
function compactExtensionLabels(extensions) {
|
|
555
|
-
const localExtensions = extensions
|
|
556
|
-
.filter(extension => !isPackageExtensionSource(extension.sourceInfo))
|
|
557
|
-
.map(extension => {
|
|
558
|
-
const path = extension.sourcePath ?? extension.resolvedPath ?? "extension";
|
|
559
|
-
const segments = compactPathSegments(path);
|
|
560
|
-
if (segments.length > 1 && (segments.at(-1) === "index.ts" || segments.at(-1) === "index.js"))
|
|
561
|
-
segments.pop();
|
|
562
|
-
return { extension, segments };
|
|
563
|
-
});
|
|
564
|
-
return extensions.map(extension => {
|
|
565
|
-
const resourcePath = extension.sourcePath ?? extension.resolvedPath ?? "extension";
|
|
566
|
-
if (isPackageExtensionSource(extension.sourceInfo)) {
|
|
567
|
-
return compactPackageExtensionLabel(resourcePath, extension.sourceInfo);
|
|
568
|
-
}
|
|
569
|
-
const localIndex = localExtensions.findIndex(item => item.extension === extension);
|
|
570
|
-
const segments = localExtensions[localIndex]?.segments;
|
|
571
|
-
if (!segments || segments.length === 0)
|
|
572
|
-
return compactResourceLabel(resourcePath);
|
|
573
|
-
for (let count = 1; count <= segments.length; count += 1) {
|
|
574
|
-
const candidate = segments.slice(-count).join("/");
|
|
575
|
-
if (localExtensions.every((item, itemIndex) => itemIndex === localIndex || item.segments.slice(-count).join("/") !== candidate)) {
|
|
576
|
-
return candidate;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
return segments.join("/");
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
function compactPackageExtensionLabel(resourcePath, sourceInfo) {
|
|
583
|
-
const sourceLabel = compactPackageSourceLabel(sourceInfo.source);
|
|
584
|
-
if (!sourceLabel)
|
|
585
|
-
return compactResourceLabel(resourcePath);
|
|
586
|
-
const shortPath = shortPackagePath(resourcePath, sourceInfo).replaceAll("\\", "/");
|
|
587
|
-
const packagePath = shortPath.startsWith("extensions/") ? shortPath.slice("extensions/".length) : shortPath;
|
|
588
|
-
const slash = packagePath.lastIndexOf("/");
|
|
589
|
-
const fileName = slash < 0 ? packagePath : packagePath.slice(slash + 1);
|
|
590
|
-
const directory = slash < 0 ? "" : packagePath.slice(0, slash);
|
|
591
|
-
const extension = fileName.lastIndexOf(".");
|
|
592
|
-
const name = extension <= 0 ? fileName : fileName.slice(0, extension);
|
|
593
|
-
if (name === "index")
|
|
594
|
-
return !directory || directory === "." ? sourceLabel : `${sourceLabel}:${directory}`;
|
|
595
|
-
return `${sourceLabel}:${packagePath}`;
|
|
596
|
-
}
|
|
597
|
-
function compactPackageSourceLabel(source) {
|
|
598
|
-
if (source.startsWith("npm:"))
|
|
599
|
-
return source.slice("npm:".length) || source;
|
|
600
|
-
if (!source.startsWith("git:"))
|
|
601
|
-
return source;
|
|
602
|
-
const gitSource = source.slice("git:".length).trim();
|
|
603
|
-
let repositoryPath;
|
|
604
|
-
const scpLike = gitSource.match(/^git@[^:]+:(.+)$/);
|
|
605
|
-
if (scpLike?.[1]) {
|
|
606
|
-
repositoryPath = scpLike[1];
|
|
607
|
-
}
|
|
608
|
-
else if (/^[a-z]+:\/\//i.test(gitSource)) {
|
|
609
|
-
try {
|
|
610
|
-
repositoryPath = new URL(gitSource).pathname.replace(/^\/+/, "");
|
|
611
|
-
}
|
|
612
|
-
catch {
|
|
613
|
-
return source;
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
else {
|
|
617
|
-
const slash = gitSource.indexOf("/");
|
|
618
|
-
if (slash >= 0)
|
|
619
|
-
repositoryPath = gitSource.slice(slash + 1);
|
|
620
|
-
}
|
|
621
|
-
if (!repositoryPath)
|
|
622
|
-
return source;
|
|
623
|
-
const ref = repositoryPath.indexOf("@");
|
|
624
|
-
const withoutRef = ref < 0 ? repositoryPath : repositoryPath.slice(0, ref);
|
|
625
|
-
return withoutRef.replace(/\.git$/, "") || source;
|
|
626
|
-
}
|
|
627
|
-
function shortPackagePath(resourcePath, sourceInfo) {
|
|
628
|
-
const fullPath = normalizeResourcePath(resourcePath);
|
|
629
|
-
const baseDir = sourceInfo.baseDir === null ? undefined : normalizeResourcePath(sourceInfo.baseDir).replace(/\/$/, "");
|
|
630
|
-
if (baseDir) {
|
|
631
|
-
const npmRoot = baseDir.match(/^(.*\/node_modules)\/(@?[^/]+(?:\/[^/]+)?)$/);
|
|
632
|
-
if (npmRoot?.[1] && fullPath.startsWith(`${npmRoot[1]}/`))
|
|
633
|
-
return relativeResourcePath(baseDir, fullPath);
|
|
634
|
-
if (fullPath === baseDir)
|
|
635
|
-
return ".";
|
|
636
|
-
if (fullPath.startsWith(`${baseDir}/`))
|
|
637
|
-
return fullPath.slice(baseDir.length + 1);
|
|
638
|
-
}
|
|
639
|
-
const npmMatch = fullPath.match(/node_modules\/(@?[^/]+(?:\/[^/]+)?)\/(.*)/);
|
|
640
|
-
if (npmMatch?.[2] && sourceInfo.source.startsWith("npm:"))
|
|
641
|
-
return npmMatch[2];
|
|
642
|
-
const gitMatch = fullPath.match(/git\/[^/]+\/[^/]+\/(.*)/);
|
|
643
|
-
if (gitMatch?.[1] && sourceInfo.source.startsWith("git:"))
|
|
644
|
-
return gitMatch[1];
|
|
645
|
-
return resourcePath;
|
|
646
|
-
}
|
|
647
|
-
function relativeResourcePath(from, to) {
|
|
648
|
-
const fromSegments = from.split("/").filter(Boolean);
|
|
649
|
-
const toSegments = to.split("/").filter(Boolean);
|
|
650
|
-
let common = 0;
|
|
651
|
-
while (common < fromSegments.length && common < toSegments.length
|
|
652
|
-
&& fromSegments[common]?.toLowerCase() === toSegments[common]?.toLowerCase())
|
|
653
|
-
common += 1;
|
|
654
|
-
return [...fromSegments.slice(common).map(() => ".."), ...toSegments.slice(common)].join("/") || ".";
|
|
655
|
-
}
|
|
656
|
-
function compactPathSegments(path) {
|
|
657
|
-
return normalizeResourcePath(path).split("/").filter(segment => segment.length > 0 && segment !== "~");
|
|
658
|
-
}
|
|
659
|
-
function normalizeResourcePath(path) {
|
|
660
|
-
return path.replaceAll("\\", "/");
|
|
661
|
-
}
|
|
662
|
-
function isPackageExtensionSource(sourceInfo) {
|
|
663
|
-
const source = sourceInfo?.source ?? "";
|
|
664
|
-
return source.startsWith("npm:") || source.startsWith("git:");
|
|
665
|
-
}
|
|
1
|
+
import { PRODUCT_TEXT } from "../../../product-identity.js";
|
|
2
|
+
import { MOUSE_TRACKING_OFF, MOUSE_TRACKING_ON, parseMouseInput, readVisibleHyperlinks } from "../../../ui/components/index.js";
|
|
3
|
+
import { PINNED_PI_HIDDEN_COMMAND_NAMES, PINNED_PI_WORKFLOW_COMMAND_NAMES, } from "../engine/index.js";
|
|
4
|
+
import { createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellOperationLoader, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellStatus, createPiShellTranscriptComponent, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, onPiThemeChange, piTheme, renderPiShellPackageUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, } from "../components/index.js";
|
|
5
|
+
import { DamageAwareTerminalAdapter, PiTuiRuntimeAdapter, classifyPiTuiInput, } from "../tui-runtime/index.js";
|
|
6
|
+
import { canonicalizeClipboardImage } from "./clipboard-image.js";
|
|
7
|
+
import { STREAM_PRESENTATION_INTERVAL_MS, StreamPresentationCoalescer, } from "./stream-presentation-coalescer.js";
|
|
8
|
+
import { preloadSystemClipboard, readSystemClipboardContent, writeSystemClipboardText, } from "./system-clipboard.js";
|
|
9
|
+
import { OwnedUiSessionShellRoot, shellResourceEntries, } from "./session-shell-root.js";
|
|
10
|
+
export { OwnedUiSessionShellRoot } from "./session-shell-root.js";
|
|
11
|
+
/** Coordinates backend, owned presentation, and Pi TUI lifecycles for one interactive session. */
|
|
666
12
|
export class OwnedUiSessionShell {
|
|
667
13
|
backend;
|
|
668
14
|
root;
|
|
@@ -674,13 +20,28 @@ export class OwnedUiSessionShell {
|
|
|
674
20
|
#stopped;
|
|
675
21
|
#resolveStopped;
|
|
676
22
|
#dialogId;
|
|
23
|
+
#dialogSource;
|
|
677
24
|
#routeHost;
|
|
678
25
|
#dialogHandle;
|
|
679
26
|
#sequence = 0;
|
|
680
27
|
#started = false;
|
|
681
28
|
#disposed = false;
|
|
29
|
+
#pointerReporting = false;
|
|
30
|
+
#customViewport;
|
|
31
|
+
#damageTerminal;
|
|
32
|
+
#streamPresentation;
|
|
33
|
+
#removeViewportPreInput;
|
|
34
|
+
#unsubscribeSettings;
|
|
35
|
+
#unbindPiSettings;
|
|
36
|
+
#unbindTerminalSettings;
|
|
37
|
+
#unbindShutdownSettings;
|
|
38
|
+
#terminalProgressEnabled = false;
|
|
39
|
+
#showImages = true;
|
|
40
|
+
#imageWidthCells = 80;
|
|
41
|
+
#fullscreenExitOutput = "transcript";
|
|
682
42
|
#compactionQueue = [];
|
|
683
43
|
#lastClearTime = 0;
|
|
44
|
+
#lastEscapeTime = 0;
|
|
684
45
|
#activeLoginDialog;
|
|
685
46
|
#sessionGeneration;
|
|
686
47
|
constructor(options) {
|
|
@@ -688,14 +49,27 @@ export class OwnedUiSessionShell {
|
|
|
688
49
|
this.#sessionGeneration = this.backend.sessionGeneration;
|
|
689
50
|
this.#cwd = options.cwd;
|
|
690
51
|
this.#routeHost = options.routeHost ?? null;
|
|
52
|
+
this.#customViewport = options.sessionLayout === "custom-viewport";
|
|
53
|
+
if (this.#customViewport && options.clipboard === undefined)
|
|
54
|
+
preloadSystemClipboard();
|
|
691
55
|
this.#stopped = new Promise(resolve => {
|
|
692
56
|
this.#resolveStopped = resolve;
|
|
693
57
|
});
|
|
694
58
|
let runtime;
|
|
59
|
+
let damageTerminal;
|
|
60
|
+
let streamPresentation;
|
|
61
|
+
let pendingClipboardWrite = Promise.resolve();
|
|
695
62
|
this.root = new OwnedUiSessionShellRoot(this.backend.view(), options.cwd, {
|
|
696
63
|
getColumns: () => runtime?.viewport().columns ?? options.terminal?.columns ?? 80,
|
|
697
64
|
getRows: () => runtime?.viewport().rows ?? options.terminal?.rows ?? 24,
|
|
698
|
-
requestRender:
|
|
65
|
+
requestRender: force => runtime?.requestRender(force),
|
|
66
|
+
requestHyperlinkCleanup: () => damageTerminal?.requestHyperlinkCleanup(),
|
|
67
|
+
onViewportFrame: frame => damageTerminal?.arm(frame.descriptor, {
|
|
68
|
+
overlayActive: runtime?.hasOverlay() ?? false,
|
|
69
|
+
selectionActive: this.root.hasActiveSelection(),
|
|
70
|
+
replacementSurfaceActive: !this.root.usesDefaultInputSurface(),
|
|
71
|
+
}),
|
|
72
|
+
enableDockInputReuse: options.inputPresentation?.viewportReuse !== false,
|
|
699
73
|
onSubmit: text => { void this.submit(text); },
|
|
700
74
|
onInterrupt: () => { void this.interrupt(); },
|
|
701
75
|
onClear: () => { void this.clearOrExit(); },
|
|
@@ -710,19 +84,189 @@ export class OwnedUiSessionShell {
|
|
|
710
84
|
onMessageCopy: () => { void this.runWorkflow({ command: "copy", argument: "" }); },
|
|
711
85
|
onFollowUp: () => { void this.queueFollowUp(); },
|
|
712
86
|
onDequeue: () => this.restoreQueuedInput(),
|
|
87
|
+
onCopyText: text => {
|
|
88
|
+
runtime?.writeControl(`\u001b]52;c;${Buffer.from(text, "utf8").toString("base64")}\u0007`);
|
|
89
|
+
const write = options.clipboard === undefined
|
|
90
|
+
? writeSystemClipboardText(text)
|
|
91
|
+
: options.clipboard.writeText?.(text) ?? Promise.resolve();
|
|
92
|
+
pendingClipboardWrite = write.catch(() => { });
|
|
93
|
+
},
|
|
94
|
+
readClipboardContent: async () => {
|
|
95
|
+
await pendingClipboardWrite;
|
|
96
|
+
if (options.clipboard === undefined)
|
|
97
|
+
return readSystemClipboardContent();
|
|
98
|
+
try {
|
|
99
|
+
const image = await options.clipboard.readImage?.();
|
|
100
|
+
if (image !== null && image !== undefined) {
|
|
101
|
+
const canonical = canonicalizeClipboardImage(image);
|
|
102
|
+
if (canonical !== null)
|
|
103
|
+
return { kind: "image", ...canonical };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Compatibility: treat an unavailable or malformed image as text-capable clipboard input.
|
|
108
|
+
}
|
|
109
|
+
const text = await options.clipboard.readText();
|
|
110
|
+
return text === null ? null : { kind: "text", text };
|
|
111
|
+
},
|
|
713
112
|
}, {
|
|
714
113
|
...options.startup,
|
|
715
114
|
resources: options.startup?.resources ?? shellResourceEntries(this.backend),
|
|
716
115
|
}, this.backend.agentDir, {
|
|
717
116
|
getMessageRenderer: customType => this.backend.pinnedMessageRenderer(customType),
|
|
718
117
|
getToolDefinition: toolName => this.backend.pinnedToolDefinition(toolName),
|
|
118
|
+
}, options.sessionLayout, {
|
|
119
|
+
resolve: assetId => this.backend.resolveTranscriptImage(assetId),
|
|
719
120
|
});
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
121
|
+
// Invariant: bare A1 owns a bounded viewport and therefore always runs on the alternate
|
|
122
|
+
// fullscreen surface. The pinned comparison profiles still honor Pi's mode.
|
|
123
|
+
const tuiMode = this.#customViewport
|
|
124
|
+
? "fullscreen"
|
|
125
|
+
: this.backend.disposed ? "regular" : this.backend.pinnedSettingsSnapshot().tuiMode;
|
|
126
|
+
const runtimeOptions = {
|
|
127
|
+
root: this.root,
|
|
128
|
+
mode: tuiMode,
|
|
129
|
+
...(this.#customViewport ? {
|
|
130
|
+
decorateTerminal: (terminal) => {
|
|
131
|
+
damageTerminal = new DamageAwareTerminalAdapter(terminal, {
|
|
132
|
+
regionalScroll: process.env.TERM !== "dumb",
|
|
133
|
+
inspectHyperlinks: readVisibleHyperlinks,
|
|
134
|
+
onResize: () => streamPresentation?.noteImmediatePresentation(),
|
|
135
|
+
onHyperlinkCleanupRequired: () => runtime?.requestRender(true),
|
|
136
|
+
});
|
|
137
|
+
return damageTerminal;
|
|
138
|
+
},
|
|
139
|
+
...(options.inputPresentation?.coordination === false ? {} : {
|
|
140
|
+
inputCoordination: {
|
|
141
|
+
classify: (data, focusedOverlay) => classifyPiTuiInput(data, focusedOverlay ?? this.root.inputCoordinationSurface()),
|
|
142
|
+
onReceipt: () => streamPresentation?.noteImmediatePresentation(),
|
|
143
|
+
...(options.inputPresentation?.scheduler === undefined
|
|
144
|
+
? {}
|
|
145
|
+
: { scheduler: options.inputPresentation.scheduler }),
|
|
146
|
+
},
|
|
147
|
+
}),
|
|
148
|
+
} : { layoutRoot: this.root.layoutRoot() }),
|
|
149
|
+
...(options.inputPresentation?.onEvent === undefined ? {} : {
|
|
150
|
+
inputDiagnostics: {
|
|
151
|
+
onEvent: options.inputPresentation.onEvent,
|
|
152
|
+
...(options.inputPresentation.now === undefined ? {} : { now: options.inputPresentation.now }),
|
|
153
|
+
},
|
|
154
|
+
}),
|
|
155
|
+
...(options.terminal === undefined ? {} : { terminal: options.terminal }),
|
|
156
|
+
hardwareCursor: this.backend.view().terminal.hardwareCursor,
|
|
157
|
+
};
|
|
724
158
|
runtime = new PiTuiRuntimeAdapter(runtimeOptions);
|
|
725
159
|
this.runtime = runtime;
|
|
160
|
+
this.#damageTerminal = damageTerminal ?? null;
|
|
161
|
+
const presentationInterval = options.streamPresentation?.intervalMs ?? STREAM_PRESENTATION_INTERVAL_MS;
|
|
162
|
+
streamPresentation = options.streamPresentation?.scheduler === undefined
|
|
163
|
+
? new StreamPresentationCoalescer(() => this.runtime.requestRender(), presentationInterval)
|
|
164
|
+
: new StreamPresentationCoalescer(() => this.runtime.requestRender(), presentationInterval, options.streamPresentation.scheduler);
|
|
165
|
+
this.#streamPresentation = streamPresentation;
|
|
166
|
+
const initialPiSettings = this.backend.pinnedSettingsSnapshot();
|
|
167
|
+
this.runtime.setHardwareCursor(initialPiSettings.showHardwareCursor);
|
|
168
|
+
this.runtime.setClearOnShrink(initialPiSettings.clearOnShrink);
|
|
169
|
+
this.#terminalProgressEnabled = initialPiSettings.showTerminalProgress;
|
|
170
|
+
this.#fullscreenExitOutput = initialPiSettings.fullscreenExitOutput;
|
|
171
|
+
this.#unbindShutdownSettings = this.backend.bindSettingsOwner("shutdown", {
|
|
172
|
+
fullscreenExitOutput: { apply() { } },
|
|
173
|
+
});
|
|
174
|
+
this.#unbindTerminalSettings = this.backend.bindSettingsOwner("terminal", {
|
|
175
|
+
showHardwareCursor: { apply: value => {
|
|
176
|
+
if (typeof value !== "boolean")
|
|
177
|
+
throw new TypeError("Hardware cursor setting is invalid");
|
|
178
|
+
this.runtime.setHardwareCursor(value);
|
|
179
|
+
} },
|
|
180
|
+
clearOnShrink: { apply: value => {
|
|
181
|
+
if (typeof value !== "boolean")
|
|
182
|
+
throw new TypeError("Clear-on-shrink setting is invalid");
|
|
183
|
+
this.runtime.setClearOnShrink(value);
|
|
184
|
+
} },
|
|
185
|
+
showTerminalProgress: { apply: value => {
|
|
186
|
+
if (typeof value !== "boolean")
|
|
187
|
+
throw new TypeError("Terminal progress setting is invalid");
|
|
188
|
+
this.#terminalProgressEnabled = value;
|
|
189
|
+
this.#syncTerminalProgress(this.view());
|
|
190
|
+
} },
|
|
191
|
+
});
|
|
192
|
+
this.#removeViewportPreInput = this.#customViewport
|
|
193
|
+
? this.runtime.addPreInputListener(data => {
|
|
194
|
+
if (options.inputPresentation?.coordination === false)
|
|
195
|
+
this.#streamPresentation.noteImmediatePresentation();
|
|
196
|
+
// Invariant: an overlay or editor-replacement screen owns its entire pointer
|
|
197
|
+
// surface. Letting the transcript pre-router inspect those reports
|
|
198
|
+
// steals settings value menus and numeric +/- controls before the
|
|
199
|
+
// settings app can receive them.
|
|
200
|
+
if (this.runtime.hasOverlay() || !this.root.usesDefaultInputSurface())
|
|
201
|
+
return undefined;
|
|
202
|
+
const routed = this.root.handleViewportPreInput(data, true);
|
|
203
|
+
if (routed.copyText !== undefined) {
|
|
204
|
+
this.runtime.writeControl(`\u001b]52;c;${Buffer.from(routed.copyText, "utf8").toString("base64")}\u0007`);
|
|
205
|
+
}
|
|
206
|
+
if (!routed.consumed)
|
|
207
|
+
return routed.data === data ? undefined : { data: routed.data };
|
|
208
|
+
return routed.data.length === 0 ? { consume: true } : { data: routed.data };
|
|
209
|
+
})
|
|
210
|
+
: () => { };
|
|
211
|
+
const applyViewportSettings = () => {
|
|
212
|
+
const snapshot = options.viewportSettings?.snapshot();
|
|
213
|
+
this.root.setViewportConfig(snapshot ?? {
|
|
214
|
+
scrollbarAppearance: "auto",
|
|
215
|
+
scrollbarStyle: "thin",
|
|
216
|
+
scrollbarSpeed: "normal",
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
applyViewportSettings();
|
|
220
|
+
this.#unsubscribeSettings = this.#customViewport && options.viewportSettings
|
|
221
|
+
? options.viewportSettings.onChange(settings => this.root.setViewportConfig(settings))
|
|
222
|
+
: () => { };
|
|
223
|
+
this.root.setEditorPaddingX(initialPiSettings.editorPaddingX);
|
|
224
|
+
this.root.setAutocompleteMaxVisible(initialPiSettings.autocompleteMaxVisible);
|
|
225
|
+
this.root.setOutputPad(initialPiSettings.outputPad);
|
|
226
|
+
this.root.setHideThinkingBlock(initialPiSettings.hideThinkingBlock);
|
|
227
|
+
this.root.setMermaidRenderingMode(initialPiSettings.mermaidRenderingMode);
|
|
228
|
+
this.#showImages = initialPiSettings.showImages;
|
|
229
|
+
this.#imageWidthCells = initialPiSettings.imageWidthCells;
|
|
230
|
+
this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
|
|
231
|
+
this.#unbindPiSettings = this.backend.bindSettingsOwner("shell", {
|
|
232
|
+
editorPaddingX: { apply: value => {
|
|
233
|
+
if (typeof value !== "number")
|
|
234
|
+
throw new TypeError("Editor padding is invalid");
|
|
235
|
+
this.root.setEditorPaddingX(value);
|
|
236
|
+
} },
|
|
237
|
+
autocompleteMaxVisible: { apply: value => {
|
|
238
|
+
if (typeof value !== "number")
|
|
239
|
+
throw new TypeError("Autocomplete maximum is invalid");
|
|
240
|
+
this.root.setAutocompleteMaxVisible(value);
|
|
241
|
+
} },
|
|
242
|
+
outputPad: { apply: value => {
|
|
243
|
+
if (value !== 0 && value !== 1)
|
|
244
|
+
throw new TypeError("Output padding is invalid");
|
|
245
|
+
this.root.setOutputPad(value);
|
|
246
|
+
} },
|
|
247
|
+
hideThinkingBlock: { apply: value => {
|
|
248
|
+
if (typeof value !== "boolean")
|
|
249
|
+
throw new TypeError("Thinking-block visibility is invalid");
|
|
250
|
+
this.root.setHideThinkingBlock(value);
|
|
251
|
+
} },
|
|
252
|
+
mermaidRenderingMode: { apply: value => {
|
|
253
|
+
if (value !== "off" && value !== "final" && value !== "streaming")
|
|
254
|
+
throw new TypeError("Mermaid mode is invalid");
|
|
255
|
+
this.root.setMermaidRenderingMode(value);
|
|
256
|
+
} },
|
|
257
|
+
showImages: { apply: value => {
|
|
258
|
+
if (typeof value !== "boolean")
|
|
259
|
+
throw new TypeError("Image visibility is invalid");
|
|
260
|
+
this.#showImages = value;
|
|
261
|
+
this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
|
|
262
|
+
} },
|
|
263
|
+
imageWidthCells: { apply: value => {
|
|
264
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)
|
|
265
|
+
throw new TypeError("Image width is invalid");
|
|
266
|
+
this.#imageWidthCells = value;
|
|
267
|
+
this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
|
|
268
|
+
} },
|
|
269
|
+
});
|
|
726
270
|
this.#extensionBridge = createPiExtensionUiBridge({
|
|
727
271
|
runtime: {
|
|
728
272
|
getColumns: () => this.runtime.viewport().columns,
|
|
@@ -730,7 +274,7 @@ export class OwnedUiSessionShell {
|
|
|
730
274
|
requestRender: () => this.runtime.requestRender(),
|
|
731
275
|
},
|
|
732
276
|
agentDir: this.backend.agentDir,
|
|
733
|
-
setInputSurface: component => this.root.setInputSurface(component),
|
|
277
|
+
setInputSurface: component => this.root.setInputSurface(component, true, "opaque"),
|
|
734
278
|
showOverlay: (component, overlayOptions) => this.runtime.showOverlay(component, overlayOptions),
|
|
735
279
|
listenInput: handler => this.runtime.addInputListener(handler),
|
|
736
280
|
replaceWidget: (key, component, placement) => this.root.setExtensionWidget(key, component, placement),
|
|
@@ -744,7 +288,7 @@ export class OwnedUiSessionShell {
|
|
|
744
288
|
setEditorText: text => this.root.editor.setText(text),
|
|
745
289
|
pasteToEditor: text => this.root.editor.insertText(text),
|
|
746
290
|
addAutocompleteProvider: factory => this.root.editor.addAutocompleteProvider(factory),
|
|
747
|
-
setCustomEditor: component => this.root.setInputSurface(component),
|
|
291
|
+
setCustomEditor: component => this.root.setInputSurface(component, true, "opaque"),
|
|
748
292
|
getFooterData: () => this.root.extensionFooterData(),
|
|
749
293
|
getToolsExpanded: () => this.root.toolsExpanded,
|
|
750
294
|
setToolsExpanded: expanded => this.root.setToolsExpanded(expanded),
|
|
@@ -753,13 +297,26 @@ export class OwnedUiSessionShell {
|
|
|
753
297
|
startLogin: request => this.#startWorkflowLogin(request),
|
|
754
298
|
prompt: request => this.#requestWorkflowInput(request),
|
|
755
299
|
notify: event => this.#notifyWorkflowLogin(event),
|
|
300
|
+
publish: message => {
|
|
301
|
+
this.root.appendWorkflowMessage(message);
|
|
302
|
+
this.runtime.requestRender();
|
|
303
|
+
},
|
|
756
304
|
finishLogin: () => this.#finishWorkflowLogin(),
|
|
757
305
|
});
|
|
758
306
|
this.root.editor.setAutocompleteCommands(this.backend.workflowAutocompleteCommands());
|
|
759
307
|
this.#unsubscribe = this.backend.onEvent(event => {
|
|
760
|
-
//
|
|
761
|
-
//
|
|
762
|
-
|
|
308
|
+
// Performance: a streamed chunk names one block, and touching only that block is what keeps the
|
|
309
|
+
// cost of a chunk the same in a long session as in a new one. Everything else
|
|
310
|
+
// resynchronizes the view, which is cheap next to re-reading the transcript.
|
|
311
|
+
if (event.type === "agent-run-started")
|
|
312
|
+
this.root.resumeViewportFollowing();
|
|
313
|
+
if (event.type === "assistant-message-completed")
|
|
314
|
+
this.root.noteCompletedAssistantMessage();
|
|
315
|
+
const semanticOnly = event.type === "agent-run-started" || event.type === "assistant-message-completed";
|
|
316
|
+
const view = event.type === "transcript-block" && this.#sessionGeneration === this.backend.sessionGeneration
|
|
317
|
+
? this.#syncBlock(event.block)
|
|
318
|
+
: semanticOnly ? this.view() : this.#syncView();
|
|
319
|
+
this.#syncTerminalProgress(view);
|
|
763
320
|
if (view.lifecycle === "ready" && this.#compactionQueue.length > 0)
|
|
764
321
|
void this.#flushCompactionQueue();
|
|
765
322
|
if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
|
|
@@ -771,11 +328,17 @@ export class OwnedUiSessionShell {
|
|
|
771
328
|
view() {
|
|
772
329
|
return this.backend.view();
|
|
773
330
|
}
|
|
331
|
+
damagePresentationDecision() {
|
|
332
|
+
return this.#damageTerminal?.lastDecision ?? null;
|
|
333
|
+
}
|
|
774
334
|
start() {
|
|
775
335
|
if (this.#started)
|
|
776
336
|
return;
|
|
777
337
|
this.#started = true;
|
|
778
338
|
this.runtime.start();
|
|
339
|
+
this.#syncTerminalProgress(this.view());
|
|
340
|
+
if (this.#customViewport)
|
|
341
|
+
this.#setPointerReporting(true);
|
|
779
342
|
void this.backend.bindExtensionUi(this.#extensionBridge.context, () => { void this.shutdown(); });
|
|
780
343
|
this.#syncView();
|
|
781
344
|
}
|
|
@@ -788,16 +351,18 @@ export class OwnedUiSessionShell {
|
|
|
788
351
|
return this.#stopped;
|
|
789
352
|
}
|
|
790
353
|
async submit(text) {
|
|
791
|
-
const
|
|
792
|
-
if (!
|
|
354
|
+
const displayInput = text.trim();
|
|
355
|
+
if (!displayInput)
|
|
793
356
|
return { outcome: "completed", diagnostic: null };
|
|
794
|
-
if (
|
|
795
|
-
return this.#slashCommand(
|
|
357
|
+
if (displayInput.startsWith("/"))
|
|
358
|
+
return this.#slashCommand(displayInput);
|
|
359
|
+
const prepared = this.root.preparePromptSubmission(displayInput);
|
|
360
|
+
const input = prepared.text.trim();
|
|
796
361
|
if (input.startsWith("!")) {
|
|
797
362
|
const excludeFromContext = input.startsWith("!!");
|
|
798
363
|
const command = input.slice(excludeFromContext ? 2 : 1).trim();
|
|
799
364
|
if (command) {
|
|
800
|
-
this.root.editor.addToHistory(
|
|
365
|
+
this.root.editor.addToHistory(displayInput);
|
|
801
366
|
try {
|
|
802
367
|
const result = await this.backend.executeBashWorkflow(command, excludeFromContext);
|
|
803
368
|
const workflow = {
|
|
@@ -819,19 +384,25 @@ export class OwnedUiSessionShell {
|
|
|
819
384
|
}
|
|
820
385
|
}
|
|
821
386
|
if (this.view().status.workingMessage?.startsWith("Compacting") === true) {
|
|
822
|
-
this.root.editor.addToHistory(
|
|
823
|
-
this.#compactionQueue.push({
|
|
387
|
+
this.root.editor.addToHistory(displayInput);
|
|
388
|
+
this.#compactionQueue.push({
|
|
389
|
+
text: input,
|
|
390
|
+
type: "steer",
|
|
391
|
+
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
392
|
+
});
|
|
824
393
|
this.root.appendWorkflowResult({ command: "compact", outcome: "completed", message: `Queued during compaction: ${input}` });
|
|
825
394
|
this.runtime.requestRender();
|
|
826
395
|
return { outcome: "completed", diagnostic: null };
|
|
827
396
|
}
|
|
828
397
|
const type = this.view().lifecycle === "busy" ? "steer" : "prompt";
|
|
829
|
-
this.root.editor.addToHistory(
|
|
398
|
+
this.root.editor.addToHistory(displayInput);
|
|
399
|
+
this.root.resumeViewportFollowing();
|
|
830
400
|
return this.#execute({
|
|
831
401
|
type,
|
|
832
402
|
correlationId: this.#correlation(type),
|
|
833
403
|
sessionId: this.backend.sessionId,
|
|
834
404
|
text: input,
|
|
405
|
+
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
835
406
|
});
|
|
836
407
|
}
|
|
837
408
|
async clearOrExit(now = Date.now()) {
|
|
@@ -842,14 +413,29 @@ export class OwnedUiSessionShell {
|
|
|
842
413
|
this.runtime.requestRender();
|
|
843
414
|
return { outcome: "completed", diagnostic: null };
|
|
844
415
|
}
|
|
845
|
-
async interrupt() {
|
|
416
|
+
async interrupt(now = Date.now()) {
|
|
846
417
|
if (this.view().lifecycle === "busy")
|
|
847
418
|
return this.abort();
|
|
848
|
-
if (this.root.editor.getText().length > 0) {
|
|
419
|
+
if (this.root.editor.getText().trim().length > 0) {
|
|
849
420
|
this.root.editor.setText("");
|
|
850
421
|
return { outcome: "completed", diagnostic: null };
|
|
851
422
|
}
|
|
852
|
-
|
|
423
|
+
// Compatibility: match Pi: with an empty editor, two escapes inside 500 ms open the
|
|
424
|
+
// configured session navigator. The first escape intentionally does not
|
|
425
|
+
// interrupt or mutate the prompt.
|
|
426
|
+
const action = this.backend.pinnedSettingsSnapshot().doubleEscapeAction;
|
|
427
|
+
if (action === "none")
|
|
428
|
+
return { outcome: "rejected", diagnostic: "nothing to interrupt" };
|
|
429
|
+
if (now - this.#lastEscapeTime < 500) {
|
|
430
|
+
this.#lastEscapeTime = 0;
|
|
431
|
+
if (action === "tree")
|
|
432
|
+
this.showTreeSelector();
|
|
433
|
+
else
|
|
434
|
+
this.showForkSelector();
|
|
435
|
+
return { outcome: "completed", diagnostic: null };
|
|
436
|
+
}
|
|
437
|
+
this.#lastEscapeTime = now;
|
|
438
|
+
return { outcome: "completed", diagnostic: null };
|
|
853
439
|
}
|
|
854
440
|
async abort() {
|
|
855
441
|
return this.#execute(this.#simple("abort"));
|
|
@@ -901,13 +487,20 @@ export class OwnedUiSessionShell {
|
|
|
901
487
|
return workflowAdapterResult(result);
|
|
902
488
|
}
|
|
903
489
|
async queueFollowUp() {
|
|
904
|
-
const
|
|
905
|
-
if (!
|
|
490
|
+
const displayInput = this.root.editor.getText().trim();
|
|
491
|
+
if (!displayInput)
|
|
906
492
|
return rejected("nothing to queue");
|
|
907
|
-
this.root.
|
|
493
|
+
const prepared = this.root.preparePromptSubmission(displayInput);
|
|
494
|
+
const text = prepared.text.trim();
|
|
495
|
+
this.root.editor.addToHistory(displayInput);
|
|
908
496
|
this.root.editor.setText("");
|
|
497
|
+
this.root.resumeViewportFollowing();
|
|
909
498
|
if (this.view().status.workingMessage?.startsWith("Compacting") === true) {
|
|
910
|
-
this.#compactionQueue.push({
|
|
499
|
+
this.#compactionQueue.push({
|
|
500
|
+
text,
|
|
501
|
+
type: "follow-up",
|
|
502
|
+
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
503
|
+
});
|
|
911
504
|
return { outcome: "completed", diagnostic: null };
|
|
912
505
|
}
|
|
913
506
|
return this.#execute({
|
|
@@ -915,6 +508,7 @@ export class OwnedUiSessionShell {
|
|
|
915
508
|
correlationId: this.#correlation("follow-up"),
|
|
916
509
|
sessionId: this.backend.sessionId,
|
|
917
510
|
text,
|
|
511
|
+
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
918
512
|
});
|
|
919
513
|
}
|
|
920
514
|
restoreQueuedInput() {
|
|
@@ -927,6 +521,8 @@ export class OwnedUiSessionShell {
|
|
|
927
521
|
}
|
|
928
522
|
showSelector(title, options, onSelect, onCancel) {
|
|
929
523
|
this.#dialogHandle?.hide();
|
|
524
|
+
this.#dialogSource = "local";
|
|
525
|
+
this.#dialogId = undefined;
|
|
930
526
|
const component = createPiShellSelector({
|
|
931
527
|
title,
|
|
932
528
|
options,
|
|
@@ -934,18 +530,25 @@ export class OwnedUiSessionShell {
|
|
|
934
530
|
onSelect(id);
|
|
935
531
|
this.#dialogHandle?.hide();
|
|
936
532
|
this.#dialogHandle = undefined;
|
|
533
|
+
this.#dialogSource = undefined;
|
|
937
534
|
},
|
|
938
535
|
onCancel: () => {
|
|
939
536
|
this.#dialogHandle?.hide();
|
|
940
537
|
this.#dialogHandle = undefined;
|
|
538
|
+
this.#dialogSource = undefined;
|
|
941
539
|
onCancel?.();
|
|
942
540
|
},
|
|
943
541
|
});
|
|
944
|
-
const handle = this.runtime.showOverlay(component, {
|
|
542
|
+
const handle = this.runtime.showOverlay(component, {
|
|
543
|
+
width: "70%",
|
|
544
|
+
maxHeight: "80%",
|
|
545
|
+
anchor: "center",
|
|
546
|
+
inputCoordination: "owned",
|
|
547
|
+
});
|
|
945
548
|
this.#dialogHandle = handle;
|
|
946
549
|
return handle;
|
|
947
550
|
}
|
|
948
|
-
showModelSelector() {
|
|
551
|
+
showModelSelector(initialSearchInput) {
|
|
949
552
|
const context = this.backend.pinnedModelSelectorContext();
|
|
950
553
|
const close = () => {
|
|
951
554
|
this.root.setInputSurface(null);
|
|
@@ -958,6 +561,7 @@ export class OwnedUiSessionShell {
|
|
|
958
561
|
getRows: () => this.runtime.viewport().rows,
|
|
959
562
|
requestRender: () => this.runtime.requestRender(),
|
|
960
563
|
},
|
|
564
|
+
...(initialSearchInput === undefined ? {} : { initialSearchInput }),
|
|
961
565
|
onSelect: model => {
|
|
962
566
|
close();
|
|
963
567
|
void this.runWorkflow({ command: "model", argument: "", selection: modelReference(model) });
|
|
@@ -970,7 +574,7 @@ export class OwnedUiSessionShell {
|
|
|
970
574
|
showForkSelector() {
|
|
971
575
|
const options = this.backend.pinnedForkOptions();
|
|
972
576
|
if (options.length === 0) {
|
|
973
|
-
this.root.appendWorkflowResult({ command: "fork", outcome: "
|
|
577
|
+
this.root.appendWorkflowResult({ command: "fork", outcome: "completed", message: "No messages to fork from", messageKind: "status" });
|
|
974
578
|
this.runtime.requestRender();
|
|
975
579
|
return;
|
|
976
580
|
}
|
|
@@ -986,9 +590,21 @@ export class OwnedUiSessionShell {
|
|
|
986
590
|
this.runtime.requestRender();
|
|
987
591
|
}
|
|
988
592
|
async showLogoutSelector() {
|
|
989
|
-
|
|
593
|
+
let options;
|
|
594
|
+
try {
|
|
595
|
+
options = await this.backend.pinnedLogoutOptions();
|
|
596
|
+
}
|
|
597
|
+
catch (error) {
|
|
598
|
+
this.root.appendWorkflowResult({
|
|
599
|
+
command: "logout",
|
|
600
|
+
outcome: "failed",
|
|
601
|
+
message: `Could not read stored credentials: ${error instanceof Error ? error.message : String(error)}`,
|
|
602
|
+
});
|
|
603
|
+
this.runtime.requestRender();
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
990
606
|
if (options.length === 0) {
|
|
991
|
-
this.root.appendWorkflowStatus("No
|
|
607
|
+
this.root.appendWorkflowStatus("No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.");
|
|
992
608
|
this.runtime.requestRender();
|
|
993
609
|
return;
|
|
994
610
|
}
|
|
@@ -1141,6 +757,10 @@ export class OwnedUiSessionShell {
|
|
|
1141
757
|
return;
|
|
1142
758
|
}
|
|
1143
759
|
if (callback === "onTuiModeChange") {
|
|
760
|
+
// Invariant: the custom bare-A1 surface is permanently fullscreen; this callback
|
|
761
|
+
// remains available only to pinned comparison profiles.
|
|
762
|
+
if (this.#customViewport)
|
|
763
|
+
return;
|
|
1144
764
|
if (value !== "regular" && value !== "fullscreen")
|
|
1145
765
|
return;
|
|
1146
766
|
if (!this.runtime.switchMode(value)) {
|
|
@@ -1148,13 +768,18 @@ export class OwnedUiSessionShell {
|
|
|
1148
768
|
this.runtime.requestRender();
|
|
1149
769
|
return;
|
|
1150
770
|
}
|
|
771
|
+
if (this.#customViewport) {
|
|
772
|
+
this.#pointerReporting = false;
|
|
773
|
+
this.#setPointerReporting(true);
|
|
774
|
+
}
|
|
1151
775
|
}
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
776
|
+
void this.backend.applyPinnedSettingValue(callback, value).then(result => {
|
|
777
|
+
if (result.outcome === "failed")
|
|
778
|
+
this.root.appendWorkflowResult(result);
|
|
779
|
+
else if (callback === "onTuiModeChange")
|
|
780
|
+
this.root.appendWorkflowStatus(`TUI mode: ${value}`);
|
|
781
|
+
this.runtime.requestRender();
|
|
782
|
+
});
|
|
1158
783
|
},
|
|
1159
784
|
onCancel: close,
|
|
1160
785
|
});
|
|
@@ -1200,10 +825,6 @@ export class OwnedUiSessionShell {
|
|
|
1200
825
|
await this.showLogoutSelector();
|
|
1201
826
|
return { outcome: "completed", diagnostic: null };
|
|
1202
827
|
}
|
|
1203
|
-
if (request.command === "import" && request.confirmed === undefined && request.argument.trim().length > 0) {
|
|
1204
|
-
const confirmed = await this.#extensionBridge.context.confirm("Import session", `Replace current session with ${request.argument.trim()}?`);
|
|
1205
|
-
return this.runWorkflow({ ...request, confirmed: confirmed === true });
|
|
1206
|
-
}
|
|
1207
828
|
if (request.command === "tree" && request.selection === undefined && request.confirmed === undefined && request.argument.trim().length === 0) {
|
|
1208
829
|
this.showTreeSelector();
|
|
1209
830
|
return { outcome: "completed", diagnostic: null };
|
|
@@ -1212,22 +833,21 @@ export class OwnedUiSessionShell {
|
|
|
1212
833
|
this.root.resetExtensionUi();
|
|
1213
834
|
this.root.resetWorkflowPresentation();
|
|
1214
835
|
}
|
|
1215
|
-
const
|
|
836
|
+
const shareSurface = request.command === "share"
|
|
1216
837
|
? createPiShellOperationLoader({
|
|
1217
838
|
getColumns: () => this.runtime.viewport().columns,
|
|
1218
839
|
getRows: () => this.runtime.viewport().rows,
|
|
1219
840
|
requestRender: () => this.runtime.requestRender(),
|
|
1220
841
|
}, "Creating gist...")
|
|
1221
|
-
:
|
|
1222
|
-
|
|
1223
|
-
: undefined;
|
|
842
|
+
: undefined;
|
|
843
|
+
const operationSurface = shareSurface ?? (request.command === "reload" ? createPiShellReloadBox() : undefined);
|
|
1224
844
|
if (operationSurface) {
|
|
1225
845
|
this.root.setInputSurface(operationSurface);
|
|
1226
846
|
this.runtime.requestRender();
|
|
1227
847
|
}
|
|
1228
848
|
let result;
|
|
1229
849
|
try {
|
|
1230
|
-
result = await this.backend.executeWorkflow(request);
|
|
850
|
+
result = await this.backend.executeWorkflow(shareSurface === undefined ? request : { ...request, signal: shareSurface.signal });
|
|
1231
851
|
}
|
|
1232
852
|
finally {
|
|
1233
853
|
if (operationSurface) {
|
|
@@ -1235,10 +855,27 @@ export class OwnedUiSessionShell {
|
|
|
1235
855
|
this.runtime.requestRender();
|
|
1236
856
|
}
|
|
1237
857
|
}
|
|
858
|
+
if (result.outcome === "requires-selection" && request.command === "model") {
|
|
859
|
+
if (result.messages !== undefined) {
|
|
860
|
+
for (const message of result.messages)
|
|
861
|
+
this.root.appendWorkflowMessage(message);
|
|
862
|
+
}
|
|
863
|
+
this.showModelSelector((result.detail ?? request.argument.trim()) || undefined);
|
|
864
|
+
return { outcome: "completed", diagnostic: null };
|
|
865
|
+
}
|
|
1238
866
|
if (result.outcome === "requires-confirmation" && request.command === "resume") {
|
|
1239
867
|
const confirmed = await this.#extensionBridge.context.confirm("Session cwd not found", result.message);
|
|
1240
868
|
return this.runWorkflow({ ...request, confirmed: confirmed === true });
|
|
1241
869
|
}
|
|
870
|
+
if (result.outcome === "requires-confirmation" && request.command === "import") {
|
|
871
|
+
const recoveringCwd = result.detail !== undefined;
|
|
872
|
+
const confirmed = await this.#extensionBridge.context.confirm(recoveringCwd ? "Session cwd not found" : "Import session", result.message);
|
|
873
|
+
return this.runWorkflow({
|
|
874
|
+
...request,
|
|
875
|
+
confirmed: confirmed === true,
|
|
876
|
+
...(confirmed === true && result.detail ? { cwdOverride: result.detail } : {}),
|
|
877
|
+
});
|
|
878
|
+
}
|
|
1242
879
|
if (result.outcome === "requires-selection" || result.outcome === "requires-confirmation") {
|
|
1243
880
|
this.root.appendWorkflowResult({ command: request.command, outcome: "failed", message: `Owned controller missing for ${request.command}` });
|
|
1244
881
|
this.runtime.requestRender();
|
|
@@ -1353,22 +990,85 @@ export class OwnedUiSessionShell {
|
|
|
1353
990
|
this.root.appendDaxnuts();
|
|
1354
991
|
}
|
|
1355
992
|
}
|
|
993
|
+
// Invariant: pointer reporting is disabled on every path that ends the owning screen.
|
|
994
|
+
#setPointerReporting(enabled, forceOff = false) {
|
|
995
|
+
const effective = forceOff ? false : this.#customViewport || enabled;
|
|
996
|
+
if (this.#pointerReporting === effective)
|
|
997
|
+
return;
|
|
998
|
+
this.#pointerReporting = effective;
|
|
999
|
+
if (!this.runtime.active)
|
|
1000
|
+
return;
|
|
1001
|
+
this.runtime.writeControl(effective ? MOUSE_TRACKING_ON : MOUSE_TRACKING_OFF);
|
|
1002
|
+
}
|
|
1356
1003
|
async dispose() {
|
|
1357
1004
|
if (this.#disposed)
|
|
1358
1005
|
return;
|
|
1359
1006
|
this.#disposed = true;
|
|
1007
|
+
this.root.clearViewportPointerState();
|
|
1008
|
+
this.#setPointerReporting(false, true);
|
|
1009
|
+
this.#removeViewportPreInput();
|
|
1010
|
+
this.#streamPresentation.dispose();
|
|
1011
|
+
this.#unsubscribeSettings();
|
|
1012
|
+
const exitMode = this.backend.disposed
|
|
1013
|
+
? this.#fullscreenExitOutput
|
|
1014
|
+
: this.backend.pinnedSettingsSnapshot().fullscreenExitOutput;
|
|
1015
|
+
const exitTranscript = this.root.exitTranscript(this.runtime.viewport().columns);
|
|
1016
|
+
const resume = this.backend.currentSessionResumeMetadata();
|
|
1017
|
+
const resumeHint = resume === null
|
|
1018
|
+
? ""
|
|
1019
|
+
: `${dim("To resume this session:")} ${formatSessionResumeCommand(resume)}`;
|
|
1020
|
+
const fullscreenExitText = this.runtime.mode !== "fullscreen"
|
|
1021
|
+
? ""
|
|
1022
|
+
: exitMode === "resume-hint"
|
|
1023
|
+
? resumeHint
|
|
1024
|
+
: [exitTranscript, resumeHint].filter(Boolean).join("\n\n");
|
|
1025
|
+
this.#unbindPiSettings();
|
|
1026
|
+
this.#unbindTerminalSettings();
|
|
1027
|
+
this.#unbindShutdownSettings();
|
|
1360
1028
|
this.#unsubscribe();
|
|
1361
1029
|
this.#dialogHandle?.hide();
|
|
1362
1030
|
await this.backend.unbindExtensionUi();
|
|
1363
1031
|
this.#extensionBridge.dispose();
|
|
1364
1032
|
await this.runtime.dispose();
|
|
1033
|
+
if (fullscreenExitText.length > 0)
|
|
1034
|
+
this.runtime.writeAfterStop(`${fullscreenExitText}\n`);
|
|
1035
|
+
}
|
|
1036
|
+
// Invariant: incremental block updates notify listeners with the same complete view contract.
|
|
1037
|
+
#syncBlock(block) {
|
|
1038
|
+
this.root.applyTranscriptBlock(block);
|
|
1039
|
+
if (this.#customViewport && block.status === "live" && isCoalescedStreamBlock(block.kind)) {
|
|
1040
|
+
this.#streamPresentation.request();
|
|
1041
|
+
}
|
|
1042
|
+
else if (this.#streamPresentation.pending) {
|
|
1043
|
+
this.#streamPresentation.flush();
|
|
1044
|
+
}
|
|
1045
|
+
else {
|
|
1046
|
+
this.#streamPresentation.presentImmediate();
|
|
1047
|
+
}
|
|
1048
|
+
const view = this.view();
|
|
1049
|
+
for (const listener of this.#listeners)
|
|
1050
|
+
listener(view);
|
|
1051
|
+
return view;
|
|
1052
|
+
}
|
|
1053
|
+
#syncTerminalProgress(view) {
|
|
1054
|
+
if (!this.runtime.active)
|
|
1055
|
+
return;
|
|
1056
|
+
this.runtime.setTerminalProgress(this.#terminalProgressEnabled && view.lifecycle === "busy");
|
|
1365
1057
|
}
|
|
1366
1058
|
#syncView() {
|
|
1059
|
+
this.#streamPresentation.noteImmediatePresentation();
|
|
1367
1060
|
const view = this.view();
|
|
1368
1061
|
if (this.backend.sessionGeneration !== this.#sessionGeneration) {
|
|
1369
1062
|
this.#sessionGeneration = this.backend.sessionGeneration;
|
|
1370
1063
|
this.#activeLoginDialog = undefined;
|
|
1371
1064
|
this.#extensionBridge.reset();
|
|
1065
|
+
// Invariant: a replaced session takes its transient viewport and owned-route state with it.
|
|
1066
|
+
this.root.resetViewport();
|
|
1067
|
+
this.#dialogHandle?.hide();
|
|
1068
|
+
this.#dialogHandle = undefined;
|
|
1069
|
+
this.#dialogId = undefined;
|
|
1070
|
+
this.#dialogSource = undefined;
|
|
1071
|
+
this.#setPointerReporting(false);
|
|
1372
1072
|
this.root.setInputSurface(null);
|
|
1373
1073
|
this.root.resetExtensionUi();
|
|
1374
1074
|
this.root.resetWorkflowPresentation();
|
|
@@ -1387,10 +1087,11 @@ export class OwnedUiSessionShell {
|
|
|
1387
1087
|
if (!this.runtime.active)
|
|
1388
1088
|
return { outcome: "failed", diagnostic: "runtime is not active" };
|
|
1389
1089
|
this.#dialogHandle?.hide();
|
|
1390
|
-
|
|
1090
|
+
this.#dialogSource = "route";
|
|
1091
|
+
// Protocol: any-event reporting: hover and drag are what the screen is driven by, and
|
|
1391
1092
|
// it also stops the terminal treating a drag as a text selection.
|
|
1392
|
-
this
|
|
1393
|
-
//
|
|
1093
|
+
this.#setPointerReporting(true);
|
|
1094
|
+
// Protocol: the interrupt chord is global, so it is watched on raw input rather than
|
|
1394
1095
|
// through the overlay: the pinned shell handles that key before an overlay
|
|
1395
1096
|
// ever sees it, which is why an owned screen must not rely on being asked.
|
|
1396
1097
|
let armedAt = 0;
|
|
@@ -1406,17 +1107,36 @@ export class OwnedUiSessionShell {
|
|
|
1406
1107
|
}
|
|
1407
1108
|
armedAt = now;
|
|
1408
1109
|
this.runtime.requestRender();
|
|
1409
|
-
//
|
|
1110
|
+
// Invariant: the presented screen owns the chord, so the pinned shell never sees a
|
|
1410
1111
|
// stray interrupt while it is up.
|
|
1411
1112
|
return { consume: true };
|
|
1412
1113
|
});
|
|
1114
|
+
let removeSurfacePreInput = () => { };
|
|
1413
1115
|
const closeSurface = () => {
|
|
1116
|
+
removeSurfacePreInput();
|
|
1414
1117
|
removeInterruptWatch();
|
|
1415
|
-
this
|
|
1118
|
+
this.#setPointerReporting(false);
|
|
1416
1119
|
this.#dialogHandle?.hide();
|
|
1417
1120
|
this.#dialogHandle = undefined;
|
|
1418
1121
|
this.#dialogId = undefined;
|
|
1122
|
+
this.#dialogSource = undefined;
|
|
1419
1123
|
};
|
|
1124
|
+
// Compatibility: fullscreen Pi owns a fallback text-selection layer before focused overlay
|
|
1125
|
+
// components see pointer input. Route every mouse report to the owned screen
|
|
1126
|
+
// at the pre-input boundary so dropdowns, value hover, and numeric +/- work,
|
|
1127
|
+
// and consume even unhandled reports so settings content is never selected.
|
|
1128
|
+
removeSurfacePreInput = this.runtime.addPreInputListener(data => {
|
|
1129
|
+
const { events, rest } = parseMouseInput(data);
|
|
1130
|
+
if (events.length === 0)
|
|
1131
|
+
return undefined;
|
|
1132
|
+
for (const event of events)
|
|
1133
|
+
surface.handleMouse(event);
|
|
1134
|
+
if (surface.isClosed())
|
|
1135
|
+
closeSurface();
|
|
1136
|
+
else
|
|
1137
|
+
this.runtime.requestRender();
|
|
1138
|
+
return rest.length === 0 ? { consume: true } : { data: rest };
|
|
1139
|
+
});
|
|
1420
1140
|
const rows = () => Math.max(1, this.runtime.viewport().rows);
|
|
1421
1141
|
const component = {
|
|
1422
1142
|
render: (width) => [...surface.render(Math.max(1, width), rows())],
|
|
@@ -1439,7 +1159,12 @@ export class OwnedUiSessionShell {
|
|
|
1439
1159
|
closeSurface();
|
|
1440
1160
|
void this.shutdown();
|
|
1441
1161
|
});
|
|
1442
|
-
this.#dialogHandle = this.runtime.showOverlay(component, {
|
|
1162
|
+
this.#dialogHandle = this.runtime.showOverlay(component, {
|
|
1163
|
+
width: "100%",
|
|
1164
|
+
maxHeight: "100%",
|
|
1165
|
+
anchor: "top-left",
|
|
1166
|
+
inputCoordination: "owned",
|
|
1167
|
+
});
|
|
1443
1168
|
this.#dialogId = surface.id;
|
|
1444
1169
|
return { outcome: "completed", diagnostic: null };
|
|
1445
1170
|
}
|
|
@@ -1447,25 +1172,40 @@ export class OwnedUiSessionShell {
|
|
|
1447
1172
|
if (!this.runtime.active)
|
|
1448
1173
|
return;
|
|
1449
1174
|
if (dialog === null) {
|
|
1175
|
+
// Invariant: locally owned routes (notably /settings) are independent of backend
|
|
1176
|
+
// lifecycle/status events and remain open while an agent is working.
|
|
1177
|
+
if (this.#dialogSource !== "backend")
|
|
1178
|
+
return;
|
|
1450
1179
|
this.#dialogHandle?.hide();
|
|
1451
1180
|
this.#dialogHandle = undefined;
|
|
1452
1181
|
this.#dialogId = undefined;
|
|
1182
|
+
this.#dialogSource = undefined;
|
|
1453
1183
|
return;
|
|
1454
1184
|
}
|
|
1455
|
-
if (this.#dialogId === dialog.id)
|
|
1185
|
+
if (this.#dialogSource === "backend" && this.#dialogId === dialog.id)
|
|
1456
1186
|
return;
|
|
1457
1187
|
this.#dialogHandle?.hide();
|
|
1188
|
+
this.#dialogSource = "backend";
|
|
1458
1189
|
const component = createPiShellDialog(dialog, {
|
|
1459
1190
|
onSelect: () => {
|
|
1460
1191
|
this.#dialogHandle?.hide();
|
|
1461
1192
|
this.#dialogHandle = undefined;
|
|
1193
|
+
this.#dialogId = undefined;
|
|
1194
|
+
this.#dialogSource = undefined;
|
|
1462
1195
|
},
|
|
1463
1196
|
onCancel: () => {
|
|
1464
1197
|
this.#dialogHandle?.hide();
|
|
1465
1198
|
this.#dialogHandle = undefined;
|
|
1199
|
+
this.#dialogId = undefined;
|
|
1200
|
+
this.#dialogSource = undefined;
|
|
1466
1201
|
},
|
|
1467
1202
|
});
|
|
1468
|
-
this.#dialogHandle = this.runtime.showOverlay(component, {
|
|
1203
|
+
this.#dialogHandle = this.runtime.showOverlay(component, {
|
|
1204
|
+
width: "70%",
|
|
1205
|
+
maxHeight: "80%",
|
|
1206
|
+
anchor: "center",
|
|
1207
|
+
inputCoordination: "owned",
|
|
1208
|
+
});
|
|
1469
1209
|
this.#dialogId = dialog.id;
|
|
1470
1210
|
}
|
|
1471
1211
|
async #slashCommand(text) {
|
|
@@ -1477,8 +1217,9 @@ export class OwnedUiSessionShell {
|
|
|
1477
1217
|
return this.#openOwnedRoute(name);
|
|
1478
1218
|
if (isWorkflowRoute(name))
|
|
1479
1219
|
return this.runWorkflow({ command: name, argument });
|
|
1480
|
-
//
|
|
1220
|
+
// Compatibility: unknown slash input, prompt templates, skills, and extension commands remain Pi prompt input.
|
|
1481
1221
|
this.root.editor.addToHistory(text);
|
|
1222
|
+
this.root.resumeViewportFollowing();
|
|
1482
1223
|
return this.#execute({
|
|
1483
1224
|
type: this.view().lifecycle === "busy" ? "steer" : "prompt",
|
|
1484
1225
|
correlationId: this.#correlation("prompt-command"),
|
|
@@ -1600,6 +1341,7 @@ export class OwnedUiSessionShell {
|
|
|
1600
1341
|
correlationId: this.#correlation(`compaction-${item.type}`),
|
|
1601
1342
|
sessionId: this.backend.sessionId,
|
|
1602
1343
|
text: item.text,
|
|
1344
|
+
...(item.images === undefined ? {} : { images: item.images }),
|
|
1603
1345
|
});
|
|
1604
1346
|
}
|
|
1605
1347
|
}
|
|
@@ -1614,6 +1356,24 @@ export class OwnedUiSessionShell {
|
|
|
1614
1356
|
return `pi-shell-${prefix}-${this.#sequence}`;
|
|
1615
1357
|
}
|
|
1616
1358
|
}
|
|
1359
|
+
function isCoalescedStreamBlock(kind) {
|
|
1360
|
+
return kind === "assistant" || kind === "thinking" || kind === "tool-call" || kind === "tool-result";
|
|
1361
|
+
}
|
|
1362
|
+
export function formatSessionResumeCommand(metadata) {
|
|
1363
|
+
const args = [PRODUCT_TEXT.commandName];
|
|
1364
|
+
if (!metadata.usesDefaultSessionDir)
|
|
1365
|
+
args.push("--session-dir", quoteCommandArgument(metadata.sessionDir));
|
|
1366
|
+
args.push("--session", metadata.sessionId);
|
|
1367
|
+
return args.join(" ");
|
|
1368
|
+
}
|
|
1369
|
+
export function quoteCommandArgument(value) {
|
|
1370
|
+
if (value.length > 0 && !/[^a-zA-Z0-9_\-./~:@]/.test(value))
|
|
1371
|
+
return value;
|
|
1372
|
+
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
1373
|
+
}
|
|
1374
|
+
function dim(value) {
|
|
1375
|
+
return `\u001b[2m${value}\u001b[22m`;
|
|
1376
|
+
}
|
|
1617
1377
|
function modelReference(model) {
|
|
1618
1378
|
if (typeof model !== "object" || model === null)
|
|
1619
1379
|
return "";
|