@timurproko/a1 0.2.7-dev.1275 → 0.2.7-dev.1285
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 +5 -1
- package/dist/app/session-shell/apps-dialog.d.ts +1 -1
- package/dist/app/session-shell/apps-dialog.js +2 -1
- package/dist/app/session-shell/dialog-coordinator.d.ts +4 -5
- package/dist/app/session-shell/dialog-coordinator.js +41 -12
- 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 +3 -3
- package/dist/app/session-shell/session-selectors.js +7 -2
- package/dist/app/session-shell/session-shell-root.d.ts +4 -68
- package/dist/app/session-shell/session-shell-root.js +6 -2
- package/dist/app/session-shell/session-shell.js +9 -13
- package/dist/app/session-shell/shell-host.js +2 -2
- package/dist/app/session-shell/shell-options.d.ts +65 -0
- package/dist/app/session-shell/shell-options.js +1 -0
- package/dist/app/session-shell/viewport-pointer.js +5 -1
- package/dist/app/session-shell/workflow-router.d.ts +4 -2
- package/dist/app/session-shell/workflow-router.js +12 -0
- package/dist/cli/dispatch.js +27 -1
- package/dist/cli/packages.js +18 -2
- package/dist/cli/session-context.js +6 -2
- package/dist/composition/owned-ui.js +20 -8
- package/dist/composition/session-naming.js +1 -1
- package/dist/composition/session-runtime-registry.d.ts +2 -0
- package/dist/composition/session-runtime-registry.js +49 -9
- package/dist/composition/settings-route-host.js +1 -0
- package/dist/contracts/agent-engine/package-ports.d.ts +10 -14
- package/dist/contracts/agent-engine/package-ports.js +5 -9
- package/dist/contracts/owned-ui/session-workflows.d.ts +6 -0
- package/dist/contracts/owned-ui/shell-components.d.ts +10 -0
- package/dist/contracts/presentation/component.d.ts +7 -0
- package/dist/contracts/presentation/index.d.ts +3 -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/progress-spinner.d.ts +7 -0
- package/dist/contracts/presentation/progress-spinner.js +1 -0
- package/dist/features/launch/session-context.d.ts +8 -0
- package/dist/features/launch/session-context.js +19 -10
- 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 +12 -5
- package/dist/features/owned-ui/session-fork-prompt.d.ts +2 -1
- package/dist/features/owned-ui/session-fork-prompt.js +11 -5
- package/dist/features/owned-ui/settings-app.d.ts +1 -1
- package/dist/features/owned-ui/settings-app.js +20 -13
- package/dist/features/owned-ui/settings-model-dialog.js +3 -3
- package/dist/features/owned-ui/settings-spinner-preview.d.ts +9 -0
- package/dist/features/owned-ui/settings-spinner-preview.js +29 -0
- package/dist/features/session-naming/context.d.ts +17 -0
- package/dist/features/session-naming/context.js +39 -0
- package/dist/features/session-naming/controller.d.ts +1 -5
- package/dist/features/session-naming/controller.js +7 -4
- package/dist/features/session-naming/generate.d.ts +2 -1
- package/dist/features/session-naming/generate.js +14 -10
- package/dist/features/session-naming/index.d.ts +1 -1
- package/dist/foundation/lifecycle/index.d.ts +3 -1
- package/dist/foundation/lifecycle/index.js +3 -1
- package/dist/foundation/lifecycle/session-claim-lock.d.ts +2 -2
- package/dist/foundation/lifecycle/session-claim-lock.js +36 -10
- package/dist/foundation/lifecycle/session-context-retry.d.ts +2 -0
- package/dist/foundation/lifecycle/session-context-retry.js +17 -0
- package/dist/foundation/lifecycle/session-repository-context.d.ts +7 -1
- package/dist/foundation/lifecycle/session-repository-context.js +105 -39
- package/dist/foundation/lifecycle/session-worktree-entry.d.ts +3 -0
- package/dist/foundation/lifecycle/session-worktree-entry.js +87 -0
- package/dist/foundation/release/automatic-update.js +2 -2
- package/dist/foundation/release/bootstrap.js +19 -3
- package/dist/foundation/release/release-gc.js +20 -5
- package/dist/foundation/release/release-state.d.ts +12 -3
- package/dist/foundation/release/release-state.js +55 -24
- package/dist/foundation/release/release-use.d.ts +10 -0
- package/dist/foundation/release/release-use.js +70 -0
- package/dist/foundation/release/update-activation.js +2 -2
- package/dist/foundation/release/update-recovery.js +2 -2
- package/dist/foundation/release/update.js +1 -1
- package/dist/foundation/release/warmup.js +8 -9
- package/dist/foundation/session-writer-lock/index.d.ts +2 -2
- package/dist/foundation/session-writer-lock/index.js +82 -12
- package/dist/foundation/startup/startup-descriptor.js +2 -2
- package/dist/foundation/terminal-cleanup/fatal-diagnostic.d.ts +2 -0
- package/dist/foundation/terminal-cleanup/fatal-diagnostic.js +59 -0
- package/dist/foundation/terminal-cleanup/fatal-exit.js +1 -29
- 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/resources/builtin-themes.d.ts +2 -2
- package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
- package/dist/integrations/pi/components/share-operation-dialog.d.ts +2 -1
- package/dist/integrations/pi/components/share-operation-dialog.js +13 -5
- package/dist/integrations/pi/components/shell-footer-status.d.ts +2 -1
- package/dist/integrations/pi/components/shell-footer-status.js +15 -8
- package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +11 -8
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +36 -35
- package/dist/integrations/pi/components/shell-session-info-reference.d.ts +1 -1
- package/dist/integrations/pi/components/shell-session-info-reference.js +55 -49
- package/dist/integrations/pi/components/theme.d.ts +2 -0
- package/dist/integrations/pi/components/theme.js +4 -0
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +1 -1
- 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 +22 -11
- 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.js +1 -1
- 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 +22 -13
- 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 +1 -1
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +3 -1
- package/dist/integrations/pi/engine/adapter.js +24 -6
- package/dist/integrations/pi/engine/changelog.js +5 -2
- package/dist/integrations/pi/engine/delivery-retention.d.ts +7 -0
- package/dist/integrations/pi/engine/delivery-retention.js +66 -0
- package/dist/integrations/pi/engine/event-delivery.d.ts +17 -1
- package/dist/integrations/pi/engine/event-delivery.js +25 -3
- package/dist/integrations/pi/engine/extension-ui-binding.d.ts +2 -1
- package/dist/integrations/pi/engine/extension-ui-binding.js +45 -0
- package/dist/integrations/pi/engine/host-ports.d.ts +2 -0
- package/dist/integrations/pi/engine/host.d.ts +3 -0
- package/dist/integrations/pi/engine/host.js +2 -0
- package/dist/integrations/pi/engine/package-integration.js +19 -4
- package/dist/integrations/pi/engine/pending-delivery.d.ts +4 -1
- package/dist/integrations/pi/engine/pending-delivery.js +51 -18
- package/dist/integrations/pi/engine/resources/changelog.json +4 -4
- package/dist/integrations/pi/engine/runtime-integration.d.ts +8 -0
- package/dist/integrations/pi/engine/runtime-integration.js +58 -9
- package/dist/integrations/pi/engine/session-cwd-recovery.d.ts +11 -0
- package/dist/integrations/pi/engine/session-cwd-recovery.js +18 -0
- package/dist/integrations/pi/engine/session-runtime.d.ts +3 -0
- package/dist/integrations/pi/engine/session-runtime.js +2 -0
- package/dist/integrations/pi/engine/session-selection.d.ts +3 -2
- package/dist/integrations/pi/engine/session-selection.js +25 -5
- package/dist/integrations/pi/engine/transcript-image-assets.d.ts +3 -0
- package/dist/integrations/pi/engine/transcript-image-assets.js +65 -14
- package/dist/integrations/pi/engine/view-state.d.ts +14 -0
- package/dist/integrations/pi/engine/view-state.js +17 -0
- package/dist/integrations/pi/engine/workflow-runner.d.ts +2 -0
- package/dist/integrations/pi/engine/workflow-runner.js +47 -26
- package/dist/integrations/pi/engine/worktree-tools.d.ts +4 -0
- package/dist/integrations/pi/engine/worktree-tools.js +26 -0
- package/dist/integrations/pi/session-presenters/components.d.ts +2 -1
- package/dist/integrations/pi/session-presenters/components.js +12 -10
- package/dist/integrations/pi/session-presenters/presenters.d.ts +3 -1
- package/dist/integrations/pi/session-presenters/presenters.js +2 -2
- package/dist/integrations/pi/startup-public.d.ts +1 -1
- package/dist/integrations/pi/startup-public.js +16 -20
- package/dist/integrations/pi/startup-public.manifest.json +29 -29
- 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/product-identity.json +1 -1
- package/dist/runtime-payload-inventory.json +5027 -5027
- 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/progress-status.d.ts +7 -0
- package/dist/ui/components/progress-status.js +21 -0
- package/dist/ui/components/value-menu.d.ts +1 -1
- package/dist/ui/components/value-menu.js +4 -2
- package/dist/ui/settings/declarations.d.ts +16 -4
- package/dist/ui/settings/declarations.js +13 -4
- package/dist/ui/settings/early-accent.d.ts +24 -0
- package/docs/architecture/internal-naming.md +1 -1
- package/docs/architecture/project-structure.md +7 -11
- package/docs/features/session-exports.md +1 -1
- package/docs/features/session-naming.md +8 -6
- package/docs/features/worktrees.md +38 -0
- package/docs/local-worktree-cleanup.md +27 -4
- package/docs/openspec-archive-automation.md +30 -4
- package/docs/worktree-link-recovery.md +2 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -73,7 +73,11 @@ a1 --session <id>
|
|
|
73
73
|
|
|
74
74
|
When a session exits, A1 prints the `a1 --session <id>` command that resumes it; a custom session store is included in the printed command. Closing the terminal ends the agent, as it does for Pi.
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
If a saved session's folder was moved or deleted, recovery offers **Continue**, **Fork**, or **Cancel**. Continue uses the current folder for this run and asks again on the next resume. Fork keeps the original and creates a new session ID in the current folder, so later resumes no longer ask. This also applies to session import and extension-triggered switching.
|
|
77
|
+
|
|
78
|
+
Bare A1 automatically names unnamed sessions from the current task and relevant discussion, using up to three descriptive words and 32 characters, and regenerates on the next prompt after a worktree-context change. Manual `/name` renames are preserved. Names appear after footer stats, with a secondary-accent reveal for automatic changes; narrow footers reduce stats before shortening the name. Agent settings offers **Session name format** with Sentence case (default, first choice), Kebab case, and Title Case for future generated names, or **Automatic session name** to disable naming. Valid saved formats are preserved; see [session names](docs/features/session-naming.md) for details.
|
|
79
|
+
|
|
80
|
+
Inside an A1 agent session, `a1 worktree enter <branch>` creates or resumes a task checkout and attaches it. `a1 worktree attach <path>` attaches an existing checkout; `a1 worktree detach` releases it without deleting work. A1 handles coordination and ordinary recovery internally; successful attachment needs no second inventory check. See [worktree commands](docs/features/worktrees.md).
|
|
77
81
|
|
|
78
82
|
Show all commands:
|
|
79
83
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type TerminalComponentPort } from "../../contracts/presentation/index.js";
|
|
2
2
|
import { type UiTheme } from "../../ui/components/index.js";
|
|
3
3
|
declare const APPS: readonly [{
|
|
4
4
|
readonly id: "agent";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { wrapChoiceIndex } from "../../contracts/presentation/index.js";
|
|
1
2
|
import { LineInput, handleLineInputKey, ShortcutRegistry, configureDialogChoiceCapacity, renderSteppedDialogPanel } from "../../ui/components/index.js";
|
|
2
3
|
const APPS = [
|
|
3
4
|
{ id: "agent", label: "Agent" },
|
|
@@ -49,7 +50,7 @@ export class AppsDialog {
|
|
|
49
50
|
return;
|
|
50
51
|
}
|
|
51
52
|
if (action === "previous" || action === "next") {
|
|
52
|
-
this.#index =
|
|
53
|
+
this.#index = wrapChoiceIndex(this.#index, action === "next" ? 1 : -1, matches.length);
|
|
53
54
|
}
|
|
54
55
|
else {
|
|
55
56
|
handleLineInputKey(this.#input, key);
|
|
@@ -12,6 +12,7 @@ interface SessionDialogPorts {
|
|
|
12
12
|
readonly viewport?: () => {
|
|
13
13
|
rows: number;
|
|
14
14
|
};
|
|
15
|
+
readonly inPlaceSession?: boolean;
|
|
15
16
|
readonly root: Pick<OwnedUiSessionShellRoot, "chrome" | "setInputSurface" | "usesDefaultInputSurface">;
|
|
16
17
|
readonly routeHost: UiRouteHost | null;
|
|
17
18
|
readonly dialogs: Pick<OwnedUiShellComponents["dialogs"], "dialog" | "selector">;
|
|
@@ -22,11 +23,7 @@ interface SessionDialogPorts {
|
|
|
22
23
|
readonly routeClosed?: (route: string) => void;
|
|
23
24
|
readonly startupRoute?: StartupRoute;
|
|
24
25
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Owns the one modal overlay a session shows at a time, whichever source opened it: an owned route,
|
|
27
|
-
* a local selector, or a backend dialog. Opening one hides the previous one, and every close path
|
|
28
|
-
* clears the same state.
|
|
29
|
-
*/
|
|
26
|
+
/** Coordinates owned routes, dock dialogs, and backend overlays through one replacement/close lifecycle. */
|
|
30
27
|
export declare class SessionDialogCoordinator {
|
|
31
28
|
#private;
|
|
32
29
|
constructor(ports: SessionDialogPorts);
|
|
@@ -39,6 +36,8 @@ export declare class SessionDialogCoordinator {
|
|
|
39
36
|
/** Mirrors the backend's pending dialog; locally owned routes and selectors are left alone when it has none. */
|
|
40
37
|
syncBackend(dialog: OwnedUiDialog | null): void;
|
|
41
38
|
openRoute(route: string, input?: UiRouteInput, onClosed?: () => void | Promise<void>): OwnedUiCommandResult;
|
|
39
|
+
/** Close the route before global abort. */
|
|
40
|
+
handleInputRouteInterrupt(data: string): boolean;
|
|
42
41
|
claimsRoute(name: string): boolean;
|
|
43
42
|
/** Retains a route requested before the runtime runs; the latest request wins. */
|
|
44
43
|
retainStartupRoute(route: string): void;
|
|
@@ -1,10 +1,7 @@
|
|
|
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;
|
|
@@ -12,6 +9,7 @@ export class SessionDialogCoordinator {
|
|
|
12
9
|
#source;
|
|
13
10
|
#route;
|
|
14
11
|
#apps;
|
|
12
|
+
#inputRoute;
|
|
15
13
|
#startupRoute;
|
|
16
14
|
#startupRouteTimer;
|
|
17
15
|
constructor(ports) {
|
|
@@ -133,24 +131,54 @@ export class SessionDialogCoordinator {
|
|
|
133
131
|
this.#handle?.hide();
|
|
134
132
|
this.#source = "route";
|
|
135
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
|
+
}
|
|
136
160
|
const handle = this.#ports.terminal.openRoute(surface, {
|
|
137
161
|
exit: () => this.#ports.exit(),
|
|
138
162
|
closed: rendered => {
|
|
139
163
|
if (this.#handle === handle)
|
|
140
164
|
this.#clear();
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
void onClosed?.()?.catch(() => undefined);
|
|
144
|
-
}
|
|
145
|
-
catch { /* Rationale: a failed acknowledgement stays pending. */ }
|
|
146
|
-
this.#ports.routeClosed?.(route);
|
|
147
|
-
}
|
|
165
|
+
closed(rendered);
|
|
148
166
|
},
|
|
149
167
|
});
|
|
150
168
|
this.#handle = handle;
|
|
151
169
|
this.#id = surface.id;
|
|
152
170
|
return { outcome: "completed", diagnostic: null };
|
|
153
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
|
+
}
|
|
154
182
|
claimsRoute(name) {
|
|
155
183
|
return this.#ports.routeHost?.claims(name) ?? false;
|
|
156
184
|
}
|
|
@@ -197,5 +225,6 @@ export class SessionDialogCoordinator {
|
|
|
197
225
|
this.#id = undefined;
|
|
198
226
|
this.#source = undefined;
|
|
199
227
|
this.#route = undefined;
|
|
228
|
+
this.#inputRoute = undefined;
|
|
200
229
|
}
|
|
201
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,7 +39,7 @@ 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
45
|
showModelsDialog(initialQuery?: string): void | Promise<void>;
|
|
@@ -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,6 +215,7 @@ 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);
|
|
@@ -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
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { OwnedUiShellComponents, OwnedUiShellHotkeysPresentation, OwnedUiShellClipboardContent, OwnedUiShellComponentPort, OwnedUiShellEditorPort, OwnedUiShellHeaderOptions, OwnedUiShellHeaderPort, OwnedUiShellHistoryEditor, OwnedUiShellImageAssetResolver, OwnedUiShellKeybindingsHost, OwnedUiShellLoadedResourcesPort, OwnedUiShellViewComponentPort } from "../../contracts/owned-ui/index.js";
|
|
2
|
-
import type { TerminalComponentPort,
|
|
2
|
+
import type { TerminalComponentPort, TerminalInputSurfaceKind, TerminalLayoutNode } from "../../contracts/presentation/index.js";
|
|
3
3
|
import type { ShellPresentationPorts, ThemeSource } from "../../contracts/presentation/index.js";
|
|
4
|
-
import type {
|
|
5
|
-
import type { UiRouteHost, UiRouteInput } from "../../ui/apps/contracts.js";
|
|
4
|
+
import type { OwnedUiPromptSuggestionGeneratorPort, OwnedUiSessionPresenters, OwnedUiSessionViewModel, OwnedUiTranscriptRendererPort, OwnedUiViewportSettings, SuggestionDecision, SuggestionDiagnosticObserver } from "../../contracts/owned-ui/index.js";
|
|
6
5
|
import type { TranscriptViewportFrame, TranscriptViewportFrameDescriptor } from "../../ui/components/transcript-viewport.js";
|
|
7
6
|
import { PromptChipStore, type PreparedPrompt } from "./prompt-chips.js";
|
|
8
7
|
import type { PastePreparationClientOptions } from "./paste-preparation-client.js";
|
|
@@ -15,70 +14,8 @@ import type { PasteEvent, PasteSource } from "./paste-protocol.js";
|
|
|
15
14
|
import { DockChrome } from "./dock-chrome.js";
|
|
16
15
|
import { WorkflowOutput } from "./workflow-output.js";
|
|
17
16
|
import { TranscriptDocument } from "./transcript-document.js";
|
|
18
|
-
import type {
|
|
19
|
-
type
|
|
20
|
-
type OwnedUiStartupOptions = OwnedUiShellHeaderOptions;
|
|
21
|
-
/** The engine session the shell presents and the composition's decisions about it. */
|
|
22
|
-
export interface OwnedUiShellEngineOptions {
|
|
23
|
-
readonly backend: OwnedUiSessionBackend;
|
|
24
|
-
readonly cwd: string;
|
|
25
|
-
/**
|
|
26
|
-
* Declared A1-owned routes. A route this host claims resolves to its app;
|
|
27
|
-
* every other route continues to the pinned workflow table unchanged.
|
|
28
|
-
*/
|
|
29
|
-
readonly routeHost?: UiRouteHost;
|
|
30
|
-
/** One product-owned route presented after the first usable frame and any startup modal. */
|
|
31
|
-
readonly startupRoute?: {
|
|
32
|
-
readonly route: string;
|
|
33
|
-
readonly input?: UiRouteInput;
|
|
34
|
-
readonly onClosed?: () => void | Promise<void>;
|
|
35
|
-
};
|
|
36
|
-
/** Bare A1 selects the owned bounded viewport; comparison profiles stay pinned. */
|
|
37
|
-
readonly sessionLayout?: "pinned" | "custom-viewport";
|
|
38
|
-
}
|
|
39
|
-
/** Terminal, startup, viewport, and presentation-cadence seams; production leaves most at their defaults. */
|
|
40
|
-
export interface OwnedUiShellPresentationOptions {
|
|
41
|
-
readonly terminal?: OwnedUiTerminalPort;
|
|
42
|
-
readonly startup?: OwnedUiStartupOptions;
|
|
43
|
-
/** Live profile-local settings, supplied only to the bare-A1 composition. */
|
|
44
|
-
readonly viewportSettings?: OwnedUiViewportSettingsPort;
|
|
45
|
-
/** Live fullscreen canvas choice, supplied only to the bare-A1 composition. */
|
|
46
|
-
readonly backgroundSettings?: OwnedUiBackgroundSettingsPort;
|
|
47
|
-
/** Deterministic scheduling seam for presentation-cadence tests. */
|
|
48
|
-
readonly stream?: {
|
|
49
|
-
readonly intervalMs?: number;
|
|
50
|
-
readonly scheduler?: StreamPresentationScheduler;
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* Minimum time the reload box stays visible so a fast reload still reads as one.
|
|
54
|
-
* Production uses the default hold; tests inject `now`/`sleep` for determinism.
|
|
55
|
-
*/
|
|
56
|
-
readonly reload?: {
|
|
57
|
-
readonly minVisibleMs?: number;
|
|
58
|
-
readonly now?: () => number;
|
|
59
|
-
readonly sleep?: (ms: number) => Promise<void>;
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Quit outro settings and seams, supplied only to the bare-A1 composition.
|
|
63
|
-
* `interactive` states whether the terminal can show the animation; production
|
|
64
|
-
* passes stdout's TTY state, tests opt in explicitly.
|
|
65
|
-
*/
|
|
66
|
-
readonly quitOutro?: OwnedUiQuitOutroSettingsPort & {
|
|
67
|
-
readonly interactive: boolean;
|
|
68
|
-
readonly now?: () => number;
|
|
69
|
-
readonly sleep?: (ms: number) => Promise<void>;
|
|
70
|
-
readonly seed?: number;
|
|
71
|
-
};
|
|
72
|
-
readonly input?: {
|
|
73
|
-
readonly scheduler?: TerminalInputCoordinationScheduler;
|
|
74
|
-
readonly onEvent?: (event: TerminalInputDiagnosticsEvent) => void;
|
|
75
|
-
readonly now?: () => number;
|
|
76
|
-
/** Evidence-only baseline seam; production leaves coordination enabled. */
|
|
77
|
-
readonly coordination?: boolean;
|
|
78
|
-
/** Evidence-only baseline seam; production leaves dock reuse enabled. */
|
|
79
|
-
readonly viewportReuse?: boolean;
|
|
80
|
-
};
|
|
81
|
-
}
|
|
17
|
+
import type { OwnedUiShellEngineOptions, OwnedUiShellPresentationOptions } from "./shell-options.js";
|
|
18
|
+
export type { OwnedUiShellEngineOptions, OwnedUiShellPresentationOptions } from "./shell-options.js";
|
|
82
19
|
/** Persistent prompt history: its store, its bound, the editor that recalls it, and the image sidecar. */
|
|
83
20
|
export interface OwnedUiShellHistoryOptions {
|
|
84
21
|
readonly store: import("../../contracts/owned-ui/index.js").PromptHistoryPort;
|
|
@@ -286,4 +223,3 @@ export type PinnedLayoutParts = Readonly<Record<PinnedLayoutPart, TerminalCompon
|
|
|
286
223
|
* so its single `transcript` scroll view is shared by whichever session the parts currently resolve to.
|
|
287
224
|
*/
|
|
288
225
|
export declare function pinnedLayoutRoot(parts: PinnedLayoutParts, theme: ThemeSource): TerminalLayoutNode;
|
|
289
|
-
export {};
|
|
@@ -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 {
|
|
@@ -7,7 +7,7 @@ import { LoginInteraction } from "./login-interaction.js";
|
|
|
7
7
|
import { PromptSubmission } from "./prompt-submission.js";
|
|
8
8
|
import { SessionConcerns } from "./session-concern.js";
|
|
9
9
|
import { composeExitText, SessionStopLatch } from "./session-lifecycle.js";
|
|
10
|
-
import { openWorkflowSelector } from "./workflow-router.js";
|
|
10
|
+
import { openWorkflowSelector, selectSessionCwdRecovery } from "./workflow-router.js";
|
|
11
11
|
import { SessionSelectors } from "./session-selectors.js";
|
|
12
12
|
import { bindSessionSettings, bindShellSettings } from "./settings-bindings.js";
|
|
13
13
|
import { promptSuggestionSurface, suggestionPresentationBlockReason, } from "./suggestion-surface.js";
|
|
@@ -181,7 +181,7 @@ export class OwnedUiSessionPresenter {
|
|
|
181
181
|
this.#dialogs = new SessionDialogCoordinator({
|
|
182
182
|
terminal: this.#terminal,
|
|
183
183
|
root: this.root,
|
|
184
|
-
routeHost: routeHost ?? null, dialogs: options.presenters.components.dialogs,
|
|
184
|
+
routeHost: routeHost ?? null, dialogs: options.presenters.components.dialogs, inPlaceSession: this.#customViewport,
|
|
185
185
|
presentation: options.presenters, viewport: () => this.#terminal.viewport(),
|
|
186
186
|
disposed: () => this.#disposed,
|
|
187
187
|
exit: () => { void this.shutdown(); },
|
|
@@ -315,6 +315,8 @@ export class OwnedUiSessionPresenter {
|
|
|
315
315
|
}
|
|
316
316
|
// Compatibility: route modal paging and boundary keys before Pi's fullscreen handlers.
|
|
317
317
|
const isDefault = this.root.usesDefaultInputSurface();
|
|
318
|
+
if (this.#dialogs.handleInputRouteInterrupt(data))
|
|
319
|
+
return { consume: true };
|
|
318
320
|
if (!this.#terminal.hasOverlay() && !isDefault
|
|
319
321
|
&& (this.root.editor.matchesTerminalKey(data, "pageUp")
|
|
320
322
|
|| this.root.editor.matchesTerminalKey(data, "pageDown"))) {
|
|
@@ -604,18 +606,12 @@ export class OwnedUiSessionPresenter {
|
|
|
604
606
|
this.selectors.showModelSelector((result.detail ?? request.argument.trim()) || undefined);
|
|
605
607
|
return { outcome: "completed", diagnostic: null };
|
|
606
608
|
}
|
|
607
|
-
if (result.outcome === "requires-
|
|
608
|
-
|
|
609
|
-
return this.runWorkflow({ ...request, confirmed: confirmed === true });
|
|
609
|
+
if (result.outcome === "requires-selection" && result.cwdRecovery !== undefined && (request.command === "resume" || request.command === "import")) {
|
|
610
|
+
return this.runWorkflow(await selectSessionCwdRecovery(request, result, this.#extensionBridge.context));
|
|
610
611
|
}
|
|
611
612
|
if (result.outcome === "requires-confirmation" && request.command === "import") {
|
|
612
|
-
const
|
|
613
|
-
|
|
614
|
-
return this.runWorkflow({
|
|
615
|
-
...request,
|
|
616
|
-
confirmed: confirmed === true,
|
|
617
|
-
...(confirmed === true && result.detail ? { cwdOverride: result.detail } : {}),
|
|
618
|
-
});
|
|
613
|
+
const confirmed = await this.#extensionBridge.context.confirm("Import session", result.message);
|
|
614
|
+
return this.runWorkflow({ ...request, confirmed: confirmed === true });
|
|
619
615
|
}
|
|
620
616
|
if (result.outcome === "requires-selection" || result.outcome === "requires-confirmation") {
|
|
621
617
|
this.root.workflow.appendResult({ command: request.command, outcome: "failed", message: `Owned controller missing for ${request.command}` });
|
|
@@ -921,7 +917,7 @@ export class OwnedUiSessionPresenter {
|
|
|
921
917
|
const skills = this.#skillSummaries();
|
|
922
918
|
const trimmed = argument.trim();
|
|
923
919
|
if (trimmed.length === 0) {
|
|
924
|
-
this.selectors.showSkillsSelector(skills);
|
|
920
|
+
await this.selectors.showSkillsSelector(skills);
|
|
925
921
|
return { outcome: "completed", diagnostic: null };
|
|
926
922
|
}
|
|
927
923
|
const separator = trimmed.search(/\s/u);
|
|
@@ -270,8 +270,8 @@ export class OwnedUiTerminalHost {
|
|
|
270
270
|
requestHyperlinkCleanup: rows => { if (attached())
|
|
271
271
|
this.#damageTerminal?.requestHyperlinkCleanup(rows); },
|
|
272
272
|
openRoute: (surface, callbacks) => this.#openRoute(presenter, surface, callbacks),
|
|
273
|
-
// Invariant: an
|
|
274
|
-
beginPresentationHold: () => attached() ? runtime.beginPresentationHold() : () => { },
|
|
273
|
+
// Invariant: only an attached presenter on a running runtime can hold frames.
|
|
274
|
+
beginPresentationHold: () => attached() && runtime.active ? runtime.beginPresentationHold() : () => { },
|
|
275
275
|
switchMode: mode => runtime.switchMode(mode),
|
|
276
276
|
setTitle: title => { if (attached())
|
|
277
277
|
runtime.setTitle(title); },
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { OwnedUiBackgroundSettingsPort, OwnedUiSessionBackend, OwnedUiShellHeaderOptions, OwnedUiViewportSettingsPort, OwnedUiQuitOutroSettingsPort } from "../../contracts/owned-ui/index.js";
|
|
2
|
+
import type { TerminalInputCoordinationScheduler, TerminalInputDiagnosticsEvent, TerminalPort } from "../../contracts/presentation/index.js";
|
|
3
|
+
import type { StreamPresentationScheduler } from "./stream-presentation-coalescer.js";
|
|
4
|
+
import type { UiRouteHost, UiRouteInput } from "../../ui/apps/index.js";
|
|
5
|
+
/** The engine session the shell presents and the composition's decisions about it. */
|
|
6
|
+
export interface OwnedUiShellEngineOptions {
|
|
7
|
+
readonly backend: OwnedUiSessionBackend;
|
|
8
|
+
readonly cwd: string;
|
|
9
|
+
/**
|
|
10
|
+
* Declared A1-owned routes. A route this host claims resolves to its app;
|
|
11
|
+
* every other route continues to the pinned workflow table unchanged.
|
|
12
|
+
*/
|
|
13
|
+
readonly routeHost?: UiRouteHost;
|
|
14
|
+
/** One product-owned route presented after the first usable frame and any startup modal. */
|
|
15
|
+
readonly startupRoute?: {
|
|
16
|
+
readonly route: string;
|
|
17
|
+
readonly input?: UiRouteInput;
|
|
18
|
+
readonly onClosed?: () => void | Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
/** Bare A1 selects the owned bounded viewport; comparison profiles stay pinned. */
|
|
21
|
+
readonly sessionLayout?: "pinned" | "custom-viewport";
|
|
22
|
+
}
|
|
23
|
+
/** Terminal, startup, viewport, and presentation-cadence seams; production leaves most at their defaults. */
|
|
24
|
+
export interface OwnedUiShellPresentationOptions {
|
|
25
|
+
readonly terminal?: TerminalPort;
|
|
26
|
+
readonly startup?: OwnedUiShellHeaderOptions;
|
|
27
|
+
/** Live profile-local settings, supplied only to the bare-A1 composition. */
|
|
28
|
+
readonly viewportSettings?: OwnedUiViewportSettingsPort;
|
|
29
|
+
/** Live fullscreen canvas choice, supplied only to the bare-A1 composition. */
|
|
30
|
+
readonly backgroundSettings?: OwnedUiBackgroundSettingsPort;
|
|
31
|
+
/** Deterministic scheduling seam for presentation-cadence tests. */
|
|
32
|
+
readonly stream?: {
|
|
33
|
+
readonly intervalMs?: number;
|
|
34
|
+
readonly scheduler?: StreamPresentationScheduler;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Minimum time the reload box stays visible so a fast reload still reads as one.
|
|
38
|
+
* Production uses the default hold; tests inject `now`/`sleep` for determinism.
|
|
39
|
+
*/
|
|
40
|
+
readonly reload?: {
|
|
41
|
+
readonly minVisibleMs?: number;
|
|
42
|
+
readonly now?: () => number;
|
|
43
|
+
readonly sleep?: (ms: number) => Promise<void>;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Quit outro settings and seams, supplied only to the bare-A1 composition.
|
|
47
|
+
* `interactive` states whether the terminal can show the animation; production
|
|
48
|
+
* passes stdout's TTY state, tests opt in explicitly.
|
|
49
|
+
*/
|
|
50
|
+
readonly quitOutro?: OwnedUiQuitOutroSettingsPort & {
|
|
51
|
+
readonly interactive: boolean;
|
|
52
|
+
readonly now?: () => number;
|
|
53
|
+
readonly sleep?: (ms: number) => Promise<void>;
|
|
54
|
+
readonly seed?: number;
|
|
55
|
+
};
|
|
56
|
+
readonly input?: {
|
|
57
|
+
readonly scheduler?: TerminalInputCoordinationScheduler;
|
|
58
|
+
readonly onEvent?: (event: TerminalInputDiagnosticsEvent) => void;
|
|
59
|
+
readonly now?: () => number;
|
|
60
|
+
/** Evidence-only baseline seam; production leaves coordination enabled. */
|
|
61
|
+
readonly coordination?: boolean;
|
|
62
|
+
/** Evidence-only baseline seam; production leaves dock reuse enabled. */
|
|
63
|
+
readonly viewportReuse?: boolean;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -110,7 +110,11 @@ export class ViewportPointerGestures {
|
|
|
110
110
|
viewport.setRailHovered(false);
|
|
111
111
|
viewport.setStickyHovered(false);
|
|
112
112
|
this.#position = undefined;
|
|
113
|
-
owner.component.
|
|
113
|
+
if (owner.component.handleLocalMouse !== undefined) {
|
|
114
|
+
owner.component.handleLocalMouse({ ...event, column: event.column - owner.columnStart + 1, row: event.row - owner.rowStart + 1 });
|
|
115
|
+
}
|
|
116
|
+
else
|
|
117
|
+
owner.component.handleInput?.(report);
|
|
114
118
|
outcome.repaint = true;
|
|
115
119
|
return true;
|
|
116
120
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OwnedUiCommandResult, OwnedUiWorkflowRequest } from "../../contracts/owned-ui/index.js";
|
|
1
|
+
import type { OwnedUiCommandResult, OwnedUiExtensionUiPort, OwnedUiWorkflowRequest, OwnedUiWorkflowResult } from "../../contracts/owned-ui/index.js";
|
|
2
2
|
/** The owned selectors a workflow can open in place of asking the engine to choose. */
|
|
3
3
|
export interface WorkflowSelectors {
|
|
4
4
|
showScopedModelsSelector(): void;
|
|
@@ -6,7 +6,7 @@ export interface WorkflowSelectors {
|
|
|
6
6
|
showModelSelector(initialSearchInput?: string): void;
|
|
7
7
|
showForkSelector(): void;
|
|
8
8
|
showThinkingSelector(): Promise<void>;
|
|
9
|
-
showTrustSelector(): void
|
|
9
|
+
showTrustSelector(): void | Promise<void>;
|
|
10
10
|
showSettingsSelector(): void;
|
|
11
11
|
showSessionSelector(): Promise<void>;
|
|
12
12
|
showLoginAuthTypeSelector(): void;
|
|
@@ -14,6 +14,8 @@ export interface WorkflowSelectors {
|
|
|
14
14
|
showLogoutSelector(): Promise<void>;
|
|
15
15
|
showTreeSelector(): Promise<void>;
|
|
16
16
|
}
|
|
17
|
+
/** Maps the pinned recovery labels back to explicit choices, including Escape as cancellation. */
|
|
18
|
+
export declare function selectSessionCwdRecovery(request: OwnedUiWorkflowRequest, result: OwnedUiWorkflowResult, ui: Pick<OwnedUiExtensionUiPort, "select">): Promise<OwnedUiWorkflowRequest>;
|
|
17
19
|
/**
|
|
18
20
|
* Opens the owned selector a workflow request asks for when the user has not chosen yet. Returns
|
|
19
21
|
* the command result when a selector handled the request, settling once an asynchronous selector
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/** Maps the pinned recovery labels back to explicit choices, including Escape as cancellation. */
|
|
2
|
+
export async function selectSessionCwdRecovery(request, result, ui) {
|
|
3
|
+
const options = result.options ?? [];
|
|
4
|
+
const selected = await ui.select(result.message, options.map(option => option.label));
|
|
5
|
+
const choice = options.find(option => option.label === selected)?.id;
|
|
6
|
+
const cwdRecoveryChoice = choice === "continue" || choice === "fork" ? choice : "cancel";
|
|
7
|
+
return {
|
|
8
|
+
...request,
|
|
9
|
+
cwdRecoveryChoice,
|
|
10
|
+
...(cwdRecoveryChoice === "continue" ? { cwdOverride: result.cwdRecovery.fallbackCwd } : {}),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
1
13
|
const unchosen = (request) => request.selection === undefined && request.confirmed === undefined;
|
|
2
14
|
const unchosenBare = (request) => unchosen(request) && request.argument.trim().length === 0;
|
|
3
15
|
// Invariant: the routes are checked in this order, matching the order the workflows were introduced.
|