@timurproko/a1 0.2.7-dev.1252 → 0.2.7-dev.1264
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/bin/ui.js +3 -3
- package/dist/app/session-shell/clipboard-diagnostics.d.ts +2 -2
- package/dist/app/session-shell/clipboard-image.d.ts +0 -1
- package/dist/app/session-shell/clipboard-image.js +1 -1
- package/dist/app/session-shell/dialog-coordinator.d.ts +6 -5
- package/dist/app/session-shell/dialog-coordinator.js +3 -4
- package/dist/app/session-shell/dock-chrome.d.ts +11 -6
- package/dist/app/session-shell/dock-chrome.js +5 -8
- package/dist/app/session-shell/editor-hyperlink-budget.d.ts +0 -2
- package/dist/app/session-shell/editor-hyperlink-budget.js +1 -1
- package/dist/app/session-shell/exit-notice.d.ts +2 -2
- package/dist/app/session-shell/exit-notice.js +1 -1
- package/dist/app/session-shell/extension-surface.d.ts +8 -7
- package/dist/app/session-shell/helper-pool.d.ts +3 -4
- package/dist/app/session-shell/helper-pool.js +1 -1
- package/dist/app/session-shell/image-preparation-client.d.ts +4 -3
- package/dist/app/session-shell/image-preparation.d.ts +0 -2
- package/dist/app/session-shell/image-preparation.js +2 -2
- package/dist/app/session-shell/image-source.d.ts +2 -3
- package/dist/app/session-shell/image-source.js +2 -2
- package/dist/app/session-shell/input-surface-switch.d.ts +9 -7
- package/dist/app/session-shell/input-surface-switch.js +1 -2
- package/dist/app/session-shell/login-interaction.d.ts +5 -4
- package/dist/app/session-shell/login-interaction.js +2 -3
- package/dist/app/session-shell/paste-executor.d.ts +4 -8
- package/dist/app/session-shell/paste-executor.js +2 -2
- package/dist/app/session-shell/paste-protocol.d.ts +2 -2
- package/dist/app/session-shell/path-chip-presentation.d.ts +0 -5
- package/dist/app/session-shell/path-chip-presentation.js +3 -3
- package/dist/app/session-shell/prompt-chips.d.ts +8 -7
- package/dist/app/session-shell/prompt-history-controller.d.ts +3 -3
- package/dist/app/session-shell/prompt-submission.d.ts +5 -2
- package/dist/app/session-shell/prompt-submission.js +13 -14
- package/dist/app/session-shell/quit-outro-effects.d.ts +3 -3
- package/dist/app/session-shell/quit-outro-effects.js +1 -4
- package/dist/app/session-shell/quit-outro.d.ts +9 -12
- package/dist/app/session-shell/quit-outro.js +11 -11
- package/dist/app/session-shell/resource-labels.d.ts +2 -0
- package/dist/app/session-shell/resource-labels.js +158 -0
- package/dist/app/session-shell/response-copy-protocol.d.ts +3 -2
- package/dist/app/session-shell/response-copy-transport.d.ts +2 -14
- package/dist/app/session-shell/response-copy-transport.js +1 -1
- package/dist/app/session-shell/session-lifecycle.d.ts +2 -1
- package/dist/app/session-shell/session-prompt-history.d.ts +29 -0
- package/dist/app/session-shell/session-prompt-history.js +80 -0
- package/dist/app/session-shell/session-selectors.d.ts +46 -0
- package/dist/app/session-shell/session-selectors.js +269 -0
- package/dist/app/session-shell/session-shell-root.d.ts +76 -113
- package/dist/app/session-shell/session-shell-root.js +103 -329
- package/dist/app/session-shell/session-shell.d.ts +14 -37
- package/dist/app/session-shell/session-shell.js +177 -612
- package/dist/app/session-shell/session-viewport-controller.d.ts +9 -16
- package/dist/app/session-shell/session-viewport-controller.js +42 -320
- package/dist/app/session-shell/settings-bindings.d.ts +25 -3
- package/dist/app/session-shell/settings-bindings.js +26 -2
- package/dist/app/session-shell/share-operation.d.ts +3 -3
- package/dist/app/session-shell/share-operation.js +4 -6
- package/dist/app/session-shell/shell-clipboard.d.ts +59 -0
- package/dist/app/session-shell/shell-clipboard.js +119 -0
- package/dist/app/session-shell/shell-editor-factory.d.ts +8 -4
- package/dist/app/session-shell/shell-editor-factory.js +13 -15
- package/dist/app/session-shell/shell-host.d.ts +16 -17
- package/dist/app/session-shell/shell-host.js +18 -19
- package/dist/app/session-shell/shell-layout.d.ts +2 -2
- package/dist/app/session-shell/shell-prompt-suggestions.d.ts +26 -0
- package/dist/app/session-shell/shell-prompt-suggestions.js +48 -0
- package/dist/app/session-shell/suggestion-surface.d.ts +1 -6
- package/dist/app/session-shell/suggestion-surface.js +1 -1
- package/dist/app/session-shell/system-clipboard.d.ts +2 -14
- package/dist/app/session-shell/system-clipboard.js +2 -7
- package/dist/app/session-shell/transcript-document.d.ts +11 -8
- package/dist/app/session-shell/transcript-document.js +13 -14
- package/dist/app/session-shell/viewport-layout.d.ts +2 -2
- package/dist/app/session-shell/viewport-pointer.d.ts +83 -0
- package/dist/app/session-shell/viewport-pointer.js +361 -0
- package/dist/app/session-shell/workflow-output.d.ts +5 -3
- package/dist/app/session-shell/workflow-output.js +13 -15
- package/dist/cli/package-messages.d.ts +0 -1
- package/dist/cli/package-messages.js +1 -1
- package/dist/cli/session-context.d.ts +1 -1
- package/dist/cli/uninstall.d.ts +3 -2
- package/dist/composition/owned-settings.d.ts +2 -1
- package/dist/composition/owned-settings.js +0 -3
- package/dist/composition/owned-ui.d.ts +1 -1
- package/dist/composition/owned-ui.js +77 -73
- package/dist/composition/reference-selection-options.d.ts +1 -1
- package/dist/composition/reference-selection-options.js +1 -1
- package/dist/composition/session-runtime-registry.d.ts +2 -1
- package/dist/composition/settings-route-host.js +3 -10
- package/dist/composition/settings-search-input.d.ts +2 -1
- package/dist/composition/startup-route.d.ts +2 -2
- package/dist/composition/startup-route.js +2 -2
- package/dist/contracts/owned-ui/extension-ui.d.ts +2 -1
- package/dist/contracts/owned-ui/index.d.ts +2 -1
- package/dist/contracts/owned-ui/index.js +1 -1
- package/dist/contracts/owned-ui/session-presenters.d.ts +3 -0
- package/dist/contracts/owned-ui/shell-components.d.ts +543 -0
- package/dist/contracts/owned-ui/validation.d.ts +1 -11
- package/dist/contracts/owned-ui/validation.js +8 -104
- package/dist/contracts/presentation/component.d.ts +17 -0
- package/dist/contracts/presentation/component.js +8 -0
- package/dist/contracts/presentation/index.d.ts +6 -15
- package/dist/contracts/presentation/index.js +2 -0
- package/dist/contracts/presentation/terminal.d.ts +284 -0
- package/dist/contracts/presentation/terminal.js +1 -0
- package/dist/contracts/presentation/theme.d.ts +46 -0
- package/dist/contracts/presentation/theme.js +1 -0
- package/dist/features/launch/development-launch.js +1 -1
- package/dist/features/launch/runtime-selection.d.ts +2 -2
- package/dist/features/launch/runtime-selection.js +2 -2
- package/dist/features/owned-ui/project-trust-prompt.d.ts +2 -2
- package/dist/features/owned-ui/project-trust-prompt.js +1 -1
- package/dist/features/owned-ui/release-note-state.d.ts +2 -1
- package/dist/features/owned-ui/settings-app.js +49 -425
- package/dist/features/owned-ui/settings-edits.d.ts +31 -0
- package/dist/features/owned-ui/settings-edits.js +139 -0
- package/dist/features/owned-ui/settings-model-dialog.d.ts +41 -0
- package/dist/features/owned-ui/settings-model-dialog.js +194 -0
- package/dist/features/owned-ui/settings-scroll-rail.d.ts +29 -0
- package/dist/features/owned-ui/settings-scroll-rail.js +79 -0
- package/dist/features/owned-ui/settings-search-input.d.ts +2 -1
- package/dist/features/prompt-history/service.d.ts +3 -2
- package/dist/foundation/lifecycle/claim-gate.d.ts +2 -1
- package/dist/foundation/release/automatic-update.d.ts +5 -14
- package/dist/foundation/release/automatic-update.js +15 -22
- package/dist/foundation/release/bootstrap.js +4 -4
- package/dist/foundation/release/dependency-certification.d.ts +0 -1
- package/dist/foundation/release/dependency-certification.js +1 -1
- package/dist/foundation/release/dependency-layer.js +3 -3
- package/dist/foundation/release/early-accent.d.ts +2 -2
- package/dist/foundation/release/early-accent.js +1 -1
- package/dist/foundation/release/index.d.ts +2 -2
- package/dist/foundation/release/index.js +1 -1
- package/dist/foundation/release/latest-release.d.ts +3 -18
- package/dist/foundation/release/latest-release.js +11 -11
- package/dist/foundation/release/managed-path.d.ts +10 -0
- package/dist/foundation/release/managed-path.js +26 -0
- package/dist/foundation/release/ordinary-launch-selection.d.ts +1 -1
- package/dist/foundation/release/ordinary-launch-selection.js +1 -1
- package/dist/foundation/release/release-gc.d.ts +3 -3
- package/dist/foundation/release/release-gc.js +10 -12
- package/dist/foundation/release/{cohort-state.d.ts → release-state.d.ts} +23 -23
- package/dist/foundation/release/{cohort-state.js → release-state.js} +8 -8
- package/dist/foundation/release/restart-certification.js +3 -4
- package/dist/foundation/release/update-activation.js +3 -3
- package/dist/foundation/release/update-execution-lease.d.ts +2 -3
- package/dist/foundation/release/update-execution-lease.js +2 -8
- package/dist/foundation/release/update-installer.d.ts +45 -0
- package/dist/foundation/release/update-installer.js +57 -0
- package/dist/foundation/release/update-launch.d.ts +2 -2
- package/dist/foundation/release/update-recovery.js +2 -9
- package/dist/foundation/release/update.d.ts +4 -25
- package/dist/foundation/release/update.js +164 -183
- package/dist/foundation/startup/startup-budget.d.ts +5 -5
- package/dist/foundation/startup/startup-budget.js +2 -2
- package/dist/integrations/pi/components/bracketed-paste.d.ts +33 -0
- package/dist/integrations/pi/components/bracketed-paste.js +123 -0
- package/dist/integrations/pi/components/editor-interaction.d.ts +4 -12
- package/dist/integrations/pi/components/index.d.ts +15 -9
- package/dist/integrations/pi/components/index.js +9 -5
- package/dist/integrations/pi/components/lazy-selectors.d.ts +2 -10
- package/dist/integrations/pi/components/lazy-selectors.js +1 -1
- package/dist/integrations/pi/components/modal-frame.d.ts +5 -22
- package/dist/integrations/pi/components/modal-frame.js +3 -23
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +4 -3
- package/dist/integrations/pi/components/owned-editor-ux.js +46 -140
- package/dist/integrations/pi/components/prompt-input-port.d.ts +2 -19
- package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -1
- package/dist/integrations/pi/components/shell-editor-autocomplete.d.ts +3 -2
- package/dist/integrations/pi/components/shell-footer-status.d.ts +2 -2
- package/dist/integrations/pi/components/shell-footer-status.js +3 -2
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +6 -5
- package/dist/integrations/pi/components/shell-presenters-info.js +2 -1
- package/dist/integrations/pi/components/shell-session-info-reference.d.ts +2 -1
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +33 -227
- package/dist/integrations/pi/components/shell-shared-facade.js +8 -1
- package/dist/integrations/pi/components/skills-command.d.ts +1 -9
- package/dist/integrations/pi/components/skills-command.js +5 -5
- package/dist/integrations/pi/components/theme.d.ts +9 -2
- package/dist/integrations/pi/components/theme.js +17 -2
- package/dist/integrations/pi/components/thinking-selector-dialog.d.ts +2 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +2 -2
- package/dist/integrations/pi/engine/adapter.d.ts +4 -13
- package/dist/integrations/pi/engine/adapter.js +9 -61
- package/dist/integrations/pi/engine/changelog.d.ts +2 -2
- package/dist/integrations/pi/engine/changelog.js +3 -3
- package/dist/integrations/pi/engine/compaction-progress.d.ts +2 -3
- package/dist/integrations/pi/engine/compaction-progress.js +1 -1
- package/dist/integrations/pi/engine/conformance.d.ts +2 -1
- package/dist/integrations/pi/engine/default-model-setting.d.ts +0 -2
- package/dist/integrations/pi/engine/default-model-setting.js +1 -2
- package/dist/integrations/pi/engine/event-delivery.d.ts +2 -1
- package/dist/integrations/pi/engine/extension-ui-binding.d.ts +2 -1
- package/dist/integrations/pi/engine/host.js +3 -3
- package/dist/integrations/pi/engine/message-values.d.ts +0 -1
- package/dist/integrations/pi/engine/message-values.js +1 -1
- package/dist/integrations/pi/engine/pending-delivery.d.ts +0 -4
- package/dist/integrations/pi/engine/pending-delivery.js +3 -3
- package/dist/integrations/pi/engine/ports.d.ts +7 -1
- package/dist/integrations/pi/engine/ports.js +4 -0
- package/dist/integrations/pi/engine/project-trust-preflight.d.ts +2 -1
- package/dist/integrations/pi/engine/prompt-suggestions.d.ts +3 -2
- package/dist/integrations/pi/engine/provider-authentication.d.ts +1 -1
- package/dist/integrations/pi/engine/public-main-entry.d.ts +1 -5
- package/dist/integrations/pi/engine/public-main-entry.js +1 -1
- package/dist/integrations/pi/engine/repository-metadata.d.ts +49 -0
- package/dist/integrations/pi/engine/repository-metadata.js +189 -0
- package/dist/integrations/pi/engine/repository-pr-rest.d.ts +1 -9
- package/dist/integrations/pi/engine/repository-pr-rest.js +2 -2
- package/dist/integrations/pi/engine/repository-pr.d.ts +1 -3
- package/dist/integrations/pi/engine/repository-pr.js +1 -1
- package/dist/integrations/pi/engine/resource-catalog.d.ts +2 -1
- package/dist/integrations/pi/engine/session-integration.d.ts +1 -1
- package/dist/integrations/pi/engine/session-runtime.d.ts +7 -12
- package/dist/integrations/pi/engine/session-runtime.js +21 -178
- package/dist/integrations/pi/engine/settings-bridge.d.ts +0 -2
- package/dist/integrations/pi/engine/settings-bridge.js +1 -1
- package/dist/integrations/pi/engine/settings-port.d.ts +3 -2
- package/dist/integrations/pi/engine/transcript-projection.d.ts +2 -1
- package/dist/integrations/pi/engine/view-state.d.ts +21 -2
- package/dist/integrations/pi/engine/view-state.js +129 -1
- package/dist/integrations/pi/engine/workflow-contexts.d.ts +1 -1
- package/dist/integrations/pi/engine/workflow-runner.d.ts +1 -2
- package/dist/integrations/pi/engine/workflow-runner.js +254 -365
- package/dist/integrations/pi/engine/workflow-share.d.ts +9 -0
- package/dist/integrations/pi/engine/workflow-share.js +168 -0
- package/dist/integrations/pi/engine/workflow-support.d.ts +0 -20
- package/dist/integrations/pi/engine/workflow-support.js +4 -65
- package/dist/integrations/pi/engine/workflows.d.ts +5 -5
- package/dist/integrations/pi/session-presenters/components.d.ts +3 -0
- package/dist/integrations/pi/session-presenters/components.js +75 -0
- package/dist/integrations/pi/session-presenters/index.d.ts +1 -0
- package/dist/integrations/pi/session-presenters/index.js +1 -0
- package/dist/integrations/pi/session-presenters/presentation.d.ts +3 -0
- package/dist/integrations/pi/session-presenters/presentation.js +10 -0
- package/dist/integrations/pi/session-presenters/presenters.d.ts +2 -1
- package/dist/integrations/pi/session-presenters/presenters.js +3 -1
- package/dist/integrations/pi/tui-runtime/adapter.d.ts +9 -19
- package/dist/integrations/pi/tui-runtime/adapter.js +56 -174
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +9 -44
- package/dist/integrations/pi/tui-runtime/index.d.ts +1 -1
- package/dist/integrations/pi/tui-runtime/index.js +1 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +4 -6
- package/dist/integrations/pi/tui-runtime/overlay-geometry.d.ts +4 -10
- package/dist/integrations/pi/tui-runtime/overlay-geometry.js +3 -9
- package/dist/integrations/pi/tui-runtime/presentation-adapter.d.ts +2 -2
- package/dist/integrations/pi/tui-runtime/runtime-factory.d.ts +3 -0
- package/dist/integrations/pi/tui-runtime/runtime-factory.js +11 -0
- package/dist/ui/components/index.d.ts +2 -2
- package/dist/ui/components/index.js +1 -1
- package/dist/ui/components/selection-copy.d.ts +0 -1
- package/dist/ui/components/selection-copy.js +0 -12
- package/dist/ui/components/theme.d.ts +4 -19
- package/dist/ui/components/theme.js +6 -0
- package/dist/ui/components/transcript-viewport-frame.d.ts +120 -0
- package/dist/ui/components/transcript-viewport-frame.js +314 -0
- package/dist/ui/components/transcript-viewport-types.d.ts +147 -0
- package/dist/ui/components/transcript-viewport-types.js +1 -0
- package/dist/ui/components/transcript-viewport.d.ts +2 -147
- package/dist/ui/components/transcript-viewport.js +87 -315
- package/dist/ui/settings/declarations.d.ts +2 -3
- package/dist/ui/settings/declarations.js +2 -3
- package/dist/ui/settings/early-accent.js +1 -1
- package/dist/ui/settings/index.d.ts +3 -5
- package/dist/ui/settings/index.js +2 -3
- package/dist/ui/settings/manager.d.ts +0 -4
- package/dist/ui/settings/manager.js +6 -62
- package/dist/ui/settings/resolution.d.ts +6 -18
- package/dist/ui/settings/resolution.js +4 -103
- package/dist/ui/settings/sections.d.ts +0 -4
- package/dist/ui/settings/sections.js +1 -1
- package/docs/architecture/boundaries.md +2 -2
- package/docs/architecture/internal-naming.md +2 -0
- package/docs/architecture/project-structure.md +4 -2
- package/docs/validation.md +1 -1
- package/package.json +3 -4
- package/dist/integrations/pi/components/components.d.ts +0 -4
- package/dist/integrations/pi/components/components.js +0 -48
- package/dist/integrations/pi/components/conformance.d.ts +0 -18
- package/dist/integrations/pi/components/conformance.js +0 -70
- package/dist/integrations/pi/components/shell-components.d.ts +0 -7
- package/dist/integrations/pi/components/shell-components.js +0 -7
- package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +0 -33
- package/dist/integrations/pi/components/upstream/theme/theme-controller.js +0 -114
- package/dist/integrations/pi/engine/diagnostics-state.d.ts +0 -9
- package/dist/integrations/pi/engine/diagnostics-state.js +0 -34
- package/dist/integrations/pi/engine/usage-view.d.ts +0 -4
- package/dist/integrations/pi/engine/usage-view.js +0 -56
- package/dist/integrations/pi/tui-runtime/contracts.d.ts +0 -166
- package/dist/ui/settings/migrations.d.ts +0 -19
- package/dist/ui/settings/migrations.js +0 -225
- package/dist/ui/settings/progress-palette.generated.d.ts +0 -139
- package/dist/ui/settings/progress-palette.generated.js +0 -139
- /package/dist/{integrations/pi/tui-runtime/contracts.js → contracts/owned-ui/shell-components.js} +0 -0
- /package/dist/{foundation/release → contracts/presentation}/progress-palette.generated.d.ts +0 -0
- /package/dist/{foundation/release → contracts/presentation}/progress-palette.generated.js +0 -0
|
@@ -1,30 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { PromptHistoryController } from "./prompt-history-controller.js";
|
|
1
|
+
import { ShellClipboard } from "./shell-clipboard.js";
|
|
2
|
+
import { SessionPromptHistory } from "./session-prompt-history.js";
|
|
3
|
+
import { shellResourceEntries } from "./resource-labels.js";
|
|
5
4
|
import { SessionDialogCoordinator } from "./dialog-coordinator.js";
|
|
6
5
|
import { LoginInteraction } from "./login-interaction.js";
|
|
7
6
|
import { PromptSubmission } from "./prompt-submission.js";
|
|
8
7
|
import { SessionConcerns } from "./session-concern.js";
|
|
9
8
|
import { composeExitText, SessionStopLatch } from "./session-lifecycle.js";
|
|
10
9
|
import { openWorkflowSelector } from "./workflow-router.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
10
|
+
import { SessionSelectors } from "./session-selectors.js";
|
|
11
|
+
import { bindSessionSettings, bindShellSettings } from "./settings-bindings.js";
|
|
12
|
+
import { promptSuggestionSurface, suggestionPresentationBlockReason, } from "./suggestion-surface.js";
|
|
13
13
|
import { CLEAR_EXIT_INTERVAL_MS, boundedCleanup } from "../../foundation/terminal-cleanup/terminal-reset.js";
|
|
14
14
|
import { OWNED_UI_HIDDEN_COMMAND_NAMES } from "../../contracts/owned-ui/index.js";
|
|
15
|
-
import { ImageAttachmentError } from "../../contracts/owned-ui/index.js";
|
|
16
15
|
import { copyAcknowledgementText } from "../../ui/components/selection-copy.js";
|
|
17
|
-
import {
|
|
18
|
-
import { workflowCommandNames } from "../../integrations/pi/engine/workflows.js";
|
|
19
|
-
import { createPiExtensionUiBridge } from "../../integrations/pi/components/shell-extension-ui.js";
|
|
20
|
-
import { ProgramStatusReporter } from "../../integrations/pi/components/upstream/program-status-reporter.js";
|
|
21
|
-
import { SKILLS_COMMAND_NAME, findSkillByArgument, rewriteSkillsTunnelSubmission, skillPrompt, skillsFromCommands, } from "../../integrations/pi/components/skills-command.js";
|
|
22
|
-
import { createPiShellAuthProviderSelector, createPiShellExtensionSelector, createPiShellLoginDialog, createPiShellReloadBox, createPiShellSkillsSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, } from "../../integrations/pi/components/shell-selectors-dialogs.js";
|
|
16
|
+
import { ShellPromptSuggestions } from "./shell-prompt-suggestions.js";
|
|
23
17
|
import { OwnedUiTerminalHost, componentRuntime, sessionTerminalHostOptions, } from "./shell-host.js";
|
|
24
|
-
import { runImageWorker } from "./image-preparation-client.js";
|
|
25
18
|
import { STREAM_PRESENTATION_INTERVAL_MS, StreamPresentationCoalescer, } from "./stream-presentation-coalescer.js";
|
|
26
|
-
import {
|
|
27
|
-
import { OwnedUiSessionShellRoot, shellResourceEntries, } from "./session-shell-root.js";
|
|
19
|
+
import { OwnedUiSessionShellRoot, } from "./session-shell-root.js";
|
|
28
20
|
// Invariant: a disposed shell leaves the engine a host that holds no reference back to it.
|
|
29
21
|
const DETACHED_WORKFLOW_INTERACTION = { prompt: async () => null, notify() { } };
|
|
30
22
|
export { OwnedUiSessionShellRoot, } from "./session-shell-root.js";
|
|
@@ -37,24 +29,19 @@ export { formatSessionResumeCommand, quoteCommandArgument } from "./session-life
|
|
|
37
29
|
export class OwnedUiSessionPresenter {
|
|
38
30
|
backend;
|
|
39
31
|
#presenters;
|
|
40
|
-
|
|
32
|
+
selectors;
|
|
41
33
|
root;
|
|
42
34
|
#host;
|
|
43
35
|
#terminal;
|
|
44
36
|
#submission;
|
|
45
37
|
#login;
|
|
46
38
|
#concerns;
|
|
47
|
-
#listeners = new Set();
|
|
48
39
|
#unsubscribe;
|
|
49
|
-
#unsubscribePromptSuggestions;
|
|
50
40
|
#promptSuggestions;
|
|
51
41
|
#promptImages;
|
|
52
42
|
#skills;
|
|
53
|
-
#unsubscribePromptImages;
|
|
54
|
-
#unsubscribeSkills;
|
|
55
43
|
#installedCommandSignature = "";
|
|
56
|
-
#
|
|
57
|
-
#historyBinding;
|
|
44
|
+
#history = null;
|
|
58
45
|
#extensionBridge;
|
|
59
46
|
#stop = new SessionStopLatch();
|
|
60
47
|
#dialogs;
|
|
@@ -65,21 +52,17 @@ export class OwnedUiSessionPresenter {
|
|
|
65
52
|
#shutdownPromise;
|
|
66
53
|
#disposePromise;
|
|
67
54
|
#layoutParts;
|
|
68
|
-
#pendingClipboardWrite = Promise.resolve();
|
|
69
55
|
// Invariant: translated startup diagnostics create at most one dock notice per kind per shell.
|
|
70
56
|
#startupTrustHandled = false;
|
|
71
57
|
#customViewport;
|
|
72
|
-
#
|
|
73
|
-
#lazySelectorsPromise;
|
|
74
|
-
#responseCopy;
|
|
58
|
+
#clipboard;
|
|
75
59
|
// Rationale: only an executor this shell created owns a spare copy helper worth warming and disposing.
|
|
76
|
-
#copyExecutor;
|
|
77
60
|
#copyIntentSequence = 0;
|
|
78
61
|
#unbindClipboardWriter;
|
|
79
62
|
#reloadPresentation;
|
|
80
63
|
#streamPresentation;
|
|
81
64
|
#inputCoordination;
|
|
82
|
-
#
|
|
65
|
+
#unbindShellSettings;
|
|
83
66
|
#unbindSessionSettings;
|
|
84
67
|
#terminalProgressEnabled = false;
|
|
85
68
|
#programStatus;
|
|
@@ -88,7 +71,6 @@ export class OwnedUiSessionPresenter {
|
|
|
88
71
|
#lastEscapeTime = 0;
|
|
89
72
|
#sessionGeneration;
|
|
90
73
|
#sessionBindingGeneration;
|
|
91
|
-
#suggestionModelKey;
|
|
92
74
|
constructor(host, options) {
|
|
93
75
|
const { backend, cwd, routeHost, sessionLayout } = options.engine;
|
|
94
76
|
const { terminal, startup, viewportSettings, reload: reloadPresentation, stream: streamPresentationOptions, input: inputPresentation, } = options.presentation ?? {};
|
|
@@ -99,15 +81,10 @@ export class OwnedUiSessionPresenter {
|
|
|
99
81
|
this.#presenters = options.presenters;
|
|
100
82
|
this.#sessionGeneration = this.backend.identity.sessionGeneration;
|
|
101
83
|
this.#sessionBindingGeneration = this.backend.identity.sessionBindingGeneration;
|
|
102
|
-
this.#suggestionModelKey = suggestionModelKey(this.backend.session.view());
|
|
103
84
|
this.#customViewport = sessionLayout === "custom-viewport";
|
|
104
85
|
this.#inputCoordination = inputPresentation?.coordination !== false;
|
|
105
86
|
this.#host = host;
|
|
106
87
|
this.#terminal = host.connect(this);
|
|
107
|
-
// Invariant: the host's optional members follow the layout, so it is built only once the layout is known.
|
|
108
|
-
this.#dialogHost = this.#createDialogHost();
|
|
109
|
-
this.#lazySelectors = options.diagnostics?.lazySelectors;
|
|
110
|
-
let promptSuggestionController = null;
|
|
111
88
|
// Invariant: owned prompt limits and collapsed skills are bare-A1 replacements; comparison profiles keep pinned behavior.
|
|
112
89
|
this.#promptImages = this.#customViewport ? options.promptImages ?? null : null;
|
|
113
90
|
this.#skills = this.#customViewport ? options.skills ?? null : null;
|
|
@@ -115,48 +92,19 @@ export class OwnedUiSessionPresenter {
|
|
|
115
92
|
// throw releases them in reverse, so a shell that never finished constructing holds nothing.
|
|
116
93
|
const constructed = [() => host.disconnect(this)];
|
|
117
94
|
try {
|
|
118
|
-
this.#
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
this.#terminal.writeControl(control);
|
|
133
|
-
} },
|
|
134
|
-
})),
|
|
135
|
-
...(responseCopy?.onEvent === undefined ? {} : { onEvent: responseCopy.onEvent }),
|
|
136
|
-
}) : null;
|
|
137
|
-
constructed.push(() => { this.#responseCopy?.dispose(); this.#copyExecutor?.dispose(); });
|
|
138
|
-
const readClipboard = async (signal) => {
|
|
139
|
-
if (signal.aborted)
|
|
140
|
-
throw new ImageAttachmentError("image-canceled");
|
|
141
|
-
if (clipboard === undefined)
|
|
142
|
-
return runImageWorker({ kind: "clipboard" }, signal);
|
|
143
|
-
try {
|
|
144
|
-
const image = await clipboard.readImage?.(signal);
|
|
145
|
-
if (image !== null && image !== undefined) {
|
|
146
|
-
const canonical = await runImageWorker({ kind: "canonicalize", source: image }, signal);
|
|
147
|
-
if (canonical !== null)
|
|
148
|
-
return { kind: "image", ...canonical };
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
catch (error) {
|
|
152
|
-
if (error instanceof ImageAttachmentError)
|
|
153
|
-
throw error;
|
|
154
|
-
// Compatibility: an unavailable image reader can still provide text.
|
|
155
|
-
}
|
|
156
|
-
const text = await clipboard.readText(signal);
|
|
157
|
-
return text === null ? null : { kind: "text", text };
|
|
158
|
-
};
|
|
159
|
-
this.root = new OwnedUiSessionShellRoot(this.backend.session.view(), cwd, {
|
|
95
|
+
this.#clipboard = new ShellClipboard({
|
|
96
|
+
ownedCopy: this.#customViewport, substituteTerminal: terminal !== undefined,
|
|
97
|
+
...(sharedClipboard === undefined ? {} : { shared: sharedClipboard }),
|
|
98
|
+
...(clipboard === undefined ? {} : { clipboard }),
|
|
99
|
+
...(responseCopy === undefined ? {} : { responseCopy }),
|
|
100
|
+
...(pastePreparation === undefined ? {} : { pastePreparation }),
|
|
101
|
+
disposed: () => this.#disposed,
|
|
102
|
+
terminalAttached: () => this.#terminal.running && this.#terminal.attached,
|
|
103
|
+
writeControl: control => this.#terminal.writeControl(control),
|
|
104
|
+
});
|
|
105
|
+
constructed.push(() => this.#clipboard.dispose());
|
|
106
|
+
const pastePreparationOptions = this.#clipboard.pastePreparation();
|
|
107
|
+
this.root = new OwnedUiSessionShellRoot(this.backend.session.view(), cwd, { presentation: options.presenters, components: options.presenters.components,
|
|
160
108
|
getColumns: () => this.#terminal.viewport().columns,
|
|
161
109
|
getRows: () => this.#terminal.viewport().rows,
|
|
162
110
|
requestRender: force => this.#terminal.requestRender(force),
|
|
@@ -174,7 +122,7 @@ export class OwnedUiSessionPresenter {
|
|
|
174
122
|
onInterrupt: () => { void this.interrupt(); },
|
|
175
123
|
onClear: () => { void this.clearOrExit(); },
|
|
176
124
|
onExit: () => { void this.shutdown(); },
|
|
177
|
-
onModelSelect: () => this.#customViewport ? this.showModelsDialog() : this.showModelSelector(),
|
|
125
|
+
onModelSelect: () => this.#customViewport ? this.selectors.showModelsDialog() : this.selectors.showModelSelector(),
|
|
178
126
|
onModelCycle: direction => { void this.cycleModel(direction); },
|
|
179
127
|
onThinkingCycle: () => { void this.cycleThinkingLevel(); },
|
|
180
128
|
onThinkingToggle: () => {
|
|
@@ -186,55 +134,31 @@ export class OwnedUiSessionPresenter {
|
|
|
186
134
|
onDequeue: () => this.restoreQueuedInput(),
|
|
187
135
|
onEditorChange: text => {
|
|
188
136
|
this.#submission.noteEditorChange();
|
|
189
|
-
|
|
137
|
+
this.#promptSuggestions?.abortPending();
|
|
190
138
|
if (text.length === 0) {
|
|
191
139
|
// Concurrency: the editor synchronizes deletion-owned autocomplete after onChange.
|
|
192
140
|
// Reassert retained ghost text in the microtask before Pi emits its scheduled frame.
|
|
193
|
-
queueMicrotask(() =>
|
|
141
|
+
queueMicrotask(() => this.#promptSuggestions?.restoreAvailable());
|
|
194
142
|
}
|
|
195
143
|
this.root.reconcilePromptImageLimitNotice(text);
|
|
196
144
|
},
|
|
197
|
-
onPromptSuggestionAccepted: () =>
|
|
145
|
+
onPromptSuggestionAccepted: () => this.#promptSuggestions?.accept(),
|
|
198
146
|
onPromptSuggestionEligibilityChanged: () => {
|
|
199
|
-
queueMicrotask(() =>
|
|
147
|
+
queueMicrotask(() => this.#promptSuggestions?.restoreAvailable());
|
|
200
148
|
},
|
|
201
149
|
onInputSurfaceChanged: () => {
|
|
202
|
-
|
|
203
|
-
this.#
|
|
150
|
+
this.#promptSuggestions?.invalidate();
|
|
151
|
+
this.#history?.synchronize();
|
|
204
152
|
},
|
|
205
153
|
onCopyText: (text, cut) => {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
const write = () => {
|
|
211
|
-
if (this.#disposed)
|
|
212
|
-
return Promise.resolve();
|
|
213
|
-
this.#terminal.writeControl(`\u001b]52;c;${Buffer.from(text, "utf8").toString("base64")}\u0007`);
|
|
214
|
-
return clipboard === undefined ? writeSystemClipboardText(text)
|
|
215
|
-
: clipboard.writeText?.(text) ?? Promise.resolve();
|
|
216
|
-
};
|
|
217
|
-
// Compatibility: comparison profiles retain their existing clipboard path.
|
|
218
|
-
this.#pendingClipboardWrite = write().catch(() => { });
|
|
219
|
-
},
|
|
220
|
-
readClipboardContent: async (signal = new AbortController().signal) => {
|
|
221
|
-
await this.#pendingClipboardWrite;
|
|
222
|
-
return readClipboard(signal);
|
|
223
|
-
},
|
|
224
|
-
captureClipboardPaste: () => {
|
|
225
|
-
const before = this.#responseCopy?.capturePasteBarrier() ?? (async () => true);
|
|
226
|
-
if (clipboard !== undefined)
|
|
227
|
-
return { kind: "provided", read: readClipboard, before };
|
|
228
|
-
if (responseCopyDestination(process.env) === "terminal")
|
|
229
|
-
return {
|
|
230
|
-
kind: "provided", before, read: async () => { throw new ImageAttachmentError("paste-unavailable"); },
|
|
231
|
-
};
|
|
232
|
-
return { kind: "native", before };
|
|
154
|
+
const delivery = this.#clipboard.copyText(text);
|
|
155
|
+
if (delivery !== undefined)
|
|
156
|
+
this.#trackCopy(delivery, cut ? undefined : text.length);
|
|
233
157
|
},
|
|
158
|
+
readClipboardContent: signal => this.#clipboard.readContent(signal),
|
|
159
|
+
captureClipboardPaste: () => this.#clipboard.capturePaste(),
|
|
234
160
|
...(pasteDiagnostics === undefined ? {} : { pasteDiagnostics: pasteDiagnostics }),
|
|
235
|
-
...(
|
|
236
|
-
pastePreparation: { ...pastePreparation, ...(sharedClipboard === undefined ? {} : { pool: sharedClipboard.paste }) },
|
|
237
|
-
}),
|
|
161
|
+
...(pastePreparationOptions === undefined ? {} : { pastePreparation: pastePreparationOptions }),
|
|
238
162
|
...(sharedKeybindings === undefined ? {} : { keybindings: sharedKeybindings }),
|
|
239
163
|
...(this.#promptImages === null ? {} : { promptImageLimit: this.#promptImages.limit }),
|
|
240
164
|
skillsPresentation: () => this.#skills?.presentation() ?? "expand",
|
|
@@ -251,68 +175,43 @@ export class OwnedUiSessionPresenter {
|
|
|
251
175
|
this.#dialogs = new SessionDialogCoordinator({
|
|
252
176
|
terminal: this.#terminal,
|
|
253
177
|
root: this.root,
|
|
254
|
-
routeHost: routeHost ?? null,
|
|
178
|
+
routeHost: routeHost ?? null, dialogs: options.presenters.components.dialogs,
|
|
255
179
|
disposed: () => this.#disposed,
|
|
256
180
|
exit: () => { void this.shutdown(); },
|
|
257
181
|
...(startupRoute === undefined ? {} : { startupRoute }),
|
|
258
182
|
});
|
|
259
183
|
constructed.push(() => this.#dialogs.dispose());
|
|
184
|
+
this.selectors = this.#createSelectors(options.presenters);
|
|
260
185
|
const initialPiSettings = this.backend.settings.snapshot();
|
|
261
|
-
this.#programStatus =
|
|
186
|
+
this.#programStatus = options.presenters.components.chrome.programStatusReporter(status => this.#terminal.setProgramStatus(status), () => this.view().status.footer?.sessionName ?? undefined);
|
|
262
187
|
this.#login = new LoginInteraction({
|
|
263
|
-
terminal: this.#terminal, root: this.root, programStatus: this.#programStatus,
|
|
188
|
+
terminal: this.#terminal, root: this.root, programStatus: this.#programStatus, dialogs: options.presenters.components.dialogs,
|
|
264
189
|
syncProgress: () => this.#syncTerminalProgress(this.view()),
|
|
265
190
|
});
|
|
266
191
|
this.#submission = this.#createSubmission(cwd);
|
|
267
192
|
this.#reloadPresentation = reloadPresentation;
|
|
268
|
-
|
|
269
|
-
this.#streamPresentation = streamPresentationOptions?.scheduler === undefined
|
|
270
|
-
? new StreamPresentationCoalescer(() => this.#terminal.requestRender(), presentationInterval)
|
|
271
|
-
: new StreamPresentationCoalescer(() => this.#terminal.requestRender(), presentationInterval, streamPresentationOptions.scheduler);
|
|
193
|
+
this.#streamPresentation = new StreamPresentationCoalescer(() => this.#terminal.requestRender(), streamPresentationOptions?.intervalMs ?? STREAM_PRESENTATION_INTERVAL_MS, streamPresentationOptions?.scheduler);
|
|
272
194
|
constructed.push(() => this.#streamPresentation.dispose());
|
|
273
|
-
|
|
274
|
-
promptSuggestionController = promptSuggestionOptions === undefined ? null : new ContextualPromptSuggestionController({
|
|
275
|
-
generator: promptSuggestionOptions.generator,
|
|
276
|
-
enabled: promptSuggestionOptions.enabled(),
|
|
277
|
-
...(promptSuggestionOptions.diagnostics === undefined ? {} : { diagnostics: promptSuggestionOptions.diagnostics }),
|
|
278
|
-
surface: promptSuggestionSurface(this.root, identity => this.#promptSuggestionPresentationBlockReason(identity), () => this.#terminal.requestRender()),
|
|
279
|
-
});
|
|
280
|
-
this.#promptSuggestions = promptSuggestionController;
|
|
195
|
+
this.#promptSuggestions = new ShellPromptSuggestions(this.#customViewport ? options.suggestions : undefined, promptSuggestionSurface(this.root, identity => suggestionPresentationBlockReason(identity, { disposed: this.#disposed, view: this.view(), sessionGeneration: this.backend.identity.sessionGeneration }, () => this.root.promptSuggestionPresentationBlockReason()), () => this.#terminal.requestRender()), this.backend.session.view());
|
|
281
196
|
constructed.push(() => this.#promptSuggestions?.dispose());
|
|
282
|
-
this.#
|
|
283
|
-
|
|
284
|
-
:
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
197
|
+
this.#fullscreenExitOutput = initialPiSettings.fullscreenExitOutput;
|
|
198
|
+
this.#unbindShellSettings = bindShellSettings({
|
|
199
|
+
customViewport: this.#customViewport, promptImages: this.#promptImages, skills: this.#skills,
|
|
200
|
+
viewport: viewportSettings, historyScope: promptHistory?.onScopeChange,
|
|
201
|
+
}, {
|
|
202
|
+
root: this.root,
|
|
203
|
+
promptImageLimitChanged: () => { if (!this.#disposed && this.root.reconcilePromptImageLimitNotice())
|
|
204
|
+
this.#terminal.requestRender(); },
|
|
205
|
+
skillsChanged: () => {
|
|
206
|
+
// Invariant: reinstalling drops extension provider wrappers, so an unrelated setting change leaves the list alone.
|
|
207
|
+
if (this.#disposed || this.#commandListSignature() === this.#installedCommandSignature)
|
|
208
|
+
return;
|
|
209
|
+
this.#installAutocompleteCommands();
|
|
288
210
|
this.#terminal.requestRender();
|
|
211
|
+
},
|
|
212
|
+
historyScopeChanged: scope => this.#rebindTranscript(scope),
|
|
289
213
|
});
|
|
290
|
-
constructed.push(this.#
|
|
291
|
-
// Rationale: the same listener refreshes the menu for the A1 presentation choice and for the engine's
|
|
292
|
-
// skill-command registration, both of which the owned settings manager reports through one change.
|
|
293
|
-
this.#unsubscribeSkills = this.#skills === null ? () => { } : this.#skills.onChange(() => {
|
|
294
|
-
// Invariant: reinstalling drops extension provider wrappers, so an unrelated setting change leaves the list alone.
|
|
295
|
-
if (this.#disposed || this.#commandListSignature() === this.#installedCommandSignature)
|
|
296
|
-
return;
|
|
297
|
-
this.#installAutocompleteCommands();
|
|
298
|
-
this.#terminal.requestRender();
|
|
299
|
-
});
|
|
300
|
-
constructed.push(this.#unsubscribeSkills);
|
|
301
|
-
this.#fullscreenExitOutput = initialPiSettings.fullscreenExitOutput;
|
|
302
|
-
const applyViewportSettings = () => {
|
|
303
|
-
const snapshot = viewportSettings?.snapshot();
|
|
304
|
-
this.root.setViewportConfig(snapshot ?? {
|
|
305
|
-
scrollbarAppearance: "auto",
|
|
306
|
-
scrollbarStyle: "thin",
|
|
307
|
-
scrollbarSpeed: "normal",
|
|
308
|
-
});
|
|
309
|
-
};
|
|
310
|
-
applyViewportSettings();
|
|
311
|
-
const unsubscribeViewport = this.#customViewport && viewportSettings ? viewportSettings.onChange(settings => this.root.setViewportConfig(settings)) : () => { };
|
|
312
|
-
const unsubscribeHistoryScope = this.#customViewport && promptHistory?.onScopeChange?.(scope => this.#rebindTranscript(scope));
|
|
313
|
-
this.#unsubscribeSettings = () => { unsubscribeViewport(); if (unsubscribeHistoryScope)
|
|
314
|
-
unsubscribeHistoryScope(); };
|
|
315
|
-
constructed.push(this.#unsubscribeSettings);
|
|
214
|
+
constructed.push(this.#unbindShellSettings);
|
|
316
215
|
this.#unbindSessionSettings = bindSessionSettings(this.backend.settings, initialPiSettings, {
|
|
317
216
|
terminal: this.#terminal,
|
|
318
217
|
root: this.root,
|
|
@@ -324,17 +223,8 @@ export class OwnedUiSessionPresenter {
|
|
|
324
223
|
}, { customViewport: this.#customViewport });
|
|
325
224
|
constructed.push(this.#unbindSessionSettings);
|
|
326
225
|
if (this.#customViewport && promptHistory !== undefined) {
|
|
327
|
-
this.#
|
|
328
|
-
this.#
|
|
329
|
-
editor: this.root.editor,
|
|
330
|
-
store: promptHistory.store,
|
|
331
|
-
limit: promptHistory.limit,
|
|
332
|
-
fallback: this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []),
|
|
333
|
-
active: () => this.root.usesDefaultInputSurface(),
|
|
334
|
-
render: () => this.#terminal.requestRender(),
|
|
335
|
-
rehydrate: value => this.root.rehydrateHistoryText(value, id => this.#historyBinding?.imageSidecar?.readAttachment(id) ?? null),
|
|
336
|
-
});
|
|
337
|
-
constructed.push(() => { void this.#promptHistory?.close().catch(() => false); });
|
|
226
|
+
this.#history = this.#createHistory(promptHistory);
|
|
227
|
+
constructed.push(() => { void this.#history?.close().catch(() => false); });
|
|
338
228
|
}
|
|
339
229
|
this.#extensionBridge = this.#createExtensionBridge();
|
|
340
230
|
constructed.push(() => this.#extensionBridge.dispose());
|
|
@@ -345,64 +235,16 @@ export class OwnedUiSessionPresenter {
|
|
|
345
235
|
prompt: request => this.#login.requestInput(request),
|
|
346
236
|
notify: event => this.#login.notify(event),
|
|
347
237
|
publish: message => {
|
|
348
|
-
this.root.
|
|
238
|
+
this.root.workflow.appendMessage(message);
|
|
349
239
|
this.#terminal.requestRender();
|
|
350
240
|
},
|
|
351
241
|
finishLogin: () => this.#login.finish(),
|
|
352
242
|
});
|
|
353
243
|
this.#installAutocompleteCommands();
|
|
354
|
-
this.#unsubscribe = this.backend.session.onEvent(event =>
|
|
355
|
-
// Invariant: once disposal begins no event touches the view; only the stop still settles the shell.
|
|
356
|
-
if (this.#disposed) {
|
|
357
|
-
if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
|
|
358
|
-
this.#stop.settleAfter(() => this.dispose());
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
// Performance: a streamed chunk names one block, and touching only that block is what keeps the
|
|
362
|
-
// cost of a chunk the same in a long session as in a new one. Everything else
|
|
363
|
-
// resynchronizes the view, which is cheap next to re-reading the transcript.
|
|
364
|
-
if (event.type === "agent-run-started") {
|
|
365
|
-
this.#promptSuggestions?.invalidate();
|
|
366
|
-
this.root.resumeViewportFollowing();
|
|
367
|
-
}
|
|
368
|
-
if (event.type === "assistant-message-completed" && !event.successful) {
|
|
369
|
-
this.#programStatus.setErrorMessage(this.view().status.diagnostics.at(-1));
|
|
370
|
-
}
|
|
371
|
-
if (event.type === "agent-run-started" || event.type === "assistant-message-completed" || event.type === "agent-run-settled") {
|
|
372
|
-
this.#programStatus.handleEvent(event);
|
|
373
|
-
}
|
|
374
|
-
if (event.type === "assistant-message-completed") {
|
|
375
|
-
this.root.noteCompletedAssistantMessage();
|
|
376
|
-
routeResponseToSuggestions(this.#promptSuggestions, event, () => this.root.promptSuggestionPrepareBlockReason());
|
|
377
|
-
}
|
|
378
|
-
const semanticOnly = event.type === "agent-run-started" || event.type === "assistant-message-completed";
|
|
379
|
-
const view = event.type === "transcript-block" && this.#sessionGeneration === this.backend.identity.sessionGeneration
|
|
380
|
-
? this.#syncBlock(event.block)
|
|
381
|
-
: semanticOnly ? this.view() : this.#syncView();
|
|
382
|
-
this.#syncTerminalProgress(view);
|
|
383
|
-
const currentModelKey = suggestionModelKey(view);
|
|
384
|
-
if (this.backend.identity.sessionGeneration !== this.#sessionGeneration || currentModelKey !== this.#suggestionModelKey) {
|
|
385
|
-
this.#promptSuggestions?.invalidate();
|
|
386
|
-
this.#suggestionModelKey = currentModelKey;
|
|
387
|
-
}
|
|
388
|
-
if (event.type === "status" && /^(Retrying|Compacting)/.test(event.status.workingMessage ?? "")) {
|
|
389
|
-
this.#promptSuggestions?.invalidate();
|
|
390
|
-
}
|
|
391
|
-
if (event.type === "agent-run-settled") {
|
|
392
|
-
routeResponseToSuggestions(this.#promptSuggestions, event, () => this.root.promptSuggestionPrepareBlockReason());
|
|
393
|
-
}
|
|
394
|
-
if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
|
|
395
|
-
this.#stop.settleAfter(() => this.dispose());
|
|
396
|
-
});
|
|
244
|
+
this.#unsubscribe = this.backend.session.onEvent(event => this.#onSessionEvent(event));
|
|
397
245
|
constructed.push(this.#unsubscribe);
|
|
398
|
-
this.#unbindClipboardWriter = this.#responseCopy === null ? () => { }
|
|
399
|
-
|
|
400
|
-
if (result.outcome === "delivered")
|
|
401
|
-
return true;
|
|
402
|
-
if (result.outcome === "submitted-unverified")
|
|
403
|
-
return false;
|
|
404
|
-
throw new Error(result.outcome === "timed-out" ? "Clipboard delivery timed out" : "Clipboard delivery could not be completed");
|
|
405
|
-
});
|
|
246
|
+
this.#unbindClipboardWriter = this.#clipboard.responseCopy === null ? () => { }
|
|
247
|
+
: this.backend.extensions.bindClipboardWriter(text => this.#clipboard.writeForExtension(text));
|
|
406
248
|
constructed.push(this.#unbindClipboardWriter);
|
|
407
249
|
if (this.backend.session.view().lifecycle === "stopped")
|
|
408
250
|
this.#stop.resolve();
|
|
@@ -439,7 +281,7 @@ export class OwnedUiSessionPresenter {
|
|
|
439
281
|
return this.root.inputCoordinationSurface();
|
|
440
282
|
}
|
|
441
283
|
setOverlaySurfaces(surfaces) {
|
|
442
|
-
this.root.
|
|
284
|
+
this.root.viewport.setOverlaySurfaces(surfaces);
|
|
443
285
|
}
|
|
444
286
|
noteImmediatePresentation() {
|
|
445
287
|
this.#streamPresentation.noteImmediatePresentation();
|
|
@@ -482,7 +324,7 @@ export class OwnedUiSessionPresenter {
|
|
|
482
324
|
const routed = this.root.handleViewportPreInput(data, true, Date.now(), this.root.usesDefaultInputSurface() && !this.#terminal.hasFocusedOverlay());
|
|
483
325
|
if (routed.copySelection !== undefined) {
|
|
484
326
|
const snapshot = routed.copySelection;
|
|
485
|
-
this.#trackCopy(this.#
|
|
327
|
+
this.#trackCopy(this.#clipboard.copySelection(snapshot), copyCharacters(snapshot));
|
|
486
328
|
}
|
|
487
329
|
if (routed.copyLastMessage)
|
|
488
330
|
void this.runWorkflow({ command: "copy", argument: "" });
|
|
@@ -490,24 +332,60 @@ export class OwnedUiSessionPresenter {
|
|
|
490
332
|
return routed.data === data ? undefined : { data: routed.data };
|
|
491
333
|
return routed.data.length === 0 ? { consume: true } : { data: routed.data };
|
|
492
334
|
}
|
|
335
|
+
#onSessionEvent(event) {
|
|
336
|
+
// Invariant: once disposal begins no event touches the view; only the stop still settles the shell.
|
|
337
|
+
if (this.#disposed) {
|
|
338
|
+
if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
|
|
339
|
+
this.#stop.settleAfter(() => this.dispose());
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
// Performance: a streamed chunk names one block, and touching only that block is what keeps the
|
|
343
|
+
// cost of a chunk the same in a long session as in a new one. Everything else
|
|
344
|
+
// resynchronizes the view, which is cheap next to re-reading the transcript.
|
|
345
|
+
if (event.type === "agent-run-started") {
|
|
346
|
+
this.#promptSuggestions?.invalidate();
|
|
347
|
+
this.root.viewport.resumeFollowing();
|
|
348
|
+
}
|
|
349
|
+
if (event.type === "assistant-message-completed" && !event.successful) {
|
|
350
|
+
this.#programStatus.setErrorMessage(this.view().status.diagnostics.at(-1));
|
|
351
|
+
}
|
|
352
|
+
if (event.type === "agent-run-started" || event.type === "assistant-message-completed" || event.type === "agent-run-settled") {
|
|
353
|
+
this.#programStatus.handleEvent(event);
|
|
354
|
+
}
|
|
355
|
+
if (event.type === "assistant-message-completed") {
|
|
356
|
+
this.root.viewport.noteCompletedAssistantMessage();
|
|
357
|
+
this.#promptSuggestions?.route(event, () => this.root.promptSuggestionPrepareBlockReason());
|
|
358
|
+
}
|
|
359
|
+
const semanticOnly = event.type === "agent-run-started" || event.type === "assistant-message-completed";
|
|
360
|
+
const view = event.type === "transcript-block" && this.#sessionGeneration === this.backend.identity.sessionGeneration
|
|
361
|
+
? this.#syncBlock(event.block)
|
|
362
|
+
: semanticOnly ? this.view() : this.#syncView();
|
|
363
|
+
this.#syncTerminalProgress(view);
|
|
364
|
+
this.#promptSuggestions?.noteView(view, this.backend.identity.sessionGeneration !== this.#sessionGeneration);
|
|
365
|
+
if (event.type === "status" && /^(Retrying|Compacting)/.test(event.status.workingMessage ?? "")) {
|
|
366
|
+
this.#promptSuggestions?.invalidate();
|
|
367
|
+
}
|
|
368
|
+
if (event.type === "agent-run-settled") {
|
|
369
|
+
this.#promptSuggestions?.route(event, () => this.root.promptSuggestionPrepareBlockReason());
|
|
370
|
+
}
|
|
371
|
+
if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
|
|
372
|
+
this.#stop.settleAfter(() => this.dispose());
|
|
373
|
+
}
|
|
493
374
|
#trackCopy(delivery, count) {
|
|
494
375
|
const intent = ++this.#copyIntentSequence;
|
|
495
376
|
void delivery?.then(({ outcome }) => {
|
|
496
377
|
if (count === undefined || this.#disposed || !this.#terminal.running || intent !== this.#copyIntentSequence
|
|
497
378
|
|| outcome !== "delivered" && outcome !== "submitted-unverified")
|
|
498
379
|
return;
|
|
499
|
-
this.root.showCopyAcknowledgement(copyAcknowledgementText(count));
|
|
380
|
+
this.root.chrome.showCopyAcknowledgement(copyAcknowledgementText(count));
|
|
500
381
|
});
|
|
501
382
|
}
|
|
502
|
-
#promptSuggestionPresentationBlockReason(identity) {
|
|
503
|
-
return suggestionPresentationBlockReason(identity, { disposed: this.#disposed, view: this.view(), sessionGeneration: this.backend.identity.sessionGeneration }, () => this.root.promptSuggestionPresentationBlockReason());
|
|
504
|
-
}
|
|
505
383
|
start() {
|
|
506
384
|
if (this.#started)
|
|
507
385
|
return;
|
|
508
386
|
this.#started = true;
|
|
509
387
|
this.#terminal.start();
|
|
510
|
-
this.#
|
|
388
|
+
this.#history?.start();
|
|
511
389
|
this.#syncTerminalProgress(this.view());
|
|
512
390
|
void this.backend.extensions.bindExtensionUi(this.#extensionBridge.context, () => { void this.shutdown(); });
|
|
513
391
|
this.#syncView();
|
|
@@ -516,16 +394,11 @@ export class OwnedUiSessionPresenter {
|
|
|
516
394
|
if (this.#disposed || !this.#customViewport)
|
|
517
395
|
return;
|
|
518
396
|
this.#dialogs.presentStartupRoute();
|
|
519
|
-
void this.#
|
|
520
|
-
this.root.
|
|
521
|
-
this.#
|
|
397
|
+
void this.#presenters.components.dialogs.lazySelectors().then(selectors => selectors.prepare()).catch(() => { });
|
|
398
|
+
this.root.promptChips.warm();
|
|
399
|
+
this.#clipboard.warm();
|
|
522
400
|
});
|
|
523
401
|
}
|
|
524
|
-
onView(listener) {
|
|
525
|
-
this.#listeners.add(listener);
|
|
526
|
-
listener(this.view());
|
|
527
|
-
return () => this.#listeners.delete(listener);
|
|
528
|
-
}
|
|
529
402
|
waitUntilStopped() {
|
|
530
403
|
return this.#stop.stopped;
|
|
531
404
|
}
|
|
@@ -562,9 +435,9 @@ export class OwnedUiSessionPresenter {
|
|
|
562
435
|
if (now - this.#lastEscapeTime < 500) {
|
|
563
436
|
this.#lastEscapeTime = 0;
|
|
564
437
|
if (action === "tree")
|
|
565
|
-
await this.showTreeSelector();
|
|
438
|
+
await this.selectors.showTreeSelector();
|
|
566
439
|
else
|
|
567
|
-
this.showForkSelector();
|
|
440
|
+
this.selectors.showForkSelector();
|
|
568
441
|
return { outcome: "completed", diagnostic: null };
|
|
569
442
|
}
|
|
570
443
|
this.#lastEscapeTime = now;
|
|
@@ -573,36 +446,6 @@ export class OwnedUiSessionPresenter {
|
|
|
573
446
|
async abort() {
|
|
574
447
|
return this.#submission.execute(this.#simple("abort"));
|
|
575
448
|
}
|
|
576
|
-
async retry() {
|
|
577
|
-
this.#promptSuggestions?.invalidate();
|
|
578
|
-
return this.#submission.execute(this.#simple("retry"));
|
|
579
|
-
}
|
|
580
|
-
async compact() {
|
|
581
|
-
this.#promptSuggestions?.invalidate();
|
|
582
|
-
return this.#submission.execute(this.#simple("compact"));
|
|
583
|
-
}
|
|
584
|
-
async newSession() {
|
|
585
|
-
this.#promptSuggestions?.invalidate();
|
|
586
|
-
return this.#submission.execute(this.#simple("new-session"));
|
|
587
|
-
}
|
|
588
|
-
async resumeSession(sessionPath) {
|
|
589
|
-
this.#promptSuggestions?.invalidate();
|
|
590
|
-
return this.#submission.execute({
|
|
591
|
-
type: "resume-session",
|
|
592
|
-
correlationId: this.#correlation("resume"),
|
|
593
|
-
sessionId: this.backend.identity.sessionId,
|
|
594
|
-
sessionPath,
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
async setModel(providerId, modelId) {
|
|
598
|
-
this.#promptSuggestions?.invalidate();
|
|
599
|
-
return this.#submission.execute({
|
|
600
|
-
type: "set-model",
|
|
601
|
-
correlationId: this.#correlation("model"),
|
|
602
|
-
sessionId: this.backend.identity.sessionId,
|
|
603
|
-
model: { providerId, modelId, displayName: modelId },
|
|
604
|
-
});
|
|
605
|
-
}
|
|
606
449
|
async setThinkingLevel(thinkingLevel) {
|
|
607
450
|
return this.#submission.execute({
|
|
608
451
|
type: "set-thinking-level",
|
|
@@ -618,7 +461,7 @@ export class OwnedUiSessionPresenter {
|
|
|
618
461
|
}
|
|
619
462
|
async cycleModel(direction) {
|
|
620
463
|
const result = await this.backend.workflows.cycleModelWorkflow(direction);
|
|
621
|
-
this.root.
|
|
464
|
+
this.root.workflow.appendResult(result);
|
|
622
465
|
this.#terminal.requestRender();
|
|
623
466
|
return workflowAdapterResult(result);
|
|
624
467
|
}
|
|
@@ -631,193 +474,6 @@ export class OwnedUiSessionPresenter {
|
|
|
631
474
|
showSelector(title, options, onSelect, onCancel) {
|
|
632
475
|
return this.#dialogs.showSelector(title, options, onSelect, onCancel);
|
|
633
476
|
}
|
|
634
|
-
// Rationale: presenters see the shell only as a dialog host; selectors open in the input dock and run choices as workflows.
|
|
635
|
-
#createDialogHost() {
|
|
636
|
-
const isDisposed = () => this.#disposed;
|
|
637
|
-
return {
|
|
638
|
-
get disposed() { return isDisposed(); },
|
|
639
|
-
setInputSurface: surface => this.root.setInputSurface(surface),
|
|
640
|
-
requestRender: () => this.#terminal.requestRender(),
|
|
641
|
-
viewport: () => this.#terminal.viewport(),
|
|
642
|
-
appendWorkflowStatus: text => this.root.appendWorkflowStatus(text),
|
|
643
|
-
appendWorkflowResult: result => this.root.appendWorkflowResult(result),
|
|
644
|
-
runWorkflow: request => this.runWorkflow(request),
|
|
645
|
-
// Invariant: the custom bare-A1 surface holds frames while optional selectors load and is permanently
|
|
646
|
-
// fullscreen; the pinned comparison profiles render immediately and keep Pi's TUI mode switch.
|
|
647
|
-
...(this.#customViewport
|
|
648
|
-
? { beginPresentationHold: () => this.#terminal.beginPresentationHold() }
|
|
649
|
-
: { switchTuiMode: mode => this.#terminal.switchMode(mode) }),
|
|
650
|
-
};
|
|
651
|
-
}
|
|
652
|
-
#loadLazySelectors() {
|
|
653
|
-
if (this.#lazySelectors !== undefined)
|
|
654
|
-
return Promise.resolve(this.#lazySelectors);
|
|
655
|
-
return this.#lazySelectorsPromise ??= import("../../integrations/pi/components/lazy-selectors.js").then(module => {
|
|
656
|
-
this.#lazySelectors = module.piShellLazySelectors;
|
|
657
|
-
return module.piShellLazySelectors;
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
async showThinkingSelector() {
|
|
661
|
-
const snapshot = this.backend.settings.snapshot();
|
|
662
|
-
const close = () => {
|
|
663
|
-
this.root.setFooterLevel(true);
|
|
664
|
-
this.root.setInputSurface(null);
|
|
665
|
-
this.#terminal.requestRender();
|
|
666
|
-
};
|
|
667
|
-
const select = (level) => {
|
|
668
|
-
close();
|
|
669
|
-
void this.runWorkflow({ command: "thinking", argument: "", selection: level });
|
|
670
|
-
};
|
|
671
|
-
const releasePresentation = this.#customViewport ? this.#terminal.beginPresentationHold() : undefined;
|
|
672
|
-
try {
|
|
673
|
-
const selectors = await this.#loadLazySelectors();
|
|
674
|
-
const component = await selectors.createThinking({
|
|
675
|
-
currentLevel: snapshot.thinkingLevel,
|
|
676
|
-
availableLevels: snapshot.availableThinkingLevels,
|
|
677
|
-
onSelect: select,
|
|
678
|
-
onCancel: close,
|
|
679
|
-
onSelectAsDefault: level => this.backend.settings.setDefaultThinkingLevel(level),
|
|
680
|
-
defaultLevel: snapshot.defaultThinkingLevel,
|
|
681
|
-
...(this.#customViewport ? {
|
|
682
|
-
presentation: {
|
|
683
|
-
profile: "bare",
|
|
684
|
-
cycleBinding: this.root.editor.keybindingConfig()["app.thinking.cycle"] ?? [],
|
|
685
|
-
},
|
|
686
|
-
} : {}),
|
|
687
|
-
});
|
|
688
|
-
if (this.#disposed)
|
|
689
|
-
return;
|
|
690
|
-
this.root.setFooterLevel(false);
|
|
691
|
-
this.root.setInputSurface(component);
|
|
692
|
-
this.#terminal.requestRender();
|
|
693
|
-
}
|
|
694
|
-
finally {
|
|
695
|
-
releasePresentation?.();
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
/** The Skills dialog: a replacement input like the model selector, applying the chosen skill through the prompt path. */
|
|
699
|
-
showSkillsSelector(skills = this.#skillSummaries()) {
|
|
700
|
-
const close = this.#dialogs.closeInputSurface;
|
|
701
|
-
const component = createPiShellSkillsSelector({
|
|
702
|
-
skills,
|
|
703
|
-
onSelect: name => {
|
|
704
|
-
close();
|
|
705
|
-
void this.#submission.sendSlashPrompt(skillPrompt(name), skillPrompt(name)).catch(() => this.#submission.reportError());
|
|
706
|
-
},
|
|
707
|
-
onCancel: close,
|
|
708
|
-
});
|
|
709
|
-
this.root.setInputSurface(component);
|
|
710
|
-
this.#terminal.requestRender();
|
|
711
|
-
}
|
|
712
|
-
showModelSelector(initialSearchInput) {
|
|
713
|
-
this.#presenters.openModelSelector(this.#dialogHost, initialSearchInput);
|
|
714
|
-
}
|
|
715
|
-
showForkSelector() {
|
|
716
|
-
const options = this.backend.catalog.pinnedForkOptions();
|
|
717
|
-
if (options.length === 0) {
|
|
718
|
-
this.root.appendWorkflowResult({ command: "fork", outcome: "completed", message: "No messages to fork from", messageKind: "status" });
|
|
719
|
-
this.#terminal.requestRender();
|
|
720
|
-
return;
|
|
721
|
-
}
|
|
722
|
-
const close = this.#dialogs.closeInputSurface;
|
|
723
|
-
const component = createPiShellUserMessageSelector(options, selection => {
|
|
724
|
-
close();
|
|
725
|
-
void this.runWorkflow({ command: "fork", argument: "", selection });
|
|
726
|
-
}, close);
|
|
727
|
-
this.root.setInputSurface(component);
|
|
728
|
-
this.#terminal.requestRender();
|
|
729
|
-
}
|
|
730
|
-
async showLogoutSelector() {
|
|
731
|
-
let options;
|
|
732
|
-
try {
|
|
733
|
-
options = await this.backend.catalog.pinnedLogoutOptions();
|
|
734
|
-
}
|
|
735
|
-
catch (error) {
|
|
736
|
-
this.root.appendWorkflowResult({
|
|
737
|
-
command: "logout",
|
|
738
|
-
outcome: "failed",
|
|
739
|
-
message: `Could not read stored credentials: ${error instanceof Error ? error.message : String(error)}`,
|
|
740
|
-
});
|
|
741
|
-
this.#terminal.requestRender();
|
|
742
|
-
return;
|
|
743
|
-
}
|
|
744
|
-
if (options.length === 0) {
|
|
745
|
-
this.root.appendWorkflowStatus("No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.");
|
|
746
|
-
this.#terminal.requestRender();
|
|
747
|
-
return;
|
|
748
|
-
}
|
|
749
|
-
const close = this.#dialogs.closeInputSurface;
|
|
750
|
-
const component = createPiShellAuthProviderSelector("logout", options, selection => {
|
|
751
|
-
close();
|
|
752
|
-
void this.runWorkflow({ command: "logout", argument: "", selection });
|
|
753
|
-
}, close);
|
|
754
|
-
this.root.setInputSurface(component);
|
|
755
|
-
this.#terminal.requestRender();
|
|
756
|
-
}
|
|
757
|
-
showLoginMethodSelector(providerReference) {
|
|
758
|
-
const method = this.backend.catalog.pinnedLoginMethodOptions(providerReference);
|
|
759
|
-
if (method.options.length === 0) {
|
|
760
|
-
this.showLoginProviderSelector(undefined, providerReference);
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
|
-
if (method.options.length === 1) {
|
|
764
|
-
const selection = method.options[0]?.id;
|
|
765
|
-
if (selection)
|
|
766
|
-
void this.runWorkflow({ command: "login", argument: "", selection });
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
|
-
const close = this.#dialogs.closeInputSurface;
|
|
770
|
-
const labels = method.options.map(option => option.label);
|
|
771
|
-
const component = createPiShellExtensionSelector(method.title, labels, label => {
|
|
772
|
-
const selection = method.options.find(option => option.label === label)?.id;
|
|
773
|
-
if (!selection)
|
|
774
|
-
return;
|
|
775
|
-
close();
|
|
776
|
-
void this.runWorkflow({ command: "login", argument: "", selection });
|
|
777
|
-
}, close);
|
|
778
|
-
this.root.setInputSurface(component);
|
|
779
|
-
this.#terminal.requestRender();
|
|
780
|
-
}
|
|
781
|
-
showTreeSelector(initialSelectedId) {
|
|
782
|
-
return this.#presenters.openTreeSelector(this.#dialogHost, (entryId, skipSummaryPrompt) => {
|
|
783
|
-
void this.#completeTreeSelection(entryId, skipSummaryPrompt);
|
|
784
|
-
}, initialSelectedId);
|
|
785
|
-
}
|
|
786
|
-
showLoginAuthTypeSelector() {
|
|
787
|
-
const close = this.#dialogs.closeInputSurface;
|
|
788
|
-
const labels = ["Sign in with an account", "Sign in with an API key"];
|
|
789
|
-
const component = createPiShellExtensionSelector("Select authentication method:", labels, label => {
|
|
790
|
-
close();
|
|
791
|
-
this.showLoginProviderSelector(label === labels[0] ? "oauth" : "api_key");
|
|
792
|
-
}, close);
|
|
793
|
-
this.root.setInputSurface(component);
|
|
794
|
-
this.#terminal.requestRender();
|
|
795
|
-
}
|
|
796
|
-
showLoginProviderSelector(authType, initialSearchInput) {
|
|
797
|
-
const options = this.backend.catalog.pinnedLoginOptions(authType);
|
|
798
|
-
if (options.length === 0) {
|
|
799
|
-
this.root.appendWorkflowStatus(authType === "oauth" ? "No account providers available." : authType === "api_key" ? "No API key providers available." : "No login providers available.");
|
|
800
|
-
this.#terminal.requestRender();
|
|
801
|
-
return;
|
|
802
|
-
}
|
|
803
|
-
const close = this.#dialogs.closeInputSurface;
|
|
804
|
-
const component = createPiShellAuthProviderSelector("login", options, id => {
|
|
805
|
-
close();
|
|
806
|
-
void this.runWorkflow({ command: "login", argument: "", selection: id });
|
|
807
|
-
}, () => {
|
|
808
|
-
close();
|
|
809
|
-
if (authType !== undefined)
|
|
810
|
-
this.showLoginAuthTypeSelector();
|
|
811
|
-
}, initialSearchInput);
|
|
812
|
-
this.root.setInputSurface(component);
|
|
813
|
-
this.#terminal.requestRender();
|
|
814
|
-
}
|
|
815
|
-
showSessionSelector() {
|
|
816
|
-
return this.#presenters.openSessionSelector(this.#dialogHost, () => { void this.shutdown(); });
|
|
817
|
-
}
|
|
818
|
-
showSettingsSelector() {
|
|
819
|
-
this.#presenters.openSettingsSelector(this.#dialogHost);
|
|
820
|
-
}
|
|
821
477
|
shutdown() {
|
|
822
478
|
this.#shutdownPromise ??= this.#shutdown().finally(() => {
|
|
823
479
|
// Invariant: a failed quit is retryable; ordinary shutdown has disposed the shell already.
|
|
@@ -860,7 +516,7 @@ export class OwnedUiSessionPresenter {
|
|
|
860
516
|
}).catch(error => {
|
|
861
517
|
if (this.#disposed)
|
|
862
518
|
return;
|
|
863
|
-
this.root.
|
|
519
|
+
this.root.workflow.appendResult({ command: "name", outcome: "failed", message: error instanceof Error ? error.message : String(error) });
|
|
864
520
|
this.#terminal.requestRender();
|
|
865
521
|
});
|
|
866
522
|
return { outcome: "completed", diagnostic: null };
|
|
@@ -870,20 +526,20 @@ export class OwnedUiSessionPresenter {
|
|
|
870
526
|
const setup = this.backend.catalog.pinnedAmbientAuthentication(request.selection);
|
|
871
527
|
if (setup) {
|
|
872
528
|
const close = this.#dialogs.closeInputSurface;
|
|
873
|
-
const dialog =
|
|
529
|
+
const dialog = this.#presenters.components.dialogs.loginDialog(componentRuntime(this.#terminal), setup.providerId, close, setup.providerName, setup.title);
|
|
874
530
|
dialog.showInfo(setup.message, [], true);
|
|
875
531
|
this.root.setInputSurface(dialog);
|
|
876
532
|
this.#terminal.requestRender();
|
|
877
533
|
return { outcome: "completed", diagnostic: null };
|
|
878
534
|
}
|
|
879
535
|
}
|
|
880
|
-
const selected = openWorkflowSelector(request, this);
|
|
536
|
+
const selected = openWorkflowSelector(request, this.selectors);
|
|
881
537
|
if (selected !== undefined)
|
|
882
538
|
return selected;
|
|
883
539
|
if (request.command === "reload") {
|
|
884
540
|
const blocked = this.backend.workflows.reloadBlockedResult();
|
|
885
541
|
if (blocked) {
|
|
886
|
-
this.root.
|
|
542
|
+
this.root.workflow.appendResult(blocked);
|
|
887
543
|
this.#terminal.requestRender();
|
|
888
544
|
return workflowAdapterResult(blocked);
|
|
889
545
|
}
|
|
@@ -893,8 +549,8 @@ export class OwnedUiSessionPresenter {
|
|
|
893
549
|
? await import("./share-operation.js")
|
|
894
550
|
: undefined;
|
|
895
551
|
const shareSurface = shareDialog === undefined ? undefined
|
|
896
|
-
:
|
|
897
|
-
const operationSurface = shareSurface ?? (request.command === "reload" ?
|
|
552
|
+
: await this.#presenters.components.dialogs.shareProgress(componentRuntime(this.#terminal), "Creating gist…", this.#customViewport ? "dialog" : "loader");
|
|
553
|
+
const operationSurface = shareSurface ?? (request.command === "reload" ? this.#presenters.components.info.reloadBox() : undefined);
|
|
898
554
|
const now = this.#reloadPresentation?.now ?? Date.now;
|
|
899
555
|
const shownAt = now();
|
|
900
556
|
if (operationSurface) {
|
|
@@ -925,9 +581,9 @@ export class OwnedUiSessionPresenter {
|
|
|
925
581
|
if (result.outcome === "requires-selection" && request.command === "model") {
|
|
926
582
|
if (result.messages !== undefined) {
|
|
927
583
|
for (const message of result.messages)
|
|
928
|
-
this.root.
|
|
584
|
+
this.root.workflow.appendMessage(message);
|
|
929
585
|
}
|
|
930
|
-
this.showModelSelector((result.detail ?? request.argument.trim()) || undefined);
|
|
586
|
+
this.selectors.showModelSelector((result.detail ?? request.argument.trim()) || undefined);
|
|
931
587
|
return { outcome: "completed", diagnostic: null };
|
|
932
588
|
}
|
|
933
589
|
if (result.outcome === "requires-confirmation" && request.command === "resume") {
|
|
@@ -944,7 +600,7 @@ export class OwnedUiSessionPresenter {
|
|
|
944
600
|
});
|
|
945
601
|
}
|
|
946
602
|
if (result.outcome === "requires-selection" || result.outcome === "requires-confirmation") {
|
|
947
|
-
this.root.
|
|
603
|
+
this.root.workflow.appendResult({ command: request.command, outcome: "failed", message: `Owned controller missing for ${request.command}` });
|
|
948
604
|
this.#terminal.requestRender();
|
|
949
605
|
return { outcome: "failed", diagnostic: `Owned controller missing for ${request.command}` };
|
|
950
606
|
}
|
|
@@ -956,13 +612,13 @@ export class OwnedUiSessionPresenter {
|
|
|
956
612
|
if (request.command === "tree" && result.outcome === "completed") {
|
|
957
613
|
if (result.detail && !this.root.editor.getText().trim())
|
|
958
614
|
this.root.editor.setText(result.detail);
|
|
959
|
-
this.root.
|
|
615
|
+
this.root.viewport.resumeFollowing();
|
|
960
616
|
}
|
|
961
617
|
if (shareDialog !== undefined && this.#customViewport && result.outcome === "completed" && result.detail !== undefined) {
|
|
962
|
-
this.root.
|
|
618
|
+
this.root.workflow.appendStatus(shareDialog.renderShellShareResult(result.message, result.detail, this.#presenters.theme.current(), url => this.#presenters.components.text.hyperlink(url)));
|
|
963
619
|
}
|
|
964
620
|
else {
|
|
965
|
-
this.root.
|
|
621
|
+
this.root.workflow.appendResult(result);
|
|
966
622
|
}
|
|
967
623
|
this.#terminal.requestRender();
|
|
968
624
|
return workflowAdapterResult(result);
|
|
@@ -975,40 +631,11 @@ export class OwnedUiSessionPresenter {
|
|
|
975
631
|
const sleep = this.#reloadPresentation?.sleep ?? ((ms) => new Promise(resolve => setTimeout(resolve, ms)));
|
|
976
632
|
await sleep(remaining);
|
|
977
633
|
}
|
|
978
|
-
showTrustSelector() {
|
|
979
|
-
const context = this.backend.catalog.pinnedProjectTrustContext();
|
|
980
|
-
const close = this.#dialogs.closeInputSurface;
|
|
981
|
-
const component = createPiShellTrustSelector({
|
|
982
|
-
...context,
|
|
983
|
-
onSelect: selection => {
|
|
984
|
-
try {
|
|
985
|
-
this.backend.catalog.persistProjectTrust(selection.updates);
|
|
986
|
-
close();
|
|
987
|
-
this.root.appendWorkflowStatus(`Saved trust decision: ${selection.trusted ? "trusted" : "untrusted"}. Restart pi for this to take effect.`);
|
|
988
|
-
}
|
|
989
|
-
catch (error) {
|
|
990
|
-
close();
|
|
991
|
-
this.root.appendWorkflowResult({ command: "trust", outcome: "failed", message: error instanceof Error ? error.message : String(error) });
|
|
992
|
-
}
|
|
993
|
-
this.#terminal.requestRender();
|
|
994
|
-
},
|
|
995
|
-
onCancel: close,
|
|
996
|
-
});
|
|
997
|
-
this.root.setInputSurface(component);
|
|
998
|
-
this.#terminal.requestRender();
|
|
999
|
-
}
|
|
1000
|
-
showScopedModelsSelector() {
|
|
1001
|
-
this.#presenters.openScopedModelsSelector(this.#dialogHost);
|
|
1002
|
-
}
|
|
1003
634
|
// Invariant: bare A1 routes `models`; the comparison profile keeps the pinned `model`/`scoped-models` pair. Hidden routes are shared.
|
|
1004
635
|
#isWorkflowRoute(value) {
|
|
1005
|
-
return
|
|
636
|
+
return this.#presenters.components.workflows.commandNames(this.backend.settings.productMode).includes(value)
|
|
1006
637
|
|| OWNED_UI_HIDDEN_COMMAND_NAMES.includes(value);
|
|
1007
638
|
}
|
|
1008
|
-
/** The bare-A1 unified Models dialog: switch on Enter, scope on Space, persist on Ctrl+S, all through the engine. */
|
|
1009
|
-
showModelsDialog(initialQuery) {
|
|
1010
|
-
this.#presenters.openModelsDialog(this.#dialogHost, initialQuery);
|
|
1011
|
-
}
|
|
1012
639
|
// Invariant: one teardown per presenter, starting on a microtask so never inside the event listener that
|
|
1013
640
|
// requested it. Callers during the teardown share its outcome; a later call finds it done. Closing the
|
|
1014
641
|
// terminal host's last presenter ends the terminal.
|
|
@@ -1039,20 +666,16 @@ export class OwnedUiSessionPresenter {
|
|
|
1039
666
|
// Invariant: events stop first, so nothing re-enters the view during history close, outro, or restoration.
|
|
1040
667
|
attempt(() => this.#unsubscribe());
|
|
1041
668
|
this.#copyIntentSequence += 1;
|
|
1042
|
-
this.#
|
|
1043
|
-
this.#copyExecutor?.dispose();
|
|
669
|
+
this.#clipboard.dispose();
|
|
1044
670
|
this.#submission.cancelWaiting();
|
|
1045
671
|
let pasteCleanup = Promise.resolve();
|
|
1046
672
|
let historyCleanup = Promise.resolve(true);
|
|
1047
|
-
attempt(() => { historyCleanup = this.#
|
|
673
|
+
attempt(() => { historyCleanup = this.#history?.close() ?? Promise.resolve(true); });
|
|
1048
674
|
attempt(() => { pasteCleanup = this.root.disposePendingPastes(); });
|
|
1049
|
-
attempt(() => this.root.
|
|
675
|
+
attempt(() => this.root.viewport.clearPointerState());
|
|
1050
676
|
attempt(() => this.#streamPresentation.dispose());
|
|
1051
677
|
attempt(() => this.#promptSuggestions?.dispose());
|
|
1052
|
-
attempt(() => this.#
|
|
1053
|
-
attempt(() => this.#unsubscribePromptImages());
|
|
1054
|
-
attempt(() => this.#unsubscribeSkills());
|
|
1055
|
-
attempt(() => this.#unsubscribeSettings());
|
|
678
|
+
attempt(() => this.#unbindShellSettings());
|
|
1056
679
|
let exitText = "";
|
|
1057
680
|
attempt(() => {
|
|
1058
681
|
exitText = composeExitText({
|
|
@@ -1060,7 +683,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1060
683
|
customViewport: this.#customViewport,
|
|
1061
684
|
exitMode: this.backend.identity.disposed ? this.#fullscreenExitOutput : this.backend.settings.snapshot().fullscreenExitOutput,
|
|
1062
685
|
resume: this.backend.identity.currentSessionResumeMetadata(),
|
|
1063
|
-
transcript: () => this.root.exitTranscript(terminal.columns),
|
|
686
|
+
transcript: () => this.root.transcript.exitTranscript(terminal.columns),
|
|
1064
687
|
});
|
|
1065
688
|
});
|
|
1066
689
|
attempt(() => this.#unbindClipboardWriter());
|
|
@@ -1088,7 +711,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1088
711
|
}
|
|
1089
712
|
// Invariant: incremental block updates notify listeners with the same complete view contract.
|
|
1090
713
|
#syncBlock(block) {
|
|
1091
|
-
this.root.
|
|
714
|
+
this.root.transcript.apply(block);
|
|
1092
715
|
if (this.#customViewport && block.status === "live" && isCoalescedStreamBlock(block.kind)) {
|
|
1093
716
|
this.#streamPresentation.request();
|
|
1094
717
|
}
|
|
@@ -1099,13 +722,11 @@ export class OwnedUiSessionPresenter {
|
|
|
1099
722
|
this.#streamPresentation.presentImmediate();
|
|
1100
723
|
}
|
|
1101
724
|
const view = this.view();
|
|
1102
|
-
for (const listener of this.#listeners)
|
|
1103
|
-
listener(view);
|
|
1104
725
|
return view;
|
|
1105
726
|
}
|
|
1106
727
|
// Rationale: extensions reach the shell only through this bridge; every surface they draw lands in the root.
|
|
1107
728
|
#createExtensionBridge() {
|
|
1108
|
-
return
|
|
729
|
+
return this.#presenters.components.dialogs.extensionUiBridge({
|
|
1109
730
|
runtime: componentRuntime(this.#terminal),
|
|
1110
731
|
agentDir: this.backend.identity.agentDir,
|
|
1111
732
|
setInputSurface: component => this.root.setInputSurface(component, true, "opaque"),
|
|
@@ -1129,14 +750,40 @@ export class OwnedUiSessionPresenter {
|
|
|
1129
750
|
setToolsExpanded: expanded => this.root.setToolsExpanded(expanded),
|
|
1130
751
|
});
|
|
1131
752
|
}
|
|
753
|
+
#createSelectors(presenters) {
|
|
754
|
+
return new SessionSelectors({
|
|
755
|
+
root: this.root,
|
|
756
|
+
terminal: this.#terminal,
|
|
757
|
+
dialogs: this.#dialogs,
|
|
758
|
+
presenters,
|
|
759
|
+
backend: this.backend,
|
|
760
|
+
customViewport: this.#customViewport,
|
|
761
|
+
disposed: () => this.#disposed,
|
|
762
|
+
runWorkflow: request => this.runWorkflow(request),
|
|
763
|
+
sendSlashPrompt: (text, typed) => this.#submission.sendSlashPrompt(text, typed),
|
|
764
|
+
reportError: () => this.#submission.reportError(),
|
|
765
|
+
input: (title, placeholder, inputOptions) => this.#extensionBridge.input(title, placeholder, inputOptions),
|
|
766
|
+
shutdown: () => { void this.shutdown(); },
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
#createHistory(promptHistory) {
|
|
770
|
+
return new SessionPromptHistory(promptHistory, {
|
|
771
|
+
editor: this.root.editor,
|
|
772
|
+
usesDefaultInputSurface: () => this.root.usesDefaultInputSurface(),
|
|
773
|
+
rehydrate: (text, resolveImage) => this.root.promptChips.rehydrateHistoryText(text, resolveImage),
|
|
774
|
+
requestRender: () => this.#terminal.requestRender(),
|
|
775
|
+
transcript: () => this.view().transcript,
|
|
776
|
+
currentHistorySessionId: () => this.backend.identity.currentHistorySessionId(),
|
|
777
|
+
});
|
|
778
|
+
}
|
|
1132
779
|
#createSubmission(cwd) {
|
|
1133
780
|
return new PromptSubmission({
|
|
1134
781
|
backend: this.backend,
|
|
1135
782
|
root: this.root,
|
|
1136
783
|
terminal: this.#terminal,
|
|
1137
|
-
cwd,
|
|
1138
|
-
promptHistory: () => this.#
|
|
1139
|
-
imageSidecar: () => this.#
|
|
784
|
+
cwd, statusText: this.#presenters.components.info.statusText,
|
|
785
|
+
promptHistory: () => this.#history?.controller ?? null,
|
|
786
|
+
imageSidecar: () => this.#history?.imageSidecar,
|
|
1140
787
|
disposed: () => this.#disposed,
|
|
1141
788
|
correlation: prefix => this.#correlation(prefix),
|
|
1142
789
|
lifecycle: () => this.view().lifecycle,
|
|
@@ -1148,7 +795,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1148
795
|
// Invariant: the order is the reset order on session replacement; copy intent before pastes before the input surface.
|
|
1149
796
|
#createConcerns() {
|
|
1150
797
|
return new SessionConcerns([
|
|
1151
|
-
{ onSessionReplaced: () => { this.#copyIntentSequence += 1; this.#
|
|
798
|
+
{ onSessionReplaced: () => { this.#copyIntentSequence += 1; this.#clipboard.reset(); } },
|
|
1152
799
|
this.#submission,
|
|
1153
800
|
{ onSessionReplaced: () => this.root.resetPendingPastes() },
|
|
1154
801
|
{ onSessionReplaced: () => this.#promptSuggestions?.invalidate() },
|
|
@@ -1157,7 +804,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1157
804
|
this.#login,
|
|
1158
805
|
{ onSessionReplaced: () => this.#extensionBridge.reset() },
|
|
1159
806
|
// Invariant: a replaced session takes its transient viewport and owned-route state with it.
|
|
1160
|
-
{ onSessionReplaced: () => this.root.
|
|
807
|
+
{ onSessionReplaced: () => this.root.viewport.reset() },
|
|
1161
808
|
this.#dialogs,
|
|
1162
809
|
{ onSessionReplaced: () => this.root.setInputSurface(null) },
|
|
1163
810
|
{ onSessionReplaced: () => this.root.resetExtensionUi() },
|
|
@@ -1171,50 +818,9 @@ export class OwnedUiSessionPresenter {
|
|
|
1171
818
|
return;
|
|
1172
819
|
if (replaced) {
|
|
1173
820
|
this.#sessionBindingGeneration = this.backend.identity.sessionBindingGeneration;
|
|
1174
|
-
this.root.
|
|
1175
|
-
}
|
|
1176
|
-
const binding = this.#historyBinding;
|
|
1177
|
-
if (binding?.options.forSession !== undefined || binding?.options.forScope !== undefined) {
|
|
1178
|
-
const sessionId = this.backend.identity.currentHistorySessionId();
|
|
1179
|
-
const selectedScope = scope ?? binding.scope;
|
|
1180
|
-
if (selectedScope !== binding.scope || sessionId !== binding.sessionId) {
|
|
1181
|
-
if (!replaced)
|
|
1182
|
-
this.root.editor.recall?.restoreDraft?.();
|
|
1183
|
-
const previous = this.#promptHistory;
|
|
1184
|
-
this.#promptHistory = null;
|
|
1185
|
-
binding.imageSidecar = undefined;
|
|
1186
|
-
binding.scope = selectedScope;
|
|
1187
|
-
binding.sessionId = sessionId ?? undefined;
|
|
1188
|
-
void previous?.close().catch(() => false);
|
|
1189
|
-
const destination = binding.options.forScope !== undefined
|
|
1190
|
-
? binding.options.forScope(selectedScope, sessionId)
|
|
1191
|
-
: sessionId === null ? null : binding.options.forSession(sessionId);
|
|
1192
|
-
if (destination !== null) {
|
|
1193
|
-
binding.imageSidecar = destination.imageSidecar;
|
|
1194
|
-
const controller = new PromptHistoryController({
|
|
1195
|
-
editor: this.root.editor,
|
|
1196
|
-
store: destination.store,
|
|
1197
|
-
limit: binding.options.limit,
|
|
1198
|
-
fallback: replaced ? this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []) : [],
|
|
1199
|
-
active: () => this.root.usesDefaultInputSurface(),
|
|
1200
|
-
render: () => this.#terminal.requestRender(),
|
|
1201
|
-
rehydrate: value => this.root.rehydrateHistoryText(value, id => this.#historyBinding?.imageSidecar?.readAttachment(id) ?? null),
|
|
1202
|
-
});
|
|
1203
|
-
this.#promptHistory = controller;
|
|
1204
|
-
if (this.#started)
|
|
1205
|
-
controller.start();
|
|
1206
|
-
}
|
|
1207
|
-
else {
|
|
1208
|
-
// Security: missing identity must not reopen Shared or retain another session's recall.
|
|
1209
|
-
const fallback = replaced ? this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []).reverse() : [];
|
|
1210
|
-
this.root.editor.recall?.reset();
|
|
1211
|
-
this.root.editor.recall?.replace(fallback);
|
|
1212
|
-
}
|
|
1213
|
-
return;
|
|
1214
|
-
}
|
|
821
|
+
this.root.transcript.reset();
|
|
1215
822
|
}
|
|
1216
|
-
|
|
1217
|
-
this.#promptHistory?.reset(this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []));
|
|
823
|
+
this.#history?.rebind(replaced, scope);
|
|
1218
824
|
}
|
|
1219
825
|
#syncTerminalProgress(view) {
|
|
1220
826
|
if (!this.#terminal.running)
|
|
@@ -1241,8 +847,6 @@ export class OwnedUiSessionPresenter {
|
|
|
1241
847
|
this.#dialogs.syncBackend(view.dialog);
|
|
1242
848
|
this.#presentStartupTrustWarning(view);
|
|
1243
849
|
this.#terminal.requestRender();
|
|
1244
|
-
for (const listener of this.#listeners)
|
|
1245
|
-
listener(view);
|
|
1246
850
|
return view;
|
|
1247
851
|
}
|
|
1248
852
|
// Rationale: a cancelled or failed trust choice explains the restricted session where the
|
|
@@ -1254,7 +858,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1254
858
|
if (diagnostic === undefined || !this.#terminal.running)
|
|
1255
859
|
return;
|
|
1256
860
|
this.#startupTrustHandled = true;
|
|
1257
|
-
this.root.
|
|
861
|
+
this.root.workflow.appendMessage({ kind: "warning", message: diagnostic.message });
|
|
1258
862
|
}
|
|
1259
863
|
openOwnedRoute(route) {
|
|
1260
864
|
if (this.#disposed)
|
|
@@ -1267,7 +871,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1267
871
|
}
|
|
1268
872
|
const result = this.#dialogs.openRoute(route);
|
|
1269
873
|
if (result.outcome !== "completed" && result.diagnostic !== null) {
|
|
1270
|
-
this.root.
|
|
874
|
+
this.root.workflow.appendMessage({ kind: "warning", message: result.diagnostic });
|
|
1271
875
|
}
|
|
1272
876
|
}
|
|
1273
877
|
hotkeysPresentation() {
|
|
@@ -1283,9 +887,9 @@ export class OwnedUiSessionPresenter {
|
|
|
1283
887
|
if (this.#isWorkflowRoute(name))
|
|
1284
888
|
return this.runWorkflow({ command: name, argument });
|
|
1285
889
|
if (this.#skillsCollapsed()) {
|
|
1286
|
-
if (name ===
|
|
890
|
+
if (name === this.#presenters.components.skills.commandName)
|
|
1287
891
|
return this.#runSkillsCommand(text, argument);
|
|
1288
|
-
const rewritten =
|
|
892
|
+
const rewritten = this.#presenters.components.skills.rewriteTunnelSubmission(text);
|
|
1289
893
|
if (rewritten !== text)
|
|
1290
894
|
return this.#submission.sendSlashPrompt(rewritten, text);
|
|
1291
895
|
}
|
|
@@ -1305,65 +909,26 @@ export class OwnedUiSessionPresenter {
|
|
|
1305
909
|
&& !this.backend.identity.disposed && this.backend.settings.snapshot().enableSkillCommands;
|
|
1306
910
|
}
|
|
1307
911
|
#skillSummaries() {
|
|
1308
|
-
return
|
|
912
|
+
return this.#presenters.components.skills.fromCommands(this.backend.workflows.workflowAutocompleteCommands());
|
|
1309
913
|
}
|
|
1310
914
|
// Protocol: bare "/skills" opens the dialog, "/skills <name> [args]" applies directly, and an unknown name is a command outcome.
|
|
1311
915
|
async #runSkillsCommand(text, argument) {
|
|
1312
916
|
const skills = this.#skillSummaries();
|
|
1313
917
|
const trimmed = argument.trim();
|
|
1314
918
|
if (trimmed.length === 0) {
|
|
1315
|
-
this.showSkillsSelector(skills);
|
|
919
|
+
this.selectors.showSkillsSelector(skills);
|
|
1316
920
|
return { outcome: "completed", diagnostic: null };
|
|
1317
921
|
}
|
|
1318
922
|
const separator = trimmed.search(/\s/u);
|
|
1319
923
|
const token = separator < 0 ? trimmed : trimmed.slice(0, separator);
|
|
1320
|
-
const skill =
|
|
924
|
+
const skill = this.#presenters.components.skills.findByArgument(skills, token);
|
|
1321
925
|
if (skill === undefined) {
|
|
1322
926
|
const message = "Unknown skill: " + token;
|
|
1323
|
-
this.root.
|
|
927
|
+
this.root.workflow.appendMessage({ kind: "error", message });
|
|
1324
928
|
this.#terminal.requestRender();
|
|
1325
929
|
return { outcome: "failed", diagnostic: message };
|
|
1326
930
|
}
|
|
1327
|
-
return this.#submission.sendSlashPrompt(
|
|
1328
|
-
}
|
|
1329
|
-
#treeSummary() {
|
|
1330
|
-
return new Promise(resolve => {
|
|
1331
|
-
this.root.setInputSurface(createPiShellExtensionSelector("Summarize Branch?", ["No summary", "Summarize", "Summarize with custom prompt"], resolve, () => resolve(undefined)), true, "opaque");
|
|
1332
|
-
this.#terminal.requestRender();
|
|
1333
|
-
});
|
|
1334
|
-
}
|
|
1335
|
-
async #completeTreeSelection(entryId, skipSummaryPrompt) {
|
|
1336
|
-
let summarize = false;
|
|
1337
|
-
let customInstructions;
|
|
1338
|
-
if (!skipSummaryPrompt) {
|
|
1339
|
-
while (true) {
|
|
1340
|
-
const choice = await this.#treeSummary();
|
|
1341
|
-
if (choice === undefined) {
|
|
1342
|
-
await this.showTreeSelector(entryId);
|
|
1343
|
-
return;
|
|
1344
|
-
}
|
|
1345
|
-
summarize = choice !== "No summary";
|
|
1346
|
-
if (choice === "Summarize with custom prompt") {
|
|
1347
|
-
customInstructions = await this.#extensionBridge.input("Custom Summarization Instructions", "", { retainSurfaceOnSettle: true });
|
|
1348
|
-
if (customInstructions === undefined)
|
|
1349
|
-
continue;
|
|
1350
|
-
}
|
|
1351
|
-
break;
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
this.root.setInputSurface(null);
|
|
1355
|
-
this.#terminal.requestRender();
|
|
1356
|
-
const result = await this.runWorkflow({
|
|
1357
|
-
command: "tree",
|
|
1358
|
-
argument: "",
|
|
1359
|
-
selection: entryId,
|
|
1360
|
-
treeSummary: {
|
|
1361
|
-
summarize,
|
|
1362
|
-
...(customInstructions === undefined ? {} : { customInstructions }),
|
|
1363
|
-
},
|
|
1364
|
-
});
|
|
1365
|
-
if (result.diagnostic === "Branch summarization cancelled")
|
|
1366
|
-
await this.showTreeSelector(entryId);
|
|
931
|
+
return this.#submission.sendSlashPrompt(this.#presenters.components.skills.prompt(skill.name, separator < 0 ? "" : trimmed.slice(separator + 1)), text);
|
|
1367
932
|
}
|
|
1368
933
|
#simple(type) {
|
|
1369
934
|
return { type, correlationId: this.#correlation(type), sessionId: this.backend.identity.sessionId };
|