@timurproko/a1 0.2.7-dev.1275 → 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.
Files changed (60) hide show
  1. package/dist/app/session-shell/apps-dialog.d.ts +1 -1
  2. package/dist/app/session-shell/apps-dialog.js +2 -1
  3. package/dist/app/session-shell/dialog-coordinator.d.ts +4 -5
  4. package/dist/app/session-shell/dialog-coordinator.js +41 -12
  5. package/dist/app/session-shell/input-route.d.ts +23 -0
  6. package/dist/app/session-shell/input-route.js +59 -0
  7. package/dist/app/session-shell/session-selectors.d.ts +3 -3
  8. package/dist/app/session-shell/session-selectors.js +7 -2
  9. package/dist/app/session-shell/session-shell-root.js +6 -2
  10. package/dist/app/session-shell/session-shell.js +4 -2
  11. package/dist/app/session-shell/viewport-pointer.js +5 -1
  12. package/dist/app/session-shell/workflow-router.d.ts +1 -1
  13. package/dist/composition/settings-route-host.js +1 -0
  14. package/dist/contracts/owned-ui/shell-components.d.ts +10 -0
  15. package/dist/contracts/presentation/component.d.ts +7 -0
  16. package/dist/contracts/presentation/index.d.ts +2 -0
  17. package/dist/contracts/presentation/index.js +4 -0
  18. package/dist/contracts/presentation/progress-palette.generated.d.ts +24 -0
  19. package/dist/contracts/presentation/progress-palette.generated.js +1 -134
  20. package/dist/features/owned-ui/project-trust-dialog.d.ts +1 -1
  21. package/dist/features/owned-ui/project-trust-dialog.js +5 -5
  22. package/dist/features/owned-ui/project-trust-prompt.js +2 -2
  23. package/dist/features/owned-ui/reference-screen-app.d.ts +2 -0
  24. package/dist/features/owned-ui/reference-screen-app.js +4 -1
  25. package/dist/features/owned-ui/settings-app.js +6 -6
  26. package/dist/features/owned-ui/settings-model-dialog.js +3 -3
  27. package/dist/integrations/pi/components/deferred-selector.d.ts +6 -0
  28. package/dist/integrations/pi/components/deferred-selector.js +40 -0
  29. package/dist/integrations/pi/components/login-dialog-loader.d.ts +3 -0
  30. package/dist/integrations/pi/components/login-dialog-loader.js +57 -0
  31. package/dist/integrations/pi/components/login-links.d.ts +6 -0
  32. package/dist/integrations/pi/components/login-links.js +31 -0
  33. package/dist/integrations/pi/components/login-text.d.ts +7 -0
  34. package/dist/integrations/pi/components/login-text.js +17 -0
  35. package/dist/integrations/pi/components/modal-frame.d.ts +5 -0
  36. package/dist/integrations/pi/components/modal-frame.js +30 -2
  37. package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +11 -8
  38. package/dist/integrations/pi/components/shell-selectors-dialogs.js +36 -35
  39. package/dist/integrations/pi/components/shell-session-info-reference.d.ts +1 -1
  40. package/dist/integrations/pi/components/shell-session-info-reference.js +49 -46
  41. package/dist/integrations/pi/components/theme.d.ts +2 -0
  42. package/dist/integrations/pi/components/theme.js +4 -0
  43. package/dist/integrations/pi/components/upstream/components/auth-url.d.ts +16 -0
  44. package/dist/integrations/pi/components/upstream/components/auth-url.js +49 -0
  45. package/dist/integrations/pi/components/upstream/components/extension-selector.d.ts +1 -0
  46. package/dist/integrations/pi/components/upstream/components/extension-selector.js +21 -10
  47. package/dist/integrations/pi/components/upstream/components/login-dialog.d.ts +3 -0
  48. package/dist/integrations/pi/components/upstream/components/login-dialog.js +216 -0
  49. package/dist/integrations/pi/components/upstream/components/oauth-selector.d.ts +19 -0
  50. package/dist/integrations/pi/components/upstream/components/oauth-selector.js +123 -0
  51. package/dist/integrations/pi/components/upstream/components/session-footer.js +10 -7
  52. package/dist/integrations/pi/components/upstream/components/trust-selector.d.ts +2 -0
  53. package/dist/integrations/pi/components/upstream/components/trust-selector.js +29 -12
  54. package/dist/integrations/pi/session-presenters/components.d.ts +1 -1
  55. package/dist/integrations/pi/session-presenters/components.js +8 -8
  56. package/dist/integrations/pi/session-presenters/presenters.js +2 -2
  57. package/dist/ui/components/list-block.d.ts +2 -2
  58. package/dist/ui/components/list-block.js +4 -3
  59. package/dist/ui/settings/early-accent.d.ts +24 -0
  60. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
- import type { TerminalComponentPort } from "../../contracts/presentation/index.js";
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 = Math.max(0, Math.min(matches.length - 1, this.#index + (action === "next" ? 1 : -1)));
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
- if (rendered) {
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
- /** The Skills dialog: a replacement input like the model selector, applying the chosen skill through the prompt path. */
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
- /** The Skills dialog: a replacement input like the model selector, applying the chosen skill through the prompt path. */
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
- // Invariant: a selector replaces the editor in the input dock and paints in the same frame.
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 {
@@ -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"))) {
@@ -921,7 +923,7 @@ export class OwnedUiSessionPresenter {
921
923
  const skills = this.#skillSummaries();
922
924
  const trimmed = argument.trim();
923
925
  if (trimmed.length === 0) {
924
- this.selectors.showSkillsSelector(skills);
926
+ await this.selectors.showSkillsSelector(skills);
925
927
  return { outcome: "completed", diagnostic: null };
926
928
  }
927
929
  const separator = trimmed.search(/\s/u);
@@ -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.handleInput?.(report);
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
  }
@@ -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;
@@ -92,6 +92,7 @@ async function loadReferenceSurface(settings, route, title, document, options) {
92
92
  id,
93
93
  title,
94
94
  document: content,
95
+ ...(route === "session" ? { presentation: "dialog" } : {}),
95
96
  scrollSettings: () => ({
96
97
  scrollbarAppearance: settings.value("scrollbarAppearance"),
97
98
  scrollbarStyle: settings.value("scrollbarStyle"),
@@ -14,9 +14,19 @@ export interface OwnedUiShellKeybindingsHost {
14
14
  reload(): void;
15
15
  }
16
16
  export interface OwnedUiShellComponentPort {
17
+ readonly ready?: Promise<void>;
17
18
  render(width: number): readonly string[];
19
+ /** Bounds scrollable replacement inputs within the dock. */
20
+ renderInDock?(width: number, maxHeight: number): readonly string[];
18
21
  invalidate(): void;
19
22
  handleInput?(data: string): void;
23
+ /** Pointer input in one-based component-local coordinates, when supported. */
24
+ handleLocalMouse?(event: {
25
+ readonly kind: "press" | "release" | "motion" | "wheel-up" | "wheel-down";
26
+ readonly button: number;
27
+ readonly column: number;
28
+ readonly row: number;
29
+ }): void;
20
30
  setFocused?(focused: boolean): void;
21
31
  dispose?(): void;
22
32
  }
@@ -2,6 +2,13 @@ export interface PresentationComponentPort {
2
2
  render(width: number): readonly string[];
3
3
  invalidate(): void;
4
4
  handleInput?(data: string): void;
5
+ /** Optional pointer input in one-based component-local coordinates. */
6
+ handleLocalMouse?(event: {
7
+ readonly kind: "press" | "release" | "motion" | "wheel-up" | "wheel-down";
8
+ readonly button: number;
9
+ readonly column: number;
10
+ readonly row: number;
11
+ }): void;
5
12
  setFocused?(focused: boolean): void;
6
13
  dispose?(): void;
7
14
  }
@@ -22,6 +22,8 @@ export declare const DIALOG_BACK_SHORTCUT_HINT: Readonly<{
22
22
  }>;
23
23
  /** Global inset inherited by every semantic row inside an A1-owned dialog frame. */
24
24
  export declare const DIALOG_CONTENT_PADDING_X = 1;
25
+ /** Wraps choice navigation, leaving empty lists at a safe index. */
26
+ export declare function wrapChoiceIndex(index: number, delta: number, count: number): number;
25
27
  export interface DialogFrameGeometry {
26
28
  readonly frameWidth: number;
27
29
  readonly contentPaddingX: number;
@@ -6,6 +6,10 @@ export const DIALOG_CLOSE_SHORTCUT_HINT = Object.freeze({ key: "esc", action: "c
6
6
  export const DIALOG_BACK_SHORTCUT_HINT = Object.freeze({ key: "esc", action: "back" });
7
7
  /** Global inset inherited by every semantic row inside an A1-owned dialog frame. */
8
8
  export const DIALOG_CONTENT_PADDING_X = 1;
9
+ /** Wraps choice navigation, leaving empty lists at a safe index. */
10
+ export function wrapChoiceIndex(index, delta, count) {
11
+ return count > 0 ? ((index + delta) % count + count) % count : 0;
12
+ }
9
13
  /** Shared full-width-rule/content-width geometry for string and component dialog renderers. */
10
14
  export function dialogFrameGeometry(width) {
11
15
  const frameWidth = Math.max(0, width);
@@ -8,20 +8,24 @@ export declare const SHARED_PROGRESS_PALETTE: Readonly<{
8
8
  truecolor: {
9
9
  accent: string;
10
10
  border: string;
11
+ selectedBg: string;
11
12
  };
12
13
  "256color": {
13
14
  accent: string;
14
15
  border: string;
16
+ selectedBg: string;
15
17
  };
16
18
  };
17
19
  light: {
18
20
  truecolor: {
19
21
  accent: string;
20
22
  border: string;
23
+ selectedBg: string;
21
24
  };
22
25
  "256color": {
23
26
  accent: string;
24
27
  border: string;
28
+ selectedBg: string;
25
29
  };
26
30
  };
27
31
  };
@@ -30,20 +34,24 @@ export declare const SHARED_PROGRESS_PALETTE: Readonly<{
30
34
  truecolor: {
31
35
  accent: string;
32
36
  border: string;
37
+ selectedBg: string;
33
38
  };
34
39
  "256color": {
35
40
  accent: string;
36
41
  border: string;
42
+ selectedBg: string;
37
43
  };
38
44
  };
39
45
  light: {
40
46
  truecolor: {
41
47
  accent: string;
42
48
  border: string;
49
+ selectedBg: string;
43
50
  };
44
51
  "256color": {
45
52
  accent: string;
46
53
  border: string;
54
+ selectedBg: string;
47
55
  };
48
56
  };
49
57
  };
@@ -52,20 +60,24 @@ export declare const SHARED_PROGRESS_PALETTE: Readonly<{
52
60
  truecolor: {
53
61
  accent: string;
54
62
  border: string;
63
+ selectedBg: string;
55
64
  };
56
65
  "256color": {
57
66
  accent: string;
58
67
  border: string;
68
+ selectedBg: string;
59
69
  };
60
70
  };
61
71
  light: {
62
72
  truecolor: {
63
73
  accent: string;
64
74
  border: string;
75
+ selectedBg: string;
65
76
  };
66
77
  "256color": {
67
78
  accent: string;
68
79
  border: string;
80
+ selectedBg: string;
69
81
  };
70
82
  };
71
83
  };
@@ -74,20 +86,24 @@ export declare const SHARED_PROGRESS_PALETTE: Readonly<{
74
86
  truecolor: {
75
87
  accent: string;
76
88
  border: string;
89
+ selectedBg: string;
77
90
  };
78
91
  "256color": {
79
92
  accent: string;
80
93
  border: string;
94
+ selectedBg: string;
81
95
  };
82
96
  };
83
97
  light: {
84
98
  truecolor: {
85
99
  accent: string;
86
100
  border: string;
101
+ selectedBg: string;
87
102
  };
88
103
  "256color": {
89
104
  accent: string;
90
105
  border: string;
106
+ selectedBg: string;
91
107
  };
92
108
  };
93
109
  };
@@ -96,20 +112,24 @@ export declare const SHARED_PROGRESS_PALETTE: Readonly<{
96
112
  truecolor: {
97
113
  accent: string;
98
114
  border: string;
115
+ selectedBg: string;
99
116
  };
100
117
  "256color": {
101
118
  accent: string;
102
119
  border: string;
120
+ selectedBg: string;
103
121
  };
104
122
  };
105
123
  light: {
106
124
  truecolor: {
107
125
  accent: string;
108
126
  border: string;
127
+ selectedBg: string;
109
128
  };
110
129
  "256color": {
111
130
  accent: string;
112
131
  border: string;
132
+ selectedBg: string;
113
133
  };
114
134
  };
115
135
  };
@@ -118,20 +138,24 @@ export declare const SHARED_PROGRESS_PALETTE: Readonly<{
118
138
  truecolor: {
119
139
  accent: string;
120
140
  border: string;
141
+ selectedBg: string;
121
142
  };
122
143
  "256color": {
123
144
  accent: string;
124
145
  border: string;
146
+ selectedBg: string;
125
147
  };
126
148
  };
127
149
  light: {
128
150
  truecolor: {
129
151
  accent: string;
130
152
  border: string;
153
+ selectedBg: string;
131
154
  };
132
155
  "256color": {
133
156
  accent: string;
134
157
  border: string;
158
+ selectedBg: string;
135
159
  };
136
160
  };
137
161
  };