@timurproko/a1 0.2.7-dev.1270 → 0.2.7-dev.1276
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/app/session-shell/apps-dialog.d.ts +33 -0
- package/dist/app/session-shell/apps-dialog.js +62 -0
- package/dist/app/session-shell/dialog-coordinator.d.ts +12 -5
- package/dist/app/session-shell/dialog-coordinator.js +113 -15
- package/dist/app/session-shell/input-route.d.ts +23 -0
- package/dist/app/session-shell/input-route.js +59 -0
- package/dist/app/session-shell/session-selectors.d.ts +4 -4
- package/dist/app/session-shell/session-selectors.js +8 -3
- package/dist/app/session-shell/session-shell-root.js +6 -2
- package/dist/app/session-shell/session-shell.js +13 -5
- package/dist/app/session-shell/shell-host.d.ts +1 -0
- package/dist/app/session-shell/shell-host.js +22 -11
- package/dist/app/session-shell/viewport-pointer.js +5 -1
- package/dist/app/session-shell/workflow-output.js +12 -0
- package/dist/app/session-shell/workflow-router.d.ts +2 -2
- package/dist/composition/owned-ui.js +17 -13
- package/dist/composition/settings-route-host.js +1 -0
- package/dist/contracts/owned-ui/session-presenters.d.ts +1 -1
- package/dist/contracts/owned-ui/session-workflows.d.ts +3 -1
- package/dist/contracts/owned-ui/shell-components.d.ts +12 -0
- package/dist/contracts/presentation/component.d.ts +7 -0
- package/dist/contracts/presentation/index.d.ts +2 -0
- package/dist/contracts/presentation/index.js +4 -0
- package/dist/contracts/presentation/progress-palette.generated.d.ts +25 -1
- package/dist/contracts/presentation/progress-palette.generated.js +2 -135
- package/dist/contracts/presentation/terminal.d.ts +4 -0
- package/dist/contracts/presentation/theme.d.ts +2 -0
- package/dist/features/owned-ui/project-trust-dialog.d.ts +1 -1
- package/dist/features/owned-ui/project-trust-dialog.js +5 -5
- package/dist/features/owned-ui/project-trust-prompt.js +2 -2
- package/dist/features/owned-ui/reference-screen-app.d.ts +2 -0
- package/dist/features/owned-ui/reference-screen-app.js +4 -1
- package/dist/features/owned-ui/settings-app.js +6 -6
- package/dist/features/owned-ui/settings-model-dialog.js +3 -3
- package/dist/foundation/lifecycle/user-exports.d.ts +5 -0
- package/dist/foundation/lifecycle/user-exports.js +37 -0
- package/dist/foundation/startup/startup-descriptor.js +2 -2
- package/dist/integrations/pi/components/deferred-selector.d.ts +6 -0
- package/dist/integrations/pi/components/deferred-selector.js +40 -0
- package/dist/integrations/pi/components/login-dialog-loader.d.ts +3 -0
- package/dist/integrations/pi/components/login-dialog-loader.js +57 -0
- package/dist/integrations/pi/components/login-links.d.ts +6 -0
- package/dist/integrations/pi/components/login-links.js +31 -0
- package/dist/integrations/pi/components/login-text.d.ts +7 -0
- package/dist/integrations/pi/components/login-text.js +17 -0
- package/dist/integrations/pi/components/modal-frame.d.ts +5 -0
- package/dist/integrations/pi/components/modal-frame.js +30 -2
- package/dist/integrations/pi/components/models-dialog-loader.d.ts +11 -0
- package/dist/integrations/pi/components/models-dialog-loader.js +45 -0
- package/dist/integrations/pi/components/models-dialog.d.ts +2 -0
- package/dist/integrations/pi/components/models-dialog.js +13 -7
- package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -2
- package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +21 -15
- package/dist/integrations/pi/components/shell-footer-status.js +3 -2
- package/dist/integrations/pi/components/shell-presenters-info.js +1 -1
- package/dist/integrations/pi/components/shell-presenters-transcript.js +3 -1
- package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +13 -9
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +38 -43
- package/dist/integrations/pi/components/shell-session-info-reference.d.ts +1 -1
- package/dist/integrations/pi/components/shell-session-info-reference.js +49 -46
- package/dist/integrations/pi/components/theme.d.ts +4 -0
- package/dist/integrations/pi/components/theme.js +9 -0
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +8 -7
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +13 -7
- package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
- package/dist/integrations/pi/components/upstream/components/auth-url.d.ts +16 -0
- package/dist/integrations/pi/components/upstream/components/auth-url.js +49 -0
- package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-selector.d.ts +1 -0
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +30 -12
- package/dist/integrations/pi/components/upstream/components/login-dialog.d.ts +3 -0
- package/dist/integrations/pi/components/upstream/components/login-dialog.js +216 -0
- package/dist/integrations/pi/components/upstream/components/mermaid.d.ts +2 -1
- package/dist/integrations/pi/components/upstream/components/mermaid.js +26 -21
- package/dist/integrations/pi/components/upstream/components/oauth-selector.d.ts +19 -0
- package/dist/integrations/pi/components/upstream/components/oauth-selector.js +123 -0
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/session-footer.js +17 -19
- package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +6 -2
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +27 -3
- package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +7 -6
- package/dist/integrations/pi/components/upstream/components/trust-selector.d.ts +2 -0
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +30 -13
- package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.js +2 -2
- package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
- package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
- package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
- package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
- package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme.js +1 -1
- package/dist/integrations/pi/engine/adapter.d.ts +1 -1
- package/dist/integrations/pi/engine/adapter.js +3 -3
- package/dist/integrations/pi/engine/host.d.ts +1 -1
- package/dist/integrations/pi/engine/resources/changelog.json +4 -4
- package/dist/integrations/pi/engine/workflow-export.d.ts +4 -0
- package/dist/integrations/pi/engine/workflow-export.js +25 -0
- package/dist/integrations/pi/engine/workflow-runner.d.ts +1 -0
- package/dist/integrations/pi/engine/workflow-runner.js +6 -10
- package/dist/integrations/pi/engine/workflow-support.d.ts +2 -1
- package/dist/integrations/pi/engine/workflow-support.js +28 -25
- package/dist/integrations/pi/engine/workflows.d.ts +6 -1
- package/dist/integrations/pi/engine/workflows.js +1 -1
- package/dist/integrations/pi/session-presenters/components.d.ts +1 -1
- package/dist/integrations/pi/session-presenters/components.js +8 -8
- package/dist/integrations/pi/session-presenters/presentation.js +2 -1
- package/dist/integrations/pi/session-presenters/presenters.js +24 -12
- package/dist/integrations/pi/startup-public.js +289 -240
- package/dist/integrations/pi/startup-public.manifest.json +579 -363
- package/dist/integrations/pi/tui-runtime/adapter.js +3 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +1 -1
- package/dist/integrations/pi/tui-runtime/overlay-geometry.d.ts +5 -2
- package/dist/integrations/pi/tui-runtime/overlay-geometry.js +12 -2
- package/dist/runtime-payload-inventory.json +8044 -6930
- package/dist/ui/components/dialog-panel.d.ts +4 -3
- package/dist/ui/components/dialog-panel.js +9 -13
- package/dist/ui/components/index.d.ts +1 -1
- package/dist/ui/components/index.js +1 -1
- package/dist/ui/components/list-block.d.ts +2 -2
- package/dist/ui/components/list-block.js +4 -3
- package/dist/ui/components/spans.d.ts +7 -0
- package/dist/ui/components/spans.js +63 -1
- package/dist/ui/settings/early-accent.d.ts +24 -0
- package/docs/architecture/prompt-suggestions.md +1 -1
- package/docs/architecture/ui-reference-provenance.md +2 -1
- package/docs/features/prompt-history.md +1 -1
- package/docs/features/session-exports.md +15 -0
- package/docs/local-worktree-cleanup.md +24 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -59,6 +59,12 @@ Launch A1, one agent in this terminal (profile: `~/.a1/agent`):
|
|
|
59
59
|
a1
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
In A1, **Ctrl+P** opens the searchable **Launcher**: Agent, Settings, Changelog, and Hotkeys. You can switch from any of those screens; returning to Agent keeps the current session and draft. Settings, Changelog, and Hotkeys are applications rather than Agent slash commands.
|
|
63
|
+
|
|
64
|
+
**Ctrl+M** cycles to the next model: all available models when no scope is set, or only available scoped models when a scope exists. **`/models`** opens the in-place Models selector to select a model or manage that scope. **Ctrl+L** cycles thinking levels, and **Alt+Up** restores queued messages. In legacy terminals that encode Ctrl+M as Enter, ordinary Enter still sends the prompt; use `/models` to select a model instead. Explicit keybinding overrides remain supported. Successful model changes update the status bar without an extra success message; errors and warnings remain visible.
|
|
65
|
+
|
|
66
|
+
Session exports without an explicit destination are saved in **`~/.a1/exports/`**, outside disposable worktrees. Use `/export` for HTML or `/export --jsonl` for JSONL; explicit destinations retain their existing meaning. See [session exports](docs/features/session-exports.md).
|
|
67
|
+
|
|
62
68
|
Resume a saved session:
|
|
63
69
|
|
|
64
70
|
```text
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type TerminalComponentPort } from "../../contracts/presentation/index.js";
|
|
2
|
+
import { type UiTheme } from "../../ui/components/index.js";
|
|
3
|
+
declare const APPS: readonly [{
|
|
4
|
+
readonly id: "agent";
|
|
5
|
+
readonly label: "Agent";
|
|
6
|
+
}, {
|
|
7
|
+
readonly id: "settings";
|
|
8
|
+
readonly label: "Settings";
|
|
9
|
+
}, {
|
|
10
|
+
readonly id: "changelog";
|
|
11
|
+
readonly label: "Changelog";
|
|
12
|
+
}, {
|
|
13
|
+
readonly id: "hotkeys";
|
|
14
|
+
readonly label: "Hotkeys";
|
|
15
|
+
}];
|
|
16
|
+
type AppId = typeof APPS[number]["id"];
|
|
17
|
+
/** A compact application chooser; actions return to the same session and never launch a process. */
|
|
18
|
+
export declare class AppsDialog implements TerminalComponentPort {
|
|
19
|
+
#private;
|
|
20
|
+
readonly ports: {
|
|
21
|
+
theme(): UiTheme;
|
|
22
|
+
height(): number;
|
|
23
|
+
legacyKey(data: string): string;
|
|
24
|
+
select(id: AppId): void;
|
|
25
|
+
cancel(): void;
|
|
26
|
+
requestRender(): void;
|
|
27
|
+
};
|
|
28
|
+
constructor(ports: AppsDialog["ports"]);
|
|
29
|
+
render(width: number): readonly string[];
|
|
30
|
+
handleInput(data: string): void;
|
|
31
|
+
invalidate(): void;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { wrapChoiceIndex } from "../../contracts/presentation/index.js";
|
|
2
|
+
import { LineInput, handleLineInputKey, ShortcutRegistry, configureDialogChoiceCapacity, renderSteppedDialogPanel } from "../../ui/components/index.js";
|
|
3
|
+
const APPS = [
|
|
4
|
+
{ id: "agent", label: "Agent" },
|
|
5
|
+
{ id: "settings", label: "Settings" },
|
|
6
|
+
{ id: "changelog", label: "Changelog" },
|
|
7
|
+
{ id: "hotkeys", label: "Hotkeys" },
|
|
8
|
+
];
|
|
9
|
+
const SCOPE = "apps";
|
|
10
|
+
const SHORTCUTS = new ShortcutRegistry();
|
|
11
|
+
SHORTCUTS.declare({ key: "up", scope: SCOPE, description: "Previous app", hint: { keys: "↑↓", does: "navigate" } }, "previous");
|
|
12
|
+
SHORTCUTS.declare({ key: "down", scope: SCOPE, description: "Next app", hint: { keys: "↑↓", does: "navigate" } }, "next");
|
|
13
|
+
SHORTCUTS.declare({ key: "enter", scope: SCOPE, description: "Open app", hint: { keys: "Enter", does: "open" } }, "open");
|
|
14
|
+
SHORTCUTS.declare({ key: "escape", scope: SCOPE, description: "Close Launcher", hint: { keys: "Esc", does: "close" } }, "close");
|
|
15
|
+
/** A compact application chooser; actions return to the same session and never launch a process. */
|
|
16
|
+
export class AppsDialog {
|
|
17
|
+
#input = new LineInput();
|
|
18
|
+
#index = 0;
|
|
19
|
+
ports;
|
|
20
|
+
constructor(ports) { this.ports = ports; }
|
|
21
|
+
#matches() { return APPS.filter(app => app.label.toLowerCase().includes(this.#input.value.toLowerCase())); }
|
|
22
|
+
render(width) {
|
|
23
|
+
const matches = this.#matches();
|
|
24
|
+
const height = Math.max(1, this.ports.height());
|
|
25
|
+
const compact = height < 12;
|
|
26
|
+
const capacity = compact ? Math.max(1, height - 3) : configureDialogChoiceCapacity(height, true, 0);
|
|
27
|
+
const start = Math.max(0, this.#index - capacity + 1);
|
|
28
|
+
return renderSteppedDialogPanel({
|
|
29
|
+
title: "Launcher", input: this.#input, compact,
|
|
30
|
+
rows: matches.length === 0 ? [{ label: "No apps found", value: "" }]
|
|
31
|
+
: matches.slice(start, start + capacity).map(app => ({ label: app.label, value: "" })),
|
|
32
|
+
index: matches.length === 0 ? -1 : this.#index - start,
|
|
33
|
+
hint: [{ key: "Type", action: "search" }, ...SHORTCUTS.hintEntries(SCOPE)],
|
|
34
|
+
}, width, this.ports.theme()).slice(0, height);
|
|
35
|
+
}
|
|
36
|
+
handleInput(data) {
|
|
37
|
+
const key = this.ports.legacyKey(data);
|
|
38
|
+
const token = key === "\u001b[A" ? "up" : key === "\u001b[B" ? "down"
|
|
39
|
+
: key === "\r" || key === "\n" ? "enter" : key === "\u001b" || key === "\u0003" ? "escape" : "edit";
|
|
40
|
+
const action = SHORTCUTS.resolve(token, SCOPE);
|
|
41
|
+
const matches = this.#matches();
|
|
42
|
+
if (action === "close") {
|
|
43
|
+
this.ports.cancel();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (action === "open") {
|
|
47
|
+
const selected = matches[this.#index];
|
|
48
|
+
if (selected !== undefined)
|
|
49
|
+
this.ports.select(selected.id);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (action === "previous" || action === "next") {
|
|
53
|
+
this.#index = wrapChoiceIndex(this.#index, action === "next" ? 1 : -1, matches.length);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
handleLineInputKey(this.#input, key);
|
|
57
|
+
this.#index = 0;
|
|
58
|
+
}
|
|
59
|
+
this.ports.requestRender();
|
|
60
|
+
}
|
|
61
|
+
invalidate() { }
|
|
62
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { OwnedUiShellComponents, OwnedUiShellSelectorOption } from "../../contracts/owned-ui/index.js";
|
|
2
|
+
import type { ShellPresentationPorts } from "../../contracts/presentation/index.js";
|
|
2
3
|
import type { TerminalOverlayHandle } from "../../contracts/presentation/index.js";
|
|
3
4
|
import type { OwnedUiCommandResult, OwnedUiDialog } from "../../contracts/owned-ui/index.js";
|
|
4
5
|
import type { UiRouteHost, UiRouteInput } from "../../ui/apps/contracts.js";
|
|
@@ -7,6 +8,11 @@ import type { OwnedUiSessionShellOptions, OwnedUiSessionShellRoot } from "./sess
|
|
|
7
8
|
type StartupRoute = NonNullable<OwnedUiSessionShellOptions["engine"]["startupRoute"]>;
|
|
8
9
|
interface SessionDialogPorts {
|
|
9
10
|
readonly terminal: Pick<OwnedUiPresenterTerminal, "running" | "hasOverlay" | "showOverlay" | "openRoute" | "requestRender">;
|
|
11
|
+
readonly presentation?: Pick<ShellPresentationPorts, "theme" | "terminalRuntime">;
|
|
12
|
+
readonly viewport?: () => {
|
|
13
|
+
rows: number;
|
|
14
|
+
};
|
|
15
|
+
readonly inPlaceSession?: boolean;
|
|
10
16
|
readonly root: Pick<OwnedUiSessionShellRoot, "chrome" | "setInputSurface" | "usesDefaultInputSurface">;
|
|
11
17
|
readonly routeHost: UiRouteHost | null;
|
|
12
18
|
readonly dialogs: Pick<OwnedUiShellComponents["dialogs"], "dialog" | "selector">;
|
|
@@ -17,20 +23,21 @@ interface SessionDialogPorts {
|
|
|
17
23
|
readonly routeClosed?: (route: string) => void;
|
|
18
24
|
readonly startupRoute?: StartupRoute;
|
|
19
25
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Owns the one modal overlay a session shows at a time, whichever source opened it: an owned route,
|
|
22
|
-
* a local selector, or a backend dialog. Opening one hides the previous one, and every close path
|
|
23
|
-
* clears the same state.
|
|
24
|
-
*/
|
|
26
|
+
/** Coordinates owned routes, dock dialogs, and backend overlays through one replacement/close lifecycle. */
|
|
25
27
|
export declare class SessionDialogCoordinator {
|
|
26
28
|
#private;
|
|
27
29
|
constructor(ports: SessionDialogPorts);
|
|
30
|
+
/** Apps may cover a full-screen route, but never steal another dialog's local shortcuts. */
|
|
31
|
+
canOpenApps(): boolean;
|
|
32
|
+
showApps(): void;
|
|
28
33
|
/** Clears the replacement input surface a selector put in the dock; the shared close action of every dock selector. */
|
|
29
34
|
readonly closeInputSurface: () => void;
|
|
30
35
|
showSelector(title: string, options: readonly OwnedUiShellSelectorOption[], onSelect: (id: string) => void, onCancel?: () => void): TerminalOverlayHandle;
|
|
31
36
|
/** Mirrors the backend's pending dialog; locally owned routes and selectors are left alone when it has none. */
|
|
32
37
|
syncBackend(dialog: OwnedUiDialog | null): void;
|
|
33
38
|
openRoute(route: string, input?: UiRouteInput, onClosed?: () => void | Promise<void>): OwnedUiCommandResult;
|
|
39
|
+
/** Close the route before global abort. */
|
|
40
|
+
handleInputRouteInterrupt(data: string): boolean;
|
|
34
41
|
claimsRoute(name: string): boolean;
|
|
35
42
|
/** Retains a route requested before the runtime runs; the latest request wins. */
|
|
36
43
|
retainStartupRoute(route: string): void;
|
|
@@ -1,21 +1,82 @@
|
|
|
1
|
+
import { InputRoute } from "./input-route.js";
|
|
1
2
|
const OVERLAY_OPTIONS = { width: "70%", maxHeight: "80%", anchor: "center", inputCoordination: "owned" };
|
|
2
3
|
const STARTUP_ROUTE_RETRY_MS = 25;
|
|
3
|
-
/**
|
|
4
|
-
* Owns the one modal overlay a session shows at a time, whichever source opened it: an owned route,
|
|
5
|
-
* a local selector, or a backend dialog. Opening one hides the previous one, and every close path
|
|
6
|
-
* clears the same state.
|
|
7
|
-
*/
|
|
4
|
+
/** Coordinates owned routes, dock dialogs, and backend overlays through one replacement/close lifecycle. */
|
|
8
5
|
export class SessionDialogCoordinator {
|
|
9
6
|
#ports;
|
|
10
7
|
#handle;
|
|
11
8
|
#id;
|
|
12
9
|
#source;
|
|
10
|
+
#route;
|
|
11
|
+
#apps;
|
|
12
|
+
#inputRoute;
|
|
13
13
|
#startupRoute;
|
|
14
14
|
#startupRouteTimer;
|
|
15
15
|
constructor(ports) {
|
|
16
16
|
this.#ports = ports;
|
|
17
17
|
this.#startupRoute = ports.startupRoute;
|
|
18
18
|
}
|
|
19
|
+
/** Apps may cover a full-screen route, but never steal another dialog's local shortcuts. */
|
|
20
|
+
canOpenApps() {
|
|
21
|
+
return this.#apps === undefined && (this.#source === "route"
|
|
22
|
+
|| !this.#ports.terminal.hasOverlay() && this.#ports.root.usesDefaultInputSurface());
|
|
23
|
+
}
|
|
24
|
+
showApps() {
|
|
25
|
+
const presentation = this.#ports.presentation;
|
|
26
|
+
if (presentation === undefined || !this.#ports.terminal.running || !this.canOpenApps())
|
|
27
|
+
return;
|
|
28
|
+
let dialog;
|
|
29
|
+
let closed = false;
|
|
30
|
+
let loading = "Loading Launcher…";
|
|
31
|
+
const pending = [];
|
|
32
|
+
const cancel = () => { closed = true; pending.length = 0; this.#apps?.hide(); this.#apps = undefined; };
|
|
33
|
+
this.#apps = this.#ports.terminal.showOverlay({
|
|
34
|
+
render: width => dialog?.render(width) ?? [loading.slice(0, width)],
|
|
35
|
+
handleInput: data => {
|
|
36
|
+
if (dialog !== undefined)
|
|
37
|
+
dialog.handleInput?.(data);
|
|
38
|
+
else if (presentation.terminalRuntime.legacyKeyInput(data) === "\u001b")
|
|
39
|
+
cancel();
|
|
40
|
+
else if (pending.length < 32)
|
|
41
|
+
pending.push(data);
|
|
42
|
+
},
|
|
43
|
+
invalidate: () => dialog?.invalidate(),
|
|
44
|
+
dispose: () => { closed = true; pending.length = 0; },
|
|
45
|
+
}, { width: 60, maxHeight: "100%", anchor: "center", inputCoordination: "owned", modal: true });
|
|
46
|
+
// Performance: Apps and its search/list controller are optional workflows, not eager startup dependencies.
|
|
47
|
+
void import("./apps-dialog.js").then(({ AppsDialog }) => {
|
|
48
|
+
if (closed || this.#ports.disposed())
|
|
49
|
+
return;
|
|
50
|
+
dialog = new AppsDialog({
|
|
51
|
+
theme: () => presentation.theme.current(),
|
|
52
|
+
height: () => this.#ports.viewport?.().rows ?? 24,
|
|
53
|
+
legacyKey: data => presentation.terminalRuntime.legacyKeyInput(data),
|
|
54
|
+
requestRender: () => this.#ports.terminal.requestRender(),
|
|
55
|
+
cancel,
|
|
56
|
+
select: route => {
|
|
57
|
+
cancel();
|
|
58
|
+
if (route === this.#route)
|
|
59
|
+
return;
|
|
60
|
+
this.#handle?.close?.();
|
|
61
|
+
if (route === "agent")
|
|
62
|
+
this.#close();
|
|
63
|
+
else {
|
|
64
|
+
const result = this.openRoute(route);
|
|
65
|
+
if (result.diagnostic !== null)
|
|
66
|
+
this.#ports.root.chrome.setNotice({ kind: "error", message: result.diagnostic });
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
for (const key of pending.splice(0)) {
|
|
71
|
+
if (!closed)
|
|
72
|
+
dialog.handleInput?.(key);
|
|
73
|
+
}
|
|
74
|
+
this.#ports.terminal.requestRender();
|
|
75
|
+
}).catch(() => { if (!closed && !this.#ports.disposed()) {
|
|
76
|
+
loading = "Launcher unavailable — Esc close";
|
|
77
|
+
this.#ports.terminal.requestRender();
|
|
78
|
+
} });
|
|
79
|
+
}
|
|
19
80
|
/** Clears the replacement input surface a selector put in the dock; the shared close action of every dock selector. */
|
|
20
81
|
closeInputSurface = () => {
|
|
21
82
|
this.#ports.root.setInputSurface(null);
|
|
@@ -29,15 +90,15 @@ export class SessionDialogCoordinator {
|
|
|
29
90
|
title,
|
|
30
91
|
options,
|
|
31
92
|
onSelect: id => {
|
|
32
|
-
onSelect(id);
|
|
33
93
|
this.#close();
|
|
94
|
+
onSelect(id);
|
|
34
95
|
},
|
|
35
96
|
onCancel: () => {
|
|
36
97
|
this.#close();
|
|
37
98
|
onCancel?.();
|
|
38
99
|
},
|
|
39
100
|
});
|
|
40
|
-
const handle = this.#ports.terminal.showOverlay(component, OVERLAY_OPTIONS);
|
|
101
|
+
const handle = this.#ports.terminal.showOverlay(component, { ...OVERLAY_OPTIONS, modal: true });
|
|
41
102
|
this.#handle = handle;
|
|
42
103
|
return handle;
|
|
43
104
|
}
|
|
@@ -57,7 +118,7 @@ export class SessionDialogCoordinator {
|
|
|
57
118
|
this.#handle?.hide();
|
|
58
119
|
this.#source = "backend";
|
|
59
120
|
const component = this.#ports.dialogs.dialog(dialog, { onSelect: () => this.#close(), onCancel: () => this.#close() });
|
|
60
|
-
this.#handle = this.#ports.terminal.showOverlay(component, OVERLAY_OPTIONS);
|
|
121
|
+
this.#handle = this.#ports.terminal.showOverlay(component, { ...OVERLAY_OPTIONS, modal: true });
|
|
61
122
|
this.#id = dialog.id;
|
|
62
123
|
}
|
|
63
124
|
openRoute(route, input, onClosed) {
|
|
@@ -69,24 +130,55 @@ export class SessionDialogCoordinator {
|
|
|
69
130
|
this.#ports.root.chrome.dismissNotice();
|
|
70
131
|
this.#handle?.hide();
|
|
71
132
|
this.#source = "route";
|
|
133
|
+
this.#route = route;
|
|
134
|
+
const closed = (rendered) => {
|
|
135
|
+
if (rendered) {
|
|
136
|
+
try {
|
|
137
|
+
void onClosed?.()?.catch(() => undefined);
|
|
138
|
+
}
|
|
139
|
+
catch { /* Rationale: a failed acknowledgement stays pending. */ }
|
|
140
|
+
this.#ports.routeClosed?.(route);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
if (route === "session" && this.#ports.inPlaceSession) {
|
|
144
|
+
const component = new InputRoute(surface, {
|
|
145
|
+
requestRender: () => this.#ports.terminal.requestRender(),
|
|
146
|
+
closed: rendered => { this.closeInputSurface(); closed(rendered); },
|
|
147
|
+
released: () => { if (this.#handle === handle)
|
|
148
|
+
this.#clear(); },
|
|
149
|
+
key: data => this.#ports.presentation?.terminalRuntime.legacyKeyInput(data) ?? data,
|
|
150
|
+
exit: () => this.#ports.exit(),
|
|
151
|
+
});
|
|
152
|
+
const handle = { hide: () => component.close(), close: () => component.close() };
|
|
153
|
+
this.#handle = handle;
|
|
154
|
+
this.#inputRoute = component;
|
|
155
|
+
this.#id = surface.id;
|
|
156
|
+
this.#ports.root.setInputSurface(component);
|
|
157
|
+
this.#ports.terminal.requestRender();
|
|
158
|
+
return { outcome: "completed", diagnostic: null };
|
|
159
|
+
}
|
|
72
160
|
const handle = this.#ports.terminal.openRoute(surface, {
|
|
73
161
|
exit: () => this.#ports.exit(),
|
|
74
162
|
closed: rendered => {
|
|
75
163
|
if (this.#handle === handle)
|
|
76
164
|
this.#clear();
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
void onClosed?.()?.catch(() => undefined);
|
|
80
|
-
}
|
|
81
|
-
catch { /* Rationale: a failed acknowledgement stays pending. */ }
|
|
82
|
-
this.#ports.routeClosed?.(route);
|
|
83
|
-
}
|
|
165
|
+
closed(rendered);
|
|
84
166
|
},
|
|
85
167
|
});
|
|
86
168
|
this.#handle = handle;
|
|
87
169
|
this.#id = surface.id;
|
|
88
170
|
return { outcome: "completed", diagnostic: null };
|
|
89
171
|
}
|
|
172
|
+
/** Close the route before global abort. */
|
|
173
|
+
handleInputRouteInterrupt(data) {
|
|
174
|
+
if (this.#inputRoute === undefined || this.#apps !== undefined)
|
|
175
|
+
return false;
|
|
176
|
+
const key = this.#ports.presentation?.terminalRuntime.legacyKeyInput(data) ?? data;
|
|
177
|
+
if (key !== "\u0003")
|
|
178
|
+
return false;
|
|
179
|
+
this.#inputRoute.handleInput(key);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
90
182
|
claimsRoute(name) {
|
|
91
183
|
return this.#ports.routeHost?.claims(name) ?? false;
|
|
92
184
|
}
|
|
@@ -118,9 +210,13 @@ export class SessionDialogCoordinator {
|
|
|
118
210
|
if (this.#startupRouteTimer !== undefined)
|
|
119
211
|
clearTimeout(this.#startupRouteTimer);
|
|
120
212
|
this.#startupRouteTimer = undefined;
|
|
213
|
+
this.#apps?.hide();
|
|
214
|
+
this.#apps = undefined;
|
|
121
215
|
this.#handle?.hide();
|
|
122
216
|
}
|
|
123
217
|
#close() {
|
|
218
|
+
this.#apps?.hide();
|
|
219
|
+
this.#apps = undefined;
|
|
124
220
|
this.#handle?.hide();
|
|
125
221
|
this.#clear();
|
|
126
222
|
}
|
|
@@ -128,5 +224,7 @@ export class SessionDialogCoordinator {
|
|
|
128
224
|
this.#handle = undefined;
|
|
129
225
|
this.#id = undefined;
|
|
130
226
|
this.#source = undefined;
|
|
227
|
+
this.#route = undefined;
|
|
228
|
+
this.#inputRoute = undefined;
|
|
131
229
|
}
|
|
132
230
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { OwnedUiShellComponentPort } from "../../contracts/owned-ui/index.js";
|
|
2
|
+
import type { UiRouteSurface } from "../../ui/apps/index.js";
|
|
3
|
+
import type { PaneMouseEvent } from "../../ui/components/index.js";
|
|
4
|
+
type InputRouteOptions = {
|
|
5
|
+
readonly requestRender: () => void;
|
|
6
|
+
readonly closed: (rendered: boolean) => void;
|
|
7
|
+
readonly exit: () => void;
|
|
8
|
+
readonly released: () => void;
|
|
9
|
+
readonly key: (data: string) => string;
|
|
10
|
+
};
|
|
11
|
+
/** Hosts a bounded dock route. */
|
|
12
|
+
export declare class InputRoute implements OwnedUiShellComponentPort {
|
|
13
|
+
#private;
|
|
14
|
+
constructor(surface: UiRouteSurface, options: InputRouteOptions);
|
|
15
|
+
render(width: number): readonly string[];
|
|
16
|
+
renderInDock(width: number, maxHeight: number): readonly string[];
|
|
17
|
+
handleInput(data: string): void;
|
|
18
|
+
handleLocalMouse(event: PaneMouseEvent): void;
|
|
19
|
+
invalidate(): void;
|
|
20
|
+
close(): void;
|
|
21
|
+
dispose(): void;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** Hosts a bounded dock route. */
|
|
2
|
+
export class InputRoute {
|
|
3
|
+
#surface;
|
|
4
|
+
#options;
|
|
5
|
+
#disposed = false;
|
|
6
|
+
#rendered = false;
|
|
7
|
+
constructor(surface, options) {
|
|
8
|
+
this.#surface = surface;
|
|
9
|
+
this.#options = options;
|
|
10
|
+
surface.onRenderRequested(() => { if (!this.#disposed)
|
|
11
|
+
this.#refresh(); });
|
|
12
|
+
surface.onExitRequested(() => { this.close(); options.exit(); });
|
|
13
|
+
}
|
|
14
|
+
render(width) { return this.renderInDock(width, 24); }
|
|
15
|
+
renderInDock(width, maxHeight) {
|
|
16
|
+
if (this.#disposed)
|
|
17
|
+
return [];
|
|
18
|
+
const frame = this.#surface.render(width, Math.max(1, Math.min(24, maxHeight)));
|
|
19
|
+
this.#rendered = true;
|
|
20
|
+
return frame;
|
|
21
|
+
}
|
|
22
|
+
handleInput(data) {
|
|
23
|
+
if (this.#disposed)
|
|
24
|
+
return;
|
|
25
|
+
const key = this.#options.key(data);
|
|
26
|
+
// Compatibility: close even while the deferred document is loading.
|
|
27
|
+
if (key === "\u001b" || key === "\u0003") {
|
|
28
|
+
this.close();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
this.#surface.handleInput(key);
|
|
32
|
+
this.#refresh();
|
|
33
|
+
}
|
|
34
|
+
handleLocalMouse(event) {
|
|
35
|
+
if (this.#disposed)
|
|
36
|
+
return;
|
|
37
|
+
this.#surface.handleMouse(event);
|
|
38
|
+
this.#refresh();
|
|
39
|
+
}
|
|
40
|
+
invalidate() { }
|
|
41
|
+
close() {
|
|
42
|
+
if (this.#disposed)
|
|
43
|
+
return;
|
|
44
|
+
this.#options.closed(this.#rendered);
|
|
45
|
+
this.dispose();
|
|
46
|
+
}
|
|
47
|
+
dispose() {
|
|
48
|
+
if (this.#disposed)
|
|
49
|
+
return;
|
|
50
|
+
this.#disposed = true;
|
|
51
|
+
this.#surface.close();
|
|
52
|
+
this.#options.released();
|
|
53
|
+
}
|
|
54
|
+
#refresh() {
|
|
55
|
+
if (this.#surface.isClosed())
|
|
56
|
+
this.close();
|
|
57
|
+
this.#options.requestRender();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -28,8 +28,8 @@ export declare class SessionSelectors implements WorkflowSelectors {
|
|
|
28
28
|
#private;
|
|
29
29
|
constructor(ports: SessionSelectorPorts);
|
|
30
30
|
showThinkingSelector(): Promise<void>;
|
|
31
|
-
/**
|
|
32
|
-
showSkillsSelector(skills: readonly OwnedUiShellSkillSummary[]): void;
|
|
31
|
+
/** Applies a dock-selected skill through the prompt path. */
|
|
32
|
+
showSkillsSelector(skills: readonly OwnedUiShellSkillSummary[]): Promise<void> | undefined;
|
|
33
33
|
showModelSelector(initialSearchInput?: string): void;
|
|
34
34
|
showForkSelector(): void;
|
|
35
35
|
showLogoutSelector(): Promise<void>;
|
|
@@ -39,8 +39,8 @@ export declare class SessionSelectors implements WorkflowSelectors {
|
|
|
39
39
|
showLoginProviderSelector(authType?: "oauth" | "api_key", initialSearchInput?: string): void;
|
|
40
40
|
showSessionSelector(): Promise<void>;
|
|
41
41
|
showSettingsSelector(): void;
|
|
42
|
-
showTrustSelector(): void;
|
|
42
|
+
showTrustSelector(): Promise<void> | undefined;
|
|
43
43
|
showScopedModelsSelector(): void;
|
|
44
44
|
/** The bare-A1 unified Models dialog: switch on Enter, scope on Space, persist on Ctrl+S, all through the engine. */
|
|
45
|
-
showModelsDialog(initialQuery?: string): void
|
|
45
|
+
showModelsDialog(initialQuery?: string): void | Promise<void>;
|
|
46
46
|
}
|
|
@@ -77,7 +77,7 @@ export class SessionSelectors {
|
|
|
77
77
|
releasePresentation?.();
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
/**
|
|
80
|
+
/** Applies a dock-selected skill through the prompt path. */
|
|
81
81
|
showSkillsSelector(skills) {
|
|
82
82
|
const close = this.#dialogs.closeInputSurface;
|
|
83
83
|
const component = this.#presenters.components.dialogs.skillsSelector({
|
|
@@ -89,6 +89,7 @@ export class SessionSelectors {
|
|
|
89
89
|
onCancel: close,
|
|
90
90
|
});
|
|
91
91
|
this.#present(component);
|
|
92
|
+
return component.ready;
|
|
92
93
|
}
|
|
93
94
|
showModelSelector(initialSearchInput) {
|
|
94
95
|
this.#presenters.openModelSelector(this.#dialogHost, initialSearchInput);
|
|
@@ -214,13 +215,14 @@ export class SessionSelectors {
|
|
|
214
215
|
onCancel: close,
|
|
215
216
|
});
|
|
216
217
|
this.#present(component);
|
|
218
|
+
return component.ready;
|
|
217
219
|
}
|
|
218
220
|
showScopedModelsSelector() {
|
|
219
221
|
this.#presenters.openScopedModelsSelector(this.#dialogHost);
|
|
220
222
|
}
|
|
221
223
|
/** The bare-A1 unified Models dialog: switch on Enter, scope on Space, persist on Ctrl+S, all through the engine. */
|
|
222
224
|
showModelsDialog(initialQuery) {
|
|
223
|
-
this.#presenters.openModelsDialog(this.#dialogHost, initialQuery);
|
|
225
|
+
return this.#presenters.openModelsDialog(this.#dialogHost, initialQuery);
|
|
224
226
|
}
|
|
225
227
|
#treeSummary() {
|
|
226
228
|
return new Promise(resolve => {
|
|
@@ -261,9 +263,12 @@ export class SessionSelectors {
|
|
|
261
263
|
if (result.diagnostic === "Branch summarization cancelled")
|
|
262
264
|
await this.showTreeSelector(entryId);
|
|
263
265
|
}
|
|
264
|
-
//
|
|
266
|
+
// Performance: retain the frame until a deferred selector is ready.
|
|
265
267
|
#present(component) {
|
|
268
|
+
const release = component?.ready === undefined ? undefined : this.#terminal.beginPresentationHold();
|
|
266
269
|
this.#root.setInputSurface(component);
|
|
270
|
+
void component?.ready?.finally(() => { release?.(); if (!this.#ports.disposed())
|
|
271
|
+
this.#terminal.requestRender(); });
|
|
267
272
|
this.#terminal.requestRender();
|
|
268
273
|
}
|
|
269
274
|
}
|
|
@@ -357,10 +357,14 @@ export class OwnedUiSessionShellRoot {
|
|
|
357
357
|
const messageStart = queued.length;
|
|
358
358
|
const copyableMessageRows = Array.from({ length: statusRows.length + noticeRows.length }, (_value, index) => ({ row: messageStart + index }));
|
|
359
359
|
const aboveWidgets = this.#extensions.renderWidgets("aboveEditor", width);
|
|
360
|
-
const input = this.#input.surface.render(width);
|
|
361
|
-
const body = this.usesDefaultInputSurface() ? this.editor.bodyGeometry?.() : undefined;
|
|
362
360
|
const belowWidgets = this.#extensions.renderWidgets("belowEditor", width);
|
|
363
361
|
const footer = this.#renderFooter(width);
|
|
362
|
+
// Invariant: reserve transcript context above scrollable routes.
|
|
363
|
+
const available = Math.max(1, this.#componentRuntime.getRows() - transientRows.length - aboveWidgets.length - belowWidgets.length - footer.length - 3);
|
|
364
|
+
const surface = this.#input.surface;
|
|
365
|
+
const input = this.#customViewport && surface.renderInDock !== undefined
|
|
366
|
+
? surface.renderInDock(width, available) : surface.render(width);
|
|
367
|
+
const body = this.usesDefaultInputSurface() ? this.editor.bodyGeometry?.() : undefined;
|
|
364
368
|
const rowsWithoutTransient = [...aboveWidgets, ...input, ...belowWidgets, ...footer];
|
|
365
369
|
const inputOffset = transientRows.length + aboveWidgets.length;
|
|
366
370
|
return {
|
|
@@ -79,7 +79,7 @@ export class OwnedUiSessionPresenter {
|
|
|
79
79
|
#sessionGeneration;
|
|
80
80
|
#sessionBindingGeneration;
|
|
81
81
|
constructor(host, options) {
|
|
82
|
-
const { backend, cwd, routeHost, sessionLayout } = options.engine;
|
|
82
|
+
const { backend, cwd, routeHost, startupRoute, sessionLayout } = options.engine;
|
|
83
83
|
const { terminal, startup, viewportSettings, reload: reloadPresentation, stream: streamPresentationOptions, input: inputPresentation, } = options.presentation ?? {};
|
|
84
84
|
const { clipboard, responseCopy, paste: pasteDiagnostics, pastePreparation } = options.diagnostics ?? {};
|
|
85
85
|
const promptHistory = options.history;
|
|
@@ -178,11 +178,11 @@ export class OwnedUiSessionPresenter {
|
|
|
178
178
|
// Invariant: the presenter owns its root (theme subscription and helper clients) and disposes it once the
|
|
179
179
|
// terminal no longer renders it.
|
|
180
180
|
constructed.push(() => this.root.dispose());
|
|
181
|
-
const startupRoute = options.engine.startupRoute;
|
|
182
181
|
this.#dialogs = new SessionDialogCoordinator({
|
|
183
182
|
terminal: this.#terminal,
|
|
184
183
|
root: this.root,
|
|
185
|
-
routeHost: routeHost ?? null, dialogs: options.presenters.components.dialogs,
|
|
184
|
+
routeHost: routeHost ?? null, dialogs: options.presenters.components.dialogs, inPlaceSession: this.#customViewport,
|
|
185
|
+
presentation: options.presenters, viewport: () => this.#terminal.viewport(),
|
|
186
186
|
disposed: () => this.#disposed,
|
|
187
187
|
exit: () => { void this.shutdown(); },
|
|
188
188
|
...(startupRoute === undefined ? {} : { startupRoute }),
|
|
@@ -308,8 +308,15 @@ export class OwnedUiSessionPresenter {
|
|
|
308
308
|
handleViewportInput(data) {
|
|
309
309
|
if (!this.#inputCoordination)
|
|
310
310
|
this.#streamPresentation.noteImmediatePresentation();
|
|
311
|
+
if (this.#customViewport && this.#dialogs.canOpenApps()
|
|
312
|
+
&& this.root.editor.matchesAction?.(data, "owned.apps.open")) {
|
|
313
|
+
this.#dialogs.showApps();
|
|
314
|
+
return { consume: true };
|
|
315
|
+
}
|
|
311
316
|
// Compatibility: route modal paging and boundary keys before Pi's fullscreen handlers.
|
|
312
317
|
const isDefault = this.root.usesDefaultInputSurface();
|
|
318
|
+
if (this.#dialogs.handleInputRouteInterrupt(data))
|
|
319
|
+
return { consume: true };
|
|
313
320
|
if (!this.#terminal.hasOverlay() && !isDefault
|
|
314
321
|
&& (this.root.editor.matchesTerminalKey(data, "pageUp")
|
|
315
322
|
|| this.root.editor.matchesTerminalKey(data, "pageDown"))) {
|
|
@@ -881,7 +888,8 @@ export class OwnedUiSessionPresenter {
|
|
|
881
888
|
const separator = body.search(/\s/);
|
|
882
889
|
const name = separator < 0 ? body : body.slice(0, separator);
|
|
883
890
|
const argument = separator < 0 ? "" : body.slice(separator + 1).trimStart();
|
|
884
|
-
|
|
891
|
+
const applicationOnly = this.#customViewport && (name === "settings" || name === "changelog" || name === "hotkeys");
|
|
892
|
+
if (!applicationOnly && this.#dialogs.claimsRoute(name))
|
|
885
893
|
return this.#dialogs.openRoute(name);
|
|
886
894
|
if (this.#isWorkflowRoute(name))
|
|
887
895
|
return this.runWorkflow({ command: name, argument });
|
|
@@ -915,7 +923,7 @@ export class OwnedUiSessionPresenter {
|
|
|
915
923
|
const skills = this.#skillSummaries();
|
|
916
924
|
const trimmed = argument.trim();
|
|
917
925
|
if (trimmed.length === 0) {
|
|
918
|
-
this.selectors.showSkillsSelector(skills);
|
|
926
|
+
await this.selectors.showSkillsSelector(skills);
|
|
919
927
|
return { outcome: "completed", diagnostic: null };
|
|
920
928
|
}
|
|
921
929
|
const separator = trimmed.search(/\s/u);
|
|
@@ -49,6 +49,7 @@ export interface OwnedUiPresenterTerminal extends OwnedUiPresenterHost {
|
|
|
49
49
|
requestHyperlinkCleanup(rows?: readonly number[]): void;
|
|
50
50
|
openRoute(surface: UiRouteSurface, callbacks: OwnedUiRouteCallbacks): {
|
|
51
51
|
hide(): void;
|
|
52
|
+
close?(): void;
|
|
52
53
|
};
|
|
53
54
|
beginPresentationHold(): () => void;
|
|
54
55
|
switchMode(mode: "regular" | "fullscreen"): boolean;
|