@timurproko/a1 0.1.8-dev.21b95d6 → 0.1.8-dev.224
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -67
- package/bin/cli.js +28 -10
- package/bin/guardian.js +4 -1
- 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 +1 -1
- package/bin/sync-pi-tui-proxy.js +97 -0
- package/bin/ui.js +25 -6
- package/bin/warmup.js +18 -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 +6 -0
- package/dist/cli/dispatch.js +202 -0
- package/dist/{src/cli → cli}/packages.d.ts +10 -2
- package/dist/{src/cli → cli}/packages.js +24 -20
- 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 +28 -0
- package/dist/composition/owned-ui.js +64 -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/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/{src/features → features}/launch/intent.d.ts +3 -2
- package/dist/features/launch/intent.js +3 -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 +1 -0
- package/dist/{src/features → features}/owned-ui/index.js +1 -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/{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.js +10 -2
- 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 +28 -0
- package/dist/{src/foundation → foundation}/lifecycle/paths.js +21 -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/{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 +1 -0
- package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.js +1 -0
- 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 +14 -4
- package/dist/{src/foundation → foundation}/release/bootstrap.js +66 -13
- package/dist/foundation/release/cohort-state.d.ts +131 -0
- package/dist/foundation/release/cohort-state.js +384 -0
- package/dist/foundation/release/dependency-layer.d.ts +78 -0
- package/dist/foundation/release/dependency-layer.js +487 -0
- package/dist/foundation/release/endpoints.d.ts +20 -0
- package/dist/foundation/release/endpoints.js +50 -0
- package/dist/{src/foundation → foundation}/release/index.d.ts +3 -0
- package/dist/{src/foundation → foundation}/release/index.js +3 -0
- package/dist/foundation/release/release-gc.d.ts +60 -0
- package/dist/foundation/release/release-gc.js +538 -0
- package/dist/{src/foundation → foundation}/release/release-store.d.ts +3 -1
- package/dist/{src/foundation → foundation}/release/release-store.js +60 -10
- package/dist/{src/foundation → foundation}/release/release.d.ts +4 -1
- package/dist/{src/foundation → foundation}/release/release.js +10 -3
- 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 +114 -54
- 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/{src/foundation → foundation}/supervision/main.js +11 -5
- 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 +51 -2
- 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/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 +32 -17
- 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 +1 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.d.ts +52 -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 +22 -4
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.js +289 -68
- 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 +3 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.js +3 -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 +2 -2
- 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 +16 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.js +39 -4
- 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/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/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 +137 -0
- package/dist/integrations/pi/session-ui/session-shell-root.js +1106 -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 +415 -775
- package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +44 -0
- package/dist/integrations/pi/session-ui/session-viewport-controller.js +434 -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 +63 -0
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +240 -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 +1 -1
- 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 +4 -0
- package/dist/{src/foundation/ui-components → ui/components}/index.js +4 -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 +235 -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 +146 -0
- package/dist/ui/components/transcript-viewport.js +629 -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/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 +34 -5
- package/docs/ci-release-runbook.md +186 -79
- package/docs/features/launch-profiles.md +10 -19
- 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.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 -112
- 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/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.d.ts +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}/launch-guardian/main.d.ts +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/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/index.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}/process-containment/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/index.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 → foundation}/supervision/main.d.ts +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}/index.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.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}/shell-selectors-dialogs.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.d.ts +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,723 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
#renderedRows = new Map();
|
|
13
|
-
#themeUnsubscribe;
|
|
14
|
-
#transcriptOrder = [];
|
|
15
|
-
#view;
|
|
16
|
-
#status;
|
|
17
|
-
#footer;
|
|
18
|
-
#queued;
|
|
19
|
-
#extensionRenderers;
|
|
20
|
-
#componentRuntime;
|
|
21
|
-
#toolsExpanded = false;
|
|
22
|
-
#thinkingVisible = true;
|
|
23
|
-
#workflowTranscriptSequence = 0;
|
|
24
|
-
#workflowStatusAnchors = new Map();
|
|
25
|
-
#workflowStatusMessages = new Map();
|
|
26
|
-
#lastWorkflowStatusId;
|
|
27
|
-
#inputSurface;
|
|
28
|
-
#extensionHeader = null;
|
|
29
|
-
#extensionFooter = null;
|
|
30
|
-
#extensionWidgets = new Map();
|
|
31
|
-
#extensionStatuses = new Map();
|
|
32
|
-
#extensionWorkingMessage;
|
|
33
|
-
#extensionWorkingVisible = true;
|
|
34
|
-
constructor(view, cwd, handlers, startup = {}, agentDir, extensionRenderers = {
|
|
35
|
-
getMessageRenderer: () => undefined,
|
|
36
|
-
getToolDefinition: () => undefined,
|
|
37
|
-
}) {
|
|
38
|
-
this.#view = view;
|
|
39
|
-
this.#cwd = cwd;
|
|
40
|
-
this.#extensionRenderers = extensionRenderers;
|
|
41
|
-
this.#componentRuntime = handlers;
|
|
42
|
-
this.header = createPiShellHeader(startup);
|
|
43
|
-
this.resources = createPiShellLoadedResources(startup.resources ?? [], startup.expanded ?? false);
|
|
44
|
-
this.#status = createPiShellStatus(view, handlers);
|
|
45
|
-
this.#footer = createPiShellFooter(this.#viewWithExtensionStatuses(view), cwd);
|
|
46
|
-
this.#queued = createPiQueuedInputStatus(view.editor.queuedSubmissions);
|
|
47
|
-
this.editor = createPiShellEditor({
|
|
48
|
-
...handlers,
|
|
49
|
-
cwd,
|
|
50
|
-
...(agentDir === undefined ? {} : { agentDir }),
|
|
51
|
-
onToolsExpand: () => this.#setToolsExpanded(!this.#toolsExpanded),
|
|
52
|
-
});
|
|
53
|
-
this.editor.setThinkingLevel(view.thinkingLevel);
|
|
54
|
-
this.#inputSurface = this.editor;
|
|
55
|
-
for (const block of view.transcript) {
|
|
56
|
-
if (block.kind === "user")
|
|
57
|
-
this.editor.addToHistory(block.text);
|
|
58
|
-
}
|
|
59
|
-
this.#syncTranscript(view.transcript);
|
|
60
|
-
// Colours come from the active theme, so rendered rows outlive their revision only
|
|
61
|
-
// until the theme under them changes.
|
|
62
|
-
this.#themeUnsubscribe = onPiThemeChange(() => this.#renderedRows.clear());
|
|
63
|
-
}
|
|
64
|
-
update(view) {
|
|
65
|
-
this.#view = view;
|
|
66
|
-
this.#status.update(view);
|
|
67
|
-
this.#footer.update(this.#viewWithExtensionStatuses(view));
|
|
68
|
-
this.#queued.update(view.editor.queuedSubmissions);
|
|
69
|
-
this.#syncTranscript(view.transcript);
|
|
70
|
-
this.editor.setSubmitEnabled(view.lifecycle !== "stopping" && view.lifecycle !== "stopped" && view.lifecycle !== "failed");
|
|
71
|
-
this.editor.setThinkingLevel(view.thinkingLevel);
|
|
72
|
-
this.invalidate();
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Applies one block: its component is created or updated in place and the order grows
|
|
76
|
-
* only when the block is new. A streamed chunk costs one component update rather than a
|
|
77
|
-
* walk of the whole transcript.
|
|
78
|
-
*/
|
|
79
|
-
applyTranscriptBlock(block) {
|
|
80
|
-
this.#blocksById.set(block.id, block);
|
|
81
|
-
const component = this.#transcript.get(block.id);
|
|
82
|
-
if (component === undefined) {
|
|
83
|
-
const created = createPiShellTranscriptComponent(block, this.#cwd, this.#extensionRenderers);
|
|
84
|
-
created.setExpanded(this.#toolsExpanded);
|
|
85
|
-
this.#transcript.set(block.id, created);
|
|
86
|
-
this.#transcriptOrder.push(block.id);
|
|
87
|
-
}
|
|
88
|
-
else if (component.revision !== block.revision) {
|
|
89
|
-
component.update(block);
|
|
90
|
-
}
|
|
91
|
-
this.invalidate();
|
|
92
|
-
}
|
|
93
|
-
render(width) {
|
|
94
|
-
const queued = this.#view.editor.queuedSubmissions.length === 0 ? [] : this.#queued.render(width);
|
|
95
|
-
return [
|
|
96
|
-
...this.#renderDocument(width),
|
|
97
|
-
...queued,
|
|
98
|
-
...this.#renderStatus(width),
|
|
99
|
-
...this.#renderWidgets("aboveEditor", width),
|
|
100
|
-
...this.#inputSurface.render(width),
|
|
101
|
-
...this.#renderWidgets("belowEditor", width),
|
|
102
|
-
...this.#renderFooter(width),
|
|
103
|
-
];
|
|
104
|
-
}
|
|
105
|
-
layoutRoot() {
|
|
106
|
-
const document = layoutPort(width => this.#renderDocument(width), () => this.invalidate());
|
|
107
|
-
const queued = layoutPort(width => this.#view.editor.queuedSubmissions.length === 0 ? [] : this.#queued.render(width), () => this.#queued.invalidate());
|
|
108
|
-
const aboveWidgets = layoutPort(width => this.#renderWidgets("aboveEditor", width), () => this.#invalidateExtensions());
|
|
109
|
-
const status = layoutPort(width => this.#renderStatus(width), () => this.#status.invalidate());
|
|
110
|
-
const editor = layoutPort(width => this.#inputSurface.render(width), () => this.#inputSurface.invalidate(), data => this.#inputSurface.handleInput?.(data));
|
|
111
|
-
const belowWidgets = layoutPort(width => this.#renderWidgets("belowEditor", width), () => this.#invalidateExtensions());
|
|
112
|
-
const footer = layoutPort(width => this.#renderFooter(width), () => (this.#extensionFooter ?? this.#footer).invalidate());
|
|
113
|
-
return {
|
|
114
|
-
type: "stack",
|
|
115
|
-
direction: "vertical",
|
|
116
|
-
children: [
|
|
117
|
-
{
|
|
118
|
-
basis: 0,
|
|
119
|
-
grow: 1,
|
|
120
|
-
shrink: 1,
|
|
121
|
-
minSize: 1,
|
|
122
|
-
node: {
|
|
123
|
-
type: "scroll",
|
|
124
|
-
id: "transcript",
|
|
125
|
-
follow: "end",
|
|
126
|
-
primary: true,
|
|
127
|
-
overscroll: "chain",
|
|
128
|
-
scrollbar: "auto",
|
|
129
|
-
scrollbarStyle: text => piTheme().bg("scrollbarThumb", text),
|
|
130
|
-
child: { type: "component", component: document },
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
basis: "auto",
|
|
135
|
-
grow: 0,
|
|
136
|
-
shrink: 1,
|
|
137
|
-
minSize: 1,
|
|
138
|
-
node: {
|
|
139
|
-
type: "stack",
|
|
140
|
-
direction: "vertical",
|
|
141
|
-
children: [
|
|
142
|
-
{ shrink: 1, minSize: 0, node: { type: "component", component: queued } },
|
|
143
|
-
{ shrink: 1, minSize: 0, node: { type: "component", component: status } },
|
|
144
|
-
{ shrink: 1, minSize: 0, node: { type: "component", component: aboveWidgets } },
|
|
145
|
-
{ shrink: 1, minSize: 3, node: { type: "component", component: editor } },
|
|
146
|
-
{ shrink: 1, minSize: 0, node: { type: "component", component: belowWidgets } },
|
|
147
|
-
{ shrink: 1, minSize: 1, node: { type: "component", component: footer } },
|
|
148
|
-
],
|
|
149
|
-
},
|
|
150
|
-
},
|
|
151
|
-
],
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
#renderDocument(width) {
|
|
155
|
-
const transcript = this.#transcriptOrder.flatMap((id, index) => {
|
|
156
|
-
const block = this.#blocksById.get(id);
|
|
157
|
-
if (!this.#thinkingVisible && block?.kind === "thinking")
|
|
158
|
-
return [];
|
|
159
|
-
const rows = this.#blockRows(id, block, width);
|
|
160
|
-
if (index > 0 && block?.kind === "user")
|
|
161
|
-
return ["", ...rows];
|
|
162
|
-
return rows;
|
|
163
|
-
});
|
|
164
|
-
const diagnostics = this.#view.diagnostics;
|
|
165
|
-
const startupRows = diagnostics
|
|
166
|
-
.filter(diagnostic => diagnostic.code === "engine-startup")
|
|
167
|
-
.flatMap(diagnostic => renderPiShellStartupDiagnostic(diagnostic, width));
|
|
168
|
-
const packageUpdateRows = diagnostics
|
|
169
|
-
.filter(diagnostic => diagnostic.code === "package-updates")
|
|
170
|
-
.flatMap(diagnostic => renderPiShellPackageUpdateNotice(diagnostic.message.split("\n").filter(line => line.startsWith("- ")).map(line => line.slice(2)), width));
|
|
171
|
-
const diagnosticRows = diagnostics
|
|
172
|
-
.filter(diagnostic => diagnostic.code !== "engine-startup" && diagnostic.code !== "package-updates")
|
|
173
|
-
.slice(-3)
|
|
174
|
-
.flatMap(diagnostic => renderPiShellTranscriptBlock({
|
|
175
|
-
id: `diagnostic-${diagnostic.sequence}`,
|
|
176
|
-
kind: diagnostic.severity === "error" ? "error" : "system",
|
|
177
|
-
status: "finalized",
|
|
178
|
-
revision: diagnostic.sequence,
|
|
179
|
-
title: diagnostic.code,
|
|
180
|
-
text: diagnostic.message,
|
|
181
|
-
payload: {},
|
|
182
|
-
}, width, this.#cwd));
|
|
183
|
-
const resourceRows = [...this.resources.render(width)];
|
|
184
|
-
if (resourceRows.at(-1) === "")
|
|
185
|
-
resourceRows.pop();
|
|
186
|
-
return [
|
|
187
|
-
...startupRows,
|
|
188
|
-
...(this.#extensionHeader ?? this.header).render(width),
|
|
189
|
-
...resourceRows,
|
|
190
|
-
...transcript,
|
|
191
|
-
...packageUpdateRows,
|
|
192
|
-
...diagnosticRows,
|
|
193
|
-
];
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Rows for one transcript block. A finalized block renders once for a given revision
|
|
197
|
-
* and width and is reused after that, so a frame costs what changed rather than what
|
|
198
|
-
* the session has accumulated. A live block, and anything the shell drives itself, is
|
|
199
|
-
* rendered every time because its content is still moving.
|
|
200
|
-
*/
|
|
201
|
-
#blockRows(id, block, width) {
|
|
202
|
-
const component = this.#transcript.get(id);
|
|
203
|
-
if (component === undefined)
|
|
204
|
-
return [];
|
|
205
|
-
if (block === undefined || block.status !== "finalized")
|
|
206
|
-
return component.render(width);
|
|
207
|
-
const cached = this.#renderedRows.get(id);
|
|
208
|
-
if (cached && cached.width === width && cached.revision === block.revision)
|
|
209
|
-
return cached.rows;
|
|
210
|
-
const rows = component.render(width);
|
|
211
|
-
this.#renderedRows.set(id, { width, revision: block.revision, rows });
|
|
212
|
-
return rows;
|
|
213
|
-
}
|
|
214
|
-
transcriptComponent(id) {
|
|
215
|
-
return this.#transcript.get(id);
|
|
216
|
-
}
|
|
217
|
-
appendWorkflowStatus(message) {
|
|
218
|
-
const previousId = this.#lastWorkflowStatusId;
|
|
219
|
-
if (previousId !== undefined
|
|
220
|
-
&& this.#transcriptOrder.at(-1) === previousId
|
|
221
|
-
&& this.#workflowStatusAnchors.get(previousId) === this.#view.transcript.length) {
|
|
222
|
-
this.#workflowStatusMessages.set(previousId, message);
|
|
223
|
-
this.invalidate();
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
const id = this.#appendAnchoredWorkflowComponent(width => [
|
|
227
|
-
"",
|
|
228
|
-
...renderPiShellStatusText(this.#workflowStatusMessages.get(id) ?? message, width),
|
|
229
|
-
]);
|
|
230
|
-
this.#workflowStatusMessages.set(id, message);
|
|
231
|
-
this.#lastWorkflowStatusId = id;
|
|
232
|
-
}
|
|
233
|
-
appendWorkflowResult(result) {
|
|
234
|
-
if (result.command === "reload" && result.outcome === "completed") {
|
|
235
|
-
this.appendWorkflowStatus(result.message);
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
if (result.command === "session" && result.outcome === "completed" && result.presentation?.kind === "session-info") {
|
|
239
|
-
this.#lastWorkflowStatusId = undefined;
|
|
240
|
-
const sessionInfo = createPiShellSessionInfo(result.presentation);
|
|
241
|
-
this.#appendAnchoredWorkflowComponent(width => sessionInfo.render(width), () => sessionInfo.dispose?.());
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
if (result.command === "hotkeys" && result.outcome === "completed") {
|
|
245
|
-
this.#lastWorkflowStatusId = undefined;
|
|
246
|
-
const hotkeys = createPiShellHotkeys();
|
|
247
|
-
this.#appendAnchoredWorkflowComponent(width => hotkeys.render(width), () => hotkeys.dispose?.());
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
if (result.command === "changelog" && result.outcome === "completed") {
|
|
251
|
-
this.#lastWorkflowStatusId = undefined;
|
|
252
|
-
const changelog = createPiShellChangelog(result.detail ?? "No changelog entries found.");
|
|
253
|
-
this.#appendAnchoredWorkflowComponent(width => changelog.render(width), () => changelog.dispose?.());
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
if (result.outcome === "failed") {
|
|
257
|
-
this.#lastWorkflowStatusId = undefined;
|
|
258
|
-
const warning = (result.command === "name" && result.message.startsWith("Usage:"))
|
|
259
|
-
|| (result.command === "reload" && result.message.startsWith("Wait for "));
|
|
260
|
-
const prefix = warning ? "Warning" : "Error";
|
|
261
|
-
const color = warning ? "warning" : "error";
|
|
262
|
-
this.#appendAnchoredWorkflowComponent(() => ["", ` ${piTheme().fg(color, `${prefix}: ${result.message}`)}`]);
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
if (result.outcome === "completed" && (result.command === "quit" || result.command === "compact"))
|
|
266
|
-
return;
|
|
267
|
-
if (result.command === "new" && result.outcome === "completed") {
|
|
268
|
-
this.#lastWorkflowStatusId = undefined;
|
|
269
|
-
this.#appendAnchoredWorkflowComponent(() => ["", ` ${piTheme().fg("accent", result.message)}`]);
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
if (result.command === "name" && result.outcome === "completed") {
|
|
273
|
-
this.#lastWorkflowStatusId = undefined;
|
|
274
|
-
this.#appendAnchoredWorkflowComponent(() => [
|
|
275
|
-
...(result.detail ? ["", ` ${piTheme().fg("warning", `Warning: ${result.detail}`)}`] : []),
|
|
276
|
-
"",
|
|
277
|
-
` ${piTheme().fg("dim", result.message)}`,
|
|
278
|
-
]);
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
if (result.command === "debug" && result.outcome === "completed") {
|
|
282
|
-
this.#lastWorkflowStatusId = undefined;
|
|
283
|
-
this.#appendAnchoredWorkflowComponent(() => [
|
|
284
|
-
"",
|
|
285
|
-
` ${piTheme().fg("accent", result.message)}`,
|
|
286
|
-
...(result.detail ? [` ${piTheme().fg("muted", result.detail)}`] : []),
|
|
287
|
-
]);
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
if (result.command === "arminsayshi" && result.outcome === "completed") {
|
|
291
|
-
this.#lastWorkflowStatusId = undefined;
|
|
292
|
-
const armin = createPiShellArmin(this.#componentRuntime);
|
|
293
|
-
this.#appendAnchoredWorkflowComponent(width => ["", ...armin.render(width)], () => armin.dispose?.());
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
if (result.command === "dementedelves" && result.outcome === "completed") {
|
|
297
|
-
this.#lastWorkflowStatusId = undefined;
|
|
298
|
-
const announcement = createPiShellEarendilAnnouncement();
|
|
299
|
-
this.#appendAnchoredWorkflowComponent(width => ["", ...announcement.render(width)], () => announcement.dispose?.());
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
const message = result.command === "share" && result.detail
|
|
303
|
-
? `${result.message}\nGist: ${result.detail}`
|
|
304
|
-
: result.message;
|
|
305
|
-
this.appendWorkflowStatus(message);
|
|
306
|
-
}
|
|
307
|
-
appendDaxnuts() {
|
|
308
|
-
this.#lastWorkflowStatusId = undefined;
|
|
309
|
-
const daxnuts = createPiShellDaxnuts(this.#componentRuntime);
|
|
310
|
-
this.#appendAnchoredWorkflowComponent(width => ["", ...daxnuts.render(width)], () => daxnuts.dispose?.());
|
|
311
|
-
}
|
|
312
|
-
toggleThinkingVisibility() {
|
|
313
|
-
this.#thinkingVisible = !this.#thinkingVisible;
|
|
314
|
-
this.invalidate();
|
|
315
|
-
}
|
|
316
|
-
get toolsExpanded() {
|
|
317
|
-
return this.#toolsExpanded;
|
|
318
|
-
}
|
|
319
|
-
setToolsExpanded(expanded) {
|
|
320
|
-
this.#setToolsExpanded(expanded);
|
|
321
|
-
}
|
|
322
|
-
setExtensionWidget(key, component, placement) {
|
|
323
|
-
const previous = this.#extensionWidgets.get(key)?.component;
|
|
324
|
-
if (component === null)
|
|
325
|
-
this.#extensionWidgets.delete(key);
|
|
326
|
-
else
|
|
327
|
-
this.#extensionWidgets.set(key, { component, placement });
|
|
328
|
-
if (previous !== undefined && previous !== component)
|
|
329
|
-
previous.dispose?.();
|
|
330
|
-
this.invalidate();
|
|
331
|
-
}
|
|
332
|
-
setExtensionHeader(component) {
|
|
333
|
-
if (this.#extensionHeader !== component)
|
|
334
|
-
this.#extensionHeader?.dispose?.();
|
|
335
|
-
this.#extensionHeader = component;
|
|
336
|
-
this.invalidate();
|
|
337
|
-
}
|
|
338
|
-
setExtensionFooter(component) {
|
|
339
|
-
if (this.#extensionFooter !== component)
|
|
340
|
-
this.#extensionFooter?.dispose?.();
|
|
341
|
-
this.#extensionFooter = component;
|
|
342
|
-
this.invalidate();
|
|
343
|
-
}
|
|
344
|
-
setExtensionStatus(key, text) {
|
|
345
|
-
if (text === undefined)
|
|
346
|
-
this.#extensionStatuses.delete(key);
|
|
347
|
-
else
|
|
348
|
-
this.#extensionStatuses.set(key, text);
|
|
349
|
-
this.#footer.update(this.#viewWithExtensionStatuses(this.#view));
|
|
350
|
-
this.invalidate();
|
|
351
|
-
}
|
|
352
|
-
setExtensionWorking(message, visible = this.#extensionWorkingVisible) {
|
|
353
|
-
this.#extensionWorkingMessage = message;
|
|
354
|
-
this.#extensionWorkingVisible = visible;
|
|
355
|
-
this.#status.setWorkingOverride(visible ? message : undefined);
|
|
356
|
-
this.invalidate();
|
|
357
|
-
}
|
|
358
|
-
resetWorkflowPresentation() {
|
|
359
|
-
for (const id of this.#workflowStatusAnchors.keys()) {
|
|
360
|
-
this.#transcript.get(id)?.dispose?.();
|
|
361
|
-
this.#transcript.delete(id);
|
|
362
|
-
}
|
|
363
|
-
this.#workflowStatusAnchors.clear();
|
|
364
|
-
this.#workflowStatusMessages.clear();
|
|
365
|
-
this.#transcriptOrder = this.#transcriptOrder.filter(id => !id.startsWith("workflow-status-"));
|
|
366
|
-
this.#lastWorkflowStatusId = undefined;
|
|
367
|
-
this.invalidate();
|
|
368
|
-
}
|
|
369
|
-
resetExtensionUi() {
|
|
370
|
-
this.#extensionHeader?.dispose?.();
|
|
371
|
-
this.#extensionFooter?.dispose?.();
|
|
372
|
-
for (const { component } of this.#extensionWidgets.values())
|
|
373
|
-
component.dispose?.();
|
|
374
|
-
this.#extensionHeader = null;
|
|
375
|
-
this.#extensionFooter = null;
|
|
376
|
-
this.#extensionWidgets.clear();
|
|
377
|
-
this.#extensionStatuses.clear();
|
|
378
|
-
this.#extensionWorkingMessage = undefined;
|
|
379
|
-
this.#status.setWorkingOverride(undefined);
|
|
380
|
-
this.#footer.update(this.#viewWithExtensionStatuses(this.#view));
|
|
381
|
-
// An extension renderer may have drawn transcript blocks that are now unrendered by it.
|
|
382
|
-
this.#renderedRows.clear();
|
|
383
|
-
this.invalidate();
|
|
384
|
-
}
|
|
385
|
-
addExtensionNotification(message, type) {
|
|
386
|
-
if (type === "info") {
|
|
387
|
-
this.appendWorkflowStatus(message);
|
|
388
|
-
return;
|
|
389
|
-
}
|
|
390
|
-
this.#lastWorkflowStatusId = undefined;
|
|
391
|
-
const prefix = type === "warning" ? "Warning" : "Error";
|
|
392
|
-
this.#appendAnchoredWorkflowComponent(() => ["", ` ${piTheme().fg(type, `${prefix}: ${message}`)}`]);
|
|
393
|
-
}
|
|
394
|
-
extensionFooterData() {
|
|
395
|
-
return {
|
|
396
|
-
getGitBranch: () => this.#view.status.footer?.branch ?? null,
|
|
397
|
-
getExtensionStatuses: () => new Map(this.#extensionStatuses),
|
|
398
|
-
getAvailableProviderCount: () => this.#view.status.footer?.availableProviderCount ?? 1,
|
|
399
|
-
onBranchChange: () => () => { },
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
setInputSurface(component, disposePrevious = true) {
|
|
403
|
-
const next = component ?? this.editor;
|
|
404
|
-
if (next === this.#inputSurface)
|
|
405
|
-
return;
|
|
406
|
-
this.#inputSurface.setFocused?.(false);
|
|
407
|
-
if (disposePrevious && this.#inputSurface !== this.editor)
|
|
408
|
-
this.#inputSurface.dispose?.();
|
|
409
|
-
this.#inputSurface = next;
|
|
410
|
-
this.#inputSurface.setFocused?.(true);
|
|
411
|
-
this.invalidate();
|
|
412
|
-
}
|
|
413
|
-
handleInput(data) {
|
|
414
|
-
this.#inputSurface.handleInput?.(data);
|
|
415
|
-
}
|
|
416
|
-
invalidate() {
|
|
417
|
-
this.header.invalidate();
|
|
418
|
-
this.resources.invalidate();
|
|
419
|
-
for (const component of this.#transcript.values())
|
|
420
|
-
component.invalidate();
|
|
421
|
-
this.editor.invalidate();
|
|
422
|
-
if (this.#inputSurface !== this.editor)
|
|
423
|
-
this.#inputSurface.invalidate();
|
|
424
|
-
this.#invalidateExtensions();
|
|
425
|
-
this.#status.invalidate();
|
|
426
|
-
this.#footer.invalidate();
|
|
427
|
-
this.#queued.invalidate();
|
|
428
|
-
}
|
|
429
|
-
setFocused(focused) {
|
|
430
|
-
this.#inputSurface.setFocused?.(focused);
|
|
431
|
-
}
|
|
432
|
-
dispose() {
|
|
433
|
-
this.#themeUnsubscribe();
|
|
434
|
-
this.header.dispose?.();
|
|
435
|
-
this.resources.dispose?.();
|
|
436
|
-
for (const component of this.#transcript.values())
|
|
437
|
-
component.dispose?.();
|
|
438
|
-
this.#transcript.clear();
|
|
439
|
-
this.#renderedRows.clear();
|
|
440
|
-
if (this.#inputSurface !== this.editor)
|
|
441
|
-
this.#inputSurface.dispose?.();
|
|
442
|
-
this.#extensionHeader?.dispose?.();
|
|
443
|
-
this.#extensionFooter?.dispose?.();
|
|
444
|
-
for (const { component } of this.#extensionWidgets.values())
|
|
445
|
-
component.dispose?.();
|
|
446
|
-
this.#extensionWidgets.clear();
|
|
447
|
-
this.editor.dispose?.();
|
|
448
|
-
this.#status.dispose?.();
|
|
449
|
-
this.#footer.dispose?.();
|
|
450
|
-
this.#queued.dispose?.();
|
|
451
|
-
}
|
|
452
|
-
#syncTranscript(blocks) {
|
|
453
|
-
this.#blocksById.clear();
|
|
454
|
-
for (const block of blocks)
|
|
455
|
-
this.#blocksById.set(block.id, block);
|
|
456
|
-
const nextIds = new Set(blocks.map(block => block.id));
|
|
457
|
-
for (const [id, component] of this.#transcript) {
|
|
458
|
-
if (id.startsWith("workflow-status-") || nextIds.has(id))
|
|
459
|
-
continue;
|
|
460
|
-
component.dispose?.();
|
|
461
|
-
this.#transcript.delete(id);
|
|
462
|
-
this.#renderedRows.delete(id);
|
|
463
|
-
}
|
|
464
|
-
for (const block of blocks) {
|
|
465
|
-
const component = this.#transcript.get(block.id);
|
|
466
|
-
if (component === undefined) {
|
|
467
|
-
const created = createPiShellTranscriptComponent(block, this.#cwd, this.#extensionRenderers);
|
|
468
|
-
created.setExpanded(this.#toolsExpanded);
|
|
469
|
-
this.#transcript.set(block.id, created);
|
|
470
|
-
}
|
|
471
|
-
else if (component.revision !== block.revision) {
|
|
472
|
-
component.update(block);
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
const statusIds = [...this.#workflowStatusAnchors.keys()];
|
|
476
|
-
const order = [];
|
|
477
|
-
for (let index = 0; index <= blocks.length; index += 1) {
|
|
478
|
-
for (const statusId of statusIds) {
|
|
479
|
-
if (this.#workflowStatusAnchors.get(statusId) === index)
|
|
480
|
-
order.push(statusId);
|
|
481
|
-
}
|
|
482
|
-
const block = blocks[index];
|
|
483
|
-
if (block !== undefined)
|
|
484
|
-
order.push(block.id);
|
|
485
|
-
}
|
|
486
|
-
const placed = new Set(order);
|
|
487
|
-
for (const statusId of statusIds) {
|
|
488
|
-
if (!placed.has(statusId))
|
|
489
|
-
order.push(statusId);
|
|
490
|
-
}
|
|
491
|
-
this.#transcriptOrder = order;
|
|
492
|
-
}
|
|
493
|
-
#appendAnchoredWorkflowComponent(render, dispose) {
|
|
494
|
-
this.#workflowTranscriptSequence += 1;
|
|
495
|
-
const id = `workflow-status-${this.#workflowTranscriptSequence}`;
|
|
496
|
-
const component = {
|
|
497
|
-
id,
|
|
498
|
-
revision: 1,
|
|
499
|
-
render,
|
|
500
|
-
handleInput() { },
|
|
501
|
-
invalidate() { },
|
|
502
|
-
update() { },
|
|
503
|
-
setExpanded() { },
|
|
504
|
-
...(dispose === undefined ? {} : { dispose }),
|
|
505
|
-
};
|
|
506
|
-
this.#transcript.set(id, component);
|
|
507
|
-
this.#workflowStatusAnchors.set(id, this.#view.transcript.length);
|
|
508
|
-
this.#transcriptOrder.push(id);
|
|
509
|
-
this.invalidate();
|
|
510
|
-
return id;
|
|
511
|
-
}
|
|
512
|
-
#renderWidgets(placement, width) {
|
|
513
|
-
const rows = [...this.#extensionWidgets.values()]
|
|
514
|
-
.filter(widget => widget.placement === placement)
|
|
515
|
-
.flatMap(widget => widget.component.render(width));
|
|
516
|
-
return placement === "aboveEditor" ? ["", ...rows] : rows;
|
|
517
|
-
}
|
|
518
|
-
#renderStatus(width) {
|
|
519
|
-
return this.#status.render(width);
|
|
520
|
-
}
|
|
521
|
-
#renderFooter(width) {
|
|
522
|
-
return (this.#extensionFooter ?? this.#footer).render(width);
|
|
523
|
-
}
|
|
524
|
-
#viewWithExtensionStatuses(view) {
|
|
525
|
-
const footer = view.status.footer;
|
|
526
|
-
const statuses = new Map(footer?.extensionStatuses ?? []);
|
|
527
|
-
for (const [key, text] of this.#extensionStatuses)
|
|
528
|
-
statuses.set(key, text);
|
|
529
|
-
return {
|
|
530
|
-
...view,
|
|
531
|
-
status: {
|
|
532
|
-
...view.status,
|
|
533
|
-
footer: {
|
|
534
|
-
branch: footer?.branch ?? null,
|
|
535
|
-
sessionName: footer?.sessionName ?? null,
|
|
536
|
-
availableProviderCount: footer?.availableProviderCount ?? 1,
|
|
537
|
-
extensionStatuses: [...statuses],
|
|
538
|
-
},
|
|
539
|
-
},
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
#invalidateExtensions() {
|
|
543
|
-
this.#extensionHeader?.invalidate();
|
|
544
|
-
this.#extensionFooter?.invalidate();
|
|
545
|
-
for (const { component } of this.#extensionWidgets.values())
|
|
546
|
-
component.invalidate();
|
|
547
|
-
}
|
|
548
|
-
#setToolsExpanded(expanded) {
|
|
549
|
-
this.#toolsExpanded = expanded;
|
|
550
|
-
this.header.setExpanded(expanded);
|
|
551
|
-
this.resources.setExpanded(expanded);
|
|
552
|
-
for (const component of this.#transcript.values())
|
|
553
|
-
component.setExpanded(expanded);
|
|
554
|
-
// Expansion changes what a block draws without changing its revision.
|
|
555
|
-
this.#renderedRows.clear();
|
|
556
|
-
this.invalidate();
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
function layoutPort(render, invalidate, handleInput) {
|
|
560
|
-
return {
|
|
561
|
-
render,
|
|
562
|
-
invalidate,
|
|
563
|
-
...(handleInput === undefined ? {} : { handleInput }),
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
function shellResourceEntries(backend) {
|
|
567
|
-
const resources = backend.nonVisualResources().map(resource => ({
|
|
568
|
-
section: resource.kind === "skill"
|
|
569
|
-
? "Skills"
|
|
570
|
-
: resource.kind === "prompt-template"
|
|
571
|
-
? "Prompts"
|
|
572
|
-
: resource.kind === "theme"
|
|
573
|
-
? "Themes"
|
|
574
|
-
: "Context",
|
|
575
|
-
label: resource.kind === "prompt-template"
|
|
576
|
-
? `/${resource.label}`
|
|
577
|
-
: resource.kind === "agent-context" || resource.kind === "system-prompt"
|
|
578
|
-
? compactResourceLabel(resource.sourcePath ?? resource.label)
|
|
579
|
-
: resource.label,
|
|
580
|
-
sourcePath: resource.sourcePath,
|
|
581
|
-
diagnostic: resource.diagnostic,
|
|
582
|
-
}));
|
|
583
|
-
const extensions = backend.extensionResources().filter(extension => !extension.hidden);
|
|
584
|
-
const loadedExtensions = extensions.filter(extension => extension.diagnostic === null);
|
|
585
|
-
const extensionLabels = compactExtensionLabels(loadedExtensions);
|
|
586
|
-
for (const extension of extensions) {
|
|
587
|
-
const labelIndex = loadedExtensions.indexOf(extension);
|
|
588
|
-
resources.push({
|
|
589
|
-
section: "Extensions",
|
|
590
|
-
label: extensionLabels[labelIndex] ?? compactResourceLabel(extension.sourcePath ?? extension.resolvedPath ?? "extension"),
|
|
591
|
-
sourcePath: extension.sourcePath ?? extension.resolvedPath,
|
|
592
|
-
diagnostic: extension.diagnostic,
|
|
593
|
-
});
|
|
594
|
-
}
|
|
595
|
-
return resources;
|
|
596
|
-
}
|
|
597
|
-
function compactResourceLabel(path) {
|
|
598
|
-
const segments = compactPathSegments(path);
|
|
599
|
-
const leaf = segments.at(-1) ?? path;
|
|
600
|
-
if ((leaf === "index.ts" || leaf === "index.js") && segments.length > 1)
|
|
601
|
-
return segments.at(-2) ?? leaf;
|
|
602
|
-
return leaf;
|
|
603
|
-
}
|
|
604
|
-
/**
|
|
605
|
-
* Pinned from InteractiveMode's compact extension-label helpers at Pi commit
|
|
606
|
-
* 914cf1472e715297caa30db4b9535d534a9eb718. The source metadata crosses an
|
|
607
|
-
* A1-owned boundary first; the owned shell never inspects Pi's private root.
|
|
608
|
-
*/
|
|
609
|
-
function compactExtensionLabels(extensions) {
|
|
610
|
-
const localExtensions = extensions
|
|
611
|
-
.filter(extension => !isPackageExtensionSource(extension.sourceInfo))
|
|
612
|
-
.map(extension => {
|
|
613
|
-
const path = extension.sourcePath ?? extension.resolvedPath ?? "extension";
|
|
614
|
-
const segments = compactPathSegments(path);
|
|
615
|
-
if (segments.length > 1 && (segments.at(-1) === "index.ts" || segments.at(-1) === "index.js"))
|
|
616
|
-
segments.pop();
|
|
617
|
-
return { extension, segments };
|
|
618
|
-
});
|
|
619
|
-
return extensions.map(extension => {
|
|
620
|
-
const resourcePath = extension.sourcePath ?? extension.resolvedPath ?? "extension";
|
|
621
|
-
if (isPackageExtensionSource(extension.sourceInfo)) {
|
|
622
|
-
return compactPackageExtensionLabel(resourcePath, extension.sourceInfo);
|
|
623
|
-
}
|
|
624
|
-
const localIndex = localExtensions.findIndex(item => item.extension === extension);
|
|
625
|
-
const segments = localExtensions[localIndex]?.segments;
|
|
626
|
-
if (!segments || segments.length === 0)
|
|
627
|
-
return compactResourceLabel(resourcePath);
|
|
628
|
-
for (let count = 1; count <= segments.length; count += 1) {
|
|
629
|
-
const candidate = segments.slice(-count).join("/");
|
|
630
|
-
if (localExtensions.every((item, itemIndex) => itemIndex === localIndex || item.segments.slice(-count).join("/") !== candidate)) {
|
|
631
|
-
return candidate;
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
return segments.join("/");
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
function compactPackageExtensionLabel(resourcePath, sourceInfo) {
|
|
638
|
-
const sourceLabel = compactPackageSourceLabel(sourceInfo.source);
|
|
639
|
-
if (!sourceLabel)
|
|
640
|
-
return compactResourceLabel(resourcePath);
|
|
641
|
-
const shortPath = shortPackagePath(resourcePath, sourceInfo).replaceAll("\\", "/");
|
|
642
|
-
const packagePath = shortPath.startsWith("extensions/") ? shortPath.slice("extensions/".length) : shortPath;
|
|
643
|
-
const slash = packagePath.lastIndexOf("/");
|
|
644
|
-
const fileName = slash < 0 ? packagePath : packagePath.slice(slash + 1);
|
|
645
|
-
const directory = slash < 0 ? "" : packagePath.slice(0, slash);
|
|
646
|
-
const extension = fileName.lastIndexOf(".");
|
|
647
|
-
const name = extension <= 0 ? fileName : fileName.slice(0, extension);
|
|
648
|
-
if (name === "index")
|
|
649
|
-
return !directory || directory === "." ? sourceLabel : `${sourceLabel}:${directory}`;
|
|
650
|
-
return `${sourceLabel}:${packagePath}`;
|
|
651
|
-
}
|
|
652
|
-
function compactPackageSourceLabel(source) {
|
|
653
|
-
if (source.startsWith("npm:"))
|
|
654
|
-
return source.slice("npm:".length) || source;
|
|
655
|
-
if (!source.startsWith("git:"))
|
|
656
|
-
return source;
|
|
657
|
-
const gitSource = source.slice("git:".length).trim();
|
|
658
|
-
let repositoryPath;
|
|
659
|
-
const scpLike = gitSource.match(/^git@[^:]+:(.+)$/);
|
|
660
|
-
if (scpLike?.[1]) {
|
|
661
|
-
repositoryPath = scpLike[1];
|
|
662
|
-
}
|
|
663
|
-
else if (/^[a-z]+:\/\//i.test(gitSource)) {
|
|
664
|
-
try {
|
|
665
|
-
repositoryPath = new URL(gitSource).pathname.replace(/^\/+/, "");
|
|
666
|
-
}
|
|
667
|
-
catch {
|
|
668
|
-
return source;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
else {
|
|
672
|
-
const slash = gitSource.indexOf("/");
|
|
673
|
-
if (slash >= 0)
|
|
674
|
-
repositoryPath = gitSource.slice(slash + 1);
|
|
675
|
-
}
|
|
676
|
-
if (!repositoryPath)
|
|
677
|
-
return source;
|
|
678
|
-
const ref = repositoryPath.indexOf("@");
|
|
679
|
-
const withoutRef = ref < 0 ? repositoryPath : repositoryPath.slice(0, ref);
|
|
680
|
-
return withoutRef.replace(/\.git$/, "") || source;
|
|
681
|
-
}
|
|
682
|
-
function shortPackagePath(resourcePath, sourceInfo) {
|
|
683
|
-
const fullPath = normalizeResourcePath(resourcePath);
|
|
684
|
-
const baseDir = sourceInfo.baseDir === null ? undefined : normalizeResourcePath(sourceInfo.baseDir).replace(/\/$/, "");
|
|
685
|
-
if (baseDir) {
|
|
686
|
-
const npmRoot = baseDir.match(/^(.*\/node_modules)\/(@?[^/]+(?:\/[^/]+)?)$/);
|
|
687
|
-
if (npmRoot?.[1] && fullPath.startsWith(`${npmRoot[1]}/`))
|
|
688
|
-
return relativeResourcePath(baseDir, fullPath);
|
|
689
|
-
if (fullPath === baseDir)
|
|
690
|
-
return ".";
|
|
691
|
-
if (fullPath.startsWith(`${baseDir}/`))
|
|
692
|
-
return fullPath.slice(baseDir.length + 1);
|
|
693
|
-
}
|
|
694
|
-
const npmMatch = fullPath.match(/node_modules\/(@?[^/]+(?:\/[^/]+)?)\/(.*)/);
|
|
695
|
-
if (npmMatch?.[2] && sourceInfo.source.startsWith("npm:"))
|
|
696
|
-
return npmMatch[2];
|
|
697
|
-
const gitMatch = fullPath.match(/git\/[^/]+\/[^/]+\/(.*)/);
|
|
698
|
-
if (gitMatch?.[1] && sourceInfo.source.startsWith("git:"))
|
|
699
|
-
return gitMatch[1];
|
|
700
|
-
return resourcePath;
|
|
701
|
-
}
|
|
702
|
-
function relativeResourcePath(from, to) {
|
|
703
|
-
const fromSegments = from.split("/").filter(Boolean);
|
|
704
|
-
const toSegments = to.split("/").filter(Boolean);
|
|
705
|
-
let common = 0;
|
|
706
|
-
while (common < fromSegments.length && common < toSegments.length
|
|
707
|
-
&& fromSegments[common]?.toLowerCase() === toSegments[common]?.toLowerCase())
|
|
708
|
-
common += 1;
|
|
709
|
-
return [...fromSegments.slice(common).map(() => ".."), ...toSegments.slice(common)].join("/") || ".";
|
|
710
|
-
}
|
|
711
|
-
function compactPathSegments(path) {
|
|
712
|
-
return normalizeResourcePath(path).split("/").filter(segment => segment.length > 0 && segment !== "~");
|
|
713
|
-
}
|
|
714
|
-
function normalizeResourcePath(path) {
|
|
715
|
-
return path.replaceAll("\\", "/");
|
|
716
|
-
}
|
|
717
|
-
function isPackageExtensionSource(sourceInfo) {
|
|
718
|
-
const source = sourceInfo?.source ?? "";
|
|
719
|
-
return source.startsWith("npm:") || source.startsWith("git:");
|
|
720
|
-
}
|
|
1
|
+
import { PRODUCT_TEXT } from "../../../product-identity.js";
|
|
2
|
+
import { MOUSE_TRACKING_OFF, MOUSE_TRACKING_ON, parseMouseInput } 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. */
|
|
721
12
|
export class OwnedUiSessionShell {
|
|
722
13
|
backend;
|
|
723
14
|
root;
|
|
@@ -729,14 +20,28 @@ export class OwnedUiSessionShell {
|
|
|
729
20
|
#stopped;
|
|
730
21
|
#resolveStopped;
|
|
731
22
|
#dialogId;
|
|
23
|
+
#dialogSource;
|
|
732
24
|
#routeHost;
|
|
733
25
|
#dialogHandle;
|
|
734
26
|
#sequence = 0;
|
|
735
27
|
#started = false;
|
|
736
28
|
#disposed = false;
|
|
737
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";
|
|
738
42
|
#compactionQueue = [];
|
|
739
43
|
#lastClearTime = 0;
|
|
44
|
+
#lastEscapeTime = 0;
|
|
740
45
|
#activeLoginDialog;
|
|
741
46
|
#sessionGeneration;
|
|
742
47
|
constructor(options) {
|
|
@@ -744,14 +49,26 @@ export class OwnedUiSessionShell {
|
|
|
744
49
|
this.#sessionGeneration = this.backend.sessionGeneration;
|
|
745
50
|
this.#cwd = options.cwd;
|
|
746
51
|
this.#routeHost = options.routeHost ?? null;
|
|
52
|
+
this.#customViewport = options.sessionLayout === "custom-viewport";
|
|
53
|
+
if (this.#customViewport && options.clipboard === undefined)
|
|
54
|
+
preloadSystemClipboard();
|
|
747
55
|
this.#stopped = new Promise(resolve => {
|
|
748
56
|
this.#resolveStopped = resolve;
|
|
749
57
|
});
|
|
750
58
|
let runtime;
|
|
59
|
+
let damageTerminal;
|
|
60
|
+
let streamPresentation;
|
|
61
|
+
let pendingClipboardWrite = Promise.resolve();
|
|
751
62
|
this.root = new OwnedUiSessionShellRoot(this.backend.view(), options.cwd, {
|
|
752
63
|
getColumns: () => runtime?.viewport().columns ?? options.terminal?.columns ?? 80,
|
|
753
64
|
getRows: () => runtime?.viewport().rows ?? options.terminal?.rows ?? 24,
|
|
754
|
-
requestRender:
|
|
65
|
+
requestRender: force => runtime?.requestRender(force),
|
|
66
|
+
onViewportFrame: frame => damageTerminal?.arm(frame.descriptor, {
|
|
67
|
+
overlayActive: runtime?.hasOverlay() ?? false,
|
|
68
|
+
selectionActive: this.root.hasActiveSelection(),
|
|
69
|
+
replacementSurfaceActive: !this.root.usesDefaultInputSurface(),
|
|
70
|
+
}),
|
|
71
|
+
enableDockInputReuse: options.inputPresentation?.viewportReuse !== false,
|
|
755
72
|
onSubmit: text => { void this.submit(text); },
|
|
756
73
|
onInterrupt: () => { void this.interrupt(); },
|
|
757
74
|
onClear: () => { void this.clearOrExit(); },
|
|
@@ -766,19 +83,187 @@ export class OwnedUiSessionShell {
|
|
|
766
83
|
onMessageCopy: () => { void this.runWorkflow({ command: "copy", argument: "" }); },
|
|
767
84
|
onFollowUp: () => { void this.queueFollowUp(); },
|
|
768
85
|
onDequeue: () => this.restoreQueuedInput(),
|
|
86
|
+
onCopyText: text => {
|
|
87
|
+
runtime?.writeControl(`\u001b]52;c;${Buffer.from(text, "utf8").toString("base64")}\u0007`);
|
|
88
|
+
const write = options.clipboard === undefined
|
|
89
|
+
? writeSystemClipboardText(text)
|
|
90
|
+
: options.clipboard.writeText?.(text) ?? Promise.resolve();
|
|
91
|
+
pendingClipboardWrite = write.catch(() => { });
|
|
92
|
+
},
|
|
93
|
+
readClipboardContent: async () => {
|
|
94
|
+
await pendingClipboardWrite;
|
|
95
|
+
if (options.clipboard === undefined)
|
|
96
|
+
return readSystemClipboardContent();
|
|
97
|
+
try {
|
|
98
|
+
const image = await options.clipboard.readImage?.();
|
|
99
|
+
if (image !== null && image !== undefined) {
|
|
100
|
+
const canonical = canonicalizeClipboardImage(image);
|
|
101
|
+
if (canonical !== null)
|
|
102
|
+
return { kind: "image", ...canonical };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// Compatibility: treat an unavailable or malformed image as text-capable clipboard input.
|
|
107
|
+
}
|
|
108
|
+
const text = await options.clipboard.readText();
|
|
109
|
+
return text === null ? null : { kind: "text", text };
|
|
110
|
+
},
|
|
769
111
|
}, {
|
|
770
112
|
...options.startup,
|
|
771
113
|
resources: options.startup?.resources ?? shellResourceEntries(this.backend),
|
|
772
114
|
}, this.backend.agentDir, {
|
|
773
115
|
getMessageRenderer: customType => this.backend.pinnedMessageRenderer(customType),
|
|
774
116
|
getToolDefinition: toolName => this.backend.pinnedToolDefinition(toolName),
|
|
117
|
+
}, options.sessionLayout, {
|
|
118
|
+
resolve: assetId => this.backend.resolveTranscriptImage(assetId),
|
|
775
119
|
});
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
120
|
+
// Invariant: bare A1 owns a bounded viewport and therefore always runs on the alternate
|
|
121
|
+
// fullscreen surface. The pinned comparison profiles still honor Pi's mode.
|
|
122
|
+
const tuiMode = this.#customViewport
|
|
123
|
+
? "fullscreen"
|
|
124
|
+
: this.backend.disposed ? "regular" : this.backend.pinnedSettingsSnapshot().tuiMode;
|
|
125
|
+
const runtimeOptions = {
|
|
126
|
+
root: this.root,
|
|
127
|
+
mode: tuiMode,
|
|
128
|
+
...(this.#customViewport ? {
|
|
129
|
+
decorateTerminal: (terminal) => {
|
|
130
|
+
damageTerminal = new DamageAwareTerminalAdapter(terminal, {
|
|
131
|
+
regionalScroll: process.env.TERM !== "dumb",
|
|
132
|
+
onResize: () => streamPresentation?.noteImmediatePresentation(),
|
|
133
|
+
});
|
|
134
|
+
return damageTerminal;
|
|
135
|
+
},
|
|
136
|
+
...(options.inputPresentation?.coordination === false ? {} : {
|
|
137
|
+
inputCoordination: {
|
|
138
|
+
classify: (data, focusedOverlay) => classifyPiTuiInput(data, focusedOverlay ?? this.root.inputCoordinationSurface()),
|
|
139
|
+
onReceipt: () => streamPresentation?.noteImmediatePresentation(),
|
|
140
|
+
...(options.inputPresentation?.scheduler === undefined
|
|
141
|
+
? {}
|
|
142
|
+
: { scheduler: options.inputPresentation.scheduler }),
|
|
143
|
+
},
|
|
144
|
+
}),
|
|
145
|
+
} : { layoutRoot: this.root.layoutRoot() }),
|
|
146
|
+
...(options.inputPresentation?.onEvent === undefined ? {} : {
|
|
147
|
+
inputDiagnostics: {
|
|
148
|
+
onEvent: options.inputPresentation.onEvent,
|
|
149
|
+
...(options.inputPresentation.now === undefined ? {} : { now: options.inputPresentation.now }),
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
...(options.terminal === undefined ? {} : { terminal: options.terminal }),
|
|
153
|
+
hardwareCursor: this.backend.view().terminal.hardwareCursor,
|
|
154
|
+
};
|
|
780
155
|
runtime = new PiTuiRuntimeAdapter(runtimeOptions);
|
|
781
156
|
this.runtime = runtime;
|
|
157
|
+
this.#damageTerminal = damageTerminal ?? null;
|
|
158
|
+
const presentationInterval = options.streamPresentation?.intervalMs ?? STREAM_PRESENTATION_INTERVAL_MS;
|
|
159
|
+
streamPresentation = options.streamPresentation?.scheduler === undefined
|
|
160
|
+
? new StreamPresentationCoalescer(() => this.runtime.requestRender(), presentationInterval)
|
|
161
|
+
: new StreamPresentationCoalescer(() => this.runtime.requestRender(), presentationInterval, options.streamPresentation.scheduler);
|
|
162
|
+
this.#streamPresentation = streamPresentation;
|
|
163
|
+
const initialPiSettings = this.backend.pinnedSettingsSnapshot();
|
|
164
|
+
this.runtime.setHardwareCursor(initialPiSettings.showHardwareCursor);
|
|
165
|
+
this.runtime.setClearOnShrink(initialPiSettings.clearOnShrink);
|
|
166
|
+
this.#terminalProgressEnabled = initialPiSettings.showTerminalProgress;
|
|
167
|
+
this.#fullscreenExitOutput = initialPiSettings.fullscreenExitOutput;
|
|
168
|
+
this.#unbindShutdownSettings = this.backend.bindSettingsOwner("shutdown", {
|
|
169
|
+
fullscreenExitOutput: { apply() { } },
|
|
170
|
+
});
|
|
171
|
+
this.#unbindTerminalSettings = this.backend.bindSettingsOwner("terminal", {
|
|
172
|
+
showHardwareCursor: { apply: value => {
|
|
173
|
+
if (typeof value !== "boolean")
|
|
174
|
+
throw new TypeError("Hardware cursor setting is invalid");
|
|
175
|
+
this.runtime.setHardwareCursor(value);
|
|
176
|
+
} },
|
|
177
|
+
clearOnShrink: { apply: value => {
|
|
178
|
+
if (typeof value !== "boolean")
|
|
179
|
+
throw new TypeError("Clear-on-shrink setting is invalid");
|
|
180
|
+
this.runtime.setClearOnShrink(value);
|
|
181
|
+
} },
|
|
182
|
+
showTerminalProgress: { apply: value => {
|
|
183
|
+
if (typeof value !== "boolean")
|
|
184
|
+
throw new TypeError("Terminal progress setting is invalid");
|
|
185
|
+
this.#terminalProgressEnabled = value;
|
|
186
|
+
this.#syncTerminalProgress(this.view());
|
|
187
|
+
} },
|
|
188
|
+
});
|
|
189
|
+
this.#removeViewportPreInput = this.#customViewport
|
|
190
|
+
? this.runtime.addPreInputListener(data => {
|
|
191
|
+
if (options.inputPresentation?.coordination === false)
|
|
192
|
+
this.#streamPresentation.noteImmediatePresentation();
|
|
193
|
+
// Invariant: an overlay or editor-replacement screen owns its entire pointer
|
|
194
|
+
// surface. Letting the transcript pre-router inspect those reports
|
|
195
|
+
// steals settings value menus and numeric +/- controls before the
|
|
196
|
+
// settings app can receive them.
|
|
197
|
+
if (this.runtime.hasOverlay() || !this.root.usesDefaultInputSurface())
|
|
198
|
+
return undefined;
|
|
199
|
+
const routed = this.root.handleViewportPreInput(data, true);
|
|
200
|
+
if (routed.copyText !== undefined) {
|
|
201
|
+
this.runtime.writeControl(`\u001b]52;c;${Buffer.from(routed.copyText, "utf8").toString("base64")}\u0007`);
|
|
202
|
+
}
|
|
203
|
+
if (!routed.consumed)
|
|
204
|
+
return routed.data === data ? undefined : { data: routed.data };
|
|
205
|
+
return routed.data.length === 0 ? { consume: true } : { data: routed.data };
|
|
206
|
+
})
|
|
207
|
+
: () => { };
|
|
208
|
+
const applyViewportSettings = () => {
|
|
209
|
+
const snapshot = options.viewportSettings?.snapshot();
|
|
210
|
+
this.root.setViewportConfig(snapshot ?? {
|
|
211
|
+
scrollbarAppearance: "auto",
|
|
212
|
+
scrollbarStyle: "thin",
|
|
213
|
+
scrollbarSpeed: "normal",
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
applyViewportSettings();
|
|
217
|
+
this.#unsubscribeSettings = this.#customViewport && options.viewportSettings
|
|
218
|
+
? options.viewportSettings.onChange(settings => this.root.setViewportConfig(settings))
|
|
219
|
+
: () => { };
|
|
220
|
+
this.root.setEditorPaddingX(initialPiSettings.editorPaddingX);
|
|
221
|
+
this.root.setAutocompleteMaxVisible(initialPiSettings.autocompleteMaxVisible);
|
|
222
|
+
this.root.setOutputPad(initialPiSettings.outputPad);
|
|
223
|
+
this.root.setHideThinkingBlock(initialPiSettings.hideThinkingBlock);
|
|
224
|
+
this.root.setMermaidRenderingMode(initialPiSettings.mermaidRenderingMode);
|
|
225
|
+
this.#showImages = initialPiSettings.showImages;
|
|
226
|
+
this.#imageWidthCells = initialPiSettings.imageWidthCells;
|
|
227
|
+
this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
|
|
228
|
+
this.#unbindPiSettings = this.backend.bindSettingsOwner("shell", {
|
|
229
|
+
editorPaddingX: { apply: value => {
|
|
230
|
+
if (typeof value !== "number")
|
|
231
|
+
throw new TypeError("Editor padding is invalid");
|
|
232
|
+
this.root.setEditorPaddingX(value);
|
|
233
|
+
} },
|
|
234
|
+
autocompleteMaxVisible: { apply: value => {
|
|
235
|
+
if (typeof value !== "number")
|
|
236
|
+
throw new TypeError("Autocomplete maximum is invalid");
|
|
237
|
+
this.root.setAutocompleteMaxVisible(value);
|
|
238
|
+
} },
|
|
239
|
+
outputPad: { apply: value => {
|
|
240
|
+
if (value !== 0 && value !== 1)
|
|
241
|
+
throw new TypeError("Output padding is invalid");
|
|
242
|
+
this.root.setOutputPad(value);
|
|
243
|
+
} },
|
|
244
|
+
hideThinkingBlock: { apply: value => {
|
|
245
|
+
if (typeof value !== "boolean")
|
|
246
|
+
throw new TypeError("Thinking-block visibility is invalid");
|
|
247
|
+
this.root.setHideThinkingBlock(value);
|
|
248
|
+
} },
|
|
249
|
+
mermaidRenderingMode: { apply: value => {
|
|
250
|
+
if (value !== "off" && value !== "final" && value !== "streaming")
|
|
251
|
+
throw new TypeError("Mermaid mode is invalid");
|
|
252
|
+
this.root.setMermaidRenderingMode(value);
|
|
253
|
+
} },
|
|
254
|
+
showImages: { apply: value => {
|
|
255
|
+
if (typeof value !== "boolean")
|
|
256
|
+
throw new TypeError("Image visibility is invalid");
|
|
257
|
+
this.#showImages = value;
|
|
258
|
+
this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
|
|
259
|
+
} },
|
|
260
|
+
imageWidthCells: { apply: value => {
|
|
261
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)
|
|
262
|
+
throw new TypeError("Image width is invalid");
|
|
263
|
+
this.#imageWidthCells = value;
|
|
264
|
+
this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
|
|
265
|
+
} },
|
|
266
|
+
});
|
|
782
267
|
this.#extensionBridge = createPiExtensionUiBridge({
|
|
783
268
|
runtime: {
|
|
784
269
|
getColumns: () => this.runtime.viewport().columns,
|
|
@@ -786,7 +271,7 @@ export class OwnedUiSessionShell {
|
|
|
786
271
|
requestRender: () => this.runtime.requestRender(),
|
|
787
272
|
},
|
|
788
273
|
agentDir: this.backend.agentDir,
|
|
789
|
-
setInputSurface: component => this.root.setInputSurface(component),
|
|
274
|
+
setInputSurface: component => this.root.setInputSurface(component, true, "opaque"),
|
|
790
275
|
showOverlay: (component, overlayOptions) => this.runtime.showOverlay(component, overlayOptions),
|
|
791
276
|
listenInput: handler => this.runtime.addInputListener(handler),
|
|
792
277
|
replaceWidget: (key, component, placement) => this.root.setExtensionWidget(key, component, placement),
|
|
@@ -800,7 +285,7 @@ export class OwnedUiSessionShell {
|
|
|
800
285
|
setEditorText: text => this.root.editor.setText(text),
|
|
801
286
|
pasteToEditor: text => this.root.editor.insertText(text),
|
|
802
287
|
addAutocompleteProvider: factory => this.root.editor.addAutocompleteProvider(factory),
|
|
803
|
-
setCustomEditor: component => this.root.setInputSurface(component),
|
|
288
|
+
setCustomEditor: component => this.root.setInputSurface(component, true, "opaque"),
|
|
804
289
|
getFooterData: () => this.root.extensionFooterData(),
|
|
805
290
|
getToolsExpanded: () => this.root.toolsExpanded,
|
|
806
291
|
setToolsExpanded: expanded => this.root.setToolsExpanded(expanded),
|
|
@@ -813,12 +298,18 @@ export class OwnedUiSessionShell {
|
|
|
813
298
|
});
|
|
814
299
|
this.root.editor.setAutocompleteCommands(this.backend.workflowAutocompleteCommands());
|
|
815
300
|
this.#unsubscribe = this.backend.onEvent(event => {
|
|
816
|
-
//
|
|
301
|
+
// Performance: a streamed chunk names one block, and touching only that block is what keeps the
|
|
817
302
|
// cost of a chunk the same in a long session as in a new one. Everything else
|
|
818
303
|
// resynchronizes the view, which is cheap next to re-reading the transcript.
|
|
304
|
+
if (event.type === "agent-run-started")
|
|
305
|
+
this.root.resumeViewportFollowing();
|
|
306
|
+
if (event.type === "assistant-message-completed")
|
|
307
|
+
this.root.noteCompletedAssistantMessage();
|
|
308
|
+
const semanticOnly = event.type === "agent-run-started" || event.type === "assistant-message-completed";
|
|
819
309
|
const view = event.type === "transcript-block" && this.#sessionGeneration === this.backend.sessionGeneration
|
|
820
310
|
? this.#syncBlock(event.block)
|
|
821
|
-
: this.#syncView();
|
|
311
|
+
: semanticOnly ? this.view() : this.#syncView();
|
|
312
|
+
this.#syncTerminalProgress(view);
|
|
822
313
|
if (view.lifecycle === "ready" && this.#compactionQueue.length > 0)
|
|
823
314
|
void this.#flushCompactionQueue();
|
|
824
315
|
if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
|
|
@@ -830,11 +321,17 @@ export class OwnedUiSessionShell {
|
|
|
830
321
|
view() {
|
|
831
322
|
return this.backend.view();
|
|
832
323
|
}
|
|
324
|
+
damagePresentationDecision() {
|
|
325
|
+
return this.#damageTerminal?.lastDecision ?? null;
|
|
326
|
+
}
|
|
833
327
|
start() {
|
|
834
328
|
if (this.#started)
|
|
835
329
|
return;
|
|
836
330
|
this.#started = true;
|
|
837
331
|
this.runtime.start();
|
|
332
|
+
this.#syncTerminalProgress(this.view());
|
|
333
|
+
if (this.#customViewport)
|
|
334
|
+
this.#setPointerReporting(true);
|
|
838
335
|
void this.backend.bindExtensionUi(this.#extensionBridge.context, () => { void this.shutdown(); });
|
|
839
336
|
this.#syncView();
|
|
840
337
|
}
|
|
@@ -847,16 +344,18 @@ export class OwnedUiSessionShell {
|
|
|
847
344
|
return this.#stopped;
|
|
848
345
|
}
|
|
849
346
|
async submit(text) {
|
|
850
|
-
const
|
|
851
|
-
if (!
|
|
347
|
+
const displayInput = text.trim();
|
|
348
|
+
if (!displayInput)
|
|
852
349
|
return { outcome: "completed", diagnostic: null };
|
|
853
|
-
if (
|
|
854
|
-
return this.#slashCommand(
|
|
350
|
+
if (displayInput.startsWith("/"))
|
|
351
|
+
return this.#slashCommand(displayInput);
|
|
352
|
+
const prepared = this.root.preparePromptSubmission(displayInput);
|
|
353
|
+
const input = prepared.text.trim();
|
|
855
354
|
if (input.startsWith("!")) {
|
|
856
355
|
const excludeFromContext = input.startsWith("!!");
|
|
857
356
|
const command = input.slice(excludeFromContext ? 2 : 1).trim();
|
|
858
357
|
if (command) {
|
|
859
|
-
this.root.editor.addToHistory(
|
|
358
|
+
this.root.editor.addToHistory(displayInput);
|
|
860
359
|
try {
|
|
861
360
|
const result = await this.backend.executeBashWorkflow(command, excludeFromContext);
|
|
862
361
|
const workflow = {
|
|
@@ -878,19 +377,25 @@ export class OwnedUiSessionShell {
|
|
|
878
377
|
}
|
|
879
378
|
}
|
|
880
379
|
if (this.view().status.workingMessage?.startsWith("Compacting") === true) {
|
|
881
|
-
this.root.editor.addToHistory(
|
|
882
|
-
this.#compactionQueue.push({
|
|
380
|
+
this.root.editor.addToHistory(displayInput);
|
|
381
|
+
this.#compactionQueue.push({
|
|
382
|
+
text: input,
|
|
383
|
+
type: "steer",
|
|
384
|
+
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
385
|
+
});
|
|
883
386
|
this.root.appendWorkflowResult({ command: "compact", outcome: "completed", message: `Queued during compaction: ${input}` });
|
|
884
387
|
this.runtime.requestRender();
|
|
885
388
|
return { outcome: "completed", diagnostic: null };
|
|
886
389
|
}
|
|
887
390
|
const type = this.view().lifecycle === "busy" ? "steer" : "prompt";
|
|
888
|
-
this.root.editor.addToHistory(
|
|
391
|
+
this.root.editor.addToHistory(displayInput);
|
|
392
|
+
this.root.resumeViewportFollowing();
|
|
889
393
|
return this.#execute({
|
|
890
394
|
type,
|
|
891
395
|
correlationId: this.#correlation(type),
|
|
892
396
|
sessionId: this.backend.sessionId,
|
|
893
397
|
text: input,
|
|
398
|
+
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
894
399
|
});
|
|
895
400
|
}
|
|
896
401
|
async clearOrExit(now = Date.now()) {
|
|
@@ -901,14 +406,29 @@ export class OwnedUiSessionShell {
|
|
|
901
406
|
this.runtime.requestRender();
|
|
902
407
|
return { outcome: "completed", diagnostic: null };
|
|
903
408
|
}
|
|
904
|
-
async interrupt() {
|
|
409
|
+
async interrupt(now = Date.now()) {
|
|
905
410
|
if (this.view().lifecycle === "busy")
|
|
906
411
|
return this.abort();
|
|
907
|
-
if (this.root.editor.getText().length > 0) {
|
|
412
|
+
if (this.root.editor.getText().trim().length > 0) {
|
|
908
413
|
this.root.editor.setText("");
|
|
909
414
|
return { outcome: "completed", diagnostic: null };
|
|
910
415
|
}
|
|
911
|
-
|
|
416
|
+
// Compatibility: match Pi: with an empty editor, two escapes inside 500 ms open the
|
|
417
|
+
// configured session navigator. The first escape intentionally does not
|
|
418
|
+
// interrupt or mutate the prompt.
|
|
419
|
+
const action = this.backend.pinnedSettingsSnapshot().doubleEscapeAction;
|
|
420
|
+
if (action === "none")
|
|
421
|
+
return { outcome: "rejected", diagnostic: "nothing to interrupt" };
|
|
422
|
+
if (now - this.#lastEscapeTime < 500) {
|
|
423
|
+
this.#lastEscapeTime = 0;
|
|
424
|
+
if (action === "tree")
|
|
425
|
+
this.showTreeSelector();
|
|
426
|
+
else
|
|
427
|
+
this.showForkSelector();
|
|
428
|
+
return { outcome: "completed", diagnostic: null };
|
|
429
|
+
}
|
|
430
|
+
this.#lastEscapeTime = now;
|
|
431
|
+
return { outcome: "completed", diagnostic: null };
|
|
912
432
|
}
|
|
913
433
|
async abort() {
|
|
914
434
|
return this.#execute(this.#simple("abort"));
|
|
@@ -960,13 +480,20 @@ export class OwnedUiSessionShell {
|
|
|
960
480
|
return workflowAdapterResult(result);
|
|
961
481
|
}
|
|
962
482
|
async queueFollowUp() {
|
|
963
|
-
const
|
|
964
|
-
if (!
|
|
483
|
+
const displayInput = this.root.editor.getText().trim();
|
|
484
|
+
if (!displayInput)
|
|
965
485
|
return rejected("nothing to queue");
|
|
966
|
-
this.root.
|
|
486
|
+
const prepared = this.root.preparePromptSubmission(displayInput);
|
|
487
|
+
const text = prepared.text.trim();
|
|
488
|
+
this.root.editor.addToHistory(displayInput);
|
|
967
489
|
this.root.editor.setText("");
|
|
490
|
+
this.root.resumeViewportFollowing();
|
|
968
491
|
if (this.view().status.workingMessage?.startsWith("Compacting") === true) {
|
|
969
|
-
this.#compactionQueue.push({
|
|
492
|
+
this.#compactionQueue.push({
|
|
493
|
+
text,
|
|
494
|
+
type: "follow-up",
|
|
495
|
+
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
496
|
+
});
|
|
970
497
|
return { outcome: "completed", diagnostic: null };
|
|
971
498
|
}
|
|
972
499
|
return this.#execute({
|
|
@@ -974,6 +501,7 @@ export class OwnedUiSessionShell {
|
|
|
974
501
|
correlationId: this.#correlation("follow-up"),
|
|
975
502
|
sessionId: this.backend.sessionId,
|
|
976
503
|
text,
|
|
504
|
+
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
977
505
|
});
|
|
978
506
|
}
|
|
979
507
|
restoreQueuedInput() {
|
|
@@ -986,6 +514,8 @@ export class OwnedUiSessionShell {
|
|
|
986
514
|
}
|
|
987
515
|
showSelector(title, options, onSelect, onCancel) {
|
|
988
516
|
this.#dialogHandle?.hide();
|
|
517
|
+
this.#dialogSource = "local";
|
|
518
|
+
this.#dialogId = undefined;
|
|
989
519
|
const component = createPiShellSelector({
|
|
990
520
|
title,
|
|
991
521
|
options,
|
|
@@ -993,14 +523,21 @@ export class OwnedUiSessionShell {
|
|
|
993
523
|
onSelect(id);
|
|
994
524
|
this.#dialogHandle?.hide();
|
|
995
525
|
this.#dialogHandle = undefined;
|
|
526
|
+
this.#dialogSource = undefined;
|
|
996
527
|
},
|
|
997
528
|
onCancel: () => {
|
|
998
529
|
this.#dialogHandle?.hide();
|
|
999
530
|
this.#dialogHandle = undefined;
|
|
531
|
+
this.#dialogSource = undefined;
|
|
1000
532
|
onCancel?.();
|
|
1001
533
|
},
|
|
1002
534
|
});
|
|
1003
|
-
const handle = this.runtime.showOverlay(component, {
|
|
535
|
+
const handle = this.runtime.showOverlay(component, {
|
|
536
|
+
width: "70%",
|
|
537
|
+
maxHeight: "80%",
|
|
538
|
+
anchor: "center",
|
|
539
|
+
inputCoordination: "owned",
|
|
540
|
+
});
|
|
1004
541
|
this.#dialogHandle = handle;
|
|
1005
542
|
return handle;
|
|
1006
543
|
}
|
|
@@ -1200,6 +737,10 @@ export class OwnedUiSessionShell {
|
|
|
1200
737
|
return;
|
|
1201
738
|
}
|
|
1202
739
|
if (callback === "onTuiModeChange") {
|
|
740
|
+
// Invariant: the custom bare-A1 surface is permanently fullscreen; this callback
|
|
741
|
+
// remains available only to pinned comparison profiles.
|
|
742
|
+
if (this.#customViewport)
|
|
743
|
+
return;
|
|
1203
744
|
if (value !== "regular" && value !== "fullscreen")
|
|
1204
745
|
return;
|
|
1205
746
|
if (!this.runtime.switchMode(value)) {
|
|
@@ -1207,13 +748,18 @@ export class OwnedUiSessionShell {
|
|
|
1207
748
|
this.runtime.requestRender();
|
|
1208
749
|
return;
|
|
1209
750
|
}
|
|
751
|
+
if (this.#customViewport) {
|
|
752
|
+
this.#pointerReporting = false;
|
|
753
|
+
this.#setPointerReporting(true);
|
|
754
|
+
}
|
|
1210
755
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
756
|
+
void this.backend.applyPinnedSettingValue(callback, value).then(result => {
|
|
757
|
+
if (result.outcome === "failed")
|
|
758
|
+
this.root.appendWorkflowResult(result);
|
|
759
|
+
else if (callback === "onTuiModeChange")
|
|
760
|
+
this.root.appendWorkflowStatus(`TUI mode: ${value}`);
|
|
761
|
+
this.runtime.requestRender();
|
|
762
|
+
});
|
|
1217
763
|
},
|
|
1218
764
|
onCancel: close,
|
|
1219
765
|
});
|
|
@@ -1412,50 +958,84 @@ export class OwnedUiSessionShell {
|
|
|
1412
958
|
this.root.appendDaxnuts();
|
|
1413
959
|
}
|
|
1414
960
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
* screen that wanted it and takes the terminal's own scrolling and selection with it.
|
|
1420
|
-
*/
|
|
1421
|
-
#setPointerReporting(enabled) {
|
|
1422
|
-
if (this.#pointerReporting === enabled)
|
|
961
|
+
// Invariant: pointer reporting is disabled on every path that ends the owning screen.
|
|
962
|
+
#setPointerReporting(enabled, forceOff = false) {
|
|
963
|
+
const effective = forceOff ? false : this.#customViewport || enabled;
|
|
964
|
+
if (this.#pointerReporting === effective)
|
|
1423
965
|
return;
|
|
1424
|
-
this.#pointerReporting =
|
|
966
|
+
this.#pointerReporting = effective;
|
|
1425
967
|
if (!this.runtime.active)
|
|
1426
968
|
return;
|
|
1427
|
-
this.runtime.writeControl(
|
|
969
|
+
this.runtime.writeControl(effective ? MOUSE_TRACKING_ON : MOUSE_TRACKING_OFF);
|
|
1428
970
|
}
|
|
1429
971
|
async dispose() {
|
|
1430
972
|
if (this.#disposed)
|
|
1431
973
|
return;
|
|
1432
974
|
this.#disposed = true;
|
|
1433
|
-
this
|
|
975
|
+
this.root.clearViewportPointerState();
|
|
976
|
+
this.#setPointerReporting(false, true);
|
|
977
|
+
this.#removeViewportPreInput();
|
|
978
|
+
this.#streamPresentation.dispose();
|
|
979
|
+
this.#unsubscribeSettings();
|
|
980
|
+
const exitMode = this.backend.disposed
|
|
981
|
+
? this.#fullscreenExitOutput
|
|
982
|
+
: this.backend.pinnedSettingsSnapshot().fullscreenExitOutput;
|
|
983
|
+
const exitTranscript = this.root.exitTranscript(this.runtime.viewport().columns);
|
|
984
|
+
const resume = this.backend.currentSessionResumeMetadata();
|
|
985
|
+
const resumeHint = resume === null
|
|
986
|
+
? ""
|
|
987
|
+
: `${dim("To resume this session:")} ${formatSessionResumeCommand(resume)}`;
|
|
988
|
+
const fullscreenExitText = this.runtime.mode !== "fullscreen"
|
|
989
|
+
? ""
|
|
990
|
+
: exitMode === "resume-hint"
|
|
991
|
+
? resumeHint
|
|
992
|
+
: [exitTranscript, resumeHint].filter(Boolean).join("\n\n");
|
|
993
|
+
this.#unbindPiSettings();
|
|
994
|
+
this.#unbindTerminalSettings();
|
|
995
|
+
this.#unbindShutdownSettings();
|
|
1434
996
|
this.#unsubscribe();
|
|
1435
997
|
this.#dialogHandle?.hide();
|
|
1436
998
|
await this.backend.unbindExtensionUi();
|
|
1437
999
|
this.#extensionBridge.dispose();
|
|
1438
1000
|
await this.runtime.dispose();
|
|
1001
|
+
if (fullscreenExitText.length > 0)
|
|
1002
|
+
this.runtime.writeAfterStop(`${fullscreenExitText}\n`);
|
|
1439
1003
|
}
|
|
1440
|
-
|
|
1441
|
-
* Applies one transcript block without re-reading the session. The listeners still hear
|
|
1442
|
-
* the view they would have heard, so nothing downstream can tell the difference.
|
|
1443
|
-
*/
|
|
1004
|
+
// Invariant: incremental block updates notify listeners with the same complete view contract.
|
|
1444
1005
|
#syncBlock(block) {
|
|
1445
1006
|
this.root.applyTranscriptBlock(block);
|
|
1446
|
-
this.
|
|
1007
|
+
if (this.#customViewport && block.status === "live" && isCoalescedStreamBlock(block.kind)) {
|
|
1008
|
+
this.#streamPresentation.request();
|
|
1009
|
+
}
|
|
1010
|
+
else if (this.#streamPresentation.pending) {
|
|
1011
|
+
this.#streamPresentation.flush();
|
|
1012
|
+
}
|
|
1013
|
+
else {
|
|
1014
|
+
this.#streamPresentation.presentImmediate();
|
|
1015
|
+
}
|
|
1447
1016
|
const view = this.view();
|
|
1448
1017
|
for (const listener of this.#listeners)
|
|
1449
1018
|
listener(view);
|
|
1450
1019
|
return view;
|
|
1451
1020
|
}
|
|
1021
|
+
#syncTerminalProgress(view) {
|
|
1022
|
+
if (!this.runtime.active)
|
|
1023
|
+
return;
|
|
1024
|
+
this.runtime.setTerminalProgress(this.#terminalProgressEnabled && view.lifecycle === "busy");
|
|
1025
|
+
}
|
|
1452
1026
|
#syncView() {
|
|
1027
|
+
this.#streamPresentation.noteImmediatePresentation();
|
|
1453
1028
|
const view = this.view();
|
|
1454
1029
|
if (this.backend.sessionGeneration !== this.#sessionGeneration) {
|
|
1455
1030
|
this.#sessionGeneration = this.backend.sessionGeneration;
|
|
1456
1031
|
this.#activeLoginDialog = undefined;
|
|
1457
1032
|
this.#extensionBridge.reset();
|
|
1458
|
-
//
|
|
1033
|
+
// Invariant: a replaced session takes its transient viewport and owned-route state with it.
|
|
1034
|
+
this.root.resetViewport();
|
|
1035
|
+
this.#dialogHandle?.hide();
|
|
1036
|
+
this.#dialogHandle = undefined;
|
|
1037
|
+
this.#dialogId = undefined;
|
|
1038
|
+
this.#dialogSource = undefined;
|
|
1459
1039
|
this.#setPointerReporting(false);
|
|
1460
1040
|
this.root.setInputSurface(null);
|
|
1461
1041
|
this.root.resetExtensionUi();
|
|
@@ -1475,10 +1055,11 @@ export class OwnedUiSessionShell {
|
|
|
1475
1055
|
if (!this.runtime.active)
|
|
1476
1056
|
return { outcome: "failed", diagnostic: "runtime is not active" };
|
|
1477
1057
|
this.#dialogHandle?.hide();
|
|
1478
|
-
|
|
1058
|
+
this.#dialogSource = "route";
|
|
1059
|
+
// Protocol: any-event reporting: hover and drag are what the screen is driven by, and
|
|
1479
1060
|
// it also stops the terminal treating a drag as a text selection.
|
|
1480
1061
|
this.#setPointerReporting(true);
|
|
1481
|
-
//
|
|
1062
|
+
// Protocol: the interrupt chord is global, so it is watched on raw input rather than
|
|
1482
1063
|
// through the overlay: the pinned shell handles that key before an overlay
|
|
1483
1064
|
// ever sees it, which is why an owned screen must not rely on being asked.
|
|
1484
1065
|
let armedAt = 0;
|
|
@@ -1494,17 +1075,36 @@ export class OwnedUiSessionShell {
|
|
|
1494
1075
|
}
|
|
1495
1076
|
armedAt = now;
|
|
1496
1077
|
this.runtime.requestRender();
|
|
1497
|
-
//
|
|
1078
|
+
// Invariant: the presented screen owns the chord, so the pinned shell never sees a
|
|
1498
1079
|
// stray interrupt while it is up.
|
|
1499
1080
|
return { consume: true };
|
|
1500
1081
|
});
|
|
1082
|
+
let removeSurfacePreInput = () => { };
|
|
1501
1083
|
const closeSurface = () => {
|
|
1084
|
+
removeSurfacePreInput();
|
|
1502
1085
|
removeInterruptWatch();
|
|
1503
1086
|
this.#setPointerReporting(false);
|
|
1504
1087
|
this.#dialogHandle?.hide();
|
|
1505
1088
|
this.#dialogHandle = undefined;
|
|
1506
1089
|
this.#dialogId = undefined;
|
|
1090
|
+
this.#dialogSource = undefined;
|
|
1507
1091
|
};
|
|
1092
|
+
// Compatibility: fullscreen Pi owns a fallback text-selection layer before focused overlay
|
|
1093
|
+
// components see pointer input. Route every mouse report to the owned screen
|
|
1094
|
+
// at the pre-input boundary so dropdowns, value hover, and numeric +/- work,
|
|
1095
|
+
// and consume even unhandled reports so settings content is never selected.
|
|
1096
|
+
removeSurfacePreInput = this.runtime.addPreInputListener(data => {
|
|
1097
|
+
const { events, rest } = parseMouseInput(data);
|
|
1098
|
+
if (events.length === 0)
|
|
1099
|
+
return undefined;
|
|
1100
|
+
for (const event of events)
|
|
1101
|
+
surface.handleMouse(event);
|
|
1102
|
+
if (surface.isClosed())
|
|
1103
|
+
closeSurface();
|
|
1104
|
+
else
|
|
1105
|
+
this.runtime.requestRender();
|
|
1106
|
+
return rest.length === 0 ? { consume: true } : { data: rest };
|
|
1107
|
+
});
|
|
1508
1108
|
const rows = () => Math.max(1, this.runtime.viewport().rows);
|
|
1509
1109
|
const component = {
|
|
1510
1110
|
render: (width) => [...surface.render(Math.max(1, width), rows())],
|
|
@@ -1527,7 +1127,12 @@ export class OwnedUiSessionShell {
|
|
|
1527
1127
|
closeSurface();
|
|
1528
1128
|
void this.shutdown();
|
|
1529
1129
|
});
|
|
1530
|
-
this.#dialogHandle = this.runtime.showOverlay(component, {
|
|
1130
|
+
this.#dialogHandle = this.runtime.showOverlay(component, {
|
|
1131
|
+
width: "100%",
|
|
1132
|
+
maxHeight: "100%",
|
|
1133
|
+
anchor: "top-left",
|
|
1134
|
+
inputCoordination: "owned",
|
|
1135
|
+
});
|
|
1531
1136
|
this.#dialogId = surface.id;
|
|
1532
1137
|
return { outcome: "completed", diagnostic: null };
|
|
1533
1138
|
}
|
|
@@ -1535,25 +1140,40 @@ export class OwnedUiSessionShell {
|
|
|
1535
1140
|
if (!this.runtime.active)
|
|
1536
1141
|
return;
|
|
1537
1142
|
if (dialog === null) {
|
|
1143
|
+
// Invariant: locally owned routes (notably /settings) are independent of backend
|
|
1144
|
+
// lifecycle/status events and remain open while an agent is working.
|
|
1145
|
+
if (this.#dialogSource !== "backend")
|
|
1146
|
+
return;
|
|
1538
1147
|
this.#dialogHandle?.hide();
|
|
1539
1148
|
this.#dialogHandle = undefined;
|
|
1540
1149
|
this.#dialogId = undefined;
|
|
1150
|
+
this.#dialogSource = undefined;
|
|
1541
1151
|
return;
|
|
1542
1152
|
}
|
|
1543
|
-
if (this.#dialogId === dialog.id)
|
|
1153
|
+
if (this.#dialogSource === "backend" && this.#dialogId === dialog.id)
|
|
1544
1154
|
return;
|
|
1545
1155
|
this.#dialogHandle?.hide();
|
|
1156
|
+
this.#dialogSource = "backend";
|
|
1546
1157
|
const component = createPiShellDialog(dialog, {
|
|
1547
1158
|
onSelect: () => {
|
|
1548
1159
|
this.#dialogHandle?.hide();
|
|
1549
1160
|
this.#dialogHandle = undefined;
|
|
1161
|
+
this.#dialogId = undefined;
|
|
1162
|
+
this.#dialogSource = undefined;
|
|
1550
1163
|
},
|
|
1551
1164
|
onCancel: () => {
|
|
1552
1165
|
this.#dialogHandle?.hide();
|
|
1553
1166
|
this.#dialogHandle = undefined;
|
|
1167
|
+
this.#dialogId = undefined;
|
|
1168
|
+
this.#dialogSource = undefined;
|
|
1554
1169
|
},
|
|
1555
1170
|
});
|
|
1556
|
-
this.#dialogHandle = this.runtime.showOverlay(component, {
|
|
1171
|
+
this.#dialogHandle = this.runtime.showOverlay(component, {
|
|
1172
|
+
width: "70%",
|
|
1173
|
+
maxHeight: "80%",
|
|
1174
|
+
anchor: "center",
|
|
1175
|
+
inputCoordination: "owned",
|
|
1176
|
+
});
|
|
1557
1177
|
this.#dialogId = dialog.id;
|
|
1558
1178
|
}
|
|
1559
1179
|
async #slashCommand(text) {
|
|
@@ -1565,8 +1185,9 @@ export class OwnedUiSessionShell {
|
|
|
1565
1185
|
return this.#openOwnedRoute(name);
|
|
1566
1186
|
if (isWorkflowRoute(name))
|
|
1567
1187
|
return this.runWorkflow({ command: name, argument });
|
|
1568
|
-
//
|
|
1188
|
+
// Compatibility: unknown slash input, prompt templates, skills, and extension commands remain Pi prompt input.
|
|
1569
1189
|
this.root.editor.addToHistory(text);
|
|
1190
|
+
this.root.resumeViewportFollowing();
|
|
1570
1191
|
return this.#execute({
|
|
1571
1192
|
type: this.view().lifecycle === "busy" ? "steer" : "prompt",
|
|
1572
1193
|
correlationId: this.#correlation("prompt-command"),
|
|
@@ -1688,6 +1309,7 @@ export class OwnedUiSessionShell {
|
|
|
1688
1309
|
correlationId: this.#correlation(`compaction-${item.type}`),
|
|
1689
1310
|
sessionId: this.backend.sessionId,
|
|
1690
1311
|
text: item.text,
|
|
1312
|
+
...(item.images === undefined ? {} : { images: item.images }),
|
|
1691
1313
|
});
|
|
1692
1314
|
}
|
|
1693
1315
|
}
|
|
@@ -1702,6 +1324,24 @@ export class OwnedUiSessionShell {
|
|
|
1702
1324
|
return `pi-shell-${prefix}-${this.#sequence}`;
|
|
1703
1325
|
}
|
|
1704
1326
|
}
|
|
1327
|
+
function isCoalescedStreamBlock(kind) {
|
|
1328
|
+
return kind === "assistant" || kind === "thinking" || kind === "tool-call" || kind === "tool-result";
|
|
1329
|
+
}
|
|
1330
|
+
export function formatSessionResumeCommand(metadata) {
|
|
1331
|
+
const args = [PRODUCT_TEXT.commandName];
|
|
1332
|
+
if (!metadata.usesDefaultSessionDir)
|
|
1333
|
+
args.push("--session-dir", quoteCommandArgument(metadata.sessionDir));
|
|
1334
|
+
args.push("--session", metadata.sessionId);
|
|
1335
|
+
return args.join(" ");
|
|
1336
|
+
}
|
|
1337
|
+
export function quoteCommandArgument(value) {
|
|
1338
|
+
if (value.length > 0 && !/[^a-zA-Z0-9_\-./~:@]/.test(value))
|
|
1339
|
+
return value;
|
|
1340
|
+
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
1341
|
+
}
|
|
1342
|
+
function dim(value) {
|
|
1343
|
+
return `\u001b[2m${value}\u001b[22m`;
|
|
1344
|
+
}
|
|
1705
1345
|
function modelReference(model) {
|
|
1706
1346
|
if (typeof model !== "object" || model === null)
|
|
1707
1347
|
return "";
|