@timurproko/a1 0.2.4 → 0.2.5-dev.698

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 (116) hide show
  1. package/dist/app/session-shell/prompt-suggestion-controller.d.ts +2 -0
  2. package/dist/app/session-shell/prompt-suggestion-controller.js +10 -0
  3. package/dist/app/session-shell/session-shell-root.d.ts +1 -0
  4. package/dist/app/session-shell/session-shell-root.js +19 -6
  5. package/dist/app/session-shell/session-shell.js +77 -19
  6. package/dist/app/session-shell/share-operation.d.ts +3 -0
  7. package/dist/app/session-shell/share-operation.js +11 -0
  8. package/dist/composition/owned-ui.js +1 -0
  9. package/dist/composition/session-info-reference.d.ts +4 -0
  10. package/dist/composition/session-info-reference.js +20 -0
  11. package/dist/composition/settings-route-host.d.ts +2 -5
  12. package/dist/composition/settings-route-host.js +8 -12
  13. package/dist/contracts/presentation/index.d.ts +5 -0
  14. package/dist/contracts/presentation/index.js +2 -0
  15. package/dist/features/owned-ui/project-trust-dialog.js +7 -5
  16. package/dist/features/owned-ui/reference-screen-app.d.ts +4 -2
  17. package/dist/features/owned-ui/reference-screen-app.js +17 -7
  18. package/dist/features/owned-ui/settings-app.js +10 -5
  19. package/dist/foundation/release/progress-palette.generated.d.ts +2 -2
  20. package/dist/foundation/release/progress-palette.generated.js +2 -2
  21. package/dist/foundation/startup/startup-descriptor.js +2 -2
  22. package/dist/integrations/pi/components/index.d.ts +3 -2
  23. package/dist/integrations/pi/components/index.js +2 -1
  24. package/dist/integrations/pi/components/modal-frame.d.ts +11 -1
  25. package/dist/integrations/pi/components/modal-frame.js +29 -1
  26. package/dist/integrations/pi/components/models-dialog.js +17 -17
  27. package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -2
  28. package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
  29. package/dist/integrations/pi/components/share-operation-dialog.d.ts +6 -0
  30. package/dist/integrations/pi/components/share-operation-dialog.js +40 -0
  31. package/dist/integrations/pi/components/shell-editor-autocomplete.js +15 -6
  32. package/dist/integrations/pi/components/shell-extension-ui.d.ts +3 -0
  33. package/dist/integrations/pi/components/shell-extension-ui.js +8 -4
  34. package/dist/integrations/pi/components/shell-presenters-info.d.ts +2 -0
  35. package/dist/integrations/pi/components/shell-presenters-info.js +1 -1
  36. package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +0 -4
  37. package/dist/integrations/pi/components/shell-selectors-dialogs.js +56 -34
  38. package/dist/integrations/pi/components/shell-session-info-reference.d.ts +10 -0
  39. package/dist/integrations/pi/components/shell-session-info-reference.js +94 -0
  40. package/dist/integrations/pi/components/shell-shared-facade.d.ts +3 -1
  41. package/dist/integrations/pi/components/shell-shared-facade.js +13 -1
  42. package/dist/integrations/pi/components/skills-dialog.js +19 -6
  43. package/dist/integrations/pi/components/theme.d.ts +8 -1
  44. package/dist/integrations/pi/components/theme.js +28 -1
  45. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +15 -7
  46. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +21 -7
  47. package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
  48. package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
  49. package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
  50. package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
  51. package/dist/integrations/pi/components/upstream/components/extension-editor.js +3 -3
  52. package/dist/integrations/pi/components/upstream/components/extension-input.js +5 -6
  53. package/dist/integrations/pi/components/upstream/components/extension-selector.js +3 -4
  54. package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
  55. package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +1 -1
  56. package/dist/integrations/pi/components/upstream/components/owned-editor.js +1 -1
  57. package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
  58. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +4 -3
  59. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +4 -15
  60. package/dist/integrations/pi/components/upstream/components/session-footer.js +1 -1
  61. package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
  62. package/dist/integrations/pi/components/upstream/components/session-selector.d.ts +2 -0
  63. package/dist/integrations/pi/components/upstream/components/session-selector.js +137 -110
  64. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +1 -1
  65. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +1 -1
  66. package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +1 -1
  67. package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
  68. package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
  69. package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
  70. package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +9 -6
  71. package/dist/integrations/pi/components/upstream/components/thinking-selector.js +64 -27
  72. package/dist/integrations/pi/components/upstream/components/tool-execution.js +1 -1
  73. package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +30 -21
  74. package/dist/integrations/pi/components/upstream/components/tree-selector.js +246 -211
  75. package/dist/integrations/pi/components/upstream/components/trust-selector.js +14 -16
  76. package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
  77. package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +1 -1
  78. package/dist/integrations/pi/components/upstream/history/editor-core.js +1 -1
  79. package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
  80. package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
  81. package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
  82. package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
  83. package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
  84. package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
  85. package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
  86. package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
  87. package/dist/integrations/pi/components/upstream/theme/system-theme.d.ts +1 -1
  88. package/dist/integrations/pi/components/upstream/theme/system-theme.js +1 -1
  89. package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
  90. package/dist/integrations/pi/components/upstream/theme/theme.js +1 -1
  91. package/dist/integrations/pi/engine/adapter.js +21 -2
  92. package/dist/integrations/pi/engine/resources/changelog.json +4 -4
  93. package/dist/integrations/pi/engine/workflow-runner.js +2 -1
  94. package/dist/integrations/pi/startup-public.js +186 -81
  95. package/dist/integrations/pi/startup-public.manifest.json +107 -95
  96. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
  97. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +1 -1
  98. package/dist/native/darwin-arm64/manifest.json +1 -1
  99. package/dist/native/linux-x64/manifest.json +1 -1
  100. package/dist/native/win32-x64/manifest.json +2 -2
  101. package/dist/native/win32-x64/process-guardian.exe +0 -0
  102. package/dist/runtime-payload-inventory.json +2717 -2630
  103. package/dist/ui/apps/host.d.ts +4 -3
  104. package/dist/ui/apps/host.js +9 -4
  105. package/dist/ui/components/dialog-panel.js +6 -7
  106. package/dist/ui/components/index.d.ts +1 -1
  107. package/dist/ui/components/index.js +1 -1
  108. package/dist/ui/components/list-view.d.ts +3 -3
  109. package/dist/ui/components/list-view.js +8 -9
  110. package/dist/ui/components/shortcut-hints.d.ts +2 -0
  111. package/dist/ui/components/shortcut-hints.js +17 -1
  112. package/dist/ui/components/theme.d.ts +1 -1
  113. package/docs/assets/readme/separator-dark.svg +2 -4
  114. package/docs/assets/readme/separator.svg +2 -4
  115. package/docs/releases/0.2.4.md +1 -5
  116. package/package.json +3 -3
@@ -0,0 +1,94 @@
1
+ import { sliceByColumn, Text, visibleWidth } from "@earendil-works/pi-tui";
2
+ import { formatCacheWarmingStatus } from "./shell-presenters-info.js";
3
+ import { ensureTheme, formatSessionTokens } from "./shell-shared-facade.js";
4
+ import { piTheme } from "./theme.js";
5
+ /** Splits a plain path by visible columns, preserving every source grapheme in order. */
6
+ function splitSessionFile(sessionFile, firstWidth, continuationWidth) {
7
+ const rows = [];
8
+ let remaining = sessionFile;
9
+ let rowWidth = firstWidth;
10
+ while (remaining) {
11
+ let row = sliceByColumn(remaining, 0, rowWidth, true);
12
+ if (!row && rowWidth !== continuationWidth) {
13
+ rows.push("");
14
+ rowWidth = continuationWidth;
15
+ continue;
16
+ }
17
+ // Compatibility: a one-column frame cannot fit a wide grapheme; preserve it for outer truncation.
18
+ if (!row)
19
+ row = sliceByColumn(remaining, 0, rowWidth);
20
+ rows.push(row);
21
+ remaining = remaining.slice(row.length);
22
+ rowWidth = continuationWidth;
23
+ }
24
+ return rows.length > 0 ? rows : [""];
25
+ }
26
+ /** Keeps the file value on its labelled row before using full continuation rows. */
27
+ function sessionFileRows(sessionFile, width) {
28
+ // Compatibility: match Text's reduced-padding rule so these explicit breaks survive its renderer.
29
+ const paddingX = Math.min(1, Math.max(0, Math.floor((width - 1) / 2)));
30
+ const contentWidth = Math.max(1, width - paddingX * 2);
31
+ const label = piTheme().fg("dim", "File:");
32
+ const firstValueWidth = Math.max(0, contentWidth - visibleWidth("File: "));
33
+ const [first = "", ...continuation] = splitSessionFile(sessionFile, firstValueWidth, contentWidth);
34
+ return firstValueWidth > 0
35
+ ? [`${label} ${first}`, ...continuation]
36
+ : [label, ...continuation];
37
+ }
38
+ /** Renders the pinned report values while leaving group names semantic for the owned screen. */
39
+ export function renderPiShellSessionInfoReferenceDocument(presentation, width) {
40
+ ensureTheme();
41
+ const { stats, sessionName, cacheWaste, usageBreakdown, cacheWarming } = presentation;
42
+ const render = (rows) => new Text(rows.join("\n"), 1, 0).render(width);
43
+ const preamble = [
44
+ ...(sessionName ? [`${piTheme().fg("dim", "Name:")} ${sessionName}`] : []),
45
+ ...sessionFileRows(stats.sessionFile ?? "In-memory", width),
46
+ `${piTheme().fg("dim", "ID:")} ${stats.sessionId}`,
47
+ ];
48
+ const messages = [
49
+ `${piTheme().fg("dim", "Total:")} ${stats.totalMessages}`,
50
+ `${piTheme().fg("dim", "User:")} ${stats.userMessages}`,
51
+ `${piTheme().fg("dim", "Assistant:")} ${stats.assistantMessages}`,
52
+ `${piTheme().fg("dim", "Tools:")} ${stats.toolCalls} calls, ${stats.toolResults} results`,
53
+ ];
54
+ const { input, cacheRead, cacheWrite } = stats.tokens;
55
+ const promptTokens = input + cacheRead + cacheWrite;
56
+ const tokens = [`${piTheme().fg("dim", "Input:")} ${promptTokens.toLocaleString()}`];
57
+ if (promptTokens > 0 && (cacheRead > 0 || cacheWrite > 0)) {
58
+ tokens.push(` ${piTheme().fg("dim", "Cached:")} ${cacheRead.toLocaleString()} ${piTheme().fg("dim", `(${((cacheRead / promptTokens) * 100).toFixed(1)}%)`)}`);
59
+ const written = cacheWrite > 0 ? ` ${piTheme().fg("dim", `(${cacheWrite.toLocaleString()} written to cache)`)}` : "";
60
+ tokens.push(` ${piTheme().fg("dim", "Uncached:")} ${(input + cacheWrite).toLocaleString()}${written}`);
61
+ }
62
+ tokens.push(`${piTheme().fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}`);
63
+ tokens.push(`${piTheme().fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}`);
64
+ const warmingStatus = cacheWarming.status;
65
+ const warming = [
66
+ `${piTheme().fg("dim", "Mode:")} ${cacheWarming.mode}`,
67
+ `${piTheme().fg("dim", "Status:")} ${warmingStatus ? formatCacheWarmingStatus(warmingStatus) : "Inactive (cache warming unavailable)"}`,
68
+ ];
69
+ const warmingDecision = warmingStatus?.decision;
70
+ if (warmingDecision?.economicsAvailable) {
71
+ warming.push(`${piTheme().fg("dim", "Cache miss penalty:")} $${warmingDecision.missCost.toFixed(3)}`);
72
+ warming.push(`${piTheme().fg("dim", "Refresh cost:")} $${warmingDecision.warmCost.toFixed(3)}`);
73
+ }
74
+ const sections = [
75
+ { title: "Messages", rows: render(messages) },
76
+ { title: "Tokens", rows: render(tokens) },
77
+ { title: "Cache Warming", rows: render(warming) },
78
+ ];
79
+ if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
80
+ const cost = [`${piTheme().fg("dim", "Total:")} $${stats.cost.toFixed(3)}`];
81
+ if (usageBreakdown.length > 1)
82
+ for (const entry of usageBreakdown) {
83
+ cost.push(` ${piTheme().fg("dim", `${entry.key}:`)} $${entry.cost.toFixed(3)} ${piTheme().fg("dim", `(${formatSessionTokens(entry.tokens)} tokens)`)}`);
84
+ }
85
+ if (cacheWaste.missedTokens > 0) {
86
+ const detail = `${cacheWaste.missedTokens.toLocaleString()} tokens, ${cacheWaste.missCount === 1 ? "1 miss" : `${cacheWaste.missCount} misses`}`;
87
+ cost.push(cacheWaste.missedCost >= 0.0001
88
+ ? `${piTheme().fg("dim", "Cache Re-billed:")} $${cacheWaste.missedCost.toFixed(3)} ${piTheme().fg("dim", `(${detail})`)}`
89
+ : `${piTheme().fg("dim", "Cache Re-billed:")} ${detail}`);
90
+ }
91
+ sections.push({ title: "Cost", rows: render(cost) });
92
+ }
93
+ return { preamble: render(preamble), sections };
94
+ }
@@ -46,7 +46,7 @@ export interface PiShellEditorPort extends PiShellComponentPort {
46
46
  keybindingConfig(): KeybindingsConfig;
47
47
  reloadKeybindings(): void;
48
48
  /** Uses Pi's terminal decoder rather than assuming one terminal escape spelling. */
49
- matchesTerminalKey(data: string, key: "home" | "end" | "ctrl+home" | "ctrl+end" | "alt+home" | "ctrl+v"): boolean;
49
+ matchesTerminalKey(data: string, key: "home" | "end" | "pageUp" | "pageDown" | "ctrl+home" | "ctrl+end" | "alt+home" | "ctrl+v"): boolean;
50
50
  getText(): string;
51
51
  setText(text: string): void;
52
52
  insertText(text: string): void;
@@ -227,6 +227,8 @@ export declare function createTuiFacade(options: Pick<PiShellEditorOptions, "get
227
227
  readonly onSubmit?: (text: string) => void;
228
228
  }): TUI;
229
229
  export declare function componentPort(component: Component, handleInput?: (data: string) => void): PiShellComponentPort;
230
+ /** Gives an extension-hosted dialog the shell's implicit close alias without rewriting its component. */
231
+ export declare function withPiDialogCancel(port: PiShellComponentPort, onCancel: () => void): PiShellComponentPort;
230
232
  export declare function componentFromPort(port: PiShellComponentPort): Component;
231
233
  export declare function formatSessionTokens(count: number): string;
232
234
  export declare function isAutocompleteProvider(value: unknown): value is AutocompleteProvider;
@@ -1,4 +1,4 @@
1
- import { hyperlink, setKeybindings, visibleWidth, truncateToWidth, } from "@earendil-works/pi-tui";
1
+ import { hyperlink, matchesKey, setKeybindings, visibleWidth, truncateToWidth, } from "@earendil-works/pi-tui";
2
2
  import { KeybindingsManager, } from "./upstream/adjacent/core/keybindings.js";
3
3
  import { ensurePiTheme, } from "./theme.js";
4
4
  /** Terminal-cell width authority used by Pi-rendered component rows. */
@@ -61,6 +61,18 @@ export function componentPort(component, handleInput) {
61
61
  ...(typeof disposable.dispose === "function" ? { dispose: () => disposable.dispose?.() } : {}),
62
62
  };
63
63
  }
64
+ /** Gives an extension-hosted dialog the shell's implicit close alias without rewriting its component. */
65
+ export function withPiDialogCancel(port, onCancel) {
66
+ return {
67
+ ...port,
68
+ handleInput: data => {
69
+ if (matchesKey(data, "ctrl+c"))
70
+ onCancel();
71
+ else
72
+ port.handleInput?.(data);
73
+ },
74
+ };
75
+ }
64
76
  export function componentFromPort(port) {
65
77
  return {
66
78
  render: width => [...port.render(width)],
@@ -1,9 +1,9 @@
1
1
  import { DynamicBorder } from "../startup-public.js";
2
2
  import { Container, getKeybindings, Input, Spacer, Text } from "@earendil-works/pi-tui";
3
3
  import { addPiModalHeader, adoptPiModalFrame } from "./modal-frame.js";
4
- import { PINNED_PI_LAYOUT, piTheme, renderPiModalShortcutHints } from "./theme.js";
4
+ import { DIALOG_CLOSE_SHORTCUT_HINT, PINNED_PI_LAYOUT, piTheme, renderPiModalListRow, renderPiModalShortcutHints, } from "./theme.js";
5
5
  import { componentPort, ensureTheme, piShellTruncateToWidth, piShellVisibleWidth } from "./shell-shared-facade.js";
6
- import { SKILL_COMMAND_PREFIX, skillMatchesQuery } from "./skills-command.js";
6
+ import { skillMatchesQuery } from "./skills-command.js";
7
7
  /** A single line clipped at the viewport width: no wrap, no ellipsis, padded to the full width. */
8
8
  class ClippedLine {
9
9
  #text;
@@ -14,10 +14,22 @@ class ClippedLine {
14
14
  return [line + " ".repeat(Math.max(0, width - piShellVisibleWidth(line)))];
15
15
  }
16
16
  }
17
+ class SkillRow {
18
+ #content;
19
+ #selected;
20
+ constructor(content, selected) {
21
+ this.#content = content;
22
+ this.#selected = selected;
23
+ }
24
+ invalidate() { }
25
+ render(width) {
26
+ return [renderPiModalListRow(this.#content, width, this.#selected)];
27
+ }
28
+ }
17
29
  /**
18
30
  * The A1-owned searchable Skills dialog. Its composition is the model selector's (border, spacer,
19
31
  * search input, spacer, list, spacer, hint footer, border) built from public pi-tui components; its
20
- * content follows the v2 skills extension: an accent bold title, `skill:<name>` rows, the selected
32
+ * content follows the v2 skills extension: an accent bold title, bare skill-name rows, the selected
21
33
  * skill's description cut to one line under the rows, the pinned scroll counter on overflow,
22
34
  * and the two empty states. Enter applies the selected skill with no arguments; the query is never appended.
23
35
  */
@@ -47,7 +59,7 @@ class SkillsSelectorComponent extends Container {
47
59
  this.addChild(new Text(renderPiModalShortcutHints([
48
60
  { key: "↑↓", action: "navigate" },
49
61
  { key: bindings.getKeys("tui.select.confirm").join("/"), action: "select" },
50
- { key: bindings.getKeys("tui.select.cancel").join("/"), action: "cancel" },
62
+ DIALOG_CLOSE_SHORTCUT_HINT,
51
63
  ]), 0, 0));
52
64
  this.addChild(new DynamicBorder());
53
65
  adoptPiModalFrame(this, { topIndex: 0, bottomIndex: this.children.length - 1, header });
@@ -108,8 +120,9 @@ class SkillsSelectorComponent extends Container {
108
120
  for (let index = start; index < end; index++) {
109
121
  const skill = this.#filtered[index];
110
122
  const selected = index === this.#selectedIndex;
111
- const label = `${SKILL_COMMAND_PREFIX}${skill.name}`;
112
- this.#listContainer.addChild(new Text(`${selected ? theme.fg("accent", "→ ") : " "}${selected ? theme.fg("accent", label) : label}`, 0, 0));
123
+ const label = skill.name;
124
+ const content = `${selected ? theme.fg("accent", "→ ") : " "}${selected ? theme.fg("text", label) : label}`;
125
+ this.#listContainer.addChild(new SkillRow(content, selected));
113
126
  }
114
127
  if (start > 0 || end < this.#filtered.length) {
115
128
  this.#listContainer.addChild(new Text(theme.fg("muted", ` (${this.#selectedIndex + 1}/${this.#filtered.length})`), 0, 0));
@@ -1,5 +1,12 @@
1
- import { type SemanticShortcutHint } from "../../../contracts/presentation/index.js";
1
+ import { DIALOG_CLOSE_SHORTCUT_HINT, displayShortcutKeyLabel, type SemanticShortcutHint } from "../../../contracts/presentation/index.js";
2
2
  export * from "./upstream/theme/theme.js";
3
3
  export type PiModalShortcutHint = SemanticShortcutHint;
4
+ export { DIALOG_CLOSE_SHORTCUT_HINT, displayShortcutKeyLabel };
5
+ /** Paint one selected bare-A1 list item with the standard blue selection surface. */
6
+ export declare function renderPiListSelection(content: string): string;
7
+ /** One standard bare-A1 modal row, clipped before its item-bounded selection is painted. */
8
+ export declare function renderPiModalListRow(content: string, width: number, selected: boolean): string;
4
9
  /** The common bare-A1 modal footer: quiet display-cased keys, muted names, and whitespace-only gaps. */
5
10
  export declare function renderPiModalShortcutHints(entries: readonly PiModalShortcutHint[], indent?: number): string;
11
+ /** Adapts Pi's closed settings footer while reserving the canonical close suffix. */
12
+ export declare function canonicalizePiSettingsHint(row: string, width: number): string;
@@ -1,6 +1,17 @@
1
- import { renderSemanticShortcutHints, } from "../../../contracts/presentation/index.js";
1
+ import { DIALOG_CLOSE_SHORTCUT_HINT, displayShortcutKeyLabel, renderSemanticShortcutHints, } from "../../../contracts/presentation/index.js";
2
+ import { stripTerminalSequences, truncateToWidth } from "@earendil-works/pi-tui";
2
3
  import { piTheme } from "./upstream/theme/theme.js";
3
4
  export * from "./upstream/theme/theme.js";
5
+ export { DIALOG_CLOSE_SHORTCUT_HINT, displayShortcutKeyLabel };
6
+ /** Paint one selected bare-A1 list item with the standard blue selection surface. */
7
+ export function renderPiListSelection(content) {
8
+ return piTheme().bg("selectedBg", content);
9
+ }
10
+ /** One standard bare-A1 modal row, clipped before its item-bounded selection is painted. */
11
+ export function renderPiModalListRow(content, width, selected) {
12
+ const clipped = truncateToWidth(content, Math.max(0, width), "");
13
+ return selected ? renderPiListSelection(clipped) : clipped;
14
+ }
4
15
  /** The common bare-A1 modal footer: quiet display-cased keys, muted names, and whitespace-only gaps. */
5
16
  export function renderPiModalShortcutHints(entries, indent = 0) {
6
17
  const theme = piTheme();
@@ -9,3 +20,19 @@ export function renderPiModalShortcutHints(entries, indent = 0) {
9
20
  action: text => theme.fg("muted", text),
10
21
  }, indent);
11
22
  }
23
+ /** Adapts Pi's closed settings footer while reserving the canonical close suffix. */
24
+ export function canonicalizePiSettingsHint(row, width) {
25
+ const plain = stripTerminalSequences(row);
26
+ const body = plain.includes("Type to search") ? " Type to search · Enter/Space to change"
27
+ : plain.includes("Enter/Space to change") ? " Enter/Space to change"
28
+ : plain.includes("Type to filter") ? " Type to filter · Enter to select"
29
+ : plain.includes("Enter to select") && plain.includes("Esc") ? " Enter to select"
30
+ : /^\s*(?:Type to|Enter(?:\/Space)? to)/u.test(plain) ? plain.replace(/\.{3}$/u, "") : null;
31
+ if (body === null)
32
+ return row;
33
+ const close = `${displayShortcutKeyLabel(DIALOG_CLOSE_SHORTCUT_HINT.key)} ${DIALOG_CLOSE_SHORTCUT_HINT.action}`;
34
+ if (width <= close.length)
35
+ return piTheme().fg("dim", truncateToWidth(close, width, ""));
36
+ const bodyWidth = width - close.length - 3;
37
+ return piTheme().fg("dim", bodyWidth <= 0 ? close : `${truncateToWidth(body, bodyWidth, "…")} · ${close}`);
38
+ }
@@ -1,11 +1,13 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/core/keybindings.ts.
4
4
  * Modifications: Mechanical source port with Node import prefixes, public package-root agent-directory
5
5
  * resolution, and an opt-in bare-A1 input profile including Ctrl+L level cycling, unbound model
6
- * selection, and cross-platform Alt+Up queued-message restoration.
6
+ * selection, Tab tree-filter cycling, tree-local navigation aliases, cross-platform Alt+Up
7
+ * queued-message restoration, and an implicit Ctrl+C selection-cancel alias omitted from shortcut
8
+ * labels.
7
9
  * Deviations: keybindings-public-config-boundary, owned-level-cycle-shortcut,
8
- * owned-input-keybinding-aliases.
10
+ * owned-input-keybinding-aliases, owned-session-tree-dialog, owned-dialog-ctrl-c-cancel.
9
11
  */
10
12
  import { type Keybinding, type KeybindingDefinitions, type KeybindingsConfig, type KeyId, KeybindingsManager as TuiKeybindingsManager } from "@earendil-works/pi-tui";
11
13
  export interface AppKeybindings {
@@ -58,6 +60,10 @@ export interface AppKeybindings {
58
60
  "owned.editor.redo": true;
59
61
  "owned.editor.extendLeft": true;
60
62
  "owned.editor.extendRight": true;
63
+ "owned.tree.collapse": true;
64
+ "owned.tree.expand": true;
65
+ "owned.tree.first": true;
66
+ "owned.tree.last": true;
61
67
  }
62
68
  export type AppKeybinding = keyof AppKeybindings;
63
69
  export declare function useWindowsKeybindings(platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): boolean;
@@ -287,11 +293,11 @@ export declare const KEYBINDINGS: {
287
293
  readonly description: "Move cursor word right";
288
294
  };
289
295
  readonly "tui.editor.cursorLineStart": {
290
- readonly defaultKeys: ["home", "ctrl+home", "ctrl+a"];
296
+ readonly defaultKeys: ["home", "ctrl+a"];
291
297
  readonly description: "Move to line start";
292
298
  };
293
299
  readonly "tui.editor.cursorLineEnd": {
294
- readonly defaultKeys: ["end", "ctrl+end", "ctrl+e"];
300
+ readonly defaultKeys: ["end", "ctrl+e"];
295
301
  readonly description: "Move to line end";
296
302
  };
297
303
  readonly "tui.editor.jumpForward": {
@@ -419,11 +425,11 @@ export declare const KEYBINDINGS: {
419
425
  readonly description: "Close transcript search";
420
426
  };
421
427
  readonly "tui.altScreen.top": {
422
- readonly defaultKeys: "home";
428
+ readonly defaultKeys: "ctrl+home";
423
429
  readonly description: "Scroll viewport to top";
424
430
  };
425
431
  readonly "tui.altScreen.bottom": {
426
- readonly defaultKeys: "end";
432
+ readonly defaultKeys: "ctrl+end";
427
433
  readonly description: "Scroll viewport to bottom";
428
434
  };
429
435
  };
@@ -437,6 +443,8 @@ export declare class KeybindingsManager extends TuiKeybindingsManager {
437
443
  static create(agentDir?: string): KeybindingsManager;
438
444
  static fromOwnedBindings(bindings?: KeybindingsConfig): KeybindingsManager;
439
445
  static createForOwnedInput(agentDir?: string): KeybindingsManager;
446
+ matches(data: string, keybinding: Keybinding): boolean;
447
+ getKeys(keybinding: Keybinding): KeyId[];
440
448
  private static createWithDefinitions;
441
449
  reload(): void;
442
450
  getEffectiveConfig(): KeybindingsConfig;
@@ -1,13 +1,15 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/core/keybindings.ts.
4
4
  * Modifications: Mechanical source port with Node import prefixes, public package-root agent-directory
5
5
  * resolution, and an opt-in bare-A1 input profile including Ctrl+L level cycling, unbound model
6
- * selection, and cross-platform Alt+Up queued-message restoration.
6
+ * selection, Tab tree-filter cycling, tree-local navigation aliases, cross-platform Alt+Up
7
+ * queued-message restoration, and an implicit Ctrl+C selection-cancel alias omitted from shortcut
8
+ * labels.
7
9
  * Deviations: keybindings-public-config-boundary, owned-level-cycle-shortcut,
8
- * owned-input-keybinding-aliases.
10
+ * owned-input-keybinding-aliases, owned-session-tree-dialog, owned-dialog-ctrl-c-cancel.
9
11
  */
10
- import { TUI_KEYBINDINGS, KeybindingsManager as TuiKeybindingsManager, } from "@earendil-works/pi-tui";
12
+ import { matchesKey, TUI_KEYBINDINGS, KeybindingsManager as TuiKeybindingsManager, } from "@earendil-works/pi-tui";
11
13
  import { existsSync, readFileSync } from "node:fs";
12
14
  import { join } from "node:path";
13
15
  import { getAgentDir } from "../../../../startup-public.js";
@@ -185,6 +187,7 @@ const OWNED_INPUT_KEYBINDINGS = {
185
187
  "app.thinking.cycle": { ...KEYBINDINGS["app.thinking.cycle"], defaultKeys: "ctrl+l" },
186
188
  "app.model.select": { ...KEYBINDINGS["app.model.select"], defaultKeys: [] },
187
189
  "app.message.dequeue": { ...KEYBINDINGS["app.message.dequeue"], defaultKeys: "alt+up" },
190
+ "app.tree.filter.cycleForward": { ...KEYBINDINGS["app.tree.filter.cycleForward"], defaultKeys: "tab" },
188
191
  "tui.editor.deleteWordBackward": {
189
192
  ...KEYBINDINGS["tui.editor.deleteWordBackward"],
190
193
  defaultKeys: [...KEYBINDINGS["tui.editor.deleteWordBackward"].defaultKeys, "ctrl+backspace"],
@@ -199,15 +202,17 @@ const OWNED_INPUT_KEYBINDINGS = {
199
202
  },
200
203
  // Ctrl+Z edits the prompt in bare A1 instead of suspending the process.
201
204
  "app.suspend": { ...KEYBINDINGS["app.suspend"], defaultKeys: [] },
202
- // Owned prompt-selection actions are intercepted before vanilla Pi editor
203
- // actions. Keeping them in the keybinding manager makes the UX declarative,
204
- // configurable, and independent of terminal escape-sequence spellings.
205
+ // Owned prompt-selection actions remain declarative and take priority.
205
206
  "owned.editor.selectAll": { defaultKeys: "ctrl+a", description: "Select all prompt text" },
206
207
  "owned.editor.cut": { defaultKeys: "ctrl+x", description: "Cut selected prompt text" },
207
208
  "owned.editor.paste": { defaultKeys: "ctrl+v", description: "Paste clipboard text" },
208
209
  "owned.editor.redo": { defaultKeys: "ctrl+y", description: "Redo prompt edit" },
209
210
  "owned.editor.extendLeft": { defaultKeys: "shift+left", description: "Extend prompt selection left" },
210
211
  "owned.editor.extendRight": { defaultKeys: "shift+right", description: "Extend prompt selection right" },
212
+ "owned.tree.collapse": { defaultKeys: "left", description: "Collapse selected tree branch" },
213
+ "owned.tree.expand": { defaultKeys: "right", description: "Expand selected tree branch" },
214
+ "owned.tree.first": { defaultKeys: "home", description: "Select first tree entry" },
215
+ "owned.tree.last": { defaultKeys: "end", description: "Select last tree entry" },
211
216
  };
212
217
  const KEYBINDING_NAME_MIGRATIONS = {
213
218
  cursorUp: "tui.editor.cursorUp",
@@ -349,6 +354,15 @@ export class KeybindingsManager extends TuiKeybindingsManager {
349
354
  static createForOwnedInput(agentDir = getAgentDir()) {
350
355
  return KeybindingsManager.createWithDefinitions(agentDir, OWNED_INPUT_KEYBINDINGS);
351
356
  }
357
+ // Protocol: Ctrl+C is a conventional dialog escape hatch, not advertised keybinding chrome.
358
+ matches(data, keybinding) {
359
+ return keybinding === "tui.select.cancel" && matchesKey(data, "ctrl+c")
360
+ || super.matches(data, keybinding);
361
+ }
362
+ getKeys(keybinding) {
363
+ const keys = super.getKeys(keybinding);
364
+ return keybinding === "tui.select.cancel" ? keys.filter(key => key !== "ctrl+c") : keys;
365
+ }
352
366
  static createWithDefinitions(agentDir, definitions) {
353
367
  const configPath = join(agentDir, "keybindings.json");
354
368
  const userBindings = KeybindingsManager.loadFromFile(configPath);
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "sourcePackage": "@earendil-works/pi-coding-agent",
3
- "sourceVersion": "1.0.2",
3
+ "sourceVersion": "1.0.4",
4
4
  "upstreamRepository": "https://github.com/earendil-works/pi.git",
5
- "upstreamCommit": "cd32f7725fdbddbaecdff5b1e68491563394e0ca",
5
+ "upstreamCommit": "7c10bd4337495ee613f2224843ecdf349b80d1df",
6
6
  "sourcePath": "dist/modes/interactive/assets/clankolas.png",
7
7
  "sourceSha256": "169acd0dfe6fbb8d8742ed24a3fc654fd0b2e2d4223c733249c5493723f1b72d",
8
8
  "license": "MIT",
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/countdown-timer.ts.
4
4
  * Modifications: Mechanical source port with ECMAScript private fields; imports remain on the public
5
5
  * Pi TUI package root.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/earendil-announcement.ts.
4
4
  * Modifications: Mechanical pinned source port with private imports remapped to public package-root
5
5
  * types/APIs and A1-owned theme boundaries. The unchanged image is loaded lazily from its attributed,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/extension-editor.ts.
4
4
  * Modifications: Mechanical port: remap pi-tui to the root public singleton, use owned
5
5
  * keybindings/theme and external-editor seams, preserve editor layout, hints, focus, submission,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/extension-editor.ts.
4
4
  * Modifications: Mechanical port: remap pi-tui to the root public singleton, use owned
5
5
  * keybindings/theme and external-editor seams, preserve editor layout, hints, focus, submission,
@@ -11,7 +11,7 @@ import { Container, Editor, Spacer, Text, } from "@earendil-works/pi-tui";
11
11
  import { DynamicBorder, getSelectListTheme } from "../../../startup-public.js";
12
12
  import { editInExternalEditor } from "../external-editor.js";
13
13
  import { addPiModalHeader, adoptPiModalFrame } from "../../modal-frame.js";
14
- import { piTheme, renderPiModalShortcutHints } from "../../theme.js";
14
+ import { DIALOG_CLOSE_SHORTCUT_HINT, piTheme, renderPiModalShortcutHints } from "../../theme.js";
15
15
  export class ExtensionEditorComponent extends Container {
16
16
  #editor;
17
17
  #tui;
@@ -54,8 +54,8 @@ export class ExtensionEditorComponent extends Container {
54
54
  const hint = renderPiModalShortcutHints([
55
55
  { key: this.#keybindings.getKeys("tui.select.confirm").join("/"), action: "submit" },
56
56
  { key: this.#keybindings.getKeys("tui.input.newLine").join("/"), action: "newline" },
57
- { key: this.#keybindings.getKeys("tui.select.cancel").join("/"), action: "cancel" },
58
57
  { key: this.#keybindings.getKeys("app.editor.external").join("/"), action: "external editor" },
58
+ DIALOG_CLOSE_SHORTCUT_HINT,
59
59
  ]);
60
60
  this.addChild(new Text(hint, 0, 0));
61
61
  this.addChild(new Spacer(1));
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/extension-input.ts.
4
4
  * Modifications: Mechanical port: remap public imports, use ECMAScript private fields, and route the
5
5
  * bare-A1 instruction row and chrome through the shared semantic shortcut and compact padded
@@ -10,7 +10,7 @@
10
10
  import { DynamicBorder } from "../../../startup-public.js";
11
11
  import { Container, getKeybindings, Input, Spacer, Text } from "@earendil-works/pi-tui";
12
12
  import { addPiModalHeader, adoptPiModalFrame } from "../../modal-frame.js";
13
- import { piTheme, renderPiModalShortcutHints } from "../../theme.js";
13
+ import { DIALOG_CLOSE_SHORTCUT_HINT, piTheme, renderPiModalShortcutHints } from "../../theme.js";
14
14
  import { CountdownTimer } from "./countdown-timer.js";
15
15
  /** Bare-A1 extension text input using the common modal shortcut row. */
16
16
  export class ExtensionInputComponent extends Container {
@@ -32,7 +32,7 @@ export class ExtensionInputComponent extends Container {
32
32
  this.#onCancel = onCancel;
33
33
  this.#baseTitle = title;
34
34
  const theme = piTheme();
35
- this.#titleText = new Text(theme.fg("accent", title), 0, 0);
35
+ this.#titleText = new Text(theme.fg("accent", theme.bold(title)), 0, 0);
36
36
  const header = addPiModalHeader(this, new DynamicBorder(), this.#titleText);
37
37
  if (opts?.description) {
38
38
  this.addChild(new Spacer(1));
@@ -42,7 +42,7 @@ export class ExtensionInputComponent extends Container {
42
42
  this.#countdown = opts?.timeout !== undefined && opts.timeout > 0 && opts.tui !== undefined
43
43
  ? new CountdownTimer(opts.timeout, opts.tui, seconds => {
44
44
  const current = piTheme();
45
- this.#titleText.setText(current.fg("accent", `${this.#baseTitle} (${seconds}s)`));
45
+ this.#titleText.setText(current.fg("accent", current.bold(`${this.#baseTitle} (${seconds}s)`)));
46
46
  }, () => this.#onCancel())
47
47
  : undefined;
48
48
  if (opts?.initialValue !== undefined)
@@ -52,9 +52,8 @@ export class ExtensionInputComponent extends Container {
52
52
  const keys = getKeybindings();
53
53
  this.addChild(new Text(renderPiModalShortcutHints([
54
54
  { key: keys.getKeys("tui.select.confirm").join("/"), action: "submit" },
55
- { key: keys.getKeys("tui.select.cancel").join("/"), action: "cancel" },
55
+ DIALOG_CLOSE_SHORTCUT_HINT,
56
56
  ]), 0, 0));
57
- this.addChild(new Spacer(1));
58
57
  this.addChild(new DynamicBorder());
59
58
  adoptPiModalFrame(this, { topIndex: 0, bottomIndex: this.children.length - 1, header });
60
59
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/extension-selector.ts.
4
4
  * Modifications: Mechanical port: remap public imports, use ECMAScript private fields, and route the
5
5
  * bare-A1 instruction row and chrome through the shared semantic shortcut and compact padded
@@ -10,7 +10,7 @@
10
10
  import { DynamicBorder } from "../../../startup-public.js";
11
11
  import { Container, getKeybindings, Spacer, Text } from "@earendil-works/pi-tui";
12
12
  import { addPiModalHeader, adoptPiModalFrame } from "../../modal-frame.js";
13
- import { piTheme, renderPiModalShortcutHints } from "../../theme.js";
13
+ import { DIALOG_CLOSE_SHORTCUT_HINT, piTheme, renderPiModalShortcutHints } from "../../theme.js";
14
14
  import { CountdownTimer } from "./countdown-timer.js";
15
15
  /** Bare-A1 extension selector using the common modal shortcut row. */
16
16
  export class ExtensionSelectorComponent extends Container {
@@ -50,9 +50,8 @@ export class ExtensionSelectorComponent extends Container {
50
50
  this.addChild(new Text(renderPiModalShortcutHints([
51
51
  { key: "↑↓", action: "navigate" },
52
52
  { key: keys.getKeys("tui.select.confirm").join("/"), action: "select" },
53
- { key: keys.getKeys("tui.select.cancel").join("/"), action: "cancel" },
53
+ DIALOG_CLOSE_SHORTCUT_HINT,
54
54
  ]), 0, 0));
55
- this.addChild(new Spacer(1));
56
55
  this.addChild(new DynamicBorder());
57
56
  adoptPiModalFrame(this, { topIndex: 0, bottomIndex: this.children.length - 1, header });
58
57
  this.#updateList();
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/mermaid.ts.
4
4
  * Modifications: Mechanical pinned source port with private imports remapped to public package-root
5
5
  * types/APIs and A1-owned theme boundaries; behavior remains acceptance-tested.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/custom-editor.ts.
4
4
  * Modifications: A1-owned class name and synchronized A1 keybinding contract replace the nominal
5
5
  * private upstream keybinding constructor dependency; bare A1 injects the shared Settings/agent input
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/custom-editor.ts.
4
4
  * Modifications: A1-owned class name and synchronized A1 keybinding contract replace the nominal
5
5
  * private upstream keybinding constructor dependency; bare A1 injects the shared Settings/agent input
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/pi-logo.ts.
4
4
  * Modifications: Remapped the private theme import to A1's public-backed adapter and composed the
5
5
  * fixed-color logo into the owned startup header.
@@ -1,12 +1,13 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/scoped-models-selector.ts.
4
4
  * Modifications: Source-synchronized scoped-model selector port: preserve session-only toggles,
5
5
  * search, bulk/provider/reorder actions, dirty state, Ctrl+S persistence, refresh status,
6
6
  * cancellation, and focus while remapping theme and public helper imports; local key labels preserve
7
7
  * pinned platform formatting before layout without changing binding identities, and bare A1 uses the
8
- * shared semantic modal shortcut row and compact padded modal frame.
9
- * Deviations: owned-modal-shortcut-hints.
8
+ * shared semantic modal shortcut row and compact padded modal frame while immediately closing on the
9
+ * implicit Ctrl+C selection-cancel alias without advertising it.
10
+ * Deviations: owned-modal-shortcut-hints, owned-dialog-ctrl-c-cancel.
10
11
  */
11
12
  interface ScopedModel {
12
13
  readonly provider: string;
@@ -1,8 +1,8 @@
1
- import { Container, fuzzyFilter, getKeybindings, Input, Key, matchesKey, Spacer, Text, } from "@earendil-works/pi-tui";
1
+ import { Container, fuzzyFilter, getKeybindings, Input, Spacer, Text, } from "@earendil-works/pi-tui";
2
2
  import { DynamicBorder } from "../../../startup-public.js";
3
3
  import { getModelSearchText } from "../model-search.js";
4
4
  import { addPiModalHeader, adoptPiModalFrame } from "../../modal-frame.js";
5
- import { piTheme, renderPiModalShortcutHints } from "../../theme.js";
5
+ import { DIALOG_CLOSE_SHORTCUT_HINT, piTheme, renderPiModalShortcutHints } from "../../theme.js";
6
6
  // Rationale: upstream's capitalized hint formatter is private to the package; the same mapping lives here.
7
7
  function keyDisplayText(keybinding) {
8
8
  return getKeybindings().getKeys(keybinding)
@@ -179,6 +179,7 @@ export class ScopedModelsSelectorComponent extends Container {
179
179
  { key: reorderKeys, action: "reorder" },
180
180
  { key: keyDisplayText("app.models.save"), action: "save" },
181
181
  { action: countText },
182
+ DIALOG_CLOSE_SHORTCUT_HINT,
182
183
  ]);
183
184
  return this.isDirty ? `${hint} ${theme.fg("warning", "(unsaved)")}` : hint;
184
185
  }
@@ -321,19 +322,7 @@ export class ScopedModelsSelectorComponent extends Container {
321
322
  this.footerText.setText(this.getFooterText());
322
323
  return;
323
324
  }
324
- // Ctrl+C - clear search or cancel if empty
325
- if (matchesKey(data, Key.ctrl("c"))) {
326
- if (this.searchInput.getValue()) {
327
- this.searchInput.setValue("");
328
- this.refresh();
329
- }
330
- else {
331
- this.callbacks.onCancel();
332
- }
333
- return;
334
- }
335
- // Escape - cancel
336
- if (matchesKey(data, Key.escape)) {
325
+ if (kb.matches(data, "tui.select.cancel")) {
337
326
  this.callbacks.onCancel();
338
327
  return;
339
328
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/footer.ts.
4
4
  * Modifications: Consumes neutral owned-UI view data instead of a fabricated concrete AgentSession;
5
5
  * preserves the latest physical route for virtual models; an explicit bare-A1 profile colors the
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Provenance: @earendil-works/pi-coding-agent 1.0.2 (MIT), commit cd32f7725fdbddbaecdff5b1e68491563394e0ca,
2
+ * Provenance: @earendil-works/pi-coding-agent 1.0.4 (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df,
3
3
  * packages/coding-agent/src/modes/interactive/components/session-selector-search.ts.
4
4
  * Modifications: Source-synchronized session search port with only the public SessionInfo type import
5
5
  * remapped.