@timurproko/a1 0.2.7-dev.1255 → 0.2.7-dev.1265
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/dist/app/session-shell/prompt-submission.d.ts +1 -1
- package/dist/app/session-shell/prompt-submission.js +9 -9
- 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/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 +6 -28
- package/dist/app/session-shell/session-shell-root.js +26 -220
- package/dist/app/session-shell/session-shell.d.ts +3 -23
- package/dist/app/session-shell/session-shell.js +70 -388
- package/dist/app/session-shell/session-terminal-presentation.d.ts +16 -0
- package/dist/app/session-shell/session-terminal-presentation.js +35 -0
- package/dist/app/session-shell/session-viewport-controller.d.ts +2 -10
- package/dist/app/session-shell/session-viewport-controller.js +40 -318
- package/dist/app/session-shell/settings-bindings.d.ts +1 -1
- package/dist/app/session-shell/settings-bindings.js +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/composition/owned-ui.js +63 -59
- package/dist/contracts/owned-ui/index.d.ts +1 -1
- package/dist/contracts/owned-ui/index.js +1 -1
- package/dist/contracts/owned-ui/validation.d.ts +1 -11
- package/dist/contracts/owned-ui/validation.js +8 -104
- package/dist/contracts/presentation/index.d.ts +1 -1
- package/dist/contracts/presentation/terminal.d.ts +0 -6
- package/dist/features/owned-ui/settings-app.js +13 -208
- 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/foundation/release/automatic-update.js +1 -8
- package/dist/foundation/release/dependency-layer.js +3 -3
- package/dist/foundation/release/latest-release.js +1 -1
- package/dist/foundation/release/managed-path.d.ts +10 -0
- package/dist/foundation/release/managed-path.js +26 -0
- package/dist/foundation/release/release-gc.js +6 -8
- package/dist/foundation/release/restart-certification.js +3 -4
- package/dist/foundation/release/update-activation.js +1 -1
- package/dist/foundation/release/update-execution-lease.js +1 -7
- package/dist/foundation/release/update-installer.d.ts +45 -0
- package/dist/foundation/release/update-installer.js +57 -0
- package/dist/foundation/release/update-recovery.js +2 -9
- package/dist/foundation/release/update.d.ts +4 -23
- package/dist/foundation/release/update.js +160 -179
- 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/owned-editor-ux.js +46 -140
- package/dist/integrations/pi/engine/adapter.d.ts +1 -8
- package/dist/integrations/pi/engine/adapter.js +6 -49
- package/dist/integrations/pi/engine/host.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/session-events.js +8 -6
- package/dist/integrations/pi/engine/session-runtime.d.ts +6 -12
- package/dist/integrations/pi/engine/session-runtime.js +21 -178
- 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-runner.d.ts +0 -1
- 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 -14
- package/dist/integrations/pi/engine/workflow-support.js +0 -47
- package/dist/integrations/pi/tui-runtime/adapter.d.ts +9 -19
- package/dist/integrations/pi/tui-runtime/adapter.js +35 -144
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +4 -4
- package/dist/integrations/pi/tui-runtime/index.d.ts +0 -1
- package/dist/integrations/pi/tui-runtime/overlay-geometry.d.ts +2 -2
- package/dist/integrations/pi/tui-runtime/presentation-adapter.d.ts +2 -2
- 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.d.ts +2 -147
- package/dist/ui/components/transcript-viewport.js +87 -315
- package/package.json +3 -3
- 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 -22
- /package/dist/{integrations/pi/tui-runtime/contracts.js → ui/components/transcript-viewport-types.js} +0 -0
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { SessionTerminalPresentation } from "./session-terminal-presentation.js";
|
|
1
2
|
import { ShellClipboard } from "./shell-clipboard.js";
|
|
2
|
-
import {
|
|
3
|
+
import { SessionPromptHistory } from "./session-prompt-history.js";
|
|
4
|
+
import { shellResourceEntries } from "./resource-labels.js";
|
|
3
5
|
import { SessionDialogCoordinator } from "./dialog-coordinator.js";
|
|
4
6
|
import { LoginInteraction } from "./login-interaction.js";
|
|
5
7
|
import { PromptSubmission } from "./prompt-submission.js";
|
|
6
8
|
import { SessionConcerns } from "./session-concern.js";
|
|
7
9
|
import { composeExitText, SessionStopLatch } from "./session-lifecycle.js";
|
|
8
10
|
import { openWorkflowSelector } from "./workflow-router.js";
|
|
11
|
+
import { SessionSelectors } from "./session-selectors.js";
|
|
9
12
|
import { bindSessionSettings, bindShellSettings } from "./settings-bindings.js";
|
|
10
13
|
import { promptSuggestionSurface, suggestionPresentationBlockReason, } from "./suggestion-surface.js";
|
|
11
14
|
import { CLEAR_EXIT_INTERVAL_MS, boundedCleanup } from "../../foundation/terminal-cleanup/terminal-reset.js";
|
|
@@ -14,7 +17,7 @@ import { copyAcknowledgementText } from "../../ui/components/selection-copy.js";
|
|
|
14
17
|
import { ShellPromptSuggestions } from "./shell-prompt-suggestions.js";
|
|
15
18
|
import { OwnedUiTerminalHost, componentRuntime, sessionTerminalHostOptions, } from "./shell-host.js";
|
|
16
19
|
import { STREAM_PRESENTATION_INTERVAL_MS, StreamPresentationCoalescer, } from "./stream-presentation-coalescer.js";
|
|
17
|
-
import { OwnedUiSessionShellRoot,
|
|
20
|
+
import { OwnedUiSessionShellRoot, } from "./session-shell-root.js";
|
|
18
21
|
// Invariant: a disposed shell leaves the engine a host that holds no reference back to it.
|
|
19
22
|
const DETACHED_WORKFLOW_INTERACTION = { prompt: async () => null, notify() { } };
|
|
20
23
|
export { OwnedUiSessionShellRoot, } from "./session-shell-root.js";
|
|
@@ -27,21 +30,19 @@ export { formatSessionResumeCommand, quoteCommandArgument } from "./session-life
|
|
|
27
30
|
export class OwnedUiSessionPresenter {
|
|
28
31
|
backend;
|
|
29
32
|
#presenters;
|
|
30
|
-
|
|
33
|
+
selectors;
|
|
31
34
|
root;
|
|
32
35
|
#host;
|
|
33
36
|
#terminal;
|
|
34
37
|
#submission;
|
|
35
38
|
#login;
|
|
36
39
|
#concerns;
|
|
37
|
-
#listeners = new Set();
|
|
38
40
|
#unsubscribe;
|
|
39
41
|
#promptSuggestions;
|
|
40
42
|
#promptImages;
|
|
41
43
|
#skills;
|
|
42
44
|
#installedCommandSignature = "";
|
|
43
|
-
#
|
|
44
|
-
#historyBinding;
|
|
45
|
+
#history = null;
|
|
45
46
|
#extensionBridge;
|
|
46
47
|
#stop = new SessionStopLatch();
|
|
47
48
|
#dialogs;
|
|
@@ -64,7 +65,11 @@ export class OwnedUiSessionPresenter {
|
|
|
64
65
|
#inputCoordination;
|
|
65
66
|
#unbindShellSettings;
|
|
66
67
|
#unbindSessionSettings;
|
|
67
|
-
#
|
|
68
|
+
#terminalPresentation = new SessionTerminalPresentation({
|
|
69
|
+
terminal: () => this.#terminal,
|
|
70
|
+
programStatus: () => this.#programStatus,
|
|
71
|
+
titleEnabled: () => this.#customViewport && this.#started && !this.#disposed,
|
|
72
|
+
});
|
|
68
73
|
#programStatus;
|
|
69
74
|
#fullscreenExitOutput = "transcript";
|
|
70
75
|
#lastClearTime = 0;
|
|
@@ -85,8 +90,6 @@ export class OwnedUiSessionPresenter {
|
|
|
85
90
|
this.#inputCoordination = inputPresentation?.coordination !== false;
|
|
86
91
|
this.#host = host;
|
|
87
92
|
this.#terminal = host.connect(this);
|
|
88
|
-
// Invariant: the host's optional members follow the layout, so it is built only once the layout is known.
|
|
89
|
-
this.#dialogHost = this.#createDialogHost();
|
|
90
93
|
// Invariant: owned prompt limits and collapsed skills are bare-A1 replacements; comparison profiles keep pinned behavior.
|
|
91
94
|
this.#promptImages = this.#customViewport ? options.promptImages ?? null : null;
|
|
92
95
|
this.#skills = this.#customViewport ? options.skills ?? null : null;
|
|
@@ -124,7 +127,7 @@ export class OwnedUiSessionPresenter {
|
|
|
124
127
|
onInterrupt: () => { void this.interrupt(); },
|
|
125
128
|
onClear: () => { void this.clearOrExit(); },
|
|
126
129
|
onExit: () => { void this.shutdown(); },
|
|
127
|
-
onModelSelect: () => this.#customViewport ? this.showModelsDialog() : this.showModelSelector(),
|
|
130
|
+
onModelSelect: () => this.#customViewport ? this.selectors.showModelsDialog() : this.selectors.showModelSelector(),
|
|
128
131
|
onModelCycle: direction => { void this.cycleModel(direction); },
|
|
129
132
|
onThinkingCycle: () => { void this.cycleThinkingLevel(); },
|
|
130
133
|
onThinkingToggle: () => {
|
|
@@ -150,7 +153,7 @@ export class OwnedUiSessionPresenter {
|
|
|
150
153
|
},
|
|
151
154
|
onInputSurfaceChanged: () => {
|
|
152
155
|
this.#promptSuggestions?.invalidate();
|
|
153
|
-
this.#
|
|
156
|
+
this.#history?.synchronize();
|
|
154
157
|
},
|
|
155
158
|
onCopyText: (text, cut) => {
|
|
156
159
|
const delivery = this.#clipboard.copyText(text);
|
|
@@ -183,11 +186,12 @@ export class OwnedUiSessionPresenter {
|
|
|
183
186
|
...(startupRoute === undefined ? {} : { startupRoute }),
|
|
184
187
|
});
|
|
185
188
|
constructed.push(() => this.#dialogs.dispose());
|
|
189
|
+
this.selectors = this.#createSelectors(options.presenters);
|
|
186
190
|
const initialPiSettings = this.backend.settings.snapshot();
|
|
187
191
|
this.#programStatus = options.presenters.components.chrome.programStatusReporter(status => this.#terminal.setProgramStatus(status), () => this.view().status.footer?.sessionName ?? undefined);
|
|
188
192
|
this.#login = new LoginInteraction({
|
|
189
193
|
terminal: this.#terminal, root: this.root, programStatus: this.#programStatus, dialogs: options.presenters.components.dialogs,
|
|
190
|
-
syncProgress: () => this.#
|
|
194
|
+
syncProgress: () => this.#terminalPresentation.syncProgress(this.view()),
|
|
191
195
|
});
|
|
192
196
|
this.#submission = this.#createSubmission(cwd);
|
|
193
197
|
this.#reloadPresentation = reloadPresentation;
|
|
@@ -217,24 +221,15 @@ export class OwnedUiSessionPresenter {
|
|
|
217
221
|
terminal: this.#terminal,
|
|
218
222
|
root: this.root,
|
|
219
223
|
setTerminalProgress: enabled => {
|
|
220
|
-
this.#
|
|
224
|
+
this.#terminalPresentation.progressEnabled = enabled;
|
|
221
225
|
if (this.#terminal.running)
|
|
222
|
-
this.#
|
|
226
|
+
this.#terminalPresentation.syncProgress(this.view());
|
|
223
227
|
},
|
|
224
228
|
}, { customViewport: this.#customViewport });
|
|
225
229
|
constructed.push(this.#unbindSessionSettings);
|
|
226
230
|
if (this.#customViewport && promptHistory !== undefined) {
|
|
227
|
-
this.#
|
|
228
|
-
this.#
|
|
229
|
-
editor: this.root.editor,
|
|
230
|
-
store: promptHistory.store,
|
|
231
|
-
limit: promptHistory.limit,
|
|
232
|
-
fallback: this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []),
|
|
233
|
-
active: () => this.root.usesDefaultInputSurface(),
|
|
234
|
-
render: () => this.#terminal.requestRender(),
|
|
235
|
-
rehydrate: value => this.root.rehydrateHistoryText(value, id => this.#historyBinding?.imageSidecar?.readAttachment(id) ?? null),
|
|
236
|
-
});
|
|
237
|
-
constructed.push(() => { void this.#promptHistory?.close().catch(() => false); });
|
|
231
|
+
this.#history = this.#createHistory(promptHistory);
|
|
232
|
+
constructed.push(() => { void this.#history?.close().catch(() => false); });
|
|
238
233
|
}
|
|
239
234
|
this.#extensionBridge = this.#createExtensionBridge();
|
|
240
235
|
constructed.push(() => this.#extensionBridge.dispose());
|
|
@@ -291,7 +286,7 @@ export class OwnedUiSessionPresenter {
|
|
|
291
286
|
return this.root.inputCoordinationSurface();
|
|
292
287
|
}
|
|
293
288
|
setOverlaySurfaces(surfaces) {
|
|
294
|
-
this.root.
|
|
289
|
+
this.root.viewport.setOverlaySurfaces(surfaces);
|
|
295
290
|
}
|
|
296
291
|
noteImmediatePresentation() {
|
|
297
292
|
this.#streamPresentation.noteImmediatePresentation();
|
|
@@ -301,7 +296,9 @@ export class OwnedUiSessionPresenter {
|
|
|
301
296
|
return this.#layoutParts[part];
|
|
302
297
|
}
|
|
303
298
|
activated() {
|
|
304
|
-
this
|
|
299
|
+
const view = this.view();
|
|
300
|
+
this.#terminalPresentation.syncProgress(view);
|
|
301
|
+
this.#terminalPresentation.syncTitle(view, true);
|
|
305
302
|
}
|
|
306
303
|
handleViewportInput(data) {
|
|
307
304
|
if (!this.#inputCoordination)
|
|
@@ -354,7 +351,7 @@ export class OwnedUiSessionPresenter {
|
|
|
354
351
|
// resynchronizes the view, which is cheap next to re-reading the transcript.
|
|
355
352
|
if (event.type === "agent-run-started") {
|
|
356
353
|
this.#promptSuggestions?.invalidate();
|
|
357
|
-
this.root.
|
|
354
|
+
this.root.viewport.resumeFollowing();
|
|
358
355
|
}
|
|
359
356
|
if (event.type === "assistant-message-completed" && !event.successful) {
|
|
360
357
|
this.#programStatus.setErrorMessage(this.view().status.diagnostics.at(-1));
|
|
@@ -363,14 +360,14 @@ export class OwnedUiSessionPresenter {
|
|
|
363
360
|
this.#programStatus.handleEvent(event);
|
|
364
361
|
}
|
|
365
362
|
if (event.type === "assistant-message-completed") {
|
|
366
|
-
this.root.noteCompletedAssistantMessage();
|
|
363
|
+
this.root.viewport.noteCompletedAssistantMessage();
|
|
367
364
|
this.#promptSuggestions?.route(event, () => this.root.promptSuggestionPrepareBlockReason());
|
|
368
365
|
}
|
|
369
366
|
const semanticOnly = event.type === "agent-run-started" || event.type === "assistant-message-completed";
|
|
370
367
|
const view = event.type === "transcript-block" && this.#sessionGeneration === this.backend.identity.sessionGeneration
|
|
371
368
|
? this.#syncBlock(event.block)
|
|
372
369
|
: semanticOnly ? this.view() : this.#syncView();
|
|
373
|
-
this.#
|
|
370
|
+
this.#terminalPresentation.syncProgress(view);
|
|
374
371
|
this.#promptSuggestions?.noteView(view, this.backend.identity.sessionGeneration !== this.#sessionGeneration);
|
|
375
372
|
if (event.type === "status" && /^(Retrying|Compacting)/.test(event.status.workingMessage ?? "")) {
|
|
376
373
|
this.#promptSuggestions?.invalidate();
|
|
@@ -395,8 +392,9 @@ export class OwnedUiSessionPresenter {
|
|
|
395
392
|
return;
|
|
396
393
|
this.#started = true;
|
|
397
394
|
this.#terminal.start();
|
|
398
|
-
this.#
|
|
399
|
-
this.#
|
|
395
|
+
this.#terminalPresentation.syncTitle(this.view());
|
|
396
|
+
this.#history?.start();
|
|
397
|
+
this.#terminalPresentation.syncProgress(this.view());
|
|
400
398
|
void this.backend.extensions.bindExtensionUi(this.#extensionBridge.context, () => { void this.shutdown(); });
|
|
401
399
|
this.#syncView();
|
|
402
400
|
// Performance: the spare clipboard helpers fork after the first frame is out, so startup never waits on them.
|
|
@@ -405,15 +403,10 @@ export class OwnedUiSessionPresenter {
|
|
|
405
403
|
return;
|
|
406
404
|
this.#dialogs.presentStartupRoute();
|
|
407
405
|
void this.#presenters.components.dialogs.lazySelectors().then(selectors => selectors.prepare()).catch(() => { });
|
|
408
|
-
this.root.
|
|
406
|
+
this.root.promptChips.warm();
|
|
409
407
|
this.#clipboard.warm();
|
|
410
408
|
});
|
|
411
409
|
}
|
|
412
|
-
onView(listener) {
|
|
413
|
-
this.#listeners.add(listener);
|
|
414
|
-
listener(this.view());
|
|
415
|
-
return () => this.#listeners.delete(listener);
|
|
416
|
-
}
|
|
417
410
|
waitUntilStopped() {
|
|
418
411
|
return this.#stop.stopped;
|
|
419
412
|
}
|
|
@@ -450,9 +443,9 @@ export class OwnedUiSessionPresenter {
|
|
|
450
443
|
if (now - this.#lastEscapeTime < 500) {
|
|
451
444
|
this.#lastEscapeTime = 0;
|
|
452
445
|
if (action === "tree")
|
|
453
|
-
await this.showTreeSelector();
|
|
446
|
+
await this.selectors.showTreeSelector();
|
|
454
447
|
else
|
|
455
|
-
this.showForkSelector();
|
|
448
|
+
this.selectors.showForkSelector();
|
|
456
449
|
return { outcome: "completed", diagnostic: null };
|
|
457
450
|
}
|
|
458
451
|
this.#lastEscapeTime = now;
|
|
@@ -461,36 +454,6 @@ export class OwnedUiSessionPresenter {
|
|
|
461
454
|
async abort() {
|
|
462
455
|
return this.#submission.execute(this.#simple("abort"));
|
|
463
456
|
}
|
|
464
|
-
async retry() {
|
|
465
|
-
this.#promptSuggestions?.invalidate();
|
|
466
|
-
return this.#submission.execute(this.#simple("retry"));
|
|
467
|
-
}
|
|
468
|
-
async compact() {
|
|
469
|
-
this.#promptSuggestions?.invalidate();
|
|
470
|
-
return this.#submission.execute(this.#simple("compact"));
|
|
471
|
-
}
|
|
472
|
-
async newSession() {
|
|
473
|
-
this.#promptSuggestions?.invalidate();
|
|
474
|
-
return this.#submission.execute(this.#simple("new-session"));
|
|
475
|
-
}
|
|
476
|
-
async resumeSession(sessionPath) {
|
|
477
|
-
this.#promptSuggestions?.invalidate();
|
|
478
|
-
return this.#submission.execute({
|
|
479
|
-
type: "resume-session",
|
|
480
|
-
correlationId: this.#correlation("resume"),
|
|
481
|
-
sessionId: this.backend.identity.sessionId,
|
|
482
|
-
sessionPath,
|
|
483
|
-
});
|
|
484
|
-
}
|
|
485
|
-
async setModel(providerId, modelId) {
|
|
486
|
-
this.#promptSuggestions?.invalidate();
|
|
487
|
-
return this.#submission.execute({
|
|
488
|
-
type: "set-model",
|
|
489
|
-
correlationId: this.#correlation("model"),
|
|
490
|
-
sessionId: this.backend.identity.sessionId,
|
|
491
|
-
model: { providerId, modelId, displayName: modelId },
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
457
|
async setThinkingLevel(thinkingLevel) {
|
|
495
458
|
return this.#submission.execute({
|
|
496
459
|
type: "set-thinking-level",
|
|
@@ -519,185 +482,6 @@ export class OwnedUiSessionPresenter {
|
|
|
519
482
|
showSelector(title, options, onSelect, onCancel) {
|
|
520
483
|
return this.#dialogs.showSelector(title, options, onSelect, onCancel);
|
|
521
484
|
}
|
|
522
|
-
// Rationale: presenters see the shell only as a dialog host; selectors open in the input dock and run choices as workflows.
|
|
523
|
-
#createDialogHost() {
|
|
524
|
-
const isDisposed = () => this.#disposed;
|
|
525
|
-
return {
|
|
526
|
-
get disposed() { return isDisposed(); },
|
|
527
|
-
setInputSurface: surface => this.root.setInputSurface(surface),
|
|
528
|
-
requestRender: () => this.#terminal.requestRender(),
|
|
529
|
-
viewport: () => this.#terminal.viewport(),
|
|
530
|
-
appendWorkflowStatus: text => this.root.workflow.appendStatus(text),
|
|
531
|
-
appendWorkflowResult: result => this.root.workflow.appendResult(result),
|
|
532
|
-
runWorkflow: request => this.runWorkflow(request),
|
|
533
|
-
// Invariant: the custom bare-A1 surface holds frames while optional selectors load and is permanently
|
|
534
|
-
// fullscreen; the pinned comparison profiles render immediately and keep Pi's TUI mode switch.
|
|
535
|
-
...(this.#customViewport
|
|
536
|
-
? { beginPresentationHold: () => this.#terminal.beginPresentationHold() }
|
|
537
|
-
: { switchTuiMode: mode => this.#terminal.switchMode(mode) }),
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
async showThinkingSelector() {
|
|
541
|
-
const snapshot = this.backend.settings.snapshot();
|
|
542
|
-
const close = () => {
|
|
543
|
-
this.root.setFooterLevel(true);
|
|
544
|
-
this.root.setInputSurface(null);
|
|
545
|
-
this.#terminal.requestRender();
|
|
546
|
-
};
|
|
547
|
-
const select = (level) => {
|
|
548
|
-
close();
|
|
549
|
-
void this.runWorkflow({ command: "thinking", argument: "", selection: level });
|
|
550
|
-
};
|
|
551
|
-
const releasePresentation = this.#customViewport ? this.#terminal.beginPresentationHold() : undefined;
|
|
552
|
-
try {
|
|
553
|
-
const selectors = await this.#presenters.components.dialogs.lazySelectors();
|
|
554
|
-
const component = await selectors.createThinking({
|
|
555
|
-
currentLevel: snapshot.thinkingLevel,
|
|
556
|
-
availableLevels: snapshot.availableThinkingLevels,
|
|
557
|
-
onSelect: select,
|
|
558
|
-
onCancel: close,
|
|
559
|
-
onSelectAsDefault: level => this.backend.settings.setDefaultThinkingLevel(level),
|
|
560
|
-
defaultLevel: snapshot.defaultThinkingLevel,
|
|
561
|
-
...(this.backend.settings.productMode === "bare" ? {
|
|
562
|
-
presentation: {
|
|
563
|
-
profile: "bare",
|
|
564
|
-
cycleBinding: this.root.editor.keybindingConfig()["app.thinking.cycle"] ?? [],
|
|
565
|
-
},
|
|
566
|
-
} : {}),
|
|
567
|
-
});
|
|
568
|
-
if (this.#disposed)
|
|
569
|
-
return;
|
|
570
|
-
this.root.setFooterLevel(false);
|
|
571
|
-
this.root.setInputSurface(component);
|
|
572
|
-
this.#terminal.requestRender();
|
|
573
|
-
}
|
|
574
|
-
finally {
|
|
575
|
-
releasePresentation?.();
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
/** The Skills dialog: a replacement input like the model selector, applying the chosen skill through the prompt path. */
|
|
579
|
-
showSkillsSelector(skills = this.#skillSummaries()) {
|
|
580
|
-
const close = this.#dialogs.closeInputSurface;
|
|
581
|
-
const component = this.#presenters.components.dialogs.skillsSelector({
|
|
582
|
-
skills,
|
|
583
|
-
onSelect: name => {
|
|
584
|
-
close();
|
|
585
|
-
void this.#submission.sendSlashPrompt(this.#presenters.components.skills.prompt(name), this.#presenters.components.skills.prompt(name)).catch(() => this.#submission.reportError());
|
|
586
|
-
},
|
|
587
|
-
onCancel: close,
|
|
588
|
-
});
|
|
589
|
-
this.root.setInputSurface(component);
|
|
590
|
-
this.#terminal.requestRender();
|
|
591
|
-
}
|
|
592
|
-
showModelSelector(initialSearchInput) {
|
|
593
|
-
this.#presenters.openModelSelector(this.#dialogHost, initialSearchInput);
|
|
594
|
-
}
|
|
595
|
-
showForkSelector() {
|
|
596
|
-
const options = this.backend.catalog.pinnedForkOptions();
|
|
597
|
-
if (options.length === 0) {
|
|
598
|
-
this.root.workflow.appendResult({ command: "fork", outcome: "completed", message: "No messages to fork from", messageKind: "status" });
|
|
599
|
-
this.#terminal.requestRender();
|
|
600
|
-
return;
|
|
601
|
-
}
|
|
602
|
-
const close = this.#dialogs.closeInputSurface;
|
|
603
|
-
const component = this.#presenters.components.dialogs.userMessageSelector(options, selection => {
|
|
604
|
-
close();
|
|
605
|
-
void this.runWorkflow({ command: "fork", argument: "", selection });
|
|
606
|
-
}, close);
|
|
607
|
-
this.root.setInputSurface(component);
|
|
608
|
-
this.#terminal.requestRender();
|
|
609
|
-
}
|
|
610
|
-
async showLogoutSelector() {
|
|
611
|
-
let options;
|
|
612
|
-
try {
|
|
613
|
-
options = await this.backend.catalog.pinnedLogoutOptions();
|
|
614
|
-
}
|
|
615
|
-
catch (error) {
|
|
616
|
-
this.root.workflow.appendResult({
|
|
617
|
-
command: "logout",
|
|
618
|
-
outcome: "failed",
|
|
619
|
-
message: `Could not read stored credentials: ${error instanceof Error ? error.message : String(error)}`,
|
|
620
|
-
});
|
|
621
|
-
this.#terminal.requestRender();
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
if (options.length === 0) {
|
|
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.");
|
|
626
|
-
this.#terminal.requestRender();
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
const close = this.#dialogs.closeInputSurface;
|
|
630
|
-
const component = this.#presenters.components.dialogs.authProviderSelector("logout", options, selection => {
|
|
631
|
-
close();
|
|
632
|
-
void this.runWorkflow({ command: "logout", argument: "", selection });
|
|
633
|
-
}, close);
|
|
634
|
-
this.root.setInputSurface(component);
|
|
635
|
-
this.#terminal.requestRender();
|
|
636
|
-
}
|
|
637
|
-
showLoginMethodSelector(providerReference) {
|
|
638
|
-
const method = this.backend.catalog.pinnedLoginMethodOptions(providerReference);
|
|
639
|
-
if (method.options.length === 0) {
|
|
640
|
-
this.showLoginProviderSelector(undefined, providerReference);
|
|
641
|
-
return;
|
|
642
|
-
}
|
|
643
|
-
if (method.options.length === 1) {
|
|
644
|
-
const selection = method.options[0]?.id;
|
|
645
|
-
if (selection)
|
|
646
|
-
void this.runWorkflow({ command: "login", argument: "", selection });
|
|
647
|
-
return;
|
|
648
|
-
}
|
|
649
|
-
const close = this.#dialogs.closeInputSurface;
|
|
650
|
-
const labels = method.options.map(option => option.label);
|
|
651
|
-
const component = this.#presenters.components.dialogs.extensionSelector(method.title, labels, label => {
|
|
652
|
-
const selection = method.options.find(option => option.label === label)?.id;
|
|
653
|
-
if (!selection)
|
|
654
|
-
return;
|
|
655
|
-
close();
|
|
656
|
-
void this.runWorkflow({ command: "login", argument: "", selection });
|
|
657
|
-
}, close);
|
|
658
|
-
this.root.setInputSurface(component);
|
|
659
|
-
this.#terminal.requestRender();
|
|
660
|
-
}
|
|
661
|
-
showTreeSelector(initialSelectedId) {
|
|
662
|
-
return this.#presenters.openTreeSelector(this.#dialogHost, (entryId, skipSummaryPrompt) => {
|
|
663
|
-
void this.#completeTreeSelection(entryId, skipSummaryPrompt);
|
|
664
|
-
}, initialSelectedId);
|
|
665
|
-
}
|
|
666
|
-
showLoginAuthTypeSelector() {
|
|
667
|
-
const close = this.#dialogs.closeInputSurface;
|
|
668
|
-
const labels = ["Sign in with an account", "Sign in with an API key"];
|
|
669
|
-
const component = this.#presenters.components.dialogs.extensionSelector("Select authentication method:", labels, label => {
|
|
670
|
-
close();
|
|
671
|
-
this.showLoginProviderSelector(label === labels[0] ? "oauth" : "api_key");
|
|
672
|
-
}, close);
|
|
673
|
-
this.root.setInputSurface(component);
|
|
674
|
-
this.#terminal.requestRender();
|
|
675
|
-
}
|
|
676
|
-
showLoginProviderSelector(authType, initialSearchInput) {
|
|
677
|
-
const options = this.backend.catalog.pinnedLoginOptions(authType);
|
|
678
|
-
if (options.length === 0) {
|
|
679
|
-
this.root.workflow.appendStatus(authType === "oauth" ? "No account providers available." : authType === "api_key" ? "No API key providers available." : "No login providers available.");
|
|
680
|
-
this.#terminal.requestRender();
|
|
681
|
-
return;
|
|
682
|
-
}
|
|
683
|
-
const close = this.#dialogs.closeInputSurface;
|
|
684
|
-
const component = this.#presenters.components.dialogs.authProviderSelector("login", options, id => {
|
|
685
|
-
close();
|
|
686
|
-
void this.runWorkflow({ command: "login", argument: "", selection: id });
|
|
687
|
-
}, () => {
|
|
688
|
-
close();
|
|
689
|
-
if (authType !== undefined)
|
|
690
|
-
this.showLoginAuthTypeSelector();
|
|
691
|
-
}, initialSearchInput);
|
|
692
|
-
this.root.setInputSurface(component);
|
|
693
|
-
this.#terminal.requestRender();
|
|
694
|
-
}
|
|
695
|
-
showSessionSelector() {
|
|
696
|
-
return this.#presenters.openSessionSelector(this.#dialogHost, () => { void this.shutdown(); });
|
|
697
|
-
}
|
|
698
|
-
showSettingsSelector() {
|
|
699
|
-
this.#presenters.openSettingsSelector(this.#dialogHost);
|
|
700
|
-
}
|
|
701
485
|
shutdown() {
|
|
702
486
|
this.#shutdownPromise ??= this.#shutdown().finally(() => {
|
|
703
487
|
// Invariant: a failed quit is retryable; ordinary shutdown has disposed the shell already.
|
|
@@ -757,7 +541,7 @@ export class OwnedUiSessionPresenter {
|
|
|
757
541
|
return { outcome: "completed", diagnostic: null };
|
|
758
542
|
}
|
|
759
543
|
}
|
|
760
|
-
const selected = openWorkflowSelector(request, this);
|
|
544
|
+
const selected = openWorkflowSelector(request, this.selectors);
|
|
761
545
|
if (selected !== undefined)
|
|
762
546
|
return selected;
|
|
763
547
|
if (request.command === "reload") {
|
|
@@ -807,7 +591,7 @@ export class OwnedUiSessionPresenter {
|
|
|
807
591
|
for (const message of result.messages)
|
|
808
592
|
this.root.workflow.appendMessage(message);
|
|
809
593
|
}
|
|
810
|
-
this.showModelSelector((result.detail ?? request.argument.trim()) || undefined);
|
|
594
|
+
this.selectors.showModelSelector((result.detail ?? request.argument.trim()) || undefined);
|
|
811
595
|
return { outcome: "completed", diagnostic: null };
|
|
812
596
|
}
|
|
813
597
|
if (result.outcome === "requires-confirmation" && request.command === "resume") {
|
|
@@ -836,7 +620,7 @@ export class OwnedUiSessionPresenter {
|
|
|
836
620
|
if (request.command === "tree" && result.outcome === "completed") {
|
|
837
621
|
if (result.detail && !this.root.editor.getText().trim())
|
|
838
622
|
this.root.editor.setText(result.detail);
|
|
839
|
-
this.root.
|
|
623
|
+
this.root.viewport.resumeFollowing();
|
|
840
624
|
}
|
|
841
625
|
if (shareDialog !== undefined && this.#customViewport && result.outcome === "completed" && result.detail !== undefined) {
|
|
842
626
|
this.root.workflow.appendStatus(shareDialog.renderShellShareResult(result.message, result.detail, this.#presenters.theme.current(), url => this.#presenters.components.text.hyperlink(url)));
|
|
@@ -855,40 +639,11 @@ export class OwnedUiSessionPresenter {
|
|
|
855
639
|
const sleep = this.#reloadPresentation?.sleep ?? ((ms) => new Promise(resolve => setTimeout(resolve, ms)));
|
|
856
640
|
await sleep(remaining);
|
|
857
641
|
}
|
|
858
|
-
showTrustSelector() {
|
|
859
|
-
const context = this.backend.catalog.pinnedProjectTrustContext();
|
|
860
|
-
const close = this.#dialogs.closeInputSurface;
|
|
861
|
-
const component = this.#presenters.components.dialogs.trustSelector({
|
|
862
|
-
...context,
|
|
863
|
-
onSelect: selection => {
|
|
864
|
-
try {
|
|
865
|
-
this.backend.catalog.persistProjectTrust(selection.updates);
|
|
866
|
-
close();
|
|
867
|
-
this.root.workflow.appendStatus(`Saved trust decision: ${selection.trusted ? "trusted" : "untrusted"}. Restart pi for this to take effect.`);
|
|
868
|
-
}
|
|
869
|
-
catch (error) {
|
|
870
|
-
close();
|
|
871
|
-
this.root.workflow.appendResult({ command: "trust", outcome: "failed", message: error instanceof Error ? error.message : String(error) });
|
|
872
|
-
}
|
|
873
|
-
this.#terminal.requestRender();
|
|
874
|
-
},
|
|
875
|
-
onCancel: close,
|
|
876
|
-
});
|
|
877
|
-
this.root.setInputSurface(component);
|
|
878
|
-
this.#terminal.requestRender();
|
|
879
|
-
}
|
|
880
|
-
showScopedModelsSelector() {
|
|
881
|
-
this.#presenters.openScopedModelsSelector(this.#dialogHost);
|
|
882
|
-
}
|
|
883
642
|
// Invariant: bare A1 routes `models`; the comparison profile keeps the pinned `model`/`scoped-models` pair. Hidden routes are shared.
|
|
884
643
|
#isWorkflowRoute(value) {
|
|
885
644
|
return this.#presenters.components.workflows.commandNames(this.backend.settings.productMode).includes(value)
|
|
886
645
|
|| OWNED_UI_HIDDEN_COMMAND_NAMES.includes(value);
|
|
887
646
|
}
|
|
888
|
-
/** The bare-A1 unified Models dialog: switch on Enter, scope on Space, persist on Ctrl+S, all through the engine. */
|
|
889
|
-
showModelsDialog(initialQuery) {
|
|
890
|
-
this.#presenters.openModelsDialog(this.#dialogHost, initialQuery);
|
|
891
|
-
}
|
|
892
647
|
// Invariant: one teardown per presenter, starting on a microtask so never inside the event listener that
|
|
893
648
|
// requested it. Callers during the teardown share its outcome; a later call finds it done. Closing the
|
|
894
649
|
// terminal host's last presenter ends the terminal.
|
|
@@ -923,9 +678,9 @@ export class OwnedUiSessionPresenter {
|
|
|
923
678
|
this.#submission.cancelWaiting();
|
|
924
679
|
let pasteCleanup = Promise.resolve();
|
|
925
680
|
let historyCleanup = Promise.resolve(true);
|
|
926
|
-
attempt(() => { historyCleanup = this.#
|
|
681
|
+
attempt(() => { historyCleanup = this.#history?.close() ?? Promise.resolve(true); });
|
|
927
682
|
attempt(() => { pasteCleanup = this.root.disposePendingPastes(); });
|
|
928
|
-
attempt(() => this.root.
|
|
683
|
+
attempt(() => this.root.viewport.clearPointerState());
|
|
929
684
|
attempt(() => this.#streamPresentation.dispose());
|
|
930
685
|
attempt(() => this.#promptSuggestions?.dispose());
|
|
931
686
|
attempt(() => this.#unbindShellSettings());
|
|
@@ -975,8 +730,6 @@ export class OwnedUiSessionPresenter {
|
|
|
975
730
|
this.#streamPresentation.presentImmediate();
|
|
976
731
|
}
|
|
977
732
|
const view = this.view();
|
|
978
|
-
for (const listener of this.#listeners)
|
|
979
|
-
listener(view);
|
|
980
733
|
return view;
|
|
981
734
|
}
|
|
982
735
|
// Rationale: extensions reach the shell only through this bridge; every surface they draw lands in the root.
|
|
@@ -1005,14 +758,40 @@ export class OwnedUiSessionPresenter {
|
|
|
1005
758
|
setToolsExpanded: expanded => this.root.setToolsExpanded(expanded),
|
|
1006
759
|
});
|
|
1007
760
|
}
|
|
761
|
+
#createSelectors(presenters) {
|
|
762
|
+
return new SessionSelectors({
|
|
763
|
+
root: this.root,
|
|
764
|
+
terminal: this.#terminal,
|
|
765
|
+
dialogs: this.#dialogs,
|
|
766
|
+
presenters,
|
|
767
|
+
backend: this.backend,
|
|
768
|
+
customViewport: this.#customViewport,
|
|
769
|
+
disposed: () => this.#disposed,
|
|
770
|
+
runWorkflow: request => this.runWorkflow(request),
|
|
771
|
+
sendSlashPrompt: (text, typed) => this.#submission.sendSlashPrompt(text, typed),
|
|
772
|
+
reportError: () => this.#submission.reportError(),
|
|
773
|
+
input: (title, placeholder, inputOptions) => this.#extensionBridge.input(title, placeholder, inputOptions),
|
|
774
|
+
shutdown: () => { void this.shutdown(); },
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
#createHistory(promptHistory) {
|
|
778
|
+
return new SessionPromptHistory(promptHistory, {
|
|
779
|
+
editor: this.root.editor,
|
|
780
|
+
usesDefaultInputSurface: () => this.root.usesDefaultInputSurface(),
|
|
781
|
+
rehydrate: (text, resolveImage) => this.root.promptChips.rehydrateHistoryText(text, resolveImage),
|
|
782
|
+
requestRender: () => this.#terminal.requestRender(),
|
|
783
|
+
transcript: () => this.view().transcript,
|
|
784
|
+
currentHistorySessionId: () => this.backend.identity.currentHistorySessionId(),
|
|
785
|
+
});
|
|
786
|
+
}
|
|
1008
787
|
#createSubmission(cwd) {
|
|
1009
788
|
return new PromptSubmission({
|
|
1010
789
|
backend: this.backend,
|
|
1011
790
|
root: this.root,
|
|
1012
791
|
terminal: this.#terminal,
|
|
1013
792
|
cwd, statusText: this.#presenters.components.info.statusText,
|
|
1014
|
-
promptHistory: () => this.#
|
|
1015
|
-
imageSidecar: () => this.#
|
|
793
|
+
promptHistory: () => this.#history?.controller ?? null,
|
|
794
|
+
imageSidecar: () => this.#history?.imageSidecar,
|
|
1016
795
|
disposed: () => this.#disposed,
|
|
1017
796
|
correlation: prefix => this.#correlation(prefix),
|
|
1018
797
|
lifecycle: () => this.view().lifecycle,
|
|
@@ -1033,7 +812,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1033
812
|
this.#login,
|
|
1034
813
|
{ onSessionReplaced: () => this.#extensionBridge.reset() },
|
|
1035
814
|
// Invariant: a replaced session takes its transient viewport and owned-route state with it.
|
|
1036
|
-
{ onSessionReplaced: () => this.root.
|
|
815
|
+
{ onSessionReplaced: () => this.root.viewport.reset() },
|
|
1037
816
|
this.#dialogs,
|
|
1038
817
|
{ onSessionReplaced: () => this.root.setInputSurface(null) },
|
|
1039
818
|
{ onSessionReplaced: () => this.root.resetExtensionUi() },
|
|
@@ -1049,64 +828,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1049
828
|
this.#sessionBindingGeneration = this.backend.identity.sessionBindingGeneration;
|
|
1050
829
|
this.root.transcript.reset();
|
|
1051
830
|
}
|
|
1052
|
-
|
|
1053
|
-
if (binding?.options.forSession !== undefined || binding?.options.forScope !== undefined) {
|
|
1054
|
-
const sessionId = this.backend.identity.currentHistorySessionId();
|
|
1055
|
-
const selectedScope = scope ?? binding.scope;
|
|
1056
|
-
if (selectedScope !== binding.scope || sessionId !== binding.sessionId) {
|
|
1057
|
-
if (!replaced)
|
|
1058
|
-
this.root.editor.recall?.restoreDraft?.();
|
|
1059
|
-
const previous = this.#promptHistory;
|
|
1060
|
-
this.#promptHistory = null;
|
|
1061
|
-
binding.imageSidecar = undefined;
|
|
1062
|
-
binding.scope = selectedScope;
|
|
1063
|
-
binding.sessionId = sessionId ?? undefined;
|
|
1064
|
-
void previous?.close().catch(() => false);
|
|
1065
|
-
const destination = binding.options.forScope !== undefined
|
|
1066
|
-
? binding.options.forScope(selectedScope, sessionId)
|
|
1067
|
-
: sessionId === null ? null : binding.options.forSession(sessionId);
|
|
1068
|
-
if (destination !== null) {
|
|
1069
|
-
binding.imageSidecar = destination.imageSidecar;
|
|
1070
|
-
const controller = new PromptHistoryController({
|
|
1071
|
-
editor: this.root.editor,
|
|
1072
|
-
store: destination.store,
|
|
1073
|
-
limit: binding.options.limit,
|
|
1074
|
-
fallback: replaced ? this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []) : [],
|
|
1075
|
-
active: () => this.root.usesDefaultInputSurface(),
|
|
1076
|
-
render: () => this.#terminal.requestRender(),
|
|
1077
|
-
rehydrate: value => this.root.rehydrateHistoryText(value, id => this.#historyBinding?.imageSidecar?.readAttachment(id) ?? null),
|
|
1078
|
-
});
|
|
1079
|
-
this.#promptHistory = controller;
|
|
1080
|
-
if (this.#started)
|
|
1081
|
-
controller.start();
|
|
1082
|
-
}
|
|
1083
|
-
else {
|
|
1084
|
-
// Security: missing identity must not reopen Shared or retain another session's recall.
|
|
1085
|
-
const fallback = replaced ? this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []).reverse() : [];
|
|
1086
|
-
this.root.editor.recall?.reset();
|
|
1087
|
-
this.root.editor.recall?.replace(fallback);
|
|
1088
|
-
}
|
|
1089
|
-
return;
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
if (replaced)
|
|
1093
|
-
this.#promptHistory?.reset(this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []));
|
|
1094
|
-
}
|
|
1095
|
-
#syncTerminalProgress(view) {
|
|
1096
|
-
if (!this.#terminal.running)
|
|
1097
|
-
return;
|
|
1098
|
-
this.#terminal.setTerminalProgress(this.#terminalProgressEnabled && view.lifecycle === "busy");
|
|
1099
|
-
if (view.lifecycle === "stopped" || view.lifecycle === "stopping") {
|
|
1100
|
-
this.#programStatus.clear();
|
|
1101
|
-
return;
|
|
1102
|
-
}
|
|
1103
|
-
this.#programStatus.setBlocked("dialog", view.dialog === null ? undefined : {
|
|
1104
|
-
kind: "question",
|
|
1105
|
-
message: view.dialog.title,
|
|
1106
|
-
});
|
|
1107
|
-
if (view.lifecycle === "failed")
|
|
1108
|
-
this.#programStatus.setErrorMessage(view.status.diagnostics.at(-1));
|
|
1109
|
-
this.#programStatus.report();
|
|
831
|
+
this.#history?.rebind(replaced, scope);
|
|
1110
832
|
}
|
|
1111
833
|
#syncView() {
|
|
1112
834
|
this.#streamPresentation.noteImmediatePresentation();
|
|
@@ -1114,11 +836,10 @@ export class OwnedUiSessionPresenter {
|
|
|
1114
836
|
if (this.backend.identity.sessionGeneration !== this.#sessionGeneration)
|
|
1115
837
|
this.#concerns.replaceSession();
|
|
1116
838
|
this.root.update(view);
|
|
839
|
+
this.#terminalPresentation.syncTitle(view);
|
|
1117
840
|
this.#dialogs.syncBackend(view.dialog);
|
|
1118
841
|
this.#presentStartupTrustWarning(view);
|
|
1119
842
|
this.#terminal.requestRender();
|
|
1120
|
-
for (const listener of this.#listeners)
|
|
1121
|
-
listener(view);
|
|
1122
843
|
return view;
|
|
1123
844
|
}
|
|
1124
845
|
// Rationale: a cancelled or failed trust choice explains the restricted session where the
|
|
@@ -1188,7 +909,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1188
909
|
const skills = this.#skillSummaries();
|
|
1189
910
|
const trimmed = argument.trim();
|
|
1190
911
|
if (trimmed.length === 0) {
|
|
1191
|
-
this.showSkillsSelector(skills);
|
|
912
|
+
this.selectors.showSkillsSelector(skills);
|
|
1192
913
|
return { outcome: "completed", diagnostic: null };
|
|
1193
914
|
}
|
|
1194
915
|
const separator = trimmed.search(/\s/u);
|
|
@@ -1202,45 +923,6 @@ export class OwnedUiSessionPresenter {
|
|
|
1202
923
|
}
|
|
1203
924
|
return this.#submission.sendSlashPrompt(this.#presenters.components.skills.prompt(skill.name, separator < 0 ? "" : trimmed.slice(separator + 1)), text);
|
|
1204
925
|
}
|
|
1205
|
-
#treeSummary() {
|
|
1206
|
-
return new Promise(resolve => {
|
|
1207
|
-
this.root.setInputSurface(this.#presenters.components.dialogs.extensionSelector("Summarize Branch?", ["No summary", "Summarize", "Summarize with custom prompt"], resolve, () => resolve(undefined)), true, "opaque");
|
|
1208
|
-
this.#terminal.requestRender();
|
|
1209
|
-
});
|
|
1210
|
-
}
|
|
1211
|
-
async #completeTreeSelection(entryId, skipSummaryPrompt) {
|
|
1212
|
-
let summarize = false;
|
|
1213
|
-
let customInstructions;
|
|
1214
|
-
if (!skipSummaryPrompt) {
|
|
1215
|
-
while (true) {
|
|
1216
|
-
const choice = await this.#treeSummary();
|
|
1217
|
-
if (choice === undefined) {
|
|
1218
|
-
await this.showTreeSelector(entryId);
|
|
1219
|
-
return;
|
|
1220
|
-
}
|
|
1221
|
-
summarize = choice !== "No summary";
|
|
1222
|
-
if (choice === "Summarize with custom prompt") {
|
|
1223
|
-
customInstructions = await this.#extensionBridge.input("Custom Summarization Instructions", "", { retainSurfaceOnSettle: true });
|
|
1224
|
-
if (customInstructions === undefined)
|
|
1225
|
-
continue;
|
|
1226
|
-
}
|
|
1227
|
-
break;
|
|
1228
|
-
}
|
|
1229
|
-
}
|
|
1230
|
-
this.root.setInputSurface(null);
|
|
1231
|
-
this.#terminal.requestRender();
|
|
1232
|
-
const result = await this.runWorkflow({
|
|
1233
|
-
command: "tree",
|
|
1234
|
-
argument: "",
|
|
1235
|
-
selection: entryId,
|
|
1236
|
-
treeSummary: {
|
|
1237
|
-
summarize,
|
|
1238
|
-
...(customInstructions === undefined ? {} : { customInstructions }),
|
|
1239
|
-
},
|
|
1240
|
-
});
|
|
1241
|
-
if (result.diagnostic === "Branch summarization cancelled")
|
|
1242
|
-
await this.showTreeSelector(entryId);
|
|
1243
|
-
}
|
|
1244
926
|
#simple(type) {
|
|
1245
927
|
return { type, correlationId: this.#correlation(type), sessionId: this.backend.identity.sessionId };
|
|
1246
928
|
}
|