@timurproko/a1 0.2.7-dev.1252 → 0.2.7-dev.1255
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 +4 -5
- 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/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-shell-root.d.ts +74 -89
- package/dist/app/session-shell/session-shell-root.js +81 -113
- package/dist/app/session-shell/session-shell.d.ts +13 -16
- package/dist/app/session-shell/session-shell.js +144 -268
- package/dist/app/session-shell/session-viewport-controller.d.ts +7 -6
- package/dist/app/session-shell/session-viewport-controller.js +2 -2
- package/dist/app/session-shell/settings-bindings.d.ts +24 -2
- package/dist/app/session-shell/settings-bindings.js +24 -0
- 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/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 +27 -27
- 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 +1 -0
- 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/shell-components.js +1 -0
- 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 +290 -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 +38 -219
- 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-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 +14 -14
- 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/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 +10 -10
- 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 +4 -4
- 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/update-activation.js +2 -2
- package/dist/foundation/release/update-execution-lease.d.ts +2 -3
- package/dist/foundation/release/update-execution-lease.js +1 -1
- package/dist/foundation/release/update-launch.d.ts +2 -2
- package/dist/foundation/release/update.d.ts +0 -2
- package/dist/foundation/release/update.js +14 -14
- package/dist/foundation/startup/startup-budget.d.ts +5 -5
- package/dist/foundation/startup/startup-budget.js +2 -2
- 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/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 +3 -5
- package/dist/integrations/pi/engine/adapter.js +3 -12
- 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 +2 -2
- 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-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 +4 -3
- 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/workflow-contexts.d.ts +1 -1
- package/dist/integrations/pi/engine/workflow-runner.d.ts +1 -1
- package/dist/integrations/pi/engine/workflow-support.d.ts +0 -6
- package/dist/integrations/pi/engine/workflow-support.js +4 -18
- 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.js +21 -30
- package/dist/integrations/pi/tui-runtime/contracts.d.ts +22 -166
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +5 -40
- package/dist/integrations/pi/tui-runtime/index.d.ts +1 -0
- 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 +2 -8
- package/dist/integrations/pi/tui-runtime/overlay-geometry.js +3 -9
- 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/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/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/{foundation/release → contracts/presentation}/progress-palette.generated.d.ts +0 -0
- /package/dist/{foundation/release → contracts/presentation}/progress-palette.generated.js +0 -0
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createResponseCopyExecutor, responseCopyDestination } from "./response-copy-transport.js";
|
|
3
|
-
import { MAX_COPY_CONTROL_BYTES } from "./response-copy-protocol.js";
|
|
1
|
+
import { ShellClipboard } from "./shell-clipboard.js";
|
|
4
2
|
import { PromptHistoryController } from "./prompt-history-controller.js";
|
|
5
3
|
import { SessionDialogCoordinator } from "./dialog-coordinator.js";
|
|
6
4
|
import { LoginInteraction } from "./login-interaction.js";
|
|
@@ -8,22 +6,14 @@ import { PromptSubmission } from "./prompt-submission.js";
|
|
|
8
6
|
import { SessionConcerns } from "./session-concern.js";
|
|
9
7
|
import { composeExitText, SessionStopLatch } from "./session-lifecycle.js";
|
|
10
8
|
import { openWorkflowSelector } from "./workflow-router.js";
|
|
11
|
-
import { bindSessionSettings } from "./settings-bindings.js";
|
|
12
|
-
import { promptSuggestionSurface,
|
|
9
|
+
import { bindSessionSettings, bindShellSettings } from "./settings-bindings.js";
|
|
10
|
+
import { promptSuggestionSurface, suggestionPresentationBlockReason, } from "./suggestion-surface.js";
|
|
13
11
|
import { CLEAR_EXIT_INTERVAL_MS, boundedCleanup } from "../../foundation/terminal-cleanup/terminal-reset.js";
|
|
14
12
|
import { OWNED_UI_HIDDEN_COMMAND_NAMES } from "../../contracts/owned-ui/index.js";
|
|
15
|
-
import { ImageAttachmentError } from "../../contracts/owned-ui/index.js";
|
|
16
13
|
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";
|
|
14
|
+
import { ShellPromptSuggestions } from "./shell-prompt-suggestions.js";
|
|
23
15
|
import { OwnedUiTerminalHost, componentRuntime, sessionTerminalHostOptions, } from "./shell-host.js";
|
|
24
|
-
import { runImageWorker } from "./image-preparation-client.js";
|
|
25
16
|
import { STREAM_PRESENTATION_INTERVAL_MS, StreamPresentationCoalescer, } from "./stream-presentation-coalescer.js";
|
|
26
|
-
import { writeSystemClipboardText, } from "./system-clipboard.js";
|
|
27
17
|
import { OwnedUiSessionShellRoot, shellResourceEntries, } from "./session-shell-root.js";
|
|
28
18
|
// Invariant: a disposed shell leaves the engine a host that holds no reference back to it.
|
|
29
19
|
const DETACHED_WORKFLOW_INTERACTION = { prompt: async () => null, notify() { } };
|
|
@@ -46,12 +36,9 @@ export class OwnedUiSessionPresenter {
|
|
|
46
36
|
#concerns;
|
|
47
37
|
#listeners = new Set();
|
|
48
38
|
#unsubscribe;
|
|
49
|
-
#unsubscribePromptSuggestions;
|
|
50
39
|
#promptSuggestions;
|
|
51
40
|
#promptImages;
|
|
52
41
|
#skills;
|
|
53
|
-
#unsubscribePromptImages;
|
|
54
|
-
#unsubscribeSkills;
|
|
55
42
|
#installedCommandSignature = "";
|
|
56
43
|
#promptHistory = null;
|
|
57
44
|
#historyBinding;
|
|
@@ -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,12 @@ 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
88
|
// Invariant: the host's optional members follow the layout, so it is built only once the layout is known.
|
|
108
89
|
this.#dialogHost = this.#createDialogHost();
|
|
109
|
-
this.#lazySelectors = options.diagnostics?.lazySelectors;
|
|
110
|
-
let promptSuggestionController = null;
|
|
111
90
|
// Invariant: owned prompt limits and collapsed skills are bare-A1 replacements; comparison profiles keep pinned behavior.
|
|
112
91
|
this.#promptImages = this.#customViewport ? options.promptImages ?? null : null;
|
|
113
92
|
this.#skills = this.#customViewport ? options.skills ?? null : null;
|
|
@@ -115,48 +94,19 @@ export class OwnedUiSessionPresenter {
|
|
|
115
94
|
// throw releases them in reverse, so a shell that never finished constructing holds nothing.
|
|
116
95
|
const constructed = [() => host.disconnect(this)];
|
|
117
96
|
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, {
|
|
97
|
+
this.#clipboard = new ShellClipboard({
|
|
98
|
+
ownedCopy: this.#customViewport, substituteTerminal: terminal !== undefined,
|
|
99
|
+
...(sharedClipboard === undefined ? {} : { shared: sharedClipboard }),
|
|
100
|
+
...(clipboard === undefined ? {} : { clipboard }),
|
|
101
|
+
...(responseCopy === undefined ? {} : { responseCopy }),
|
|
102
|
+
...(pastePreparation === undefined ? {} : { pastePreparation }),
|
|
103
|
+
disposed: () => this.#disposed,
|
|
104
|
+
terminalAttached: () => this.#terminal.running && this.#terminal.attached,
|
|
105
|
+
writeControl: control => this.#terminal.writeControl(control),
|
|
106
|
+
});
|
|
107
|
+
constructed.push(() => this.#clipboard.dispose());
|
|
108
|
+
const pastePreparationOptions = this.#clipboard.pastePreparation();
|
|
109
|
+
this.root = new OwnedUiSessionShellRoot(this.backend.session.view(), cwd, { presentation: options.presenters, components: options.presenters.components,
|
|
160
110
|
getColumns: () => this.#terminal.viewport().columns,
|
|
161
111
|
getRows: () => this.#terminal.viewport().rows,
|
|
162
112
|
requestRender: force => this.#terminal.requestRender(force),
|
|
@@ -186,55 +136,31 @@ export class OwnedUiSessionPresenter {
|
|
|
186
136
|
onDequeue: () => this.restoreQueuedInput(),
|
|
187
137
|
onEditorChange: text => {
|
|
188
138
|
this.#submission.noteEditorChange();
|
|
189
|
-
|
|
139
|
+
this.#promptSuggestions?.abortPending();
|
|
190
140
|
if (text.length === 0) {
|
|
191
141
|
// Concurrency: the editor synchronizes deletion-owned autocomplete after onChange.
|
|
192
142
|
// Reassert retained ghost text in the microtask before Pi emits its scheduled frame.
|
|
193
|
-
queueMicrotask(() =>
|
|
143
|
+
queueMicrotask(() => this.#promptSuggestions?.restoreAvailable());
|
|
194
144
|
}
|
|
195
145
|
this.root.reconcilePromptImageLimitNotice(text);
|
|
196
146
|
},
|
|
197
|
-
onPromptSuggestionAccepted: () =>
|
|
147
|
+
onPromptSuggestionAccepted: () => this.#promptSuggestions?.accept(),
|
|
198
148
|
onPromptSuggestionEligibilityChanged: () => {
|
|
199
|
-
queueMicrotask(() =>
|
|
149
|
+
queueMicrotask(() => this.#promptSuggestions?.restoreAvailable());
|
|
200
150
|
},
|
|
201
151
|
onInputSurfaceChanged: () => {
|
|
202
|
-
|
|
152
|
+
this.#promptSuggestions?.invalidate();
|
|
203
153
|
this.#promptHistory?.synchronize();
|
|
204
154
|
},
|
|
205
155
|
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 };
|
|
156
|
+
const delivery = this.#clipboard.copyText(text);
|
|
157
|
+
if (delivery !== undefined)
|
|
158
|
+
this.#trackCopy(delivery, cut ? undefined : text.length);
|
|
233
159
|
},
|
|
160
|
+
readClipboardContent: signal => this.#clipboard.readContent(signal),
|
|
161
|
+
captureClipboardPaste: () => this.#clipboard.capturePaste(),
|
|
234
162
|
...(pasteDiagnostics === undefined ? {} : { pasteDiagnostics: pasteDiagnostics }),
|
|
235
|
-
...(
|
|
236
|
-
pastePreparation: { ...pastePreparation, ...(sharedClipboard === undefined ? {} : { pool: sharedClipboard.paste }) },
|
|
237
|
-
}),
|
|
163
|
+
...(pastePreparationOptions === undefined ? {} : { pastePreparation: pastePreparationOptions }),
|
|
238
164
|
...(sharedKeybindings === undefined ? {} : { keybindings: sharedKeybindings }),
|
|
239
165
|
...(this.#promptImages === null ? {} : { promptImageLimit: this.#promptImages.limit }),
|
|
240
166
|
skillsPresentation: () => this.#skills?.presentation() ?? "expand",
|
|
@@ -251,68 +177,42 @@ export class OwnedUiSessionPresenter {
|
|
|
251
177
|
this.#dialogs = new SessionDialogCoordinator({
|
|
252
178
|
terminal: this.#terminal,
|
|
253
179
|
root: this.root,
|
|
254
|
-
routeHost: routeHost ?? null,
|
|
180
|
+
routeHost: routeHost ?? null, dialogs: options.presenters.components.dialogs,
|
|
255
181
|
disposed: () => this.#disposed,
|
|
256
182
|
exit: () => { void this.shutdown(); },
|
|
257
183
|
...(startupRoute === undefined ? {} : { startupRoute }),
|
|
258
184
|
});
|
|
259
185
|
constructed.push(() => this.#dialogs.dispose());
|
|
260
186
|
const initialPiSettings = this.backend.settings.snapshot();
|
|
261
|
-
this.#programStatus =
|
|
187
|
+
this.#programStatus = options.presenters.components.chrome.programStatusReporter(status => this.#terminal.setProgramStatus(status), () => this.view().status.footer?.sessionName ?? undefined);
|
|
262
188
|
this.#login = new LoginInteraction({
|
|
263
|
-
terminal: this.#terminal, root: this.root, programStatus: this.#programStatus,
|
|
189
|
+
terminal: this.#terminal, root: this.root, programStatus: this.#programStatus, dialogs: options.presenters.components.dialogs,
|
|
264
190
|
syncProgress: () => this.#syncTerminalProgress(this.view()),
|
|
265
191
|
});
|
|
266
192
|
this.#submission = this.#createSubmission(cwd);
|
|
267
193
|
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);
|
|
194
|
+
this.#streamPresentation = new StreamPresentationCoalescer(() => this.#terminal.requestRender(), streamPresentationOptions?.intervalMs ?? STREAM_PRESENTATION_INTERVAL_MS, streamPresentationOptions?.scheduler);
|
|
272
195
|
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;
|
|
196
|
+
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
197
|
constructed.push(() => this.#promptSuggestions?.dispose());
|
|
282
|
-
this.#
|
|
283
|
-
|
|
284
|
-
:
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
198
|
+
this.#fullscreenExitOutput = initialPiSettings.fullscreenExitOutput;
|
|
199
|
+
this.#unbindShellSettings = bindShellSettings({
|
|
200
|
+
customViewport: this.#customViewport, promptImages: this.#promptImages, skills: this.#skills,
|
|
201
|
+
viewport: viewportSettings, historyScope: promptHistory?.onScopeChange,
|
|
202
|
+
}, {
|
|
203
|
+
root: this.root,
|
|
204
|
+
promptImageLimitChanged: () => { if (!this.#disposed && this.root.reconcilePromptImageLimitNotice())
|
|
205
|
+
this.#terminal.requestRender(); },
|
|
206
|
+
skillsChanged: () => {
|
|
207
|
+
// Invariant: reinstalling drops extension provider wrappers, so an unrelated setting change leaves the list alone.
|
|
208
|
+
if (this.#disposed || this.#commandListSignature() === this.#installedCommandSignature)
|
|
209
|
+
return;
|
|
210
|
+
this.#installAutocompleteCommands();
|
|
288
211
|
this.#terminal.requestRender();
|
|
212
|
+
},
|
|
213
|
+
historyScopeChanged: scope => this.#rebindTranscript(scope),
|
|
289
214
|
});
|
|
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);
|
|
215
|
+
constructed.push(this.#unbindShellSettings);
|
|
316
216
|
this.#unbindSessionSettings = bindSessionSettings(this.backend.settings, initialPiSettings, {
|
|
317
217
|
terminal: this.#terminal,
|
|
318
218
|
root: this.root,
|
|
@@ -345,64 +245,16 @@ export class OwnedUiSessionPresenter {
|
|
|
345
245
|
prompt: request => this.#login.requestInput(request),
|
|
346
246
|
notify: event => this.#login.notify(event),
|
|
347
247
|
publish: message => {
|
|
348
|
-
this.root.
|
|
248
|
+
this.root.workflow.appendMessage(message);
|
|
349
249
|
this.#terminal.requestRender();
|
|
350
250
|
},
|
|
351
251
|
finishLogin: () => this.#login.finish(),
|
|
352
252
|
});
|
|
353
253
|
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
|
-
});
|
|
254
|
+
this.#unsubscribe = this.backend.session.onEvent(event => this.#onSessionEvent(event));
|
|
397
255
|
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
|
-
});
|
|
256
|
+
this.#unbindClipboardWriter = this.#clipboard.responseCopy === null ? () => { }
|
|
257
|
+
: this.backend.extensions.bindClipboardWriter(text => this.#clipboard.writeForExtension(text));
|
|
406
258
|
constructed.push(this.#unbindClipboardWriter);
|
|
407
259
|
if (this.backend.session.view().lifecycle === "stopped")
|
|
408
260
|
this.#stop.resolve();
|
|
@@ -482,7 +334,7 @@ export class OwnedUiSessionPresenter {
|
|
|
482
334
|
const routed = this.root.handleViewportPreInput(data, true, Date.now(), this.root.usesDefaultInputSurface() && !this.#terminal.hasFocusedOverlay());
|
|
483
335
|
if (routed.copySelection !== undefined) {
|
|
484
336
|
const snapshot = routed.copySelection;
|
|
485
|
-
this.#trackCopy(this.#
|
|
337
|
+
this.#trackCopy(this.#clipboard.copySelection(snapshot), copyCharacters(snapshot));
|
|
486
338
|
}
|
|
487
339
|
if (routed.copyLastMessage)
|
|
488
340
|
void this.runWorkflow({ command: "copy", argument: "" });
|
|
@@ -490,18 +342,54 @@ export class OwnedUiSessionPresenter {
|
|
|
490
342
|
return routed.data === data ? undefined : { data: routed.data };
|
|
491
343
|
return routed.data.length === 0 ? { consume: true } : { data: routed.data };
|
|
492
344
|
}
|
|
345
|
+
#onSessionEvent(event) {
|
|
346
|
+
// Invariant: once disposal begins no event touches the view; only the stop still settles the shell.
|
|
347
|
+
if (this.#disposed) {
|
|
348
|
+
if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
|
|
349
|
+
this.#stop.settleAfter(() => this.dispose());
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
// Performance: a streamed chunk names one block, and touching only that block is what keeps the
|
|
353
|
+
// cost of a chunk the same in a long session as in a new one. Everything else
|
|
354
|
+
// resynchronizes the view, which is cheap next to re-reading the transcript.
|
|
355
|
+
if (event.type === "agent-run-started") {
|
|
356
|
+
this.#promptSuggestions?.invalidate();
|
|
357
|
+
this.root.resumeViewportFollowing();
|
|
358
|
+
}
|
|
359
|
+
if (event.type === "assistant-message-completed" && !event.successful) {
|
|
360
|
+
this.#programStatus.setErrorMessage(this.view().status.diagnostics.at(-1));
|
|
361
|
+
}
|
|
362
|
+
if (event.type === "agent-run-started" || event.type === "assistant-message-completed" || event.type === "agent-run-settled") {
|
|
363
|
+
this.#programStatus.handleEvent(event);
|
|
364
|
+
}
|
|
365
|
+
if (event.type === "assistant-message-completed") {
|
|
366
|
+
this.root.noteCompletedAssistantMessage();
|
|
367
|
+
this.#promptSuggestions?.route(event, () => this.root.promptSuggestionPrepareBlockReason());
|
|
368
|
+
}
|
|
369
|
+
const semanticOnly = event.type === "agent-run-started" || event.type === "assistant-message-completed";
|
|
370
|
+
const view = event.type === "transcript-block" && this.#sessionGeneration === this.backend.identity.sessionGeneration
|
|
371
|
+
? this.#syncBlock(event.block)
|
|
372
|
+
: semanticOnly ? this.view() : this.#syncView();
|
|
373
|
+
this.#syncTerminalProgress(view);
|
|
374
|
+
this.#promptSuggestions?.noteView(view, this.backend.identity.sessionGeneration !== this.#sessionGeneration);
|
|
375
|
+
if (event.type === "status" && /^(Retrying|Compacting)/.test(event.status.workingMessage ?? "")) {
|
|
376
|
+
this.#promptSuggestions?.invalidate();
|
|
377
|
+
}
|
|
378
|
+
if (event.type === "agent-run-settled") {
|
|
379
|
+
this.#promptSuggestions?.route(event, () => this.root.promptSuggestionPrepareBlockReason());
|
|
380
|
+
}
|
|
381
|
+
if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
|
|
382
|
+
this.#stop.settleAfter(() => this.dispose());
|
|
383
|
+
}
|
|
493
384
|
#trackCopy(delivery, count) {
|
|
494
385
|
const intent = ++this.#copyIntentSequence;
|
|
495
386
|
void delivery?.then(({ outcome }) => {
|
|
496
387
|
if (count === undefined || this.#disposed || !this.#terminal.running || intent !== this.#copyIntentSequence
|
|
497
388
|
|| outcome !== "delivered" && outcome !== "submitted-unverified")
|
|
498
389
|
return;
|
|
499
|
-
this.root.showCopyAcknowledgement(copyAcknowledgementText(count));
|
|
390
|
+
this.root.chrome.showCopyAcknowledgement(copyAcknowledgementText(count));
|
|
500
391
|
});
|
|
501
392
|
}
|
|
502
|
-
#promptSuggestionPresentationBlockReason(identity) {
|
|
503
|
-
return suggestionPresentationBlockReason(identity, { disposed: this.#disposed, view: this.view(), sessionGeneration: this.backend.identity.sessionGeneration }, () => this.root.promptSuggestionPresentationBlockReason());
|
|
504
|
-
}
|
|
505
393
|
start() {
|
|
506
394
|
if (this.#started)
|
|
507
395
|
return;
|
|
@@ -516,9 +404,9 @@ export class OwnedUiSessionPresenter {
|
|
|
516
404
|
if (this.#disposed || !this.#customViewport)
|
|
517
405
|
return;
|
|
518
406
|
this.#dialogs.presentStartupRoute();
|
|
519
|
-
void this.#
|
|
407
|
+
void this.#presenters.components.dialogs.lazySelectors().then(selectors => selectors.prepare()).catch(() => { });
|
|
520
408
|
this.root.warmPastePreparation();
|
|
521
|
-
this.#
|
|
409
|
+
this.#clipboard.warm();
|
|
522
410
|
});
|
|
523
411
|
}
|
|
524
412
|
onView(listener) {
|
|
@@ -618,7 +506,7 @@ export class OwnedUiSessionPresenter {
|
|
|
618
506
|
}
|
|
619
507
|
async cycleModel(direction) {
|
|
620
508
|
const result = await this.backend.workflows.cycleModelWorkflow(direction);
|
|
621
|
-
this.root.
|
|
509
|
+
this.root.workflow.appendResult(result);
|
|
622
510
|
this.#terminal.requestRender();
|
|
623
511
|
return workflowAdapterResult(result);
|
|
624
512
|
}
|
|
@@ -639,8 +527,8 @@ export class OwnedUiSessionPresenter {
|
|
|
639
527
|
setInputSurface: surface => this.root.setInputSurface(surface),
|
|
640
528
|
requestRender: () => this.#terminal.requestRender(),
|
|
641
529
|
viewport: () => this.#terminal.viewport(),
|
|
642
|
-
appendWorkflowStatus: text => this.root.
|
|
643
|
-
appendWorkflowResult: result => this.root.
|
|
530
|
+
appendWorkflowStatus: text => this.root.workflow.appendStatus(text),
|
|
531
|
+
appendWorkflowResult: result => this.root.workflow.appendResult(result),
|
|
644
532
|
runWorkflow: request => this.runWorkflow(request),
|
|
645
533
|
// Invariant: the custom bare-A1 surface holds frames while optional selectors load and is permanently
|
|
646
534
|
// fullscreen; the pinned comparison profiles render immediately and keep Pi's TUI mode switch.
|
|
@@ -649,14 +537,6 @@ export class OwnedUiSessionPresenter {
|
|
|
649
537
|
: { switchTuiMode: mode => this.#terminal.switchMode(mode) }),
|
|
650
538
|
};
|
|
651
539
|
}
|
|
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
540
|
async showThinkingSelector() {
|
|
661
541
|
const snapshot = this.backend.settings.snapshot();
|
|
662
542
|
const close = () => {
|
|
@@ -670,7 +550,7 @@ export class OwnedUiSessionPresenter {
|
|
|
670
550
|
};
|
|
671
551
|
const releasePresentation = this.#customViewport ? this.#terminal.beginPresentationHold() : undefined;
|
|
672
552
|
try {
|
|
673
|
-
const selectors = await this.#
|
|
553
|
+
const selectors = await this.#presenters.components.dialogs.lazySelectors();
|
|
674
554
|
const component = await selectors.createThinking({
|
|
675
555
|
currentLevel: snapshot.thinkingLevel,
|
|
676
556
|
availableLevels: snapshot.availableThinkingLevels,
|
|
@@ -678,7 +558,7 @@ export class OwnedUiSessionPresenter {
|
|
|
678
558
|
onCancel: close,
|
|
679
559
|
onSelectAsDefault: level => this.backend.settings.setDefaultThinkingLevel(level),
|
|
680
560
|
defaultLevel: snapshot.defaultThinkingLevel,
|
|
681
|
-
...(this
|
|
561
|
+
...(this.backend.settings.productMode === "bare" ? {
|
|
682
562
|
presentation: {
|
|
683
563
|
profile: "bare",
|
|
684
564
|
cycleBinding: this.root.editor.keybindingConfig()["app.thinking.cycle"] ?? [],
|
|
@@ -698,11 +578,11 @@ export class OwnedUiSessionPresenter {
|
|
|
698
578
|
/** The Skills dialog: a replacement input like the model selector, applying the chosen skill through the prompt path. */
|
|
699
579
|
showSkillsSelector(skills = this.#skillSummaries()) {
|
|
700
580
|
const close = this.#dialogs.closeInputSurface;
|
|
701
|
-
const component =
|
|
581
|
+
const component = this.#presenters.components.dialogs.skillsSelector({
|
|
702
582
|
skills,
|
|
703
583
|
onSelect: name => {
|
|
704
584
|
close();
|
|
705
|
-
void this.#submission.sendSlashPrompt(
|
|
585
|
+
void this.#submission.sendSlashPrompt(this.#presenters.components.skills.prompt(name), this.#presenters.components.skills.prompt(name)).catch(() => this.#submission.reportError());
|
|
706
586
|
},
|
|
707
587
|
onCancel: close,
|
|
708
588
|
});
|
|
@@ -715,12 +595,12 @@ export class OwnedUiSessionPresenter {
|
|
|
715
595
|
showForkSelector() {
|
|
716
596
|
const options = this.backend.catalog.pinnedForkOptions();
|
|
717
597
|
if (options.length === 0) {
|
|
718
|
-
this.root.
|
|
598
|
+
this.root.workflow.appendResult({ command: "fork", outcome: "completed", message: "No messages to fork from", messageKind: "status" });
|
|
719
599
|
this.#terminal.requestRender();
|
|
720
600
|
return;
|
|
721
601
|
}
|
|
722
602
|
const close = this.#dialogs.closeInputSurface;
|
|
723
|
-
const component =
|
|
603
|
+
const component = this.#presenters.components.dialogs.userMessageSelector(options, selection => {
|
|
724
604
|
close();
|
|
725
605
|
void this.runWorkflow({ command: "fork", argument: "", selection });
|
|
726
606
|
}, close);
|
|
@@ -733,7 +613,7 @@ export class OwnedUiSessionPresenter {
|
|
|
733
613
|
options = await this.backend.catalog.pinnedLogoutOptions();
|
|
734
614
|
}
|
|
735
615
|
catch (error) {
|
|
736
|
-
this.root.
|
|
616
|
+
this.root.workflow.appendResult({
|
|
737
617
|
command: "logout",
|
|
738
618
|
outcome: "failed",
|
|
739
619
|
message: `Could not read stored credentials: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -742,12 +622,12 @@ export class OwnedUiSessionPresenter {
|
|
|
742
622
|
return;
|
|
743
623
|
}
|
|
744
624
|
if (options.length === 0) {
|
|
745
|
-
this.root.
|
|
625
|
+
this.root.workflow.appendStatus("No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.");
|
|
746
626
|
this.#terminal.requestRender();
|
|
747
627
|
return;
|
|
748
628
|
}
|
|
749
629
|
const close = this.#dialogs.closeInputSurface;
|
|
750
|
-
const component =
|
|
630
|
+
const component = this.#presenters.components.dialogs.authProviderSelector("logout", options, selection => {
|
|
751
631
|
close();
|
|
752
632
|
void this.runWorkflow({ command: "logout", argument: "", selection });
|
|
753
633
|
}, close);
|
|
@@ -768,7 +648,7 @@ export class OwnedUiSessionPresenter {
|
|
|
768
648
|
}
|
|
769
649
|
const close = this.#dialogs.closeInputSurface;
|
|
770
650
|
const labels = method.options.map(option => option.label);
|
|
771
|
-
const component =
|
|
651
|
+
const component = this.#presenters.components.dialogs.extensionSelector(method.title, labels, label => {
|
|
772
652
|
const selection = method.options.find(option => option.label === label)?.id;
|
|
773
653
|
if (!selection)
|
|
774
654
|
return;
|
|
@@ -786,7 +666,7 @@ export class OwnedUiSessionPresenter {
|
|
|
786
666
|
showLoginAuthTypeSelector() {
|
|
787
667
|
const close = this.#dialogs.closeInputSurface;
|
|
788
668
|
const labels = ["Sign in with an account", "Sign in with an API key"];
|
|
789
|
-
const component =
|
|
669
|
+
const component = this.#presenters.components.dialogs.extensionSelector("Select authentication method:", labels, label => {
|
|
790
670
|
close();
|
|
791
671
|
this.showLoginProviderSelector(label === labels[0] ? "oauth" : "api_key");
|
|
792
672
|
}, close);
|
|
@@ -796,12 +676,12 @@ export class OwnedUiSessionPresenter {
|
|
|
796
676
|
showLoginProviderSelector(authType, initialSearchInput) {
|
|
797
677
|
const options = this.backend.catalog.pinnedLoginOptions(authType);
|
|
798
678
|
if (options.length === 0) {
|
|
799
|
-
this.root.
|
|
679
|
+
this.root.workflow.appendStatus(authType === "oauth" ? "No account providers available." : authType === "api_key" ? "No API key providers available." : "No login providers available.");
|
|
800
680
|
this.#terminal.requestRender();
|
|
801
681
|
return;
|
|
802
682
|
}
|
|
803
683
|
const close = this.#dialogs.closeInputSurface;
|
|
804
|
-
const component =
|
|
684
|
+
const component = this.#presenters.components.dialogs.authProviderSelector("login", options, id => {
|
|
805
685
|
close();
|
|
806
686
|
void this.runWorkflow({ command: "login", argument: "", selection: id });
|
|
807
687
|
}, () => {
|
|
@@ -860,7 +740,7 @@ export class OwnedUiSessionPresenter {
|
|
|
860
740
|
}).catch(error => {
|
|
861
741
|
if (this.#disposed)
|
|
862
742
|
return;
|
|
863
|
-
this.root.
|
|
743
|
+
this.root.workflow.appendResult({ command: "name", outcome: "failed", message: error instanceof Error ? error.message : String(error) });
|
|
864
744
|
this.#terminal.requestRender();
|
|
865
745
|
});
|
|
866
746
|
return { outcome: "completed", diagnostic: null };
|
|
@@ -870,7 +750,7 @@ export class OwnedUiSessionPresenter {
|
|
|
870
750
|
const setup = this.backend.catalog.pinnedAmbientAuthentication(request.selection);
|
|
871
751
|
if (setup) {
|
|
872
752
|
const close = this.#dialogs.closeInputSurface;
|
|
873
|
-
const dialog =
|
|
753
|
+
const dialog = this.#presenters.components.dialogs.loginDialog(componentRuntime(this.#terminal), setup.providerId, close, setup.providerName, setup.title);
|
|
874
754
|
dialog.showInfo(setup.message, [], true);
|
|
875
755
|
this.root.setInputSurface(dialog);
|
|
876
756
|
this.#terminal.requestRender();
|
|
@@ -883,7 +763,7 @@ export class OwnedUiSessionPresenter {
|
|
|
883
763
|
if (request.command === "reload") {
|
|
884
764
|
const blocked = this.backend.workflows.reloadBlockedResult();
|
|
885
765
|
if (blocked) {
|
|
886
|
-
this.root.
|
|
766
|
+
this.root.workflow.appendResult(blocked);
|
|
887
767
|
this.#terminal.requestRender();
|
|
888
768
|
return workflowAdapterResult(blocked);
|
|
889
769
|
}
|
|
@@ -893,8 +773,8 @@ export class OwnedUiSessionPresenter {
|
|
|
893
773
|
? await import("./share-operation.js")
|
|
894
774
|
: undefined;
|
|
895
775
|
const shareSurface = shareDialog === undefined ? undefined
|
|
896
|
-
:
|
|
897
|
-
const operationSurface = shareSurface ?? (request.command === "reload" ?
|
|
776
|
+
: await this.#presenters.components.dialogs.shareProgress(componentRuntime(this.#terminal), "Creating gist…", this.#customViewport ? "dialog" : "loader");
|
|
777
|
+
const operationSurface = shareSurface ?? (request.command === "reload" ? this.#presenters.components.info.reloadBox() : undefined);
|
|
898
778
|
const now = this.#reloadPresentation?.now ?? Date.now;
|
|
899
779
|
const shownAt = now();
|
|
900
780
|
if (operationSurface) {
|
|
@@ -925,7 +805,7 @@ export class OwnedUiSessionPresenter {
|
|
|
925
805
|
if (result.outcome === "requires-selection" && request.command === "model") {
|
|
926
806
|
if (result.messages !== undefined) {
|
|
927
807
|
for (const message of result.messages)
|
|
928
|
-
this.root.
|
|
808
|
+
this.root.workflow.appendMessage(message);
|
|
929
809
|
}
|
|
930
810
|
this.showModelSelector((result.detail ?? request.argument.trim()) || undefined);
|
|
931
811
|
return { outcome: "completed", diagnostic: null };
|
|
@@ -944,7 +824,7 @@ export class OwnedUiSessionPresenter {
|
|
|
944
824
|
});
|
|
945
825
|
}
|
|
946
826
|
if (result.outcome === "requires-selection" || result.outcome === "requires-confirmation") {
|
|
947
|
-
this.root.
|
|
827
|
+
this.root.workflow.appendResult({ command: request.command, outcome: "failed", message: `Owned controller missing for ${request.command}` });
|
|
948
828
|
this.#terminal.requestRender();
|
|
949
829
|
return { outcome: "failed", diagnostic: `Owned controller missing for ${request.command}` };
|
|
950
830
|
}
|
|
@@ -959,10 +839,10 @@ export class OwnedUiSessionPresenter {
|
|
|
959
839
|
this.root.resumeViewportFollowing();
|
|
960
840
|
}
|
|
961
841
|
if (shareDialog !== undefined && this.#customViewport && result.outcome === "completed" && result.detail !== undefined) {
|
|
962
|
-
this.root.
|
|
842
|
+
this.root.workflow.appendStatus(shareDialog.renderShellShareResult(result.message, result.detail, this.#presenters.theme.current(), url => this.#presenters.components.text.hyperlink(url)));
|
|
963
843
|
}
|
|
964
844
|
else {
|
|
965
|
-
this.root.
|
|
845
|
+
this.root.workflow.appendResult(result);
|
|
966
846
|
}
|
|
967
847
|
this.#terminal.requestRender();
|
|
968
848
|
return workflowAdapterResult(result);
|
|
@@ -978,17 +858,17 @@ export class OwnedUiSessionPresenter {
|
|
|
978
858
|
showTrustSelector() {
|
|
979
859
|
const context = this.backend.catalog.pinnedProjectTrustContext();
|
|
980
860
|
const close = this.#dialogs.closeInputSurface;
|
|
981
|
-
const component =
|
|
861
|
+
const component = this.#presenters.components.dialogs.trustSelector({
|
|
982
862
|
...context,
|
|
983
863
|
onSelect: selection => {
|
|
984
864
|
try {
|
|
985
865
|
this.backend.catalog.persistProjectTrust(selection.updates);
|
|
986
866
|
close();
|
|
987
|
-
this.root.
|
|
867
|
+
this.root.workflow.appendStatus(`Saved trust decision: ${selection.trusted ? "trusted" : "untrusted"}. Restart pi for this to take effect.`);
|
|
988
868
|
}
|
|
989
869
|
catch (error) {
|
|
990
870
|
close();
|
|
991
|
-
this.root.
|
|
871
|
+
this.root.workflow.appendResult({ command: "trust", outcome: "failed", message: error instanceof Error ? error.message : String(error) });
|
|
992
872
|
}
|
|
993
873
|
this.#terminal.requestRender();
|
|
994
874
|
},
|
|
@@ -1002,7 +882,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1002
882
|
}
|
|
1003
883
|
// Invariant: bare A1 routes `models`; the comparison profile keeps the pinned `model`/`scoped-models` pair. Hidden routes are shared.
|
|
1004
884
|
#isWorkflowRoute(value) {
|
|
1005
|
-
return
|
|
885
|
+
return this.#presenters.components.workflows.commandNames(this.backend.settings.productMode).includes(value)
|
|
1006
886
|
|| OWNED_UI_HIDDEN_COMMAND_NAMES.includes(value);
|
|
1007
887
|
}
|
|
1008
888
|
/** The bare-A1 unified Models dialog: switch on Enter, scope on Space, persist on Ctrl+S, all through the engine. */
|
|
@@ -1039,8 +919,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1039
919
|
// Invariant: events stop first, so nothing re-enters the view during history close, outro, or restoration.
|
|
1040
920
|
attempt(() => this.#unsubscribe());
|
|
1041
921
|
this.#copyIntentSequence += 1;
|
|
1042
|
-
this.#
|
|
1043
|
-
this.#copyExecutor?.dispose();
|
|
922
|
+
this.#clipboard.dispose();
|
|
1044
923
|
this.#submission.cancelWaiting();
|
|
1045
924
|
let pasteCleanup = Promise.resolve();
|
|
1046
925
|
let historyCleanup = Promise.resolve(true);
|
|
@@ -1049,10 +928,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1049
928
|
attempt(() => this.root.clearViewportPointerState());
|
|
1050
929
|
attempt(() => this.#streamPresentation.dispose());
|
|
1051
930
|
attempt(() => this.#promptSuggestions?.dispose());
|
|
1052
|
-
attempt(() => this.#
|
|
1053
|
-
attempt(() => this.#unsubscribePromptImages());
|
|
1054
|
-
attempt(() => this.#unsubscribeSkills());
|
|
1055
|
-
attempt(() => this.#unsubscribeSettings());
|
|
931
|
+
attempt(() => this.#unbindShellSettings());
|
|
1056
932
|
let exitText = "";
|
|
1057
933
|
attempt(() => {
|
|
1058
934
|
exitText = composeExitText({
|
|
@@ -1060,7 +936,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1060
936
|
customViewport: this.#customViewport,
|
|
1061
937
|
exitMode: this.backend.identity.disposed ? this.#fullscreenExitOutput : this.backend.settings.snapshot().fullscreenExitOutput,
|
|
1062
938
|
resume: this.backend.identity.currentSessionResumeMetadata(),
|
|
1063
|
-
transcript: () => this.root.exitTranscript(terminal.columns),
|
|
939
|
+
transcript: () => this.root.transcript.exitTranscript(terminal.columns),
|
|
1064
940
|
});
|
|
1065
941
|
});
|
|
1066
942
|
attempt(() => this.#unbindClipboardWriter());
|
|
@@ -1088,7 +964,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1088
964
|
}
|
|
1089
965
|
// Invariant: incremental block updates notify listeners with the same complete view contract.
|
|
1090
966
|
#syncBlock(block) {
|
|
1091
|
-
this.root.
|
|
967
|
+
this.root.transcript.apply(block);
|
|
1092
968
|
if (this.#customViewport && block.status === "live" && isCoalescedStreamBlock(block.kind)) {
|
|
1093
969
|
this.#streamPresentation.request();
|
|
1094
970
|
}
|
|
@@ -1105,7 +981,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1105
981
|
}
|
|
1106
982
|
// Rationale: extensions reach the shell only through this bridge; every surface they draw lands in the root.
|
|
1107
983
|
#createExtensionBridge() {
|
|
1108
|
-
return
|
|
984
|
+
return this.#presenters.components.dialogs.extensionUiBridge({
|
|
1109
985
|
runtime: componentRuntime(this.#terminal),
|
|
1110
986
|
agentDir: this.backend.identity.agentDir,
|
|
1111
987
|
setInputSurface: component => this.root.setInputSurface(component, true, "opaque"),
|
|
@@ -1134,7 +1010,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1134
1010
|
backend: this.backend,
|
|
1135
1011
|
root: this.root,
|
|
1136
1012
|
terminal: this.#terminal,
|
|
1137
|
-
cwd,
|
|
1013
|
+
cwd, statusText: this.#presenters.components.info.statusText,
|
|
1138
1014
|
promptHistory: () => this.#promptHistory,
|
|
1139
1015
|
imageSidecar: () => this.#historyBinding?.imageSidecar,
|
|
1140
1016
|
disposed: () => this.#disposed,
|
|
@@ -1148,7 +1024,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1148
1024
|
// Invariant: the order is the reset order on session replacement; copy intent before pastes before the input surface.
|
|
1149
1025
|
#createConcerns() {
|
|
1150
1026
|
return new SessionConcerns([
|
|
1151
|
-
{ onSessionReplaced: () => { this.#copyIntentSequence += 1; this.#
|
|
1027
|
+
{ onSessionReplaced: () => { this.#copyIntentSequence += 1; this.#clipboard.reset(); } },
|
|
1152
1028
|
this.#submission,
|
|
1153
1029
|
{ onSessionReplaced: () => this.root.resetPendingPastes() },
|
|
1154
1030
|
{ onSessionReplaced: () => this.#promptSuggestions?.invalidate() },
|
|
@@ -1171,7 +1047,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1171
1047
|
return;
|
|
1172
1048
|
if (replaced) {
|
|
1173
1049
|
this.#sessionBindingGeneration = this.backend.identity.sessionBindingGeneration;
|
|
1174
|
-
this.root.
|
|
1050
|
+
this.root.transcript.reset();
|
|
1175
1051
|
}
|
|
1176
1052
|
const binding = this.#historyBinding;
|
|
1177
1053
|
if (binding?.options.forSession !== undefined || binding?.options.forScope !== undefined) {
|
|
@@ -1254,7 +1130,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1254
1130
|
if (diagnostic === undefined || !this.#terminal.running)
|
|
1255
1131
|
return;
|
|
1256
1132
|
this.#startupTrustHandled = true;
|
|
1257
|
-
this.root.
|
|
1133
|
+
this.root.workflow.appendMessage({ kind: "warning", message: diagnostic.message });
|
|
1258
1134
|
}
|
|
1259
1135
|
openOwnedRoute(route) {
|
|
1260
1136
|
if (this.#disposed)
|
|
@@ -1267,7 +1143,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1267
1143
|
}
|
|
1268
1144
|
const result = this.#dialogs.openRoute(route);
|
|
1269
1145
|
if (result.outcome !== "completed" && result.diagnostic !== null) {
|
|
1270
|
-
this.root.
|
|
1146
|
+
this.root.workflow.appendMessage({ kind: "warning", message: result.diagnostic });
|
|
1271
1147
|
}
|
|
1272
1148
|
}
|
|
1273
1149
|
hotkeysPresentation() {
|
|
@@ -1283,9 +1159,9 @@ export class OwnedUiSessionPresenter {
|
|
|
1283
1159
|
if (this.#isWorkflowRoute(name))
|
|
1284
1160
|
return this.runWorkflow({ command: name, argument });
|
|
1285
1161
|
if (this.#skillsCollapsed()) {
|
|
1286
|
-
if (name ===
|
|
1162
|
+
if (name === this.#presenters.components.skills.commandName)
|
|
1287
1163
|
return this.#runSkillsCommand(text, argument);
|
|
1288
|
-
const rewritten =
|
|
1164
|
+
const rewritten = this.#presenters.components.skills.rewriteTunnelSubmission(text);
|
|
1289
1165
|
if (rewritten !== text)
|
|
1290
1166
|
return this.#submission.sendSlashPrompt(rewritten, text);
|
|
1291
1167
|
}
|
|
@@ -1305,7 +1181,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1305
1181
|
&& !this.backend.identity.disposed && this.backend.settings.snapshot().enableSkillCommands;
|
|
1306
1182
|
}
|
|
1307
1183
|
#skillSummaries() {
|
|
1308
|
-
return
|
|
1184
|
+
return this.#presenters.components.skills.fromCommands(this.backend.workflows.workflowAutocompleteCommands());
|
|
1309
1185
|
}
|
|
1310
1186
|
// Protocol: bare "/skills" opens the dialog, "/skills <name> [args]" applies directly, and an unknown name is a command outcome.
|
|
1311
1187
|
async #runSkillsCommand(text, argument) {
|
|
@@ -1317,18 +1193,18 @@ export class OwnedUiSessionPresenter {
|
|
|
1317
1193
|
}
|
|
1318
1194
|
const separator = trimmed.search(/\s/u);
|
|
1319
1195
|
const token = separator < 0 ? trimmed : trimmed.slice(0, separator);
|
|
1320
|
-
const skill =
|
|
1196
|
+
const skill = this.#presenters.components.skills.findByArgument(skills, token);
|
|
1321
1197
|
if (skill === undefined) {
|
|
1322
1198
|
const message = "Unknown skill: " + token;
|
|
1323
|
-
this.root.
|
|
1199
|
+
this.root.workflow.appendMessage({ kind: "error", message });
|
|
1324
1200
|
this.#terminal.requestRender();
|
|
1325
1201
|
return { outcome: "failed", diagnostic: message };
|
|
1326
1202
|
}
|
|
1327
|
-
return this.#submission.sendSlashPrompt(
|
|
1203
|
+
return this.#submission.sendSlashPrompt(this.#presenters.components.skills.prompt(skill.name, separator < 0 ? "" : trimmed.slice(separator + 1)), text);
|
|
1328
1204
|
}
|
|
1329
1205
|
#treeSummary() {
|
|
1330
1206
|
return new Promise(resolve => {
|
|
1331
|
-
this.root.setInputSurface(
|
|
1207
|
+
this.root.setInputSurface(this.#presenters.components.dialogs.extensionSelector("Summarize Branch?", ["No summary", "Summarize", "Summarize with custom prompt"], resolve, () => resolve(undefined)), true, "opaque");
|
|
1332
1208
|
this.#terminal.requestRender();
|
|
1333
1209
|
});
|
|
1334
1210
|
}
|