@timurproko/a1 0.1.8-dev.235df0e → 0.1.8-dev.259
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -67
- package/bin/cli.js +28 -10
- package/bin/guardian.js +8 -3
- package/bin/module-identity.js +69 -35
- package/bin/pi-tui.d.ts +6 -0
- package/bin/pi-tui.js +28 -0
- package/bin/release-cleanup.js +8 -0
- package/bin/supervisor.js +2 -2
- package/bin/sync-pi-tui-proxy.js +97 -0
- package/bin/ui.js +47 -20
- package/bin/warmup.js +27 -0
- package/dist/cli/capabilities.d.ts +6 -0
- package/dist/{src/cli → cli}/capabilities.js +1 -1
- package/dist/{src/cli → cli}/dispatch.d.ts +15 -1
- package/dist/cli/dispatch.js +261 -0
- package/dist/cli/package-messages.d.ts +26 -0
- package/dist/cli/package-messages.js +71 -0
- package/dist/{src/cli → cli}/packages.d.ts +11 -2
- package/dist/{src/cli → cli}/packages.js +24 -27
- package/dist/{src/cli → cli}/version-stats.d.ts +6 -0
- package/dist/cli/version-stats.js +112 -0
- package/dist/composition/agent-engine-bridge.d.ts +3 -0
- package/dist/composition/agent-engine-bridge.js +108 -0
- package/dist/composition/index.d.ts +3 -0
- package/dist/composition/index.js +3 -0
- package/dist/composition/owned-ui.d.ts +31 -0
- package/dist/composition/owned-ui.js +66 -0
- package/dist/composition/process.d.ts +16 -0
- package/dist/composition/process.js +45 -0
- package/dist/composition/settings-route-host.d.ts +8 -0
- package/dist/composition/settings-route-host.js +75 -0
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.d.ts +2 -2
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.js +22 -4
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.d.ts +17 -0
- package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.d.ts +6 -0
- package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.d.ts +36 -0
- package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.js +25 -0
- package/dist/{src/features → features}/launch/development-launch.js +11 -3
- package/dist/{src/features → features}/launch/index.d.ts +0 -1
- package/dist/{src/features → features}/launch/index.js +0 -1
- package/dist/features/launch/intent.d.ts +10 -0
- package/dist/features/launch/intent.js +8 -0
- package/dist/{src/features → features}/launch/prepare-launch.d.ts +0 -2
- package/dist/{src/features → features}/launch/prepare-launch.js +2 -9
- package/dist/{src/features → features}/launch/profile-paths.d.ts +1 -2
- package/dist/{src/features → features}/launch/profile-paths.js +2 -8
- package/dist/{src/features → features}/launch/runtime-selection.d.ts +2 -5
- package/dist/{src/features → features}/owned-ui/customization.d.ts +3 -1
- package/dist/{src/features → features}/owned-ui/customization.js +3 -1
- package/dist/{src/features → features}/owned-ui/diagnostics.d.ts +2 -1
- package/dist/{src/features → features}/owned-ui/diagnostics.js +1 -0
- package/dist/{src/features → features}/owned-ui/index.d.ts +2 -0
- package/dist/{src/features → features}/owned-ui/index.js +2 -0
- package/dist/features/owned-ui/project-trust-prompt.d.ts +25 -0
- package/dist/features/owned-ui/project-trust-prompt.js +149 -0
- package/dist/{src/features → features}/owned-ui/run.d.ts +2 -2
- package/dist/{src/features → features}/owned-ui/run.js +2 -0
- package/dist/features/owned-ui/session-fork-prompt.d.ts +8 -0
- package/dist/features/owned-ui/session-fork-prompt.js +34 -0
- package/dist/{src/features → features}/owned-ui/settings-app.d.ts +3 -3
- package/dist/{src/features → features}/owned-ui/settings-app.js +103 -54
- package/dist/{src/features → features}/workspace/capabilities.d.ts +1 -1
- package/dist/{src/features → features}/workspace/reducer.d.ts +2 -1
- package/dist/{src/features → features}/workspace/reducer.js +2 -1
- package/dist/{src/features → features}/workspace/router.d.ts +2 -1
- package/dist/{src/features → features}/workspace/router.js +1 -0
- package/dist/{src/features → features}/workspace/store.d.ts +2 -1
- package/dist/{src/features → features}/workspace/store.js +1 -0
- package/dist/{src/foundation → foundation}/launch-guardian/main.d.ts +2 -0
- package/dist/{src/foundation → foundation}/launch-guardian/main.js +18 -5
- package/dist/{src/foundation → foundation}/lifecycle/index.d.ts +2 -0
- package/dist/{src/foundation → foundation}/lifecycle/index.js +2 -0
- package/dist/{src/foundation → foundation}/lifecycle/model.d.ts +1 -1
- package/dist/{src/foundation → foundation}/lifecycle/model.js +1 -1
- package/dist/foundation/lifecycle/paths.d.ts +30 -0
- package/dist/{src/foundation → foundation}/lifecycle/paths.js +29 -1
- package/dist/foundation/lifecycle/session-selection.d.ts +9 -0
- package/dist/foundation/lifecycle/session-selection.js +39 -0
- package/dist/foundation/lifecycle/supervisor-startup.d.ts +30 -0
- package/dist/foundation/lifecycle/supervisor-startup.js +106 -0
- package/dist/{src/foundation → foundation}/native-host-protocol/codec.d.ts +2 -0
- package/dist/{src/foundation → foundation}/native-host-protocol/codec.js +2 -0
- package/dist/{src/foundation → foundation}/native-host-protocol/messages.d.ts +1 -1
- package/dist/{src/foundation → foundation}/native-host-protocol/messages.js +1 -1
- package/dist/foundation/process-containment/darwin-process-inspector.d.ts +5 -0
- package/dist/foundation/process-containment/darwin-process-inspector.js +7 -0
- package/dist/{src/foundation → foundation}/process-containment/index.d.ts +1 -0
- package/dist/{src/foundation → foundation}/process-containment/index.js +1 -0
- package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.d.ts +1 -0
- package/dist/{src/foundation → foundation}/process-containment/linux-process-inspector.js +1 -0
- package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.d.ts +1 -0
- package/dist/{src/foundation → foundation}/process-containment/native-guardian-containment.js +1 -0
- package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.d.ts +3 -1
- package/dist/{src/foundation → foundation}/process-containment/windows-process-inspector.js +5 -2
- package/dist/{src/foundation → foundation}/protocol/client.d.ts +1 -0
- package/dist/{src/foundation → foundation}/protocol/client.js +1 -0
- package/dist/{src/foundation → foundation}/protocol/messages.d.ts +1 -0
- package/dist/{src/foundation → foundation}/protocol/messages.js +1 -0
- package/dist/{src/foundation → foundation}/release/bootstrap.d.ts +23 -6
- package/dist/{src/foundation → foundation}/release/bootstrap.js +120 -34
- package/dist/foundation/release/cohort-state.d.ts +156 -0
- package/dist/foundation/release/cohort-state.js +471 -0
- package/dist/foundation/release/dependency-layer.d.ts +78 -0
- package/dist/foundation/release/dependency-layer.js +488 -0
- package/dist/foundation/release/endpoints.d.ts +20 -0
- package/dist/foundation/release/endpoints.js +50 -0
- package/dist/foundation/release/immutable-platform.d.ts +6 -0
- package/dist/foundation/release/immutable-platform.js +13 -0
- package/dist/{src/foundation → foundation}/release/index.d.ts +4 -0
- package/dist/{src/foundation → foundation}/release/index.js +4 -0
- package/dist/foundation/release/release-gc.d.ts +71 -0
- package/dist/foundation/release/release-gc.js +734 -0
- package/dist/{src/foundation → foundation}/release/release-store.d.ts +4 -2
- package/dist/{src/foundation → foundation}/release/release-store.js +64 -12
- package/dist/{src/foundation → foundation}/release/release.d.ts +4 -1
- package/dist/{src/foundation → foundation}/release/release.js +10 -3
- package/dist/foundation/release/restart-certification.d.ts +67 -0
- package/dist/foundation/release/restart-certification.js +211 -0
- package/dist/{src/foundation → foundation}/release/update-transaction.d.ts +1 -0
- package/dist/{src/foundation → foundation}/release/update-transaction.js +1 -0
- package/dist/{src/foundation → foundation}/release/update.d.ts +19 -3
- package/dist/{src/foundation → foundation}/release/update.js +116 -56
- package/dist/foundation/release/warmup.d.ts +3 -0
- package/dist/foundation/release/warmup.js +35 -0
- package/dist/foundation/startup/index.d.ts +1 -0
- package/dist/foundation/startup/index.js +1 -0
- package/dist/foundation/startup/startup-runtime.d.ts +36 -0
- package/dist/foundation/startup/startup-runtime.js +140 -0
- package/dist/{src/foundation → foundation}/storage/control-store.d.ts +2 -1
- package/dist/{src/foundation → foundation}/storage/control-store.js +39 -4
- package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/backpressure.js +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/commands.js +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.d.ts +1 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/handshake.js +1 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/reconnection.js +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/state.d.ts +2 -1
- package/dist/{src/foundation → foundation}/structured-agent-runtime/state.js +2 -1
- package/dist/foundation/supervision/index.d.ts +3 -0
- package/dist/foundation/supervision/index.js +3 -0
- package/dist/foundation/supervision/main.d.ts +1 -0
- package/dist/foundation/supervision/main.js +77 -0
- package/dist/foundation/supervision/paths.d.ts +1 -0
- package/dist/foundation/supervision/paths.js +1 -0
- package/dist/{src/foundation → foundation}/supervision/server.d.ts +19 -1
- package/dist/{src/foundation → foundation}/supervision/server.js +65 -3
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.d.ts +1 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.d.ts +1 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/conformance.js +3 -2
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.d.ts +1 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/index.js +1 -1
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +55 -0
- package/dist/integrations/pi/components/owned-editor-ux.js +778 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.d.ts +1 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-components.js +1 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-editor-autocomplete.js +54 -6
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.d.ts +1 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.d.ts +3 -3
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-footer-status.js +49 -18
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +36 -0
- package/dist/integrations/pi/components/shell-presenters-info.js +78 -0
- package/dist/integrations/pi/components/shell-presenters-transcript.d.ts +25 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-presenters-transcript.js +92 -131
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.d.ts +5 -2
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-selectors-dialogs.js +2 -1
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.d.ts +57 -8
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-shared-facade.js +4 -2
- package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +13 -0
- package/dist/integrations/pi/components/submitted-prompt-adapter.js +27 -0
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.d.ts +10 -2
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/adjacent/core/keybindings.js +36 -3
- package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.d.ts +1 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.d.ts +28 -4
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/adapter.js +714 -127
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.d.ts +2 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/conformance.js +4 -2
- package/dist/integrations/pi/engine/http-dispatcher.d.ts +4 -0
- package/dist/integrations/pi/engine/http-dispatcher.js +25 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.d.ts +4 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/index.js +4 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.d.ts +2 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/model-auth-integration.js +1 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.d.ts +1 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/package-integration.js +32 -26
- package/dist/integrations/pi/engine/project-trust-preflight.d.ts +22 -0
- package/dist/integrations/pi/engine/project-trust-preflight.js +50 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.d.ts +2 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/resource-extension-integration.js +1 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.d.ts +19 -1
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/runtime-integration.js +47 -5
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.d.ts +4 -2
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/session-integration.js +19 -4
- package/dist/integrations/pi/engine/session-selection.d.ts +28 -0
- package/dist/integrations/pi/engine/session-selection.js +90 -0
- package/dist/integrations/pi/engine/settings-effects.d.ts +66 -0
- package/dist/integrations/pi/engine/settings-effects.js +249 -0
- package/dist/integrations/pi/engine/settings-integration.d.ts +43 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/settings-integration.js +102 -108
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.d.ts +3 -2
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflow-controllers.js +1 -0
- package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.d.ts +18 -1
- package/dist/integrations/pi/session-ui/clipboard-image.d.ts +11 -0
- package/dist/integrations/pi/session-ui/clipboard-image.js +29 -0
- package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/index.d.ts +1 -0
- package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/index.js +1 -0
- package/dist/integrations/pi/session-ui/prompt-chips.d.ts +23 -0
- package/dist/integrations/pi/session-ui/prompt-chips.js +246 -0
- package/dist/integrations/pi/session-ui/route-host.d.ts +5 -0
- package/dist/integrations/pi/session-ui/session-shell-root.d.ts +141 -0
- package/dist/integrations/pi/session-ui/session-shell-root.js +1158 -0
- package/dist/integrations/pi/session-ui/session-shell.d.ts +55 -0
- package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/session-shell.js +479 -719
- package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +45 -0
- package/dist/integrations/pi/session-ui/session-viewport-controller.js +463 -0
- package/dist/integrations/pi/session-ui/stream-presentation-coalescer.d.ts +29 -0
- package/dist/integrations/pi/session-ui/stream-presentation-coalescer.js +79 -0
- package/dist/integrations/pi/session-ui/system-clipboard.d.ts +20 -0
- package/dist/integrations/pi/session-ui/system-clipboard.js +130 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.d.ts +8 -1
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/adapter.js +216 -9
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/contracts.d.ts +29 -6
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +74 -0
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +380 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/index.d.ts +2 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/index.js +2 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +39 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.js +139 -0
- package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.d.ts +1 -1
- package/dist/native/darwin-arm64/manifest.json +4 -4
- package/dist/native/darwin-arm64/process-guardian +0 -0
- package/dist/native/linux-x64/manifest.json +3 -3
- package/dist/native/linux-x64/process-guardian +0 -0
- package/dist/native/win32-x64/manifest.json +3 -3
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/{src/product-identity.d.ts → product-identity.d.ts} +3 -3
- package/dist/{src/product-identity.js → product-identity.js} +7 -5
- package/dist/{src/product-identity.json → product-identity.json} +11 -6
- package/dist/runtime-payload-inventory.json +122328 -0
- package/dist/{src/foundation/ui-apps → ui/apps}/contracts.d.ts +23 -1
- package/dist/{src/foundation/ui-apps → ui/apps}/host.d.ts +1 -1
- package/dist/{src/foundation/ui-apps → ui/apps}/host.js +14 -10
- package/dist/{src/foundation/ui-apps → ui/apps}/registry.d.ts +1 -0
- package/dist/{src/foundation/ui-apps → ui/apps}/registry.js +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.js +5 -3
- package/dist/{src/foundation/ui-components → ui/components}/frame.d.ts +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/frame.js +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/index.d.ts +5 -0
- package/dist/{src/foundation/ui-components → ui/components}/index.js +5 -0
- package/dist/{src/foundation/ui-components → ui/components}/line-input.d.ts +1 -6
- package/dist/{src/foundation/ui-components → ui/components}/line-input.js +4 -9
- package/dist/{src/foundation/ui-components → ui/components}/list-view.d.ts +0 -6
- package/dist/{src/foundation/ui-components → ui/components}/list-view.js +14 -7
- package/dist/{src/foundation/ui-components → ui/components}/mouse.d.ts +10 -0
- package/dist/{src/foundation/ui-components → ui/components}/mouse.js +23 -0
- package/dist/ui/components/progress-status.d.ts +2 -0
- package/dist/ui/components/progress-status.js +4 -0
- package/dist/ui/components/prompt-row.d.ts +14 -0
- package/dist/ui/components/prompt-row.js +20 -0
- package/dist/{src/foundation/ui-components → ui/components}/scrollbar.d.ts +26 -0
- package/dist/{src/foundation/ui-components → ui/components}/scrollbar.js +35 -0
- package/dist/{src/foundation/ui-components → ui/components}/shortcuts.d.ts +1 -0
- package/dist/{src/foundation/ui-components → ui/components}/shortcuts.js +1 -0
- package/dist/ui/components/spans.d.ts +25 -0
- package/dist/ui/components/spans.js +257 -0
- package/dist/ui/components/submitted-prompt.d.ts +23 -0
- package/dist/ui/components/submitted-prompt.js +50 -0
- package/dist/{src/foundation/ui-components → ui/components}/surface.d.ts +0 -5
- package/dist/{src/foundation/ui-components → ui/components}/surface.js +1 -5
- package/dist/ui/components/text-selection.d.ts +62 -0
- package/dist/ui/components/text-selection.js +208 -0
- package/dist/{src/foundation/ui-components → ui/components}/text.d.ts +14 -0
- package/dist/{src/foundation/ui-components → ui/components}/text.js +66 -4
- package/dist/ui/components/transcript-viewport.d.ts +152 -0
- package/dist/ui/components/transcript-viewport.js +631 -0
- package/dist/ui/components/visible-hyperlinks.d.ts +19 -0
- package/dist/ui/components/visible-hyperlinks.js +64 -0
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/declarations.d.ts +8 -1
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/declarations.js +33 -5
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.d.ts +1 -1
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/migrations.js +21 -2
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.d.ts +6 -19
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/sections.js +32 -23
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/session.d.ts +9 -17
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/session.js +65 -55
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.d.ts +1 -0
- package/dist/{src/foundation/owned-ui-settings → ui/settings}/store.js +2 -1
- package/docs/architecture/boundaries.md +9 -9
- package/docs/architecture/code-documentation.md +77 -0
- package/docs/architecture/process-guardian-provenance.md +3 -1
- package/docs/architecture/project-structure.md +67 -30
- package/docs/architecture/resource-and-data-policy.md +1 -1
- package/docs/architecture/toolchain.md +10 -10
- package/docs/architecture/ui-reference-provenance.md +36 -5
- package/docs/ci-release-runbook.md +186 -79
- package/docs/features/launch-profiles.md +24 -17
- package/docs/manual-ghost-link-baseline.md +89 -0
- package/docs/manual-launch-instance-acceptance.md +12 -35
- package/docs/manual-owned-ui-checkpoint.md +78 -0
- package/docs/manual-pi-boundary-candidate.md +4 -5
- package/docs/manual-terminal-colour-check.md +4 -3
- package/docs/repository-governance-live-acceptance.md +77 -0
- package/package.json +37 -27
- package/dist/src/cli/capabilities.d.ts +0 -15
- package/dist/src/cli/dispatch.js +0 -177
- package/dist/src/cli/version-stats.js +0 -72
- package/dist/src/composition/index.d.ts +0 -48
- package/dist/src/composition/index.js +0 -258
- package/dist/src/features/launch/intent.d.ts +0 -7
- package/dist/src/features/launch/intent.js +0 -4
- package/dist/src/features/launch/profiles.d.ts +0 -12
- package/dist/src/features/launch/profiles.js +0 -26
- package/dist/src/foundation/lifecycle/paths.d.ts +0 -10
- package/dist/src/foundation/pi-component-adapter/shell-presenters-transcript.d.ts +0 -57
- package/dist/src/foundation/pi-engine-adapter/settings-integration.d.ts +0 -55
- package/dist/src/foundation/pi-owned-ui-integration/route-host.d.ts +0 -29
- package/dist/src/foundation/pi-owned-ui-integration/session-shell.d.ts +0 -106
- package/dist/src/foundation/release/cohort-state.d.ts +0 -70
- package/dist/src/foundation/release/cohort-state.js +0 -202
- package/dist/src/foundation/release/release-gc.d.ts +0 -5
- package/dist/src/foundation/release/release-gc.js +0 -16
- package/dist/src/foundation/supervision/index.d.ts +0 -3
- package/dist/src/foundation/supervision/index.js +0 -3
- package/dist/src/foundation/supervision/main.d.ts +0 -1
- package/dist/src/foundation/supervision/main.js +0 -41
- package/dist/src/foundation/supervision/paths.d.ts +0 -1
- package/dist/src/foundation/supervision/paths.js +0 -1
- package/dist/src/foundation/ui-components/spans.d.ts +0 -7
- package/dist/src/foundation/ui-components/spans.js +0 -59
- package/docs/manual-transparent-checkpoint.md +0 -53
- /package/dist/{src/cli → cli}/index.d.ts +0 -0
- /package/dist/{src/cli → cli}/index.js +0 -0
- /package/dist/{src/cli → cli}/version.d.ts +0 -0
- /package/dist/{src/cli → cli}/version.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/capability-ports.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain-validation.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/domain.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/index.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/model.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/package-ports.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/ports.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/serialization.js +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.d.ts +0 -0
- /package/dist/{src/foundation/agent-engine-contracts → contracts/agent-engine}/validation.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/extension-ui.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/index.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/index.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/model.js +0 -0
- /package/dist/{src/foundation/owned-ui-contracts → contracts/owned-ui}/validation.d.ts +0 -0
- /package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.d.ts +0 -0
- /package/dist/{src/foundation/presentation-contracts → contracts/presentation}/index.js +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.d.ts +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/index.js +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.d.ts +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/model.js +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.d.ts +0 -0
- /package/dist/{src/foundation/workspace-contracts → contracts/workspace}/validation.js +0 -0
- /package/dist/{src/features → features}/launch/development-launch.d.ts +0 -0
- /package/dist/{src/features → features}/launch/initialize-profile.d.ts +0 -0
- /package/dist/{src/features → features}/launch/initialize-profile.js +0 -0
- /package/dist/{src/features → features}/launch/runtime-selection.js +0 -0
- /package/dist/{src/features → features}/workspace/capabilities.js +0 -0
- /package/dist/{src/features → features}/workspace/index.d.ts +0 -0
- /package/dist/{src/features → features}/workspace/index.js +0 -0
- /package/dist/{src/features → features}/workspace/presentation.d.ts +0 -0
- /package/dist/{src/features → features}/workspace/presentation.js +0 -0
- /package/dist/{src/features → features}/workspace/reconciliation.d.ts +0 -0
- /package/dist/{src/features → features}/workspace/reconciliation.js +0 -0
- /package/dist/{src/foundation → foundation}/launch-guardian/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/launch-guardian/index.js +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/commands.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/commands.js +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/lifecycle/launch-instance.js +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/evidence.js +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/index.js +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/native-host-protocol/proof-gate.js +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/artifact.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/artifact.js +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/contracts.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/process-containment/contracts.js +0 -0
- /package/dist/{src/foundation → foundation}/protocol/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/protocol/index.js +0 -0
- /package/dist/{src/foundation → foundation}/release/cohort-selection.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/cohort-selection.js +0 -0
- /package/dist/{src/foundation → foundation}/release/concurrency.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/concurrency.js +0 -0
- /package/dist/{src/foundation → foundation}/release/process-cleanup.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/process-cleanup.js +0 -0
- /package/dist/{src/foundation → foundation}/release/stable-release.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/release/stable-release.js +0 -0
- /package/dist/{src/foundation → foundation}/storage/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/storage/index.js +0 -0
- /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.d.ts +0 -0
- /package/dist/{src/foundation → foundation}/structured-agent-runtime/index.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/components.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/resources/builtin-themes.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-editor-autocomplete.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/shell-extension-ui.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/theme.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/countdown-timer.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/custom-entry.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/daxnuts.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/earendil-announcement.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/earendil-announcement.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/extension-editor.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/first-time-setup.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/markdown-transform.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/mermaid.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/owned-editor.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/owned-editor.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/scoped-models-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-footer.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector-search.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/session-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/skill-invocation-message.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/status-indicator.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/tree-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/components/trust-selector.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/external-editor.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/model-search.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme-controller.js +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.d.ts +0 -0
- /package/dist/{src/foundation/pi-component-adapter → integrations/pi/components}/upstream/theme/theme.js +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/pi-settings-metadata.json +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.d.ts +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/public-main-entry.js +0 -0
- /package/dist/{src/foundation/pi-engine-adapter → integrations/pi/engine}/workflows.js +0 -0
- /package/dist/{src/foundation/pi-owned-ui-integration → integrations/pi/session-ui}/route-host.js +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.d.ts +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/conformance.js +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/contracts.js +0 -0
- /package/dist/{src/foundation/pi-tui-runtime-adapter → integrations/pi/tui-runtime}/presentation-adapter.js +0 -0
- /package/dist/{src/foundation/ui-apps → ui/apps}/contracts.js +0 -0
- /package/dist/{src/foundation/ui-apps → ui/apps}/index.d.ts +0 -0
- /package/dist/{src/foundation/ui-apps → ui/apps}/index.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/dialog-panel.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/label.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/label.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/list-block.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/list-block.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/pane.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/pane.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/revision.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/revision.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/status-line.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/status-line.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/stepper.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/stepper.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/theme.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/theme.js +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/value-menu.d.ts +0 -0
- /package/dist/{src/foundation/ui-components → ui/components}/value-menu.js +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/index.js +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.d.ts +0 -0
- /package/dist/{src/foundation/owned-ui-settings → ui/settings}/resolution.js +0 -0
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
2
4
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
5
|
import { tmpdir } from "node:os";
|
|
4
6
|
import { dirname, join, resolve } from "node:path";
|
|
5
7
|
import { promisify } from "node:util";
|
|
6
|
-
import { PRODUCT_IDENTITY } from "
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
8
|
+
import { PRODUCT_IDENTITY } from "../../../product-identity.js";
|
|
9
|
+
import { configureOwnedHttpDispatcher } from "./http-dispatcher.js";
|
|
10
|
+
import { copyToClipboard, CredentialSynchronizationError, DefaultPackageManager, getAgentDir, ProjectTrustStore, SessionManager, VERSION, } from "@earendil-works/pi-coding-agent";
|
|
11
|
+
import { OWNED_UI_EXTENSION_CONTRACT_VERSION, OWNED_UI_EXTENSION_RENDER_CALLBACKS, OWNED_UI_EXTENSION_UI_CALLBACKS, OWNED_UI_EXTENSION_UI_PROPERTIES, assertOwnedUiCommand, assertOwnedUiExtensionUiPort, assertOwnedUiSnapshot, } from "../../../contracts/owned-ui/index.js";
|
|
9
12
|
import { PINNED_PI_SETTINGS_CALLBACKS, PINNED_PI_WORKFLOW_COMMAND_NAMES, } from "./workflows.js";
|
|
10
13
|
import { createPiRuntimeIntegration } from "./runtime-integration.js";
|
|
11
14
|
import { PiSessionCommandIntegration } from "./session-integration.js";
|
|
@@ -16,19 +19,71 @@ const execFileAsync = promisify(execFile);
|
|
|
16
19
|
* that a streaming burst never holds input, large enough that an ordinary turn is one
|
|
17
20
|
* batch.
|
|
18
21
|
*/
|
|
19
|
-
|
|
22
|
+
// Performance: deliver at most one engine event per event-loop turn. Transcript updates can
|
|
23
|
+
// be expensive in long sessions; a larger synchronous batch starves terminal
|
|
24
|
+
// input and makes an in-progress mouse selection appear frozen.
|
|
25
|
+
const EVENT_DELIVERY_BATCH = 1;
|
|
26
|
+
const TOOL_UPDATE_COALESCE_MS = 50;
|
|
27
|
+
const AUTH_REFRESH_TIMEOUT_MS = 15_000;
|
|
28
|
+
// Provenance: Pi 0.84.2 core/model-resolver.ts defaultModelPerProvider.
|
|
29
|
+
const PINNED_DEFAULT_MODEL_BY_PROVIDER = Object.freeze({
|
|
30
|
+
"amazon-bedrock": "us.anthropic.claude-opus-4-6-v1",
|
|
31
|
+
"ant-ling": "Ring-2.6-1T",
|
|
32
|
+
anthropic: "claude-opus-4-8",
|
|
33
|
+
openai: "gpt-5.5",
|
|
34
|
+
"azure-openai-responses": "gpt-5.4",
|
|
35
|
+
"openai-codex": "gpt-5.5",
|
|
36
|
+
radius: "auto",
|
|
37
|
+
nvidia: "nvidia/nemotron-3-super-120b-a12b",
|
|
38
|
+
deepseek: "deepseek-v4-pro",
|
|
39
|
+
google: "gemini-3.1-pro-preview",
|
|
40
|
+
"google-vertex": "gemini-3.1-pro-preview",
|
|
41
|
+
"github-copilot": "gpt-5.4",
|
|
42
|
+
openrouter: "moonshotai/kimi-k2.6",
|
|
43
|
+
"vercel-ai-gateway": "zai/glm-5.1",
|
|
44
|
+
xai: "grok-4.5",
|
|
45
|
+
groq: "openai/gpt-oss-120b",
|
|
46
|
+
cerebras: "zai-glm-4.7",
|
|
47
|
+
zai: "glm-5.1",
|
|
48
|
+
"zai-coding-cn": "glm-5.1",
|
|
49
|
+
mistral: "devstral-medium-latest",
|
|
50
|
+
minimax: "MiniMax-M2.7",
|
|
51
|
+
"minimax-cn": "MiniMax-M2.7",
|
|
52
|
+
moonshotai: "kimi-k2.6",
|
|
53
|
+
"moonshotai-cn": "kimi-k2.6",
|
|
54
|
+
huggingface: "moonshotai/Kimi-K2.6",
|
|
55
|
+
fireworks: "accounts/fireworks/models/kimi-k2p6",
|
|
56
|
+
together: "moonshotai/Kimi-K2.6",
|
|
57
|
+
baseten: "zai-org/GLM-5.2",
|
|
58
|
+
opencode: "kimi-k2.6",
|
|
59
|
+
"opencode-go": "kimi-k2.6",
|
|
60
|
+
"kimi-coding": "kimi-for-coding",
|
|
61
|
+
"cloudflare-workers-ai": "@cf/moonshotai/kimi-k2.6",
|
|
62
|
+
"cloudflare-ai-gateway": "workers-ai/@cf/moonshotai/kimi-k2.6",
|
|
63
|
+
"qwen-token-plan": "qwen3.7-max",
|
|
64
|
+
"qwen-token-plan-cn": "qwen3.7-max",
|
|
65
|
+
"qwen-token-plan-individual": "qwen3.8-max",
|
|
66
|
+
xiaomi: "mimo-v2.5-pro",
|
|
67
|
+
"xiaomi-token-plan-cn": "mimo-v2.5-pro",
|
|
68
|
+
"xiaomi-token-plan-ams": "mimo-v2.5-pro",
|
|
69
|
+
"xiaomi-token-plan-sgp": "mimo-v2.5-pro",
|
|
70
|
+
});
|
|
20
71
|
const DEFAULT_SURFACE = {
|
|
21
72
|
columns: 100,
|
|
22
73
|
rows: 32,
|
|
23
74
|
focusedRegion: "editor",
|
|
24
75
|
hardwareCursor: false,
|
|
25
76
|
};
|
|
77
|
+
/** Owns the pinned Pi session lifecycle and translates its events into the neutral agent-engine contract. */
|
|
26
78
|
export class PiEngineAdapter {
|
|
27
79
|
#runtimeFactory;
|
|
28
80
|
#checkPackageUpdates;
|
|
29
81
|
#cwd;
|
|
30
82
|
#agentDir;
|
|
31
83
|
#sessionId;
|
|
84
|
+
#sessionPath;
|
|
85
|
+
#sessionSelection;
|
|
86
|
+
#sessionForkPrompt;
|
|
32
87
|
#workflowHost;
|
|
33
88
|
#workflowInteraction;
|
|
34
89
|
#listeners = new Set();
|
|
@@ -59,9 +114,15 @@ export class PiEngineAdapter {
|
|
|
59
114
|
#activeCommandIds = [];
|
|
60
115
|
#completedCommands = new Map();
|
|
61
116
|
#transcript = [];
|
|
117
|
+
#transcriptIndex = new Map();
|
|
118
|
+
#transcriptSnapshot;
|
|
62
119
|
#messageBlockIds = new WeakMap();
|
|
63
120
|
#messageFallbackIds = new Map();
|
|
64
121
|
#toolBlockIds = new Map();
|
|
122
|
+
#transcriptImageAssets = new Map();
|
|
123
|
+
#pendingToolUpdates = new Map();
|
|
124
|
+
#toolUpdateFlush = null;
|
|
125
|
+
#usageCache;
|
|
65
126
|
#nextBlockSequence = 0;
|
|
66
127
|
#diagnostics = [];
|
|
67
128
|
#eventQueue = [];
|
|
@@ -75,12 +136,18 @@ export class PiEngineAdapter {
|
|
|
75
136
|
#extensionShutdown;
|
|
76
137
|
#extensionBound = false;
|
|
77
138
|
#disposed = false;
|
|
78
|
-
|
|
139
|
+
#settingsProductMode;
|
|
140
|
+
#projectTrustPrompt;
|
|
141
|
+
#settingsIntegration;
|
|
142
|
+
#settingsIntegrationManager;
|
|
79
143
|
#availableThemes;
|
|
80
144
|
constructor(options = {}) {
|
|
81
145
|
this.#cwd = options.cwd ?? process.cwd();
|
|
82
146
|
this.#agentDir = options.agentDir ?? getAgentDir();
|
|
83
147
|
this.#sessionId = options.sessionId ?? "owned-session-1";
|
|
148
|
+
this.#sessionPath = options.sessionPath;
|
|
149
|
+
this.#sessionSelection = options.sessionSelection;
|
|
150
|
+
this.#sessionForkPrompt = options.sessionForkPrompt;
|
|
84
151
|
this.#runtimeFactory = options.createRuntime ?? createDefaultPiRuntime;
|
|
85
152
|
this.#checkPackageUpdates = options.checkPackageUpdates
|
|
86
153
|
?? (options.createRuntime
|
|
@@ -88,6 +155,8 @@ export class PiEngineAdapter {
|
|
|
88
155
|
: settingsManager => checkDefaultPiPackageUpdates(this.#cwd, this.#agentDir, settingsManager));
|
|
89
156
|
this.#workflowHost = options.workflowHost ?? defaultWorkflowHost();
|
|
90
157
|
this.#availableThemes = options.availableThemes ?? null;
|
|
158
|
+
this.#settingsProductMode = options.settingsProductMode ?? "bare";
|
|
159
|
+
this.#projectTrustPrompt = options.projectTrustPrompt;
|
|
91
160
|
this.#workflowInteraction = { prompt: async () => null, notify() { } };
|
|
92
161
|
}
|
|
93
162
|
setWorkflowInteractionHost(interaction) {
|
|
@@ -99,9 +168,35 @@ export class PiEngineAdapter {
|
|
|
99
168
|
get sessionGeneration() {
|
|
100
169
|
return this.#sessionGeneration;
|
|
101
170
|
}
|
|
171
|
+
get cwd() {
|
|
172
|
+
return this.#runtime?.cwd ?? this.#cwd;
|
|
173
|
+
}
|
|
102
174
|
get agentDir() {
|
|
103
175
|
return this.#agentDir;
|
|
104
176
|
}
|
|
177
|
+
resolveTranscriptImage(assetId) {
|
|
178
|
+
return this.#transcriptImageAssets.get(assetId) ?? null;
|
|
179
|
+
}
|
|
180
|
+
currentSessionFile() {
|
|
181
|
+
const value = this.#session?.sessionManager?.getSessionFile?.();
|
|
182
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
183
|
+
}
|
|
184
|
+
currentSessionResumeMetadata() {
|
|
185
|
+
const manager = this.#session?.sessionManager;
|
|
186
|
+
if (manager === undefined
|
|
187
|
+
|| typeof manager.isPersisted !== "function"
|
|
188
|
+
|| typeof manager.getSessionId !== "function"
|
|
189
|
+
|| typeof manager.getSessionDir !== "function"
|
|
190
|
+
|| typeof manager.usesDefaultSessionDir !== "function"
|
|
191
|
+
|| manager.isPersisted() !== true
|
|
192
|
+
|| !existsSync(this.currentSessionFile() ?? ""))
|
|
193
|
+
return null;
|
|
194
|
+
const sessionId = manager.getSessionId();
|
|
195
|
+
const sessionDir = manager.getSessionDir();
|
|
196
|
+
if (!sessionId || !sessionDir)
|
|
197
|
+
return null;
|
|
198
|
+
return { sessionId, sessionDir, usesDefaultSessionDir: manager.usesDefaultSessionDir() };
|
|
199
|
+
}
|
|
105
200
|
get disposed() {
|
|
106
201
|
return this.#disposed;
|
|
107
202
|
}
|
|
@@ -112,12 +207,17 @@ export class PiEngineAdapter {
|
|
|
112
207
|
cwd: this.#cwd,
|
|
113
208
|
agentDir: this.#agentDir,
|
|
114
209
|
sessionId: this.#sessionId,
|
|
210
|
+
...(this.#sessionPath === undefined ? {} : { sessionPath: this.#sessionPath }),
|
|
211
|
+
...(this.#sessionSelection === undefined ? {} : { sessionSelection: this.#sessionSelection }),
|
|
212
|
+
...(this.#sessionForkPrompt === undefined ? {} : { sessionForkPrompt: this.#sessionForkPrompt }),
|
|
213
|
+
...(this.#projectTrustPrompt === undefined ? {} : { projectTrustPrompt: this.#projectTrustPrompt }),
|
|
115
214
|
}).catch(error => {
|
|
116
215
|
this.#lifecycle = "failed";
|
|
117
216
|
this.#addDiagnostic("error", "engine-startup", error instanceof Error ? error.message : String(error), false);
|
|
118
217
|
throw error;
|
|
119
218
|
});
|
|
120
219
|
this.#runtime = runtime;
|
|
220
|
+
this.#cwd = runtime.cwd ?? this.#cwd;
|
|
121
221
|
this.#gitBranch = await readGitBranch(this.#cwd);
|
|
122
222
|
this.#terminal = {
|
|
123
223
|
...this.#terminal,
|
|
@@ -131,6 +231,7 @@ export class PiEngineAdapter {
|
|
|
131
231
|
this.#addDiagnostic(diagnostic.type === "error" ? "error" : diagnostic.type === "warning" ? "warning" : "info", "engine-startup", diagnostic.message, diagnostic.type !== "error");
|
|
132
232
|
}
|
|
133
233
|
this.#bindSession(runtime.session);
|
|
234
|
+
await this.#announceChangelog(runtime.services.settingsManager);
|
|
134
235
|
this.#lifecycle = "ready";
|
|
135
236
|
this.#editor = { ...this.#editor, submitEnabled: true };
|
|
136
237
|
this.#emitEvent({ type: "session-lifecycle", lifecycle: "ready", reason: null });
|
|
@@ -138,6 +239,19 @@ export class PiEngineAdapter {
|
|
|
138
239
|
void this.#announcePackageUpdates(runtime.services.settingsManager);
|
|
139
240
|
return this.view();
|
|
140
241
|
}
|
|
242
|
+
async #announceChangelog(settingsManager) {
|
|
243
|
+
if (!settingsManager || typeof settingsManager.getLastChangelogVersion !== "function"
|
|
244
|
+
|| typeof settingsManager.setLastChangelogVersion !== "function")
|
|
245
|
+
return;
|
|
246
|
+
if (settingsManager.getLastChangelogVersion() === VERSION)
|
|
247
|
+
return;
|
|
248
|
+
const markdown = await this.#workflowHost.readChangelog().catch(() => "");
|
|
249
|
+
if (markdown.trim().length > 0) {
|
|
250
|
+
this.#addDiagnostic("info", settingsManager.getCollapseChangelog() ? "changelog-collapsed" : "changelog-expanded", markdown, true);
|
|
251
|
+
}
|
|
252
|
+
settingsManager.setLastChangelogVersion(VERSION);
|
|
253
|
+
await settingsManager.flush();
|
|
254
|
+
}
|
|
141
255
|
async #announcePackageUpdates(settingsManager) {
|
|
142
256
|
if (process.env.PI_OFFLINE)
|
|
143
257
|
return;
|
|
@@ -160,6 +274,7 @@ export class PiEngineAdapter {
|
|
|
160
274
|
return () => this.#listeners.delete(listener);
|
|
161
275
|
}
|
|
162
276
|
async flushEvents() {
|
|
277
|
+
this.#flushPendingToolUpdates();
|
|
163
278
|
while (this.#eventQueueProcessing)
|
|
164
279
|
await this.#eventQueueProcessing;
|
|
165
280
|
}
|
|
@@ -398,7 +513,8 @@ export class PiEngineAdapter {
|
|
|
398
513
|
const session = this.#requireWorkflowSession();
|
|
399
514
|
const result = await requireCapability(session.cycleModel, "cycleModel").call(session, direction);
|
|
400
515
|
if (!isRecord(result) || !isRecord(result.model)) {
|
|
401
|
-
|
|
516
|
+
const scoped = Array.isArray(session.scopedModels) && session.scopedModels.length > 0;
|
|
517
|
+
return workflowResult("model", "completed", scoped ? "Only one model in scope" : "Only one model available", undefined, "status");
|
|
402
518
|
}
|
|
403
519
|
const model = readModel(result.model);
|
|
404
520
|
if (model)
|
|
@@ -406,7 +522,11 @@ export class PiEngineAdapter {
|
|
|
406
522
|
if (result.thinkingLevel !== undefined)
|
|
407
523
|
this.#thinkingLevel = readThinkingLevel(result.thinkingLevel);
|
|
408
524
|
this.#emitView();
|
|
409
|
-
|
|
525
|
+
const modelName = stringProperty(result.model, "name") ?? stringProperty(result.model, "id") ?? "model";
|
|
526
|
+
const reasoning = result.model.reasoning === true;
|
|
527
|
+
const thinking = this.#thinkingLevel;
|
|
528
|
+
const suffix = reasoning && thinking !== "off" ? ` (thinking: ${thinking})` : "";
|
|
529
|
+
return workflowResult("model", "completed", `Switched to ${modelName}${suffix}`, undefined, "status");
|
|
410
530
|
}
|
|
411
531
|
catch (error) {
|
|
412
532
|
return workflowResult("model", "failed", error instanceof Error ? error.message : String(error));
|
|
@@ -422,16 +542,107 @@ export class PiEngineAdapter {
|
|
|
422
542
|
/** Settings port for the live runtime, or null before the runtime is available. */
|
|
423
543
|
settingsPort() {
|
|
424
544
|
const settings = this.#runtime?.services.settingsManager;
|
|
425
|
-
if (!settings)
|
|
545
|
+
if (!settings || typeof settings.getCompactionEnabled !== "function")
|
|
426
546
|
return null;
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
547
|
+
if (this.#settingsIntegration === undefined || this.#settingsIntegrationManager !== settings) {
|
|
548
|
+
this.#settingsIntegrationManager = settings;
|
|
549
|
+
configureOwnedHttpDispatcher(settings.getHttpIdleTimeoutMs());
|
|
550
|
+
this.#settingsIntegration = new PiSettingsIntegration(settings, {
|
|
551
|
+
...(this.#availableThemes === null ? {} : { themes: this.#availableThemes }),
|
|
552
|
+
thinkingLevels: () => {
|
|
553
|
+
const levels = this.#runtime?.session?.getAvailableThinkingLevels?.();
|
|
554
|
+
return Array.isArray(levels) ? levels.map(level => String(level)) : [];
|
|
555
|
+
},
|
|
556
|
+
productMode: this.#settingsProductMode,
|
|
557
|
+
});
|
|
558
|
+
this.#settingsIntegration.bindOwner("shell", {
|
|
559
|
+
enableSkillCommands: { apply: value => {
|
|
560
|
+
if (typeof value !== "boolean")
|
|
561
|
+
throw new TypeError("Skill commands value is invalid");
|
|
562
|
+
settings.setEnableSkillCommands(value);
|
|
563
|
+
} },
|
|
564
|
+
doubleEscapeAction: { apply: value => {
|
|
565
|
+
if (value !== "tree" && value !== "fork" && value !== "none")
|
|
566
|
+
throw new TypeError("Double-Escape action is invalid");
|
|
567
|
+
settings.setDoubleEscapeAction(value);
|
|
568
|
+
} },
|
|
569
|
+
treeFilterMode: { apply: value => {
|
|
570
|
+
if (value !== "default" && value !== "no-tools" && value !== "user-only" && value !== "labeled-only" && value !== "all")
|
|
571
|
+
throw new TypeError("Tree filter mode is invalid");
|
|
572
|
+
settings.setTreeFilterMode(value);
|
|
573
|
+
} },
|
|
574
|
+
showCacheMissNotices: { apply: value => {
|
|
575
|
+
if (typeof value !== "boolean")
|
|
576
|
+
throw new TypeError("Cache-miss notice setting is invalid");
|
|
577
|
+
settings.setShowCacheMissNotices(value);
|
|
578
|
+
} },
|
|
579
|
+
});
|
|
580
|
+
this.#settingsIntegration.bindOwner("startup", {
|
|
581
|
+
// Invariant: deferred application is the owner operation: the next preflight reads
|
|
582
|
+
// the persisted default before constructing project-backed services.
|
|
583
|
+
defaultProjectTrust: { apply() { } },
|
|
584
|
+
collapseChangelog: { apply() { } },
|
|
585
|
+
});
|
|
586
|
+
this.#settingsIntegration.bindOwner("agent", {
|
|
587
|
+
autoCompact: { apply: value => {
|
|
588
|
+
if (typeof value !== "boolean")
|
|
589
|
+
throw new TypeError("Auto compact value is invalid");
|
|
590
|
+
this.#requireWorkflowSession().setAutoCompactionEnabled(value);
|
|
591
|
+
} },
|
|
592
|
+
autoResizeImages: { apply: value => {
|
|
593
|
+
if (typeof value !== "boolean")
|
|
594
|
+
throw new TypeError("Auto-resize images value is invalid");
|
|
595
|
+
settings.setImageAutoResize(value);
|
|
596
|
+
} },
|
|
597
|
+
blockImages: { apply: value => {
|
|
598
|
+
if (typeof value !== "boolean")
|
|
599
|
+
throw new TypeError("Block images value is invalid");
|
|
600
|
+
settings.setBlockImages(value);
|
|
601
|
+
} },
|
|
602
|
+
steeringMode: { apply: value => {
|
|
603
|
+
if (value !== "all" && value !== "one-at-a-time")
|
|
604
|
+
throw new TypeError("Steering mode is invalid");
|
|
605
|
+
this.#requireWorkflowSession().setSteeringMode(value);
|
|
606
|
+
} },
|
|
607
|
+
followUpMode: { apply: value => {
|
|
608
|
+
if (value !== "all" && value !== "one-at-a-time")
|
|
609
|
+
throw new TypeError("Follow-up mode is invalid");
|
|
610
|
+
this.#requireWorkflowSession().setFollowUpMode(value);
|
|
611
|
+
} },
|
|
612
|
+
transport: { apply: value => {
|
|
613
|
+
if (value !== "sse" && value !== "websocket" && value !== "websocket-cached" && value !== "auto")
|
|
614
|
+
throw new TypeError("Transport is invalid");
|
|
615
|
+
this.#requireWorkflowSession().agent.transport = value;
|
|
616
|
+
} },
|
|
617
|
+
httpIdleTimeoutMs: { apply: value => {
|
|
618
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
|
|
619
|
+
throw new TypeError("HTTP idle timeout is invalid");
|
|
620
|
+
// Invariant: provider streaming reads the manager per request; global fetch uses
|
|
621
|
+
// the matching owned dispatcher and zero maps to disabled semantics.
|
|
622
|
+
configureOwnedHttpDispatcher(value);
|
|
623
|
+
settings.setHttpIdleTimeoutMs(value);
|
|
624
|
+
} },
|
|
625
|
+
thinkingLevel: { apply: value => {
|
|
626
|
+
if (!isThinkingLevel(value))
|
|
627
|
+
throw new TypeError("Thinking level is invalid");
|
|
628
|
+
this.#requireWorkflowSession().setThinkingLevel(value);
|
|
629
|
+
this.#thinkingLevel = readThinkingLevel(this.#requireWorkflowSession().thinkingLevel);
|
|
630
|
+
this.#emitView();
|
|
631
|
+
} },
|
|
632
|
+
warnings: { apply: value => {
|
|
633
|
+
if (!isRecord(value) || Object.values(value).some(flag => typeof flag !== "boolean"))
|
|
634
|
+
throw new TypeError("Warnings setting is invalid");
|
|
635
|
+
settings.setWarnings(value);
|
|
636
|
+
} },
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
return this.#settingsIntegration;
|
|
640
|
+
}
|
|
641
|
+
bindSettingsOwner(owner, handlers) {
|
|
642
|
+
const settings = this.settingsPort();
|
|
643
|
+
if (settings === null)
|
|
644
|
+
return () => { };
|
|
645
|
+
return settings.bindOwner(owner, handlers);
|
|
435
646
|
}
|
|
436
647
|
pinnedModelSelectorContext() {
|
|
437
648
|
const session = this.#requireWorkflowSession();
|
|
@@ -708,9 +919,9 @@ export class PiEngineAdapter {
|
|
|
708
919
|
excludeFromContext,
|
|
709
920
|
};
|
|
710
921
|
}
|
|
711
|
-
applyPinnedSettingValue(callback, value) {
|
|
922
|
+
async applyPinnedSettingValue(callback, value) {
|
|
712
923
|
try {
|
|
713
|
-
return this.#applyPinnedSetting(callback, value, true);
|
|
924
|
+
return await this.#applyPinnedSetting(callback, value, true);
|
|
714
925
|
}
|
|
715
926
|
catch (error) {
|
|
716
927
|
return workflowResult("settings", "failed", error instanceof Error ? error.message : String(error));
|
|
@@ -724,7 +935,13 @@ export class PiEngineAdapter {
|
|
|
724
935
|
const message = error instanceof Error ? error.message : String(error);
|
|
725
936
|
const contextualMessage = request.command === "export"
|
|
726
937
|
? `Failed to export session: ${message}`
|
|
727
|
-
: request.command === "
|
|
938
|
+
: request.command === "import"
|
|
939
|
+
? `Failed to import session: ${message}`
|
|
940
|
+
: request.command === "new"
|
|
941
|
+
? `Failed to create session: ${message}`
|
|
942
|
+
: request.command === "resume"
|
|
943
|
+
? `Failed to resume session: ${message}`
|
|
944
|
+
: request.command === "reload" ? `Reload failed: ${message}` : message;
|
|
728
945
|
return workflowResult(request.command, "failed", contextualMessage);
|
|
729
946
|
}
|
|
730
947
|
}
|
|
@@ -734,13 +951,13 @@ export class PiEngineAdapter {
|
|
|
734
951
|
sessionId: this.#sessionId,
|
|
735
952
|
revision: this.#viewRevision,
|
|
736
953
|
lifecycle: this.#lifecycle,
|
|
737
|
-
transcript: this.#
|
|
954
|
+
transcript: this.#transcriptSnapshot ??= Object.freeze([...this.#transcript]),
|
|
738
955
|
editor: { ...this.#editor, queuedSubmissions: [...this.#editor.queuedSubmissions] },
|
|
739
956
|
status: {
|
|
740
957
|
...this.#status,
|
|
741
958
|
diagnostics: [...this.#status.diagnostics],
|
|
742
959
|
badges: [...this.#status.badges],
|
|
743
|
-
usage: this.#readUsage(),
|
|
960
|
+
usage: this.#usageCache ??= this.#readUsage(),
|
|
744
961
|
footer: {
|
|
745
962
|
branch: this.#gitBranch,
|
|
746
963
|
sessionName: this.#session?.sessionManager?.getSessionName() ?? null,
|
|
@@ -806,6 +1023,12 @@ export class PiEngineAdapter {
|
|
|
806
1023
|
if (this.#disposed)
|
|
807
1024
|
return;
|
|
808
1025
|
this.#disposed = true;
|
|
1026
|
+
if (this.#toolUpdateFlush !== null) {
|
|
1027
|
+
clearTimeout(this.#toolUpdateFlush);
|
|
1028
|
+
this.#toolUpdateFlush = null;
|
|
1029
|
+
}
|
|
1030
|
+
this.#pendingToolUpdates.clear();
|
|
1031
|
+
this.#transcriptImageAssets.clear();
|
|
809
1032
|
this.#extensionBound = false;
|
|
810
1033
|
this.#extensionUi = undefined;
|
|
811
1034
|
this.#extensionShutdown = undefined;
|
|
@@ -831,22 +1054,66 @@ export class PiEngineAdapter {
|
|
|
831
1054
|
case "settings": {
|
|
832
1055
|
if (!selection)
|
|
833
1056
|
return workflowResult(request.command, "failed", "Settings requires the owned settings controller");
|
|
834
|
-
return this.#applyPinnedSetting(selection);
|
|
1057
|
+
return await this.#applyPinnedSetting(selection);
|
|
835
1058
|
}
|
|
836
1059
|
case "model": {
|
|
837
1060
|
const reference = selection ?? argument;
|
|
838
1061
|
if (!reference)
|
|
839
1062
|
return workflowResult(request.command, "failed", "Model requires the owned model controller");
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
1063
|
+
const scopedModels = Array.isArray(session.scopedModels)
|
|
1064
|
+
? session.scopedModels.map(item => item.model)
|
|
1065
|
+
: [];
|
|
1066
|
+
let availableModels = scopedModels.length > 0
|
|
1067
|
+
? scopedModels
|
|
1068
|
+
: [...(runtime.services.modelRuntime.getAvailableSnapshot?.() ?? [])];
|
|
1069
|
+
let model = findExactWorkflowModel(reference, availableModels);
|
|
1070
|
+
const messages = [];
|
|
1071
|
+
if (model === undefined && scopedModels.length === 0) {
|
|
1072
|
+
messages.push({ kind: "status", message: "Refreshing model catalogs…" });
|
|
1073
|
+
const controller = new AbortController();
|
|
1074
|
+
let timedOut = false;
|
|
1075
|
+
const timeout = setTimeout(() => {
|
|
1076
|
+
timedOut = true;
|
|
1077
|
+
controller.abort();
|
|
1078
|
+
}, AUTH_REFRESH_TIMEOUT_MS);
|
|
1079
|
+
try {
|
|
1080
|
+
const refreshed = await runtime.services.modelRuntime.refresh?.({ signal: controller.signal });
|
|
1081
|
+
if (isRecord(refreshed) && refreshed.aborted === true && timedOut) {
|
|
1082
|
+
messages.push({ kind: "warning", message: "Model refresh timed out; searching cached models." });
|
|
1083
|
+
}
|
|
1084
|
+
else if (isRecord(refreshed) && refreshed.errors instanceof Map && refreshed.errors.size > 0) {
|
|
1085
|
+
messages.push({ kind: "warning", message: `Could not refresh ${[...refreshed.errors.keys()].join(", ")}; searching cached models.` });
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
catch (error) {
|
|
1089
|
+
messages.push({
|
|
1090
|
+
kind: "warning",
|
|
1091
|
+
message: timedOut
|
|
1092
|
+
? "Model refresh timed out; searching cached models."
|
|
1093
|
+
: `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`,
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
finally {
|
|
1097
|
+
clearTimeout(timeout);
|
|
1098
|
+
}
|
|
1099
|
+
availableModels = [...(runtime.services.modelRuntime.getAvailableSnapshot?.() ?? [])];
|
|
1100
|
+
model = findExactWorkflowModel(reference, availableModels);
|
|
1101
|
+
}
|
|
1102
|
+
if (model === undefined) {
|
|
1103
|
+
return {
|
|
1104
|
+
...workflowResult(request.command, "requires-selection", "Select a model", reference, "silent"),
|
|
1105
|
+
...(messages.length === 0 ? {} : { messages: Object.freeze(messages) }),
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
846
1108
|
await session.setModel(model);
|
|
1109
|
+
const providerId = stringProperty(model, "provider") ?? "unknown";
|
|
1110
|
+
const modelId = stringProperty(model, "id") ?? reference;
|
|
847
1111
|
this.#activeModel = { providerId, modelId, displayName: stringProperty(model, "name") ?? modelId };
|
|
848
1112
|
this.#emitView();
|
|
849
|
-
|
|
1113
|
+
const resultMessage = { kind: "status", message: `Model: ${modelId}` };
|
|
1114
|
+
return messages.length === 0
|
|
1115
|
+
? workflowResult(request.command, "completed", resultMessage.message)
|
|
1116
|
+
: workflowResult(request.command, "completed", resultMessage.message, undefined, "status", [...messages, resultMessage]);
|
|
850
1117
|
}
|
|
851
1118
|
case "scoped-models": {
|
|
852
1119
|
if (!selection)
|
|
@@ -873,27 +1140,71 @@ export class PiEngineAdapter {
|
|
|
873
1140
|
return workflowConfirmation(request.command, `Replace current session with ${path}?`);
|
|
874
1141
|
}
|
|
875
1142
|
if (!request.confirmed)
|
|
876
|
-
return workflowResult(request.command, "cancelled", "Import cancelled");
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1143
|
+
return workflowResult(request.command, "cancelled", "Import cancelled", undefined, "status");
|
|
1144
|
+
try {
|
|
1145
|
+
const result = await requireCapability(runtime.importFromJsonl, "importFromJsonl").call(runtime, path, request.cwdOverride);
|
|
1146
|
+
if (isRecord(result) && result.cancelled === true)
|
|
1147
|
+
return workflowResult(request.command, "cancelled", "Import cancelled", undefined, "status");
|
|
1148
|
+
return workflowResult(request.command, "completed", `Session imported from: ${path}`);
|
|
1149
|
+
}
|
|
1150
|
+
catch (error) {
|
|
1151
|
+
const issue = isRecord(error) && isRecord(error.issue) ? error.issue : undefined;
|
|
1152
|
+
const fallbackCwd = issue === undefined ? undefined : stringProperty(issue, "fallbackCwd");
|
|
1153
|
+
if (fallbackCwd !== undefined && request.cwdOverride === undefined) {
|
|
1154
|
+
const sessionCwd = stringProperty(issue, "sessionCwd") ?? "the session working directory";
|
|
1155
|
+
return workflowConfirmation(request.command, `cwd from session file does not exist\n${sessionCwd}\n\ncontinue in current cwd\n${fallbackCwd}`, fallbackCwd);
|
|
1156
|
+
}
|
|
1157
|
+
throw error;
|
|
1158
|
+
}
|
|
881
1159
|
}
|
|
882
1160
|
case "share": {
|
|
883
|
-
const
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
1161
|
+
const signal = request.signal;
|
|
1162
|
+
if (signal?.aborted)
|
|
1163
|
+
return workflowResult(request.command, "cancelled", "Share cancelled", undefined, "status");
|
|
1164
|
+
let auth;
|
|
1165
|
+
try {
|
|
1166
|
+
auth = await this.#workflowHost.runCommand("gh", ["auth", "status"], signal === undefined ? undefined : { signal });
|
|
1167
|
+
}
|
|
1168
|
+
catch (error) {
|
|
1169
|
+
if (signal?.aborted || isAbortError(error))
|
|
1170
|
+
return workflowResult(request.command, "cancelled", "Share cancelled", undefined, "status");
|
|
1171
|
+
const message = commandMissing(error)
|
|
1172
|
+
? "GitHub CLI (gh) is not installed. Install it from https://cli.github.com/"
|
|
1173
|
+
: "GitHub CLI is not logged in. Run 'gh auth login' first.";
|
|
1174
|
+
return workflowResult(request.command, "failed", message);
|
|
1175
|
+
}
|
|
1176
|
+
if (auth.stderr && !auth.stdout) {
|
|
1177
|
+
return workflowResult(request.command, "failed", "GitHub CLI is not logged in. Run 'gh auth login' first.");
|
|
1178
|
+
}
|
|
888
1179
|
const temporary = join(tmpdir(), `${PRODUCT_IDENTITY.filesystem.temporaryPrefix}pi-session-${process.pid}.html`);
|
|
889
1180
|
try {
|
|
890
|
-
|
|
891
|
-
|
|
1181
|
+
try {
|
|
1182
|
+
await requireCapability(session.exportToHtml, "exportToHtml").call(session, temporary);
|
|
1183
|
+
}
|
|
1184
|
+
catch (error) {
|
|
1185
|
+
return workflowResult(request.command, "failed", `Failed to export session: ${errorMessage(error, "Unknown error")}`);
|
|
1186
|
+
}
|
|
1187
|
+
if (signal?.aborted)
|
|
1188
|
+
return workflowResult(request.command, "cancelled", "Share cancelled", undefined, "status");
|
|
1189
|
+
let gist;
|
|
1190
|
+
try {
|
|
1191
|
+
gist = await this.#workflowHost.runCommand("gh", ["gist", "create", "--public=false", temporary], signal === undefined ? undefined : { signal });
|
|
1192
|
+
}
|
|
1193
|
+
catch (error) {
|
|
1194
|
+
if (signal?.aborted || isAbortError(error))
|
|
1195
|
+
return workflowResult(request.command, "cancelled", "Share cancelled", undefined, "status");
|
|
1196
|
+
return workflowResult(request.command, "failed", `Failed to create gist: ${errorMessage(error, "Unknown error")}`);
|
|
1197
|
+
}
|
|
1198
|
+
if (signal?.aborted)
|
|
1199
|
+
return workflowResult(request.command, "cancelled", "Share cancelled", undefined, "status");
|
|
1200
|
+
if (gist.stderr && !gist.stdout) {
|
|
1201
|
+
return workflowResult(request.command, "failed", `Failed to create gist: ${gist.stderr.trim() || "Unknown error"}`);
|
|
1202
|
+
}
|
|
892
1203
|
const gistUrl = gist.stdout.trim();
|
|
893
1204
|
const gistId = gistUrl.split("/").at(-1);
|
|
894
1205
|
if (!gistId)
|
|
895
|
-
|
|
896
|
-
return workflowResult(request.command, "completed", `Share URL:
|
|
1206
|
+
return workflowResult(request.command, "failed", "Failed to parse gist ID from gh output");
|
|
1207
|
+
return workflowResult(request.command, "completed", `Share URL: ${shareViewerUrl(gistId)}`, gistUrl);
|
|
897
1208
|
}
|
|
898
1209
|
finally {
|
|
899
1210
|
await rm(temporary, { force: true });
|
|
@@ -912,7 +1223,7 @@ export class PiEngineAdapter {
|
|
|
912
1223
|
const current = manager?.getSessionName();
|
|
913
1224
|
return typeof current === "string"
|
|
914
1225
|
? workflowResult(request.command, "completed", `Session name: ${current}`)
|
|
915
|
-
: workflowResult(request.command, "failed", "Usage: /name <name>");
|
|
1226
|
+
: workflowResult(request.command, "failed", "Usage: /name <name>", undefined, "warning");
|
|
916
1227
|
}
|
|
917
1228
|
requireCapability(session.setSessionName, "setSessionName").call(session, argument);
|
|
918
1229
|
const normalized = manager?.getSessionName();
|
|
@@ -939,17 +1250,17 @@ export class PiEngineAdapter {
|
|
|
939
1250
|
return workflowResult(request.command, "failed", "Fork requires the owned user-message controller");
|
|
940
1251
|
const result = await requireCapability(runtime.fork, "fork").call(runtime, selection, { position: "before" });
|
|
941
1252
|
if (isRecord(result) && result.cancelled === true)
|
|
942
|
-
return workflowResult(request.command, "cancelled", "Fork cancelled");
|
|
1253
|
+
return workflowResult(request.command, "cancelled", "Fork cancelled", undefined, "silent");
|
|
943
1254
|
return workflowResult(request.command, "completed", "Forked to new session");
|
|
944
1255
|
}
|
|
945
1256
|
case "clone": {
|
|
946
1257
|
const manager = session.sessionManager;
|
|
947
1258
|
const leaf = manager?.getLeafId?.();
|
|
948
1259
|
if (typeof leaf !== "string")
|
|
949
|
-
return workflowResult(request.command, "
|
|
1260
|
+
return workflowResult(request.command, "completed", "Nothing to clone yet", undefined, "status");
|
|
950
1261
|
const result = await requireCapability(runtime.fork, "fork").call(runtime, leaf, { position: "at" });
|
|
951
1262
|
if (isRecord(result) && result.cancelled === true)
|
|
952
|
-
return workflowResult(request.command, "cancelled", "Clone cancelled");
|
|
1263
|
+
return workflowResult(request.command, "cancelled", "Clone cancelled", undefined, "silent");
|
|
953
1264
|
return workflowResult(request.command, "completed", "Cloned to new session");
|
|
954
1265
|
}
|
|
955
1266
|
case "tree": {
|
|
@@ -963,9 +1274,9 @@ export class PiEngineAdapter {
|
|
|
963
1274
|
...(request.treeSummary.customInstructions === undefined ? {} : { customInstructions: request.treeSummary.customInstructions }),
|
|
964
1275
|
});
|
|
965
1276
|
if (isRecord(result) && result.aborted === true)
|
|
966
|
-
return workflowResult(request.command, "cancelled", "Branch summarization cancelled");
|
|
1277
|
+
return workflowResult(request.command, "cancelled", "Branch summarization cancelled", undefined, "status");
|
|
967
1278
|
if (isRecord(result) && result.cancelled === true)
|
|
968
|
-
return workflowResult(request.command, "cancelled", "Navigation cancelled");
|
|
1279
|
+
return workflowResult(request.command, "cancelled", "Navigation cancelled", undefined, "status");
|
|
969
1280
|
return workflowResult(request.command, "completed", "Navigated to selected point");
|
|
970
1281
|
}
|
|
971
1282
|
case "trust": {
|
|
@@ -1000,6 +1311,7 @@ export class PiEngineAdapter {
|
|
|
1000
1311
|
const authType = authTypeValue === "api_key" ? "api_key" : "oauth";
|
|
1001
1312
|
const provider = modelRuntime.getProvider?.(providerId);
|
|
1002
1313
|
const providerName = stringProperty(provider, "name") ?? providerId;
|
|
1314
|
+
const previousModel = session.model;
|
|
1003
1315
|
this.#workflowInteraction.startLogin?.({ providerId, providerName, authType });
|
|
1004
1316
|
try {
|
|
1005
1317
|
await requireCapability(modelRuntime.login, "login").call(modelRuntime, providerId, authType, {
|
|
@@ -1037,25 +1349,40 @@ export class PiEngineAdapter {
|
|
|
1037
1349
|
});
|
|
1038
1350
|
}
|
|
1039
1351
|
catch (error) {
|
|
1040
|
-
if (error instanceof Error && error.message === "Login cancelled")
|
|
1041
|
-
return workflowResult(request.command, "cancelled", "Login cancelled");
|
|
1042
|
-
|
|
1352
|
+
if (error instanceof Error && error.message === "Login cancelled") {
|
|
1353
|
+
return workflowResult(request.command, "cancelled", "Login cancelled", undefined, "silent");
|
|
1354
|
+
}
|
|
1355
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
1356
|
+
const actionLabel = authType === "api_key" ? `Saved API key for ${providerName}` : `Logged in to ${providerName}`;
|
|
1357
|
+
const message = error instanceof CredentialSynchronizationError
|
|
1358
|
+
? `${actionLabel}, but local model state could not be synchronized: ${detail}`
|
|
1359
|
+
: authType === "api_key"
|
|
1360
|
+
? `Failed to save API key for ${providerName}: ${detail}`
|
|
1361
|
+
: `Failed to login to ${providerName}: ${detail}`;
|
|
1362
|
+
return workflowResult(request.command, "failed", message);
|
|
1043
1363
|
}
|
|
1044
1364
|
finally {
|
|
1045
1365
|
this.#workflowInteraction.finishLogin?.();
|
|
1046
1366
|
}
|
|
1047
|
-
this.#
|
|
1048
|
-
this.#emitView();
|
|
1049
|
-
return workflowResult(request.command, "completed", `Logged in to ${providerName}. Credentials saved to ${join(this.#agentDir, "auth.json")}`);
|
|
1367
|
+
return await this.#completeProviderAuthentication(providerId, providerName, authType, previousModel);
|
|
1050
1368
|
}
|
|
1051
1369
|
case "logout": {
|
|
1052
1370
|
if (!selection)
|
|
1053
1371
|
return workflowResult(request.command, "failed", "Logout requires the owned authentication controller");
|
|
1054
1372
|
const [credentialType = "oauth", providerId = selection] = selection.includes(":") ? selection.split(":", 2) : ["oauth", selection];
|
|
1055
1373
|
const modelRuntime = runtime.services.modelRuntime;
|
|
1056
|
-
await requireCapability(modelRuntime.logout, "logout").call(modelRuntime, providerId, { signal: AbortSignal.timeout(15_000) });
|
|
1057
1374
|
const provider = modelRuntime.getProvider?.(providerId);
|
|
1058
1375
|
const providerName = stringProperty(provider, "name") ?? providerId;
|
|
1376
|
+
try {
|
|
1377
|
+
await requireCapability(modelRuntime.logout, "logout").call(modelRuntime, providerId, { signal: AbortSignal.timeout(15_000) });
|
|
1378
|
+
}
|
|
1379
|
+
catch (error) {
|
|
1380
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
1381
|
+
const message = error instanceof CredentialSynchronizationError
|
|
1382
|
+
? `Credentials removed for ${providerName}, but local model state could not be synchronized: ${detail}`
|
|
1383
|
+
: `Logout failed: ${detail}`;
|
|
1384
|
+
return workflowResult(request.command, "failed", message);
|
|
1385
|
+
}
|
|
1059
1386
|
this.#reconcileActiveModelAvailability();
|
|
1060
1387
|
this.#emitView();
|
|
1061
1388
|
return workflowResult(request.command, "completed", credentialType === "api_key"
|
|
@@ -1065,12 +1392,17 @@ export class PiEngineAdapter {
|
|
|
1065
1392
|
case "new": {
|
|
1066
1393
|
const result = await runtime.newSession();
|
|
1067
1394
|
if (isRecord(result) && result.cancelled === true)
|
|
1068
|
-
return workflowResult(request.command, "cancelled", "New session cancelled");
|
|
1069
|
-
return workflowResult(request.command, "completed", "✓ New session started");
|
|
1395
|
+
return workflowResult(request.command, "cancelled", "New session cancelled", undefined, "silent");
|
|
1396
|
+
return workflowResult(request.command, "completed", "✓ New session started", undefined, "accent");
|
|
1070
1397
|
}
|
|
1071
1398
|
case "compact": {
|
|
1072
|
-
|
|
1073
|
-
|
|
1399
|
+
try {
|
|
1400
|
+
await session.compact(argument || undefined);
|
|
1401
|
+
return workflowResult(request.command, "completed", "Compaction requested", undefined, "silent");
|
|
1402
|
+
}
|
|
1403
|
+
catch (error) {
|
|
1404
|
+
return workflowResult(request.command, "failed", error instanceof Error ? error.message : String(error), undefined, "silent");
|
|
1405
|
+
}
|
|
1074
1406
|
}
|
|
1075
1407
|
case "resume": {
|
|
1076
1408
|
if (!selection && !argument)
|
|
@@ -1079,7 +1411,7 @@ export class PiEngineAdapter {
|
|
|
1079
1411
|
try {
|
|
1080
1412
|
const result = await runtime.switchSession(sessionPath);
|
|
1081
1413
|
if (isRecord(result) && result.cancelled === true)
|
|
1082
|
-
return workflowResult(request.command, "cancelled", "Resume cancelled");
|
|
1414
|
+
return workflowResult(request.command, "cancelled", "Resume cancelled", undefined, "silent");
|
|
1083
1415
|
return workflowResult(request.command, "completed", "Resumed session");
|
|
1084
1416
|
}
|
|
1085
1417
|
catch (error) {
|
|
@@ -1092,18 +1424,18 @@ export class PiEngineAdapter {
|
|
|
1092
1424
|
return workflowConfirmation(request.command, `cwd from session file does not exist\n${sessionCwd}\n\ncontinue in current cwd\n${fallbackCwd}`);
|
|
1093
1425
|
}
|
|
1094
1426
|
if (!request.confirmed)
|
|
1095
|
-
return workflowResult(request.command, "cancelled", "Resume cancelled");
|
|
1427
|
+
return workflowResult(request.command, "cancelled", "Resume cancelled", undefined, "status");
|
|
1096
1428
|
const result = await runtime.switchSession(sessionPath, { cwdOverride: fallbackCwd });
|
|
1097
1429
|
if (isRecord(result) && result.cancelled === true)
|
|
1098
|
-
return workflowResult(request.command, "cancelled", "Resume cancelled");
|
|
1430
|
+
return workflowResult(request.command, "cancelled", "Resume cancelled", undefined, "silent");
|
|
1099
1431
|
return workflowResult(request.command, "completed", "Resumed session in current cwd");
|
|
1100
1432
|
}
|
|
1101
1433
|
}
|
|
1102
1434
|
case "reload": {
|
|
1103
1435
|
if (session.isStreaming)
|
|
1104
|
-
return workflowResult(request.command, "failed", "Wait for the current response to finish before reloading.");
|
|
1436
|
+
return workflowResult(request.command, "failed", "Wait for the current response to finish before reloading.", undefined, "warning");
|
|
1105
1437
|
if (session.isCompacting)
|
|
1106
|
-
return workflowResult(request.command, "failed", "Wait for compaction to finish before reloading.");
|
|
1438
|
+
return workflowResult(request.command, "failed", "Wait for compaction to finish before reloading.", undefined, "warning");
|
|
1107
1439
|
await requireCapability(session.reload, "reload").call(session);
|
|
1108
1440
|
await this.#bindExtensionUiToSession();
|
|
1109
1441
|
return workflowResult(request.command, "completed", "Reloaded keybindings, extensions, skills, prompts, themes, and context files");
|
|
@@ -1124,6 +1456,91 @@ export class PiEngineAdapter {
|
|
|
1124
1456
|
return workflowResult(request.command, "completed", "Demented elves announcement");
|
|
1125
1457
|
}
|
|
1126
1458
|
}
|
|
1459
|
+
async #completeProviderAuthentication(providerId, providerName, authType, previousModel) {
|
|
1460
|
+
const session = this.#requireWorkflowSession();
|
|
1461
|
+
const modelRuntime = this.#runtime?.services.modelRuntime;
|
|
1462
|
+
if (!modelRuntime)
|
|
1463
|
+
throw new Error("engine runtime is unavailable");
|
|
1464
|
+
const actionLabel = authType === "oauth" ? `Logged in to ${providerName}` : `Saved API key for ${providerName}`;
|
|
1465
|
+
let selectedModelId;
|
|
1466
|
+
let selectionError;
|
|
1467
|
+
if (isUnknownModel(previousModel)) {
|
|
1468
|
+
const available = modelRuntime.getAvailableSnapshot?.() ?? [];
|
|
1469
|
+
const providerModels = available.filter(model => stringProperty(model, "provider") === providerId);
|
|
1470
|
+
const defaultModelId = PINNED_DEFAULT_MODEL_BY_PROVIDER[providerId];
|
|
1471
|
+
if (defaultModelId === undefined) {
|
|
1472
|
+
selectionError = `${actionLabel}, but no default model is configured for provider "${providerId}". Use /model to select a model.`;
|
|
1473
|
+
}
|
|
1474
|
+
else if (providerModels.length === 0) {
|
|
1475
|
+
selectionError = `${actionLabel}, but no models are available for that provider. Use /model to select a model.`;
|
|
1476
|
+
}
|
|
1477
|
+
else {
|
|
1478
|
+
const selectedModel = providerModels.find(model => stringProperty(model, "id") === defaultModelId);
|
|
1479
|
+
if (selectedModel === undefined) {
|
|
1480
|
+
selectionError = `${actionLabel}, but its default model "${defaultModelId}" is not available. Use /model to select a model.`;
|
|
1481
|
+
}
|
|
1482
|
+
else {
|
|
1483
|
+
try {
|
|
1484
|
+
await session.setModel(selectedModel);
|
|
1485
|
+
selectedModelId = stringProperty(selectedModel, "id") ?? defaultModelId;
|
|
1486
|
+
this.#activeModel = {
|
|
1487
|
+
providerId,
|
|
1488
|
+
modelId: selectedModelId,
|
|
1489
|
+
displayName: stringProperty(selectedModel, "name") ?? selectedModelId,
|
|
1490
|
+
};
|
|
1491
|
+
}
|
|
1492
|
+
catch (error) {
|
|
1493
|
+
selectionError = `${actionLabel}, but selecting its default model failed: ${error instanceof Error ? error.message : String(error)}. Use /model to select a model.`;
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
this.#reconcileActiveModelAvailability();
|
|
1499
|
+
this.#emitView();
|
|
1500
|
+
const status = `${actionLabel}.${selectedModelId ? ` Selected ${selectedModelId}.` : ""} Credentials saved to ${join(this.#agentDir, "auth.json")}`;
|
|
1501
|
+
const messages = [
|
|
1502
|
+
{ kind: "status", message: status },
|
|
1503
|
+
...(selectionError === undefined ? [] : [{ kind: "error", message: selectionError }]),
|
|
1504
|
+
];
|
|
1505
|
+
this.#scheduleAuthenticatedProviderRefresh(providerId, actionLabel);
|
|
1506
|
+
return workflowResult("login", "completed", status, undefined, "status", messages);
|
|
1507
|
+
}
|
|
1508
|
+
#scheduleAuthenticatedProviderRefresh(providerId, actionLabel) {
|
|
1509
|
+
const runtime = this.#runtime;
|
|
1510
|
+
const refresh = runtime?.services.modelRuntime.refresh;
|
|
1511
|
+
if (!runtime || typeof refresh !== "function")
|
|
1512
|
+
return;
|
|
1513
|
+
const generation = this.#sessionGeneration;
|
|
1514
|
+
const publish = this.#workflowInteraction.publish;
|
|
1515
|
+
const controller = new AbortController();
|
|
1516
|
+
const timeout = setTimeout(() => controller.abort(), AUTH_REFRESH_TIMEOUT_MS);
|
|
1517
|
+
// Compatibility: post-authentication refresh starts on the next turn so its notices follow the saved-credential status.
|
|
1518
|
+
void new Promise(resolve => setTimeout(resolve, 0))
|
|
1519
|
+
.then(() => refresh.call(runtime.services.modelRuntime, { providers: [providerId], signal: controller.signal }))
|
|
1520
|
+
.then(result => {
|
|
1521
|
+
if (this.#disposed || this.#sessionGeneration !== generation)
|
|
1522
|
+
return;
|
|
1523
|
+
if (isRecord(result) && result.aborted === true) {
|
|
1524
|
+
publish?.({ kind: "warning", message: `${actionLabel}, but its model catalog refresh timed out; using cached models.` });
|
|
1525
|
+
}
|
|
1526
|
+
else if (isRecord(result) && result.errors instanceof Map && result.errors.size > 0) {
|
|
1527
|
+
publish?.({ kind: "warning", message: `${actionLabel}, but its model catalog could not be refreshed; using cached models.` });
|
|
1528
|
+
}
|
|
1529
|
+
this.#reconcileActiveModelAvailability();
|
|
1530
|
+
this.#emitView();
|
|
1531
|
+
})
|
|
1532
|
+
.catch(error => {
|
|
1533
|
+
if (this.#disposed || this.#sessionGeneration !== generation)
|
|
1534
|
+
return;
|
|
1535
|
+
publish?.({
|
|
1536
|
+
kind: "warning",
|
|
1537
|
+
message: controller.signal.aborted
|
|
1538
|
+
? `${actionLabel}, but its model catalog refresh timed out; using cached models.`
|
|
1539
|
+
: `${actionLabel}, but its model catalog could not be refreshed: ${error instanceof Error ? error.message : String(error)}`,
|
|
1540
|
+
});
|
|
1541
|
+
})
|
|
1542
|
+
.finally(() => clearTimeout(timeout));
|
|
1543
|
+
}
|
|
1127
1544
|
#requireWorkflowSession() {
|
|
1128
1545
|
if (this.#disposed || !this.#runtime || !this.#session)
|
|
1129
1546
|
throw new Error("engine adapter is not running");
|
|
@@ -1221,7 +1638,7 @@ export class PiEngineAdapter {
|
|
|
1221
1638
|
return [];
|
|
1222
1639
|
return sessionInfoOptions(await SessionManager.list(cwd, typeof sessionDir === "string" ? sessionDir : undefined));
|
|
1223
1640
|
}
|
|
1224
|
-
#applyPinnedSetting(selection, selectedValue, hasSelectedValue = false) {
|
|
1641
|
+
async #applyPinnedSetting(selection, selectedValue, hasSelectedValue = false) {
|
|
1225
1642
|
if (!PINNED_PI_SETTINGS_CALLBACKS.includes(selection)) {
|
|
1226
1643
|
return workflowResult("settings", "failed", `Unknown setting callback: ${selection}`);
|
|
1227
1644
|
}
|
|
@@ -1268,29 +1685,19 @@ export class PiEngineAdapter {
|
|
|
1268
1685
|
selectedValue = currentValues[callback];
|
|
1269
1686
|
hasSelectedValue = true;
|
|
1270
1687
|
}
|
|
1271
|
-
const
|
|
1272
|
-
if (
|
|
1688
|
+
const port = this.settingsPort();
|
|
1689
|
+
if (port === null)
|
|
1273
1690
|
return workflowResult("settings", "failed", "Settings are unavailable");
|
|
1274
|
-
const
|
|
1275
|
-
if (
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
else {
|
|
1281
|
-
const key = settingKeyForCallback(callback);
|
|
1282
|
-
if (key === null)
|
|
1283
|
-
return workflowResult("settings", "failed", `${settingLabel(callback)} is unavailable in this runtime`);
|
|
1284
|
-
const value = agentJsonValue(selectedValue);
|
|
1285
|
-
if (callback === "onAutoCompactChange") {
|
|
1286
|
-
if (typeof value !== "boolean")
|
|
1287
|
-
return workflowResult("settings", "failed", "Auto compact value is invalid");
|
|
1288
|
-
session.setAutoCompactionEnabled?.(value);
|
|
1289
|
-
}
|
|
1290
|
-
new PiSettingsIntegration(settings).writeSettingNow(key, value);
|
|
1691
|
+
const key = settingKeyForCallback(callback);
|
|
1692
|
+
if (key === null)
|
|
1693
|
+
return workflowResult("settings", "failed", `${settingLabel(callback)} is unavailable in this runtime`);
|
|
1694
|
+
const result = await port.writeSetting(key, agentJsonValue(selectedValue));
|
|
1695
|
+
if (result.status === "failed" || result.status === "unavailable") {
|
|
1696
|
+
return workflowResult("settings", "failed", result.failure ?? result.limitationReason ?? `${settingLabel(callback)} is unavailable`);
|
|
1291
1697
|
}
|
|
1292
1698
|
this.#emitView();
|
|
1293
|
-
|
|
1699
|
+
const suffix = result.status === "deferred" ? ` (${result.application})` : "";
|
|
1700
|
+
return workflowResult("settings", "completed", `${settingLabel(callback)}: ${String(selectedValue)}${suffix}`);
|
|
1294
1701
|
}
|
|
1295
1702
|
async #perform(command) {
|
|
1296
1703
|
const runtime = this.#runtime;
|
|
@@ -1305,7 +1712,11 @@ export class PiEngineAdapter {
|
|
|
1305
1712
|
case "retry":
|
|
1306
1713
|
case "compact": {
|
|
1307
1714
|
const result = await this.#sessionCommands?.execute(command.type === "prompt" || command.type === "steer" || command.type === "follow-up"
|
|
1308
|
-
? {
|
|
1715
|
+
? {
|
|
1716
|
+
type: command.type,
|
|
1717
|
+
text: command.text,
|
|
1718
|
+
...(command.images === undefined ? {} : { images: [...command.images] }),
|
|
1719
|
+
}
|
|
1309
1720
|
: { type: command.type });
|
|
1310
1721
|
if (!result || result.outcome === "rejected" || result.outcome === "failed") {
|
|
1311
1722
|
throw new Error(command.type === "retry" ? "no previous prompt is available to retry" : `Pi session command failed: ${command.type}`);
|
|
@@ -1365,6 +1776,7 @@ export class PiEngineAdapter {
|
|
|
1365
1776
|
this.#activeModel = readModel(session.model);
|
|
1366
1777
|
this.#reconcileActiveModelAvailability();
|
|
1367
1778
|
this.#thinkingLevel = readThinkingLevel(session.thinkingLevel);
|
|
1779
|
+
this.#transcriptImageAssets.clear();
|
|
1368
1780
|
this.#rebuildTranscript(session.messages, "finalized");
|
|
1369
1781
|
this.#unsubscribe = session.subscribe(event => this.#handlePiEvent(event));
|
|
1370
1782
|
if (this.#extensionUi !== undefined)
|
|
@@ -1414,7 +1826,24 @@ export class PiEngineAdapter {
|
|
|
1414
1826
|
this.#emitView();
|
|
1415
1827
|
}
|
|
1416
1828
|
}
|
|
1417
|
-
|
|
1829
|
+
// Performance: replacing the transcript rebuilds its index so block lookup stays constant-time.
|
|
1830
|
+
#setTranscript(blocks) {
|
|
1831
|
+
this.#transcript = blocks;
|
|
1832
|
+
this.#transcriptIndex.clear();
|
|
1833
|
+
for (const [index, block] of blocks.entries())
|
|
1834
|
+
this.#transcriptIndex.set(block.id, index);
|
|
1835
|
+
const retainedAssets = new Set(blocks.flatMap(block => block.imageReferences?.map(reference => reference.assetId) ?? []));
|
|
1836
|
+
for (const assetId of this.#transcriptImageAssets.keys()) {
|
|
1837
|
+
if (!retainedAssets.has(assetId))
|
|
1838
|
+
this.#transcriptImageAssets.delete(assetId);
|
|
1839
|
+
}
|
|
1840
|
+
this.#transcriptSnapshot = undefined;
|
|
1841
|
+
}
|
|
1842
|
+
#transcriptBlock(id) {
|
|
1843
|
+
const index = this.#transcriptIndex.get(id);
|
|
1844
|
+
return index === undefined ? undefined : this.#transcript[index];
|
|
1845
|
+
}
|
|
1846
|
+
// Invariant: the named work state is the only state a matching end may clear.
|
|
1418
1847
|
#enterWorkState(kind, message) {
|
|
1419
1848
|
const wasBusy = this.#lifecycle === "busy";
|
|
1420
1849
|
this.#statusKind = kind;
|
|
@@ -1424,21 +1853,16 @@ export class PiEngineAdapter {
|
|
|
1424
1853
|
this.#emitEvent({ type: "session-lifecycle", lifecycle: "busy", reason: null });
|
|
1425
1854
|
this.#emitEvent({ type: "status", status: this.#status });
|
|
1426
1855
|
}
|
|
1427
|
-
|
|
1428
|
-
* Ends one named state. A state the shell is not in is left alone, so a finished
|
|
1429
|
-
* compaction or retry cannot clear the working state it never replaced. While the run
|
|
1430
|
-
* continues, ending either of those returns to working rather than to idle.
|
|
1431
|
-
*/
|
|
1856
|
+
// Invariant: ending retry or compaction cannot clear a different active work state.
|
|
1432
1857
|
#endWorkState(kind) {
|
|
1433
1858
|
if (this.#statusKind !== kind)
|
|
1434
1859
|
return;
|
|
1435
1860
|
if (this.#agentRunActive) {
|
|
1436
|
-
this.#enterWorkState("working", "Working
|
|
1861
|
+
this.#enterWorkState("working", "Working");
|
|
1437
1862
|
return;
|
|
1438
1863
|
}
|
|
1439
1864
|
this.#leaveWorkStates();
|
|
1440
1865
|
}
|
|
1441
|
-
/** Leaves every work state and reports the session idle. */
|
|
1442
1866
|
#leaveWorkStates() {
|
|
1443
1867
|
this.#statusKind = null;
|
|
1444
1868
|
this.#lifecycle = "ready";
|
|
@@ -1449,28 +1873,41 @@ export class PiEngineAdapter {
|
|
|
1449
1873
|
#handlePiEvent(event) {
|
|
1450
1874
|
if (!isRecord(event) || typeof event.type !== "string")
|
|
1451
1875
|
return;
|
|
1876
|
+
// Invariant: usage moves at message and lifecycle boundaries, not with stream chunks, so the
|
|
1877
|
+
// two streaming event kinds keep the memo and everything else drops it.
|
|
1878
|
+
if (event.type !== "message_update" && event.type !== "tool_execution_update")
|
|
1879
|
+
this.#usageCache = undefined;
|
|
1452
1880
|
switch (event.type) {
|
|
1453
1881
|
case "agent_start":
|
|
1454
1882
|
this.#agentRunActive = true;
|
|
1455
|
-
this.#
|
|
1883
|
+
this.#emitEvent({ type: "agent-run-started" });
|
|
1884
|
+
this.#enterWorkState("working", "Working");
|
|
1456
1885
|
return;
|
|
1457
1886
|
case "message_start":
|
|
1458
1887
|
this.#upsertMessageBlock(event.message, "live");
|
|
1459
1888
|
return;
|
|
1460
1889
|
case "message_update": {
|
|
1461
|
-
const
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1890
|
+
const delta = isRecord(event.assistantMessageEvent) && typeof event.assistantMessageEvent.delta === "string"
|
|
1891
|
+
? event.assistantMessageEvent.delta
|
|
1892
|
+
: undefined;
|
|
1893
|
+
// Invariant: the delta is folded in before the block is stored, so a chunk is one update to
|
|
1894
|
+
// one block rather than a store without the delta followed by a store with it.
|
|
1895
|
+
const blocks = this.#messageBlocks(event.message, "live", this.#transcript.length);
|
|
1896
|
+
for (const [index, block] of blocks.entries()) {
|
|
1897
|
+
this.#upsertTranscriptBlock(index === 0 && delta !== undefined && !block.text.endsWith(delta)
|
|
1898
|
+
? { ...block, text: `${block.text}${delta}` }
|
|
1899
|
+
: block);
|
|
1469
1900
|
}
|
|
1470
1901
|
return;
|
|
1471
1902
|
}
|
|
1472
1903
|
case "message_end":
|
|
1473
1904
|
this.#upsertMessageBlock(event.message, "finalized");
|
|
1905
|
+
// Compatibility: preserve the same semantic boundary v2 counted. Transcript block
|
|
1906
|
+
// finalization is intentionally not a substitute: rebuilds, retries,
|
|
1907
|
+
// thinking parts, and tool rows can all finalize independently.
|
|
1908
|
+
if (isRecord(event.message) && event.message.role === "assistant") {
|
|
1909
|
+
this.#emitEvent({ type: "assistant-message-completed" });
|
|
1910
|
+
}
|
|
1474
1911
|
return;
|
|
1475
1912
|
case "turn_end":
|
|
1476
1913
|
this.#upsertMessageBlock(event.message, "finalized");
|
|
@@ -1480,10 +1917,17 @@ export class PiEngineAdapter {
|
|
|
1480
1917
|
}
|
|
1481
1918
|
return;
|
|
1482
1919
|
case "tool_execution_start":
|
|
1483
|
-
case "
|
|
1484
|
-
|
|
1920
|
+
case "tool_execution_end": {
|
|
1921
|
+
// Concurrency: the end supersedes any update still waiting on the coalescing timer.
|
|
1922
|
+
const toolCallId = stringValue(event.toolCallId);
|
|
1923
|
+
if (toolCallId !== undefined)
|
|
1924
|
+
this.#pendingToolUpdates.delete(toolCallId);
|
|
1485
1925
|
this.#upsertToolExecutionBlock(event);
|
|
1486
1926
|
return;
|
|
1927
|
+
}
|
|
1928
|
+
case "tool_execution_update":
|
|
1929
|
+
this.#coalesceToolExecutionUpdate(event);
|
|
1930
|
+
return;
|
|
1487
1931
|
case "agent_settled":
|
|
1488
1932
|
case "agent_end": {
|
|
1489
1933
|
if (event.type === "agent_end" && event.willRetry === true)
|
|
@@ -1494,8 +1938,8 @@ export class PiEngineAdapter {
|
|
|
1494
1938
|
if (finalMessages.length > 0)
|
|
1495
1939
|
this.#rebuildTranscript(finalMessages, "finalized");
|
|
1496
1940
|
else
|
|
1497
|
-
this.#
|
|
1498
|
-
//
|
|
1941
|
+
this.#setTranscript(this.#transcript.map(block => block.status === "live" ? { ...block, status: "finalized" } : block));
|
|
1942
|
+
// Compatibility: ending a turn leaves the working state, as the recorded pinned baseline does, but
|
|
1499
1943
|
// it leaves only that state: a compaction or retry being shown outlives the turn
|
|
1500
1944
|
// that ended under it. Settlement ends the run, and with it every state — the
|
|
1501
1945
|
// engine ends a turn for each continuation it makes and settles once.
|
|
@@ -1521,13 +1965,13 @@ export class PiEngineAdapter {
|
|
|
1521
1965
|
return;
|
|
1522
1966
|
}
|
|
1523
1967
|
case "auto_retry_start":
|
|
1524
|
-
this.#enterWorkState("retry", "Retrying
|
|
1968
|
+
this.#enterWorkState("retry", "Retrying");
|
|
1525
1969
|
return;
|
|
1526
1970
|
case "auto_retry_end":
|
|
1527
1971
|
this.#endWorkState("retry");
|
|
1528
1972
|
return;
|
|
1529
1973
|
case "compaction_start":
|
|
1530
|
-
this.#enterWorkState("compaction", "Compacting
|
|
1974
|
+
this.#enterWorkState("compaction", "Compacting");
|
|
1531
1975
|
return;
|
|
1532
1976
|
case "compaction_end":
|
|
1533
1977
|
this.#endWorkState("compaction");
|
|
@@ -1620,7 +2064,13 @@ export class PiEngineAdapter {
|
|
|
1620
2064
|
}
|
|
1621
2065
|
}
|
|
1622
2066
|
}
|
|
1623
|
-
|
|
2067
|
+
// Performance: an authoritative rebuild restates most of what is already there. Reusing the block
|
|
2068
|
+
// that already says it keeps its revision, and with it the rows the shell rendered for
|
|
2069
|
+
// it — otherwise every turn that ends re-renders the whole session.
|
|
2070
|
+
this.#setTranscript(blocks.map(block => {
|
|
2071
|
+
const existing = this.#transcriptBlock(block.id);
|
|
2072
|
+
return existing !== undefined && sameBlockContent(existing, block) ? existing : block;
|
|
2073
|
+
}));
|
|
1624
2074
|
}
|
|
1625
2075
|
#upsertMessageBlock(message, status) {
|
|
1626
2076
|
const blocks = this.#messageBlocks(message, status, this.#transcript.length);
|
|
@@ -1641,7 +2091,12 @@ export class PiEngineAdapter {
|
|
|
1641
2091
|
revision: this.#nextBlockRevision(baseId),
|
|
1642
2092
|
title: "User",
|
|
1643
2093
|
text: textFromContent(message.content),
|
|
1644
|
-
|
|
2094
|
+
imageReferences: this.#imageReferences(message.content, "user"),
|
|
2095
|
+
payload: {
|
|
2096
|
+
role: "user",
|
|
2097
|
+
imageCount: contentImageCount(message.content),
|
|
2098
|
+
timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : null,
|
|
2099
|
+
},
|
|
1645
2100
|
}];
|
|
1646
2101
|
}
|
|
1647
2102
|
if (message.role === "bashExecution") {
|
|
@@ -1705,7 +2160,7 @@ export class PiEngineAdapter {
|
|
|
1705
2160
|
: this.#toolBlockIds.get(toolCallId) ?? `tool-${toolCallId}`;
|
|
1706
2161
|
if (toolCallId !== undefined)
|
|
1707
2162
|
this.#toolBlockIds.set(toolCallId, blockId);
|
|
1708
|
-
const existing = this.#
|
|
2163
|
+
const existing = this.#transcriptBlock(blockId);
|
|
1709
2164
|
const existingPayload = isRecord(existing?.payload) ? existing.payload : undefined;
|
|
1710
2165
|
return [{
|
|
1711
2166
|
id: blockId,
|
|
@@ -1714,6 +2169,7 @@ export class PiEngineAdapter {
|
|
|
1714
2169
|
revision: this.#nextBlockRevision(blockId),
|
|
1715
2170
|
title: stringValue(message.toolName) ?? existing?.title ?? "Tool result",
|
|
1716
2171
|
text: textFromContent(message.content),
|
|
2172
|
+
imageReferences: this.#imageReferences(message.content, "tool-result"),
|
|
1717
2173
|
payload: {
|
|
1718
2174
|
...(existingPayload ?? {}),
|
|
1719
2175
|
role: "toolResult",
|
|
@@ -1769,6 +2225,48 @@ export class PiEngineAdapter {
|
|
|
1769
2225
|
}
|
|
1770
2226
|
return blocks;
|
|
1771
2227
|
}
|
|
2228
|
+
#imageReferences(content, source) {
|
|
2229
|
+
if (!Array.isArray(content))
|
|
2230
|
+
return [];
|
|
2231
|
+
const references = [];
|
|
2232
|
+
for (const item of content) {
|
|
2233
|
+
if (references.length >= 16 || !isRecord(item) || item.type !== "image"
|
|
2234
|
+
|| typeof item.data !== "string" || item.data.length === 0
|
|
2235
|
+
|| typeof item.mimeType !== "string" || !/^image\/[a-z0-9.+-]+$/i.test(item.mimeType))
|
|
2236
|
+
continue;
|
|
2237
|
+
const byteLength = Buffer.from(item.data, "base64").byteLength;
|
|
2238
|
+
if (byteLength < 1 || byteLength > 20 * 1024 * 1024)
|
|
2239
|
+
continue;
|
|
2240
|
+
const assetId = `image-${createHash("sha256").update(item.mimeType).update("\0").update(item.data).digest("hex").slice(0, 24)}`;
|
|
2241
|
+
this.#transcriptImageAssets.set(assetId, { type: "image", data: item.data, mimeType: item.mimeType });
|
|
2242
|
+
references.push({ assetId, mimeType: item.mimeType, byteLength, source });
|
|
2243
|
+
}
|
|
2244
|
+
return references;
|
|
2245
|
+
}
|
|
2246
|
+
// Performance: coalescing each tool to its newest chunk bounds work by frames, not stream events.
|
|
2247
|
+
#coalesceToolExecutionUpdate(event) {
|
|
2248
|
+
const toolCallId = stringValue(event.toolCallId);
|
|
2249
|
+
if (!toolCallId)
|
|
2250
|
+
return;
|
|
2251
|
+
this.#pendingToolUpdates.set(toolCallId, event);
|
|
2252
|
+
this.#toolUpdateFlush ??= setTimeout(() => {
|
|
2253
|
+
this.#toolUpdateFlush = null;
|
|
2254
|
+
if (!this.#disposed)
|
|
2255
|
+
this.#flushPendingToolUpdates();
|
|
2256
|
+
}, TOOL_UPDATE_COALESCE_MS);
|
|
2257
|
+
}
|
|
2258
|
+
#flushPendingToolUpdates() {
|
|
2259
|
+
if (this.#toolUpdateFlush !== null) {
|
|
2260
|
+
clearTimeout(this.#toolUpdateFlush);
|
|
2261
|
+
this.#toolUpdateFlush = null;
|
|
2262
|
+
}
|
|
2263
|
+
if (this.#pendingToolUpdates.size === 0)
|
|
2264
|
+
return;
|
|
2265
|
+
const pending = [...this.#pendingToolUpdates.values()];
|
|
2266
|
+
this.#pendingToolUpdates.clear();
|
|
2267
|
+
for (const update of pending)
|
|
2268
|
+
this.#upsertToolExecutionBlock(update);
|
|
2269
|
+
}
|
|
1772
2270
|
#upsertToolExecutionBlock(event) {
|
|
1773
2271
|
const toolCallId = stringValue(event.toolCallId);
|
|
1774
2272
|
if (!toolCallId)
|
|
@@ -1788,7 +2286,9 @@ export class PiEngineAdapter {
|
|
|
1788
2286
|
toolCallId,
|
|
1789
2287
|
toolName: stringValue(event.toolName) ?? "unknown",
|
|
1790
2288
|
arguments: jsonSummary(event.args),
|
|
1791
|
-
|
|
2289
|
+
// Performance: a partial result repeats the whole accumulated output on every chunk;
|
|
2290
|
+
// summarizing it each time would cost quadratic work over the stream.
|
|
2291
|
+
result: ended ? jsonSummary(source) : { summary: "", json: null },
|
|
1792
2292
|
partialResult: event.type === "tool_execution_update",
|
|
1793
2293
|
argsComplete: ended,
|
|
1794
2294
|
isError: event.isError === true,
|
|
@@ -1796,11 +2296,20 @@ export class PiEngineAdapter {
|
|
|
1796
2296
|
});
|
|
1797
2297
|
}
|
|
1798
2298
|
#upsertTranscriptBlock(block) {
|
|
1799
|
-
const index = this.#
|
|
1800
|
-
if (index
|
|
2299
|
+
const index = this.#transcriptIndex.get(block.id);
|
|
2300
|
+
if (index !== undefined) {
|
|
2301
|
+
const existing = this.#transcript[index];
|
|
2302
|
+
// Performance: nothing is emitted for a block that repeats itself, and keeping the
|
|
2303
|
+
// revision keeps the rows it already rendered.
|
|
2304
|
+
if (existing !== undefined && sameBlockContent(existing, block))
|
|
2305
|
+
return;
|
|
1801
2306
|
this.#transcript[index] = block;
|
|
1802
|
-
|
|
2307
|
+
}
|
|
2308
|
+
else {
|
|
2309
|
+
this.#transcriptIndex.set(block.id, this.#transcript.length);
|
|
1803
2310
|
this.#transcript.push(block);
|
|
2311
|
+
}
|
|
2312
|
+
this.#transcriptSnapshot = undefined;
|
|
1804
2313
|
this.#emitEvent({ type: "transcript-block", block });
|
|
1805
2314
|
}
|
|
1806
2315
|
#messageBlockId(message, fallbackIndex, status, occurrence) {
|
|
@@ -1818,7 +2327,7 @@ export class PiEngineAdapter {
|
|
|
1818
2327
|
}
|
|
1819
2328
|
}
|
|
1820
2329
|
else {
|
|
1821
|
-
id = [...cached].reverse().find(candidate => this.#
|
|
2330
|
+
id = [...cached].reverse().find(candidate => this.#transcriptBlock(candidate)?.status === "live");
|
|
1822
2331
|
if (id === undefined && status === "finalized")
|
|
1823
2332
|
id = cached.at(-1);
|
|
1824
2333
|
if (id === undefined) {
|
|
@@ -1831,7 +2340,7 @@ export class PiEngineAdapter {
|
|
|
1831
2340
|
return id;
|
|
1832
2341
|
}
|
|
1833
2342
|
#nextBlockRevision(id) {
|
|
1834
|
-
const existing = this.#
|
|
2343
|
+
const existing = this.#transcriptBlock(id);
|
|
1835
2344
|
if (existing)
|
|
1836
2345
|
return existing.revision + 1;
|
|
1837
2346
|
this.#nextBlockSequence += 1;
|
|
@@ -1862,6 +2371,7 @@ export class PiEngineAdapter {
|
|
|
1862
2371
|
this.#emitEvent({ type: "diagnostic", diagnostic });
|
|
1863
2372
|
}
|
|
1864
2373
|
#emitView() {
|
|
2374
|
+
this.#usageCache = undefined;
|
|
1865
2375
|
this.#viewRevision += 1;
|
|
1866
2376
|
this.#emitEvent({ type: "session-view", view: this.view() });
|
|
1867
2377
|
}
|
|
@@ -1906,7 +2416,7 @@ export class PiEngineAdapter {
|
|
|
1906
2416
|
}
|
|
1907
2417
|
}
|
|
1908
2418
|
deliveredSinceYield += 1;
|
|
1909
|
-
//
|
|
2419
|
+
// Concurrency: a microtask chain runs to exhaustion before the loop turns, so a streaming
|
|
1910
2420
|
// burst would hold typed input, pointer reports, and timed indicators until it
|
|
1911
2421
|
// drained. Yielding on a macrotask hands those their turn between batches.
|
|
1912
2422
|
if (deliveredSinceYield >= EVENT_DELIVERY_BATCH && this.#eventQueue.length > 0) {
|
|
@@ -1950,7 +2460,14 @@ export async function createPiEngineAdapter(options = {}) {
|
|
|
1950
2460
|
return adapter;
|
|
1951
2461
|
}
|
|
1952
2462
|
async function createDefaultPiRuntime(input) {
|
|
1953
|
-
return createPiRuntimeIntegration({
|
|
2463
|
+
return createPiRuntimeIntegration({
|
|
2464
|
+
cwd: input.cwd,
|
|
2465
|
+
agentDir: input.agentDir,
|
|
2466
|
+
...(input.sessionPath === undefined ? {} : { sessionPath: input.sessionPath }),
|
|
2467
|
+
...(input.sessionSelection === undefined ? {} : { sessionSelection: input.sessionSelection }),
|
|
2468
|
+
...(input.sessionForkPrompt === undefined ? {} : { sessionForkPrompt: input.sessionForkPrompt }),
|
|
2469
|
+
...(input.projectTrustPrompt === undefined ? {} : { projectTrustPrompt: input.projectTrustPrompt }),
|
|
2470
|
+
});
|
|
1954
2471
|
}
|
|
1955
2472
|
async function checkDefaultPiPackageUpdates(cwd, agentDir, settingsManager) {
|
|
1956
2473
|
const packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });
|
|
@@ -2073,8 +2590,8 @@ function pinnedCacheWaste(entries, modelRuntime) {
|
|
|
2073
2590
|
function defaultWorkflowHost() {
|
|
2074
2591
|
return {
|
|
2075
2592
|
copyText: copyToClipboard,
|
|
2076
|
-
async runCommand(command, arguments_) {
|
|
2077
|
-
const result = await execFileAsync(command, [...arguments_], { encoding: "utf8" });
|
|
2593
|
+
async runCommand(command, arguments_, options) {
|
|
2594
|
+
const result = await execFileAsync(command, [...arguments_], { encoding: "utf8", signal: options?.signal });
|
|
2078
2595
|
return { stdout: result.stdout, stderr: result.stderr };
|
|
2079
2596
|
},
|
|
2080
2597
|
readChangelog: async () => "No changelog entries found.",
|
|
@@ -2110,14 +2627,22 @@ function workflowLoginNotification(event) {
|
|
|
2110
2627
|
}
|
|
2111
2628
|
return { type: event.type === "waiting" ? "waiting" : "progress", message };
|
|
2112
2629
|
}
|
|
2113
|
-
function workflowResult(command, outcome, message, detail) {
|
|
2114
|
-
return {
|
|
2630
|
+
function workflowResult(command, outcome, message, detail, messageKind, messages) {
|
|
2631
|
+
return {
|
|
2632
|
+
command,
|
|
2633
|
+
outcome,
|
|
2634
|
+
message,
|
|
2635
|
+
...(detail === undefined ? {} : { detail }),
|
|
2636
|
+
...(messageKind === undefined ? {} : { messageKind }),
|
|
2637
|
+
...(messages === undefined ? {} : { messages: Object.freeze([...messages]) }),
|
|
2638
|
+
};
|
|
2115
2639
|
}
|
|
2116
|
-
function workflowConfirmation(command, message) {
|
|
2640
|
+
function workflowConfirmation(command, message, detail) {
|
|
2117
2641
|
return {
|
|
2118
2642
|
command,
|
|
2119
2643
|
outcome: "requires-confirmation",
|
|
2120
2644
|
message,
|
|
2645
|
+
...(detail === undefined ? {} : { detail }),
|
|
2121
2646
|
selectorTitle: "Confirm",
|
|
2122
2647
|
options: [
|
|
2123
2648
|
{ id: "yes", label: "Yes" },
|
|
@@ -2125,6 +2650,19 @@ function workflowConfirmation(command, message) {
|
|
|
2125
2650
|
],
|
|
2126
2651
|
};
|
|
2127
2652
|
}
|
|
2653
|
+
function errorMessage(error, fallback) {
|
|
2654
|
+
return error instanceof Error ? error.message : fallback;
|
|
2655
|
+
}
|
|
2656
|
+
function commandMissing(error) {
|
|
2657
|
+
return isRecord(error) && error.code === "ENOENT";
|
|
2658
|
+
}
|
|
2659
|
+
function isAbortError(error) {
|
|
2660
|
+
return isRecord(error) && (error.name === "AbortError" || error.code === "ABORT_ERR");
|
|
2661
|
+
}
|
|
2662
|
+
function shareViewerUrl(gistId) {
|
|
2663
|
+
const baseUrl = process.env.PI_SHARE_VIEWER_URL || "https://pi.dev/session/";
|
|
2664
|
+
return `${baseUrl}#${gistId}`;
|
|
2665
|
+
}
|
|
2128
2666
|
function workflowOptions(value, idKey, labelKey) {
|
|
2129
2667
|
if (!Array.isArray(value))
|
|
2130
2668
|
return [];
|
|
@@ -2176,7 +2714,7 @@ function settingKeyForCallback(callback) {
|
|
|
2176
2714
|
onAutoCompactChange: "autoCompact", onShowImagesChange: "showImages", onImageWidthCellsChange: "imageWidthCells",
|
|
2177
2715
|
onAutoResizeImagesChange: "autoResizeImages", onBlockImagesChange: "blockImages", onEnableSkillCommandsChange: "enableSkillCommands",
|
|
2178
2716
|
onSteeringModeChange: "steeringMode", onFollowUpModeChange: "followUpMode", onTransportChange: "transport",
|
|
2179
|
-
onHttpIdleTimeoutMsChange: "httpIdleTimeoutMs", onThemeChange: "theme", onThemePreview: "theme",
|
|
2717
|
+
onHttpIdleTimeoutMsChange: "httpIdleTimeoutMs", onThinkingLevelChange: "thinkingLevel", onThemeChange: "theme", onThemePreview: "theme",
|
|
2180
2718
|
onHideThinkingBlockChange: "hideThinkingBlock", onMermaidRenderingModeChange: "mermaidRenderingMode",
|
|
2181
2719
|
onShowCacheMissNoticesChange: "showCacheMissNotices", onCollapseChangelogChange: "collapseChangelog",
|
|
2182
2720
|
onEnableInstallTelemetryChange: "enableInstallTelemetry", onQuietStartupChange: "quietStartup",
|
|
@@ -2343,6 +2881,24 @@ function stringProperty(value, key) {
|
|
|
2343
2881
|
const item = value[key];
|
|
2344
2882
|
return typeof item === "string" && item.length > 0 ? item : undefined;
|
|
2345
2883
|
}
|
|
2884
|
+
function isUnknownModel(value) {
|
|
2885
|
+
return isRecord(value)
|
|
2886
|
+
&& value.provider === "unknown"
|
|
2887
|
+
&& value.id === "unknown"
|
|
2888
|
+
&& value.api === "unknown";
|
|
2889
|
+
}
|
|
2890
|
+
function findExactWorkflowModel(reference, models) {
|
|
2891
|
+
const normalized = reference.trim().toLowerCase();
|
|
2892
|
+
const canonical = models.filter(model => {
|
|
2893
|
+
const provider = stringProperty(model, "provider");
|
|
2894
|
+
const id = stringProperty(model, "id");
|
|
2895
|
+
return provider !== undefined && id !== undefined && `${provider}/${id}`.toLowerCase() === normalized;
|
|
2896
|
+
});
|
|
2897
|
+
if (canonical.length === 1)
|
|
2898
|
+
return canonical[0];
|
|
2899
|
+
const bare = models.filter(model => stringProperty(model, "id")?.toLowerCase() === normalized);
|
|
2900
|
+
return bare.length === 1 ? bare[0] : undefined;
|
|
2901
|
+
}
|
|
2346
2902
|
/**
|
|
2347
2903
|
* Some ecosystem extensions retain a `pi-<name>` slash-command alias beside
|
|
2348
2904
|
* their unprefixed command. A1 presents the product-neutral command once while
|
|
@@ -2367,6 +2923,37 @@ function compactResourceLabel(path) {
|
|
|
2367
2923
|
const segments = path.replaceAll("\\", "/").split("/").filter(Boolean);
|
|
2368
2924
|
return segments.at(-1) ?? path;
|
|
2369
2925
|
}
|
|
2926
|
+
/**
|
|
2927
|
+
* Whether two blocks say the same thing. A block that says what it already said is not a
|
|
2928
|
+
* new revision: the shell renders a block once per revision, so bumping one it did not
|
|
2929
|
+
* need re-renders it for nothing.
|
|
2930
|
+
*/
|
|
2931
|
+
function sameBlockContent(left, right) {
|
|
2932
|
+
return left.kind === right.kind
|
|
2933
|
+
&& left.status === right.status
|
|
2934
|
+
&& left.title === right.title
|
|
2935
|
+
&& left.text === right.text
|
|
2936
|
+
&& sameValue(left.payload, right.payload)
|
|
2937
|
+
&& sameValue(left.imageReferences ?? [], right.imageReferences ?? []);
|
|
2938
|
+
}
|
|
2939
|
+
function sameValue(left, right) {
|
|
2940
|
+
if (left === right)
|
|
2941
|
+
return true;
|
|
2942
|
+
if (typeof left !== typeof right || left === null || right === null)
|
|
2943
|
+
return false;
|
|
2944
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
2945
|
+
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length)
|
|
2946
|
+
return false;
|
|
2947
|
+
return left.every((value, index) => sameValue(value, right[index]));
|
|
2948
|
+
}
|
|
2949
|
+
if (typeof left !== "object")
|
|
2950
|
+
return false;
|
|
2951
|
+
const leftKeys = Object.keys(left);
|
|
2952
|
+
const rightRecord = right;
|
|
2953
|
+
if (leftKeys.length !== Object.keys(rightRecord).length)
|
|
2954
|
+
return false;
|
|
2955
|
+
return leftKeys.every(key => Object.hasOwn(rightRecord, key) && sameValue(left[key], rightRecord[key]));
|
|
2956
|
+
}
|
|
2370
2957
|
function textFromContent(content) {
|
|
2371
2958
|
if (typeof content === "string")
|
|
2372
2959
|
return content;
|