@timurproko/a1 0.2.7-dev.1270 → 0.2.7-dev.1275

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 (114) hide show
  1. package/README.md +6 -0
  2. package/dist/app/session-shell/apps-dialog.d.ts +33 -0
  3. package/dist/app/session-shell/apps-dialog.js +61 -0
  4. package/dist/app/session-shell/dialog-coordinator.d.ts +8 -0
  5. package/dist/app/session-shell/dialog-coordinator.js +72 -3
  6. package/dist/app/session-shell/session-selectors.d.ts +1 -1
  7. package/dist/app/session-shell/session-selectors.js +1 -1
  8. package/dist/app/session-shell/session-shell.js +9 -3
  9. package/dist/app/session-shell/shell-host.d.ts +1 -0
  10. package/dist/app/session-shell/shell-host.js +22 -11
  11. package/dist/app/session-shell/workflow-output.js +12 -0
  12. package/dist/app/session-shell/workflow-router.d.ts +1 -1
  13. package/dist/composition/owned-ui.js +17 -13
  14. package/dist/contracts/owned-ui/session-presenters.d.ts +1 -1
  15. package/dist/contracts/owned-ui/session-workflows.d.ts +3 -1
  16. package/dist/contracts/owned-ui/shell-components.d.ts +2 -0
  17. package/dist/contracts/presentation/progress-palette.generated.d.ts +1 -1
  18. package/dist/contracts/presentation/progress-palette.generated.js +1 -1
  19. package/dist/contracts/presentation/terminal.d.ts +4 -0
  20. package/dist/contracts/presentation/theme.d.ts +2 -0
  21. package/dist/foundation/lifecycle/user-exports.d.ts +5 -0
  22. package/dist/foundation/lifecycle/user-exports.js +37 -0
  23. package/dist/foundation/startup/startup-descriptor.js +2 -2
  24. package/dist/integrations/pi/components/models-dialog-loader.d.ts +11 -0
  25. package/dist/integrations/pi/components/models-dialog-loader.js +45 -0
  26. package/dist/integrations/pi/components/models-dialog.d.ts +2 -0
  27. package/dist/integrations/pi/components/models-dialog.js +13 -7
  28. package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -2
  29. package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
  30. package/dist/integrations/pi/components/shell-editor-autocomplete.js +21 -15
  31. package/dist/integrations/pi/components/shell-footer-status.js +3 -2
  32. package/dist/integrations/pi/components/shell-presenters-info.js +1 -1
  33. package/dist/integrations/pi/components/shell-presenters-transcript.js +3 -1
  34. package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +2 -1
  35. package/dist/integrations/pi/components/shell-selectors-dialogs.js +2 -8
  36. package/dist/integrations/pi/components/theme.d.ts +2 -0
  37. package/dist/integrations/pi/components/theme.js +5 -0
  38. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +8 -7
  39. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +13 -7
  40. package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
  41. package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
  42. package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
  43. package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
  44. package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
  45. package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
  46. package/dist/integrations/pi/components/upstream/components/extension-selector.js +9 -2
  47. package/dist/integrations/pi/components/upstream/components/mermaid.d.ts +2 -1
  48. package/dist/integrations/pi/components/upstream/components/mermaid.js +26 -21
  49. package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +1 -1
  50. package/dist/integrations/pi/components/upstream/components/owned-editor.js +1 -1
  51. package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
  52. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +1 -1
  53. package/dist/integrations/pi/components/upstream/components/session-footer.js +9 -14
  54. package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
  55. package/dist/integrations/pi/components/upstream/components/session-selector.js +1 -1
  56. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +6 -2
  57. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +27 -3
  58. package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +1 -1
  59. package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
  60. package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
  61. package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
  62. package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +1 -1
  63. package/dist/integrations/pi/components/upstream/components/thinking-selector.js +1 -1
  64. package/dist/integrations/pi/components/upstream/components/tool-execution.js +1 -1
  65. package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +1 -1
  66. package/dist/integrations/pi/components/upstream/components/tree-selector.js +7 -6
  67. package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
  68. package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
  69. package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +1 -1
  70. package/dist/integrations/pi/components/upstream/history/editor-core.js +2 -2
  71. package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
  72. package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
  73. package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
  74. package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
  75. package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
  76. package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
  77. package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
  78. package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
  79. package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +1 -1
  80. package/dist/integrations/pi/components/upstream/theme/theme.js +1 -1
  81. package/dist/integrations/pi/engine/adapter.d.ts +1 -1
  82. package/dist/integrations/pi/engine/adapter.js +3 -3
  83. package/dist/integrations/pi/engine/host.d.ts +1 -1
  84. package/dist/integrations/pi/engine/resources/changelog.json +4 -4
  85. package/dist/integrations/pi/engine/workflow-export.d.ts +4 -0
  86. package/dist/integrations/pi/engine/workflow-export.js +25 -0
  87. package/dist/integrations/pi/engine/workflow-runner.d.ts +1 -0
  88. package/dist/integrations/pi/engine/workflow-runner.js +6 -10
  89. package/dist/integrations/pi/engine/workflow-support.d.ts +2 -1
  90. package/dist/integrations/pi/engine/workflow-support.js +28 -25
  91. package/dist/integrations/pi/engine/workflows.d.ts +6 -1
  92. package/dist/integrations/pi/engine/workflows.js +1 -1
  93. package/dist/integrations/pi/session-presenters/presentation.js +2 -1
  94. package/dist/integrations/pi/session-presenters/presenters.js +22 -10
  95. package/dist/integrations/pi/startup-public.js +289 -240
  96. package/dist/integrations/pi/startup-public.manifest.json +579 -363
  97. package/dist/integrations/pi/tui-runtime/adapter.js +3 -1
  98. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
  99. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +1 -1
  100. package/dist/integrations/pi/tui-runtime/overlay-geometry.d.ts +5 -2
  101. package/dist/integrations/pi/tui-runtime/overlay-geometry.js +12 -2
  102. package/dist/runtime-payload-inventory.json +8044 -6930
  103. package/dist/ui/components/dialog-panel.d.ts +4 -3
  104. package/dist/ui/components/dialog-panel.js +9 -13
  105. package/dist/ui/components/index.d.ts +1 -1
  106. package/dist/ui/components/index.js +1 -1
  107. package/dist/ui/components/spans.d.ts +7 -0
  108. package/dist/ui/components/spans.js +63 -1
  109. package/docs/architecture/prompt-suggestions.md +1 -1
  110. package/docs/architecture/ui-reference-provenance.md +2 -1
  111. package/docs/features/prompt-history.md +1 -1
  112. package/docs/features/session-exports.md +15 -0
  113. package/docs/local-worktree-cleanup.md +24 -0
  114. package/package.json +6 -6
@@ -0,0 +1,4 @@
1
+ import type { AgentSession } from "../startup-public.js";
2
+ import type { PiWorkflowHost, PiWorkflowRequest, PiWorkflowResult } from "./workflows.js";
3
+ /** Explicit paths and comparison defaults stay pinned; only bare-A1 implicit exports use persistent user storage. */
4
+ export declare function exportWorkflow(request: PiWorkflowRequest, session: AgentSession, bare: boolean, reserve?: PiWorkflowHost["reserveExport"]): Promise<PiWorkflowResult>;
@@ -0,0 +1,25 @@
1
+ import { requireCapability } from "./message-values.js";
2
+ import { pathArgument, workflowResult } from "./workflow-support.js";
3
+ /** Explicit paths and comparison defaults stay pinned; only bare-A1 implicit exports use persistent user storage. */
4
+ export async function exportWorkflow(request, session, bare, reserve) {
5
+ const argument = request.argument.trim();
6
+ const flag = bare ? /^(--jsonl|--html)(?:\s+([\s\S]+))?$/u.exec(argument) : null;
7
+ const explicit = pathArgument(flag ? flag[2] ?? "" : argument);
8
+ if (bare && (flag?.[2] || argument && !flag) && explicit === undefined)
9
+ throw new Error("Export destination is invalid");
10
+ const format = flag ? flag[1] === "--jsonl" ? "jsonl" : "html" : explicit?.toLowerCase().endsWith(".jsonl") ? "jsonl" : "html";
11
+ if (bare && explicit === undefined && reserve === undefined)
12
+ throw new Error("Session export storage is unavailable");
13
+ const reserved = bare && explicit === undefined ? await reserve(session.sessionId ?? "session", format) : undefined;
14
+ const path = reserved?.path ?? explicit;
15
+ try {
16
+ const file = format === "jsonl"
17
+ ? await requireCapability(session.exportToJsonl, "exportToJsonl").call(session, path)
18
+ : await requireCapability(session.exportToHtml, "exportToHtml").call(session, path);
19
+ return workflowResult(request.command, "completed", `Session exported to: ${String(file)}`);
20
+ }
21
+ catch (error) {
22
+ await reserved?.failed();
23
+ throw error;
24
+ }
25
+ }
@@ -5,6 +5,7 @@ import type { PiBashWorkflowResult, PiWorkflowHost, PiWorkflowInteractionHost, P
5
5
  type PiSessionApi = AgentSession;
6
6
  type PiRuntimeApi = AgentSessionRuntime;
7
7
  interface PiWorkflowRunnerOptions {
8
+ readonly productMode?: "bare" | "comparison";
8
9
  readonly agentDir: string;
9
10
  readonly host: PiWorkflowHost;
10
11
  readonly contexts: PiWorkflowContexts;
@@ -14,6 +14,7 @@ const MAX_PENDING_WORK = 32;
14
14
  */
15
15
  export class PiWorkflowRunner {
16
16
  #agentDir;
17
+ #bare;
17
18
  #host;
18
19
  #authentication;
19
20
  #ports;
@@ -21,6 +22,7 @@ export class PiWorkflowRunner {
21
22
  #clipboardWriter;
22
23
  constructor(options, ports) {
23
24
  this.#agentDir = options.agentDir;
25
+ this.#bare = options.productMode === "bare";
24
26
  this.#host = options.host;
25
27
  this.#ports = ports;
26
28
  this.#authentication = new PiProviderAuthentication({ agentDir: options.agentDir, contexts: options.contexts }, {
@@ -68,7 +70,7 @@ export class PiWorkflowRunner {
68
70
  const reasoning = result.model.reasoning === true;
69
71
  const thinking = this.#ports.thinkingLevel();
70
72
  const suffix = reasoning && thinking !== "off" ? ` (thinking: ${thinking})` : "";
71
- return workflowResult("model", "completed", `Switched to ${modelName}${suffix}`, undefined, "status");
73
+ return { ...workflowResult("model", "completed", `Switched to ${modelName}${suffix}`, undefined, "status"), presentation: { kind: "model-change" } };
72
74
  }
73
75
  catch (error) {
74
76
  return workflowResult("model", "failed", error instanceof Error ? error.message : String(error));
@@ -221,9 +223,10 @@ export class PiWorkflowRunner {
221
223
  this.#ports.setActiveModel({ providerId, modelId, displayName: stringProperty(model, "name") ?? modelId });
222
224
  this.#ports.emitView();
223
225
  const resultMessage = { kind: "status", message: options.persist ? `Default model: ${providerId}/${modelId}` : `Model: ${modelId}` };
224
- return messages.length === 0
226
+ const result = messages.length === 0
225
227
  ? workflowResult(request.command, "completed", resultMessage.message)
226
228
  : workflowResult(request.command, "completed", resultMessage.message, undefined, "status", [...messages, resultMessage]);
229
+ return { ...result, presentation: { kind: "model-change" } };
227
230
  }
228
231
  async #performWorkflow(request) {
229
232
  const session = this.#requireSession();
@@ -240,7 +243,7 @@ export class PiWorkflowRunner {
240
243
  case "model": return this.#modelWorkflow(call);
241
244
  case "models": return this.#modelsWorkflow(call);
242
245
  case "scoped-models": return scopedModelsWorkflow(call);
243
- case "export": return exportWorkflow(call);
246
+ case "export": return (await import("./workflow-export.js")).exportWorkflow(request, session, this.#bare, this.#host.reserveExport);
244
247
  case "import": return importWorkflow(call);
245
248
  case "share": return (await import("./workflow-share.js")).runShareWorkflow({ request, session, runtime, host: this.#host });
246
249
  case "copy": return copyWorkflow(call, text => this.copyWorkflowText(text));
@@ -340,13 +343,6 @@ function scopedModelsWorkflow({ request, session, runtime, selection }) {
340
343
  requireCapability(session.setScopedModels, "setScopedModels").call(session, [{ model }]);
341
344
  return workflowResult(request.command, "completed", `Enabled scoped model ${selection}`);
342
345
  }
343
- async function exportWorkflow({ request, session, argument }) {
344
- const path = pathArgument(argument);
345
- const file = path?.toLowerCase().endsWith(".jsonl")
346
- ? requireCapability(session.exportToJsonl, "exportToJsonl").call(session, path)
347
- : await requireCapability(session.exportToHtml, "exportToHtml").call(session, path);
348
- return workflowResult(request.command, "completed", `Session exported to: ${String(file)}`);
349
- }
350
346
  async function importWorkflow({ request, runtime, argument }) {
351
347
  const path = pathArgument(argument);
352
348
  if (!path)
@@ -7,7 +7,8 @@ export declare function pinnedSessionInfoPresentation(value: unknown, sessionNam
7
7
  readonly mode: unknown;
8
8
  readonly status: unknown;
9
9
  }): PiSessionInfoPresentation;
10
- export declare function defaultWorkflowHost(): PiWorkflowHost;
10
+ /** Fill optional host services while retaining class methods and their original receiver. */
11
+ export declare function resolveWorkflowHost(host?: Partial<PiWorkflowHost>): PiWorkflowHost;
11
12
  export declare function workflowLoginNotification(event: unknown): PiWorkflowLoginNotification | undefined;
12
13
  export declare function workflowResult(command: PiWorkflowRequest["command"], outcome: PiWorkflowResult["outcome"], message: string, detail?: string, messageKind?: PiWorkflowResult["messageKind"], messages?: readonly PiWorkflowMessage[]): PiWorkflowResult;
13
14
  export declare function workflowConfirmation(command: PiWorkflowRequest["command"], message: string, detail?: string): PiWorkflowResult;
@@ -1,7 +1,6 @@
1
1
  /** Pure helpers behind pinned Pi's workflows: result wording, session-info presentation, model matching, and option shaping. */
2
2
  import { execFile } from "node:child_process";
3
3
  import { promisify } from "node:util";
4
- import { readPinnedCommandChangelog } from "./changelog.js";
5
4
  import { dynamicObject, finiteNumber, isRecord, stringProperty, stringValue } from "./message-values.js";
6
5
  import { copyToClipboard } from "../startup-public.js";
7
6
  const execFileAsync = promisify(execFile);
@@ -9,43 +8,44 @@ export const AUTH_REFRESH_TIMEOUT_MS = 15_000;
9
8
  // Provenance: the pinned engine's core/model-resolver.ts defaultModelPerProvider, which every
10
9
  // upgrade that adds a provider extends; the version this mirrors is the pin, not one named here.
11
10
  export const PINNED_DEFAULT_MODEL_BY_PROVIDER = Object.freeze({
12
- "amazon-bedrock": "us.anthropic.claude-opus-4-6-v1",
11
+ "amazon-bedrock": "us.anthropic.claude-opus-5-5",
13
12
  "ant-ling": "Ring-2.6-1T",
14
- anthropic: "claude-opus-4-8",
13
+ anthropic: "claude-opus-5-5",
15
14
  openai: "gpt-6.1-sol",
16
- azure: "gpt-5.4",
15
+ azure: "gpt-6.1-sol",
17
16
  "openai-codex": "gpt-6.1-sol",
18
17
  radius: "balanced",
19
18
  nvidia: "nvidia/nemotron-3.5-super-vl-120b-a12b",
20
19
  deepseek: "deepseek-v4-pro",
21
- google: "gemini-3.1-pro-preview",
22
- "google-vertex": "gemini-3.1-pro-preview",
20
+ google: "gemini-4-argon",
21
+ "google-vertex": "gemini-4-argon",
23
22
  "github-copilot": "gpt-6.1-sol",
24
- openrouter: "moonshotai/kimi-k2.6",
25
- "vercel-ai-gateway": "zai/glm-5.1",
23
+ openrouter: "moonshotai/kimi-k2.7-code",
24
+ "vercel-ai-gateway": "zai/glm-5.3",
26
25
  xai: "grok-4.7",
27
26
  groq: "openai/gpt-oss-120b",
28
27
  cerebras: "gpt-oss-120b",
29
28
  zai: "glm-5.3",
30
29
  "zai-coding-cn": "glm-5.3",
31
30
  mistral: "devstral-medium-latest",
32
- minimax: "MiniMax-M2.7",
33
- "minimax-cn": "MiniMax-M2.7",
34
- moonshotai: "kimi-k2.6",
35
- "moonshotai-cn": "kimi-k2.6",
36
- huggingface: "moonshotai/Kimi-K2.6",
31
+ minimax: "MiniMax-M3",
32
+ "minimax-cn": "MiniMax-M3",
33
+ moonshotai: "kimi-k2.7-code",
34
+ "moonshotai-cn": "kimi-k2.7-code",
35
+ huggingface: "moonshotai/Kimi-K2.7-Code",
37
36
  fireworks: "accounts/fireworks/models/kimi-k3",
38
37
  together: "moonshotai/Kimi-K3",
39
- baseten: "zai-org/GLM-5.2",
40
- opencode: "kimi-k2.6",
41
- "opencode-go": "kimi-k3",
38
+ baseten: "zai-org/GLM-5.3",
39
+ opencode: "kimi-k2.7-code",
40
+ "opencode-go": "kimi-k3.1-pro",
42
41
  "kimi-coding": "kimi-for-coding",
43
42
  meta: "muse-spark-1.3",
44
- "cloudflare-workers-ai": "@cf/moonshotai/kimi-k2.6",
45
- "cloudflare-ai-gateway": "workers-ai/@cf/moonshotai/kimi-k2.6",
46
- "qwen-token-plan": "qwen3.7-max",
47
- "qwen-token-plan-cn": "qwen3.7-max",
43
+ "cloudflare-workers-ai": "@cf/moonshotai/kimi-k2.7-code",
44
+ "cloudflare-ai-gateway": "workers-ai/@cf/moonshotai/kimi-k2.7-code",
45
+ "qwen-token-plan": "qwen3.8-max",
46
+ "qwen-token-plan-cn": "qwen3.8-max",
48
47
  "qwen-token-plan-individual": "qwen3.8-max",
48
+ "qwen-token-plan-individual-cn": "qwen3.8-max",
49
49
  xiaomi: "mimo-v2.6-pro",
50
50
  "xiaomi-token-plan-cn": "mimo-v2.6-pro",
51
51
  "xiaomi-token-plan-ams": "mimo-v2.6-pro",
@@ -196,14 +196,17 @@ function pinnedCacheWaste(entries, modelRuntime) {
196
196
  }
197
197
  return totals;
198
198
  }
199
- export function defaultWorkflowHost() {
199
+ /** Fill optional host services while retaining class methods and their original receiver. */
200
+ export function resolveWorkflowHost(host) {
200
201
  return {
201
- copyText: copyToClipboard,
202
- async runCommand(command, arguments_, options) {
202
+ copyText: host?.copyText?.bind(host) ?? copyToClipboard,
203
+ runCommand: host?.runCommand?.bind(host) ?? (async (command, arguments_, options) => {
203
204
  const result = await execFileAsync(command, [...arguments_], { encoding: "utf8", signal: options?.signal });
204
205
  return { stdout: result.stdout, stderr: result.stderr };
205
- },
206
- readChangelog: readPinnedCommandChangelog,
206
+ }),
207
+ readChangelog: host?.readChangelog?.bind(host) ?? (async (since) => (await import("./changelog.js")).readPinnedCommandChangelog(since)),
208
+ ...(host?.reserveExport === undefined ? {} : { reserveExport: host.reserveExport.bind(host) }),
209
+ ...(host?.fetch === undefined ? {} : { fetch: host.fetch.bind(host) }),
207
210
  };
208
211
  }
209
212
  export function workflowLoginNotification(event) {
@@ -13,7 +13,7 @@ export type PiWorkflowCommandName = OwnedUiWorkflowCommandName;
13
13
  export type PiHiddenWorkflowCommandName = OwnedUiHiddenWorkflowCommandName;
14
14
  export declare const OWNED_MODELS_COMMAND_NAME: "models";
15
15
  type OwnedModelsCommandName = OwnedUiModelsCommandName;
16
- type OwnedWorkflowCommandName = Exclude<PiWorkflowCommandName, "model" | "scoped-models"> | OwnedModelsCommandName;
16
+ type OwnedWorkflowCommandName = Exclude<PiWorkflowCommandName, "model" | "scoped-models" | "settings" | "changelog" | "hotkeys"> | OwnedModelsCommandName;
17
17
  /** Bare A1's advertised catalog: `models` replaces the pinned pair and is followed by `thinking`. */
18
18
  export declare const OWNED_WORKFLOW_COMMAND_NAMES: readonly OwnedWorkflowCommandName[];
19
19
  export type PiProductMode = OwnedUiSessionProductMode;
@@ -52,6 +52,11 @@ export type PiScopedModelsRefreshResult = OwnedUiScopedModelsRefreshResult;
52
52
  export type PiModelsContext = OwnedUiModelsContext;
53
53
  export type PiModelsRefreshResult = OwnedUiModelsRefreshResult;
54
54
  export interface PiWorkflowHost {
55
+ /** Product-owned persistent storage; integrations never choose the user's home or disposable roots. */
56
+ reserveExport?(sessionId: string, format: "html" | "jsonl"): Promise<{
57
+ readonly path: string;
58
+ failed(): Promise<void>;
59
+ }>;
55
60
  copyText(text: string): Promise<void>;
56
61
  runCommand(command: string, arguments_: readonly string[], options?: {
57
62
  readonly signal?: AbortSignal;
@@ -14,7 +14,7 @@ export const OWNED_MODELS_COMMAND_NAME = OWNED_UI_MODELS_COMMAND_NAME;
14
14
  /** Bare A1's advertised catalog: `models` replaces the pinned pair and is followed by `thinking`. */
15
15
  export const OWNED_WORKFLOW_COMMAND_NAMES = Object.freeze(PINNED_PI_WORKFLOW_COMMAND_NAMES.flatMap((name) => name === "model"
16
16
  ? [OWNED_MODELS_COMMAND_NAME, "thinking"]
17
- : name === "thinking" || name === "scoped-models" ? [] : [name]));
17
+ : name === "thinking" || name === "scoped-models" || name === "settings" || name === "changelog" || name === "hotkeys" ? [] : [name]));
18
18
  /** The advertised command catalog for a product mode; hidden routes are shared by both. */
19
19
  export function workflowCommandNames(productMode) {
20
20
  return productMode === "bare" ? OWNED_WORKFLOW_COMMAND_NAMES : PINNED_PI_WORKFLOW_COMMAND_NAMES;
@@ -1,4 +1,4 @@
1
- import { PI_THEME_SOURCE } from "../components/theme.js";
1
+ import { PI_THEME_SOURCE, paintPiFloatingDialog } from "../components/theme.js";
2
2
  import { piCanvasBackgroundAnsi, PINNED_PI_LAYOUT } from "../components/upstream/theme/theme.js";
3
3
  import { PI_TERMINAL_RUNTIME } from "../tui-runtime/runtime-factory.js";
4
4
  /** Everything the shell takes from Pi's presentation, assembled once from the component and TUI adapters. */
@@ -6,5 +6,6 @@ export const PI_SHELL_PRESENTATION = Object.freeze({
6
6
  theme: PI_THEME_SOURCE,
7
7
  canvasBackground: (style) => piCanvasBackgroundAnsi(style),
8
8
  pinnedOutputPad: PINNED_PI_LAYOUT.outputPad,
9
+ floatingDialogSurface: paintPiFloatingDialog,
9
10
  terminalRuntime: PI_TERMINAL_RUNTIME,
10
11
  });
@@ -1,6 +1,12 @@
1
1
  import { createPiShellModelSelector, createPiShellModelsDialog, createPiShellScopedModelsSelector, createPiShellSessionSelector, createPiShellSettingsSelector, } from "../components/shell-selectors-dialogs.js";
2
2
  import { PI_SHELL_PRESENTATION } from "./presentation.js";
3
3
  import { createPiShellComponents } from "./components.js";
4
+ /** An explicit session scope wins; otherwise use persisted members still present in the catalog. */
5
+ function modelDialogScope(context) {
6
+ const available = new Set(context.models.map(model => `${model.provider}/${model.id}`));
7
+ const savedScopeIds = context.persistedScopeIds.filter(id => available.has(id));
8
+ return { savedScopeIds, scopeIds: context.sessionScopeIds.length > 0 ? context.sessionScopeIds : savedScopeIds };
9
+ }
4
10
  const MODEL_REFRESH_TIMEOUT_MS = 15_000;
5
11
  const MODEL_REFRESH_TIMED_OUT = "Model refresh timed out; showing cached models.";
6
12
  /**
@@ -179,13 +185,10 @@ export function createPiSessionPresenters(adapter, options = {}) {
179
185
  host.requestRender();
180
186
  },
181
187
  /** The bare-A1 unified Models dialog: switch on Enter, scope on Space, persist on Ctrl+S, all through the engine. */
182
- openModelsDialog(host, initialQuery) {
188
+ async openModelsDialog(host, initialQuery) {
183
189
  const catalog = adapter.catalog;
184
190
  const context = catalog.modelsContext();
185
- const available = new Set(context.models.map(model => `${model.provider}/${model.id}`));
186
- const savedScopeIds = context.persistedScopeIds.filter(id => available.has(id));
187
- // Invariant: an explicit session scope wins; otherwise the dialog starts from what is persisted, never from "all rows scoped".
188
- const scopeIds = context.sessionScopeIds.length > 0 ? context.sessionScopeIds : savedScopeIds;
191
+ const { savedScopeIds, scopeIds } = modelDialogScope(context);
189
192
  const refresh = new ModelCatalogRefresh();
190
193
  const close = () => {
191
194
  refresh.stop();
@@ -193,12 +196,11 @@ export function createPiSessionPresenters(adapter, options = {}) {
193
196
  host.requestRender();
194
197
  };
195
198
  const dialog = createPiShellModelsDialog({
196
- models: context.models,
199
+ viewportHeight: () => host.viewport().rows, models: context.models,
197
200
  activeModelId: context.activeModelId,
198
201
  scopeIds,
199
202
  savedScopeIds,
200
203
  ...(initialQuery === undefined ? {} : { initialQuery }),
201
- refreshStatus: "Refreshing model catalogs…",
202
204
  requestRender: () => host.requestRender(),
203
205
  onSelect: modelId => {
204
206
  void host.runWorkflow({ command: "models", argument: "", selection: modelId }).then(result => {
@@ -231,9 +233,7 @@ export function createPiSessionPresenters(adapter, options = {}) {
231
233
  dialog.dispose?.();
232
234
  },
233
235
  };
234
- host.setInputSurface(component);
235
- host.requestRender();
236
- refresh.run(host, component, signal => catalog.refreshModels(signal), refreshed => component.updateModels(refreshed.models));
236
+ await presentModelsSurface(host, component, refresh, catalog);
237
237
  },
238
238
  openScopedModelsSelector(host) {
239
239
  const catalog = adapter.catalog;
@@ -286,6 +286,18 @@ export function createPiSessionPresenters(adapter, options = {}) {
286
286
  },
287
287
  };
288
288
  }
289
+ async function presentModelsSurface(host, component, refresh, catalog) {
290
+ const releasePresentation = host.beginPresentationHold?.();
291
+ try {
292
+ host.setInputSurface(component);
293
+ host.requestRender();
294
+ refresh.run(host, component, signal => catalog.refreshModels(signal), refreshed => component.updateModels(refreshed.models));
295
+ await component.ready;
296
+ }
297
+ finally {
298
+ releasePresentation?.();
299
+ }
300
+ }
289
301
  /**
290
302
  * One model-catalog refresh owned by an open dialog: it aborts after fifteen seconds or when the dialog
291
303
  * closes, and a result that arrives after the dialog closed is dropped.