@timurproko/a1 0.1.8-dev.407 → 0.1.8-dev.436

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 (102) hide show
  1. package/bin/cli.js +14 -9
  2. package/bin/guardian.js +3 -3
  3. package/bin/module-identity.js +21 -3
  4. package/bin/pinned-pi-public.d.ts +3 -0
  5. package/bin/pinned-pi-public.js +74 -0
  6. package/bin/ui.js +17 -18
  7. package/bin/warmup.js +8 -10
  8. package/dist/composition/owned-ui.d.ts +5 -3
  9. package/dist/composition/owned-ui.js +17 -10
  10. package/dist/composition/settings-route-host.d.ts +4 -5
  11. package/dist/composition/settings-route-host.js +90 -55
  12. package/dist/features/launch/intent.d.ts +5 -3
  13. package/dist/features/launch/intent.js +2 -2
  14. package/dist/features/launch/profile-paths.js +1 -1
  15. package/dist/features/launch/runtime-selection.d.ts +1 -1
  16. package/dist/features/launch/runtime-selection.js +1 -1
  17. package/dist/features/owned-ui/run.d.ts +6 -0
  18. package/dist/features/owned-ui/run.js +34 -2
  19. package/dist/features/owned-ui/settings-app.d.ts +1 -3
  20. package/dist/features/owned-ui/settings-app.js +2 -2
  21. package/dist/features/owned-ui/settings-route.d.ts +2 -0
  22. package/dist/features/owned-ui/settings-route.js +2 -0
  23. package/dist/foundation/release/update.js +5 -3
  24. package/dist/foundation/startup/startup-descriptor.js +34 -0
  25. package/dist/foundation/startup/startup-runtime.d.ts +10 -0
  26. package/dist/foundation/startup/startup-runtime.js +11 -3
  27. package/dist/foundation/terminal-cleanup/fatal-exit.js +4 -2
  28. package/dist/integrations/pi/components/components.js +1 -1
  29. package/dist/integrations/pi/components/owned-editor-ux.d.ts +1 -1
  30. package/dist/integrations/pi/components/owned-editor-ux.js +6 -2
  31. package/dist/integrations/pi/components/shell-editor-autocomplete.js +2 -2
  32. package/dist/integrations/pi/components/shell-extension-ui.d.ts +1 -1
  33. package/dist/integrations/pi/components/shell-extension-ui.js +1 -1
  34. package/dist/integrations/pi/components/shell-footer-status.js +1 -1
  35. package/dist/integrations/pi/components/shell-presenters-info.js +1 -1
  36. package/dist/integrations/pi/components/shell-presenters-transcript.d.ts +2 -2
  37. package/dist/integrations/pi/components/shell-presenters-transcript.js +2 -2
  38. package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +1 -1
  39. package/dist/integrations/pi/components/shell-selectors-dialogs.js +1 -1
  40. package/dist/integrations/pi/components/shell-shared-facade.d.ts +1 -1
  41. package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +2 -0
  42. package/dist/integrations/pi/components/submitted-prompt-adapter.js +8 -2
  43. package/dist/integrations/pi/components/tool-image-presentation.d.ts +1 -1
  44. package/dist/integrations/pi/components/tool-image-presentation.js +1 -1
  45. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +1 -1
  46. package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
  47. package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
  48. package/dist/integrations/pi/components/upstream/components/first-time-setup.js +1 -1
  49. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +1 -1
  50. package/dist/integrations/pi/components/upstream/components/session-selector.js +1 -1
  51. package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
  52. package/dist/integrations/pi/components/upstream/components/tool-execution.js +1 -1
  53. package/dist/integrations/pi/components/upstream/components/tree-selector.js +1 -1
  54. package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
  55. package/dist/integrations/pi/components/upstream/theme/theme.js +1 -1
  56. package/dist/integrations/pi/engine/adapter.d.ts +1 -1
  57. package/dist/integrations/pi/engine/adapter.js +1 -1
  58. package/dist/integrations/pi/engine/model-auth-integration.d.ts +1 -1
  59. package/dist/integrations/pi/engine/package-integration.js +1 -1
  60. package/dist/integrations/pi/engine/project-trust-preflight.js +1 -1
  61. package/dist/integrations/pi/engine/resource-extension-integration.d.ts +1 -1
  62. package/dist/integrations/pi/engine/runtime-integration.d.ts +1 -1
  63. package/dist/integrations/pi/engine/runtime-integration.js +2 -2
  64. package/dist/integrations/pi/engine/session-integration.d.ts +1 -1
  65. package/dist/integrations/pi/engine/session-selection.d.ts +1 -1
  66. package/dist/integrations/pi/engine/session-selection.js +1 -1
  67. package/dist/integrations/pi/engine/settings-integration.d.ts +1 -1
  68. package/dist/integrations/pi/engine/windows-filesystem-hygiene.d.ts +1 -1
  69. package/dist/integrations/pi/engine/windows-filesystem-hygiene.js +1 -1
  70. package/dist/integrations/pi/session-ui/clipboard-diagnostics.d.ts +1 -1
  71. package/dist/integrations/pi/session-ui/clipboard-diagnostics.js +1 -1
  72. package/dist/integrations/pi/session-ui/paste-executor.d.ts +1 -1
  73. package/dist/integrations/pi/session-ui/paste-executor.js +1 -1
  74. package/dist/integrations/pi/session-ui/paste-protocol.d.ts +1 -1
  75. package/dist/integrations/pi/session-ui/prompt-chips.d.ts +1 -1
  76. package/dist/integrations/pi/session-ui/prompt-chips.js +1 -1
  77. package/dist/integrations/pi/session-ui/response-copy-coordinator.d.ts +1 -1
  78. package/dist/integrations/pi/session-ui/response-copy-coordinator.js +1 -1
  79. package/dist/integrations/pi/session-ui/response-copy-transport.d.ts +1 -1
  80. package/dist/integrations/pi/session-ui/session-shell-root.d.ts +8 -6
  81. package/dist/integrations/pi/session-ui/session-shell-root.js +31 -10
  82. package/dist/integrations/pi/session-ui/session-shell.d.ts +6 -3
  83. package/dist/integrations/pi/session-ui/session-shell.js +54 -11
  84. package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +8 -3
  85. package/dist/integrations/pi/session-ui/session-viewport-controller.js +33 -5
  86. package/dist/integrations/pi/session-ui/system-clipboard.d.ts +1 -1
  87. package/dist/integrations/pi/session-ui/system-clipboard.js +7 -4
  88. package/dist/integrations/pi/startup-public.d.ts +2 -0
  89. package/dist/integrations/pi/startup-public.js +2128 -0
  90. package/dist/integrations/pi/startup-public.manifest.json +11696 -0
  91. package/dist/integrations/pi/tui-runtime/adapter.js +1 -1
  92. package/dist/native/darwin-arm64/manifest.json +1 -1
  93. package/dist/native/linux-x64/manifest.json +1 -1
  94. package/dist/native/win32-x64/manifest.json +2 -2
  95. package/dist/native/win32-x64/process-guardian.exe +0 -0
  96. package/dist/runtime-payload-inventory.json +4 -1
  97. package/docs/architecture/response-copy-delivery.md +3 -1
  98. package/docs/ci-release-runbook.md +20 -7
  99. package/docs/local-worktree-cleanup.md +30 -12
  100. package/docs/openspec-archive-automation.md +191 -73
  101. package/docs/validation.md +62 -0
  102. package/package.json +4 -2
@@ -1,4 +1,4 @@
1
- import { isBashToolResult, isEditToolResult, isWriteToolResult, } from "@earendil-works/pi-coding-agent";
1
+ import { isBashToolResult, isEditToolResult, isWriteToolResult, } from "../startup-public.js";
2
2
  import { lstat, unlink } from "node:fs/promises";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  const DEFAULT_FILE_SYSTEM = { lstat, unlink };
@@ -1,4 +1,4 @@
1
- import type { PiTuiInputDiagnosticsEvent } from "../tui-runtime/index.js";
1
+ import type { PiTuiInputDiagnosticsEvent } from "../tui-runtime/contracts.js";
2
2
  import type { ResponseCopyEvent } from "./response-copy-protocol.js";
3
3
  import type { PasteEvent } from "./paste-protocol.js";
4
4
  /** Opt-in scalar-only snapshots, bounded to 128 rows and one pending asynchronous write. */
@@ -1,6 +1,6 @@
1
1
  import { writeFile } from "node:fs/promises";
2
2
  const PHASES = new Set(["capture", "selection-clear", "queued", "preparing", "extracted", "encoded", "submitting", "settled", "cleanup",
3
- "framing", "admitted", "predecessor", "acquiring", "acquired-text", "acquired-image", "classifying", "path-fallback", "prepared", "inserting",
3
+ "shortcut-received", "shortcut-matched", "shortcut-admitted", "pointer-admitted", "framing", "admitted", "predecessor", "acquiring", "acquired-text", "acquired-image", "classifying", "path-fallback", "prepared", "inserting",
4
4
  "receipt", "semantic-start", "semantic-end", "composition-start", "composition-end", "write-start", "write-end", "heartbeat"]);
5
5
  /** Opt-in scalar-only snapshots, bounded to 128 rows and one pending asynchronous write. */
6
6
  export class ClipboardDiagnosticCapture {
@@ -1,4 +1,4 @@
1
- import type { PiShellClipboardContent } from "../components/index.js";
1
+ import type { PiShellClipboardContent } from "../components/shell-shared-facade.js";
2
2
  import { type PreparedPaste, type PasteEvent } from "./paste-protocol.js";
3
3
  export interface PasteExecutorJob {
4
4
  readonly result: Promise<PreparedPaste>;
@@ -1,5 +1,5 @@
1
1
  import { fork } from "node:child_process";
2
- import { ImageAttachmentError } from "../../../contracts/owned-ui/index.js";
2
+ import { ImageAttachmentError } from "../../../contracts/owned-ui/image-attachments.js";
3
3
  import { MAX_SOURCE_IMAGE_BYTES } from "./image-source.js";
4
4
  import { PASTE_CHUNK_UNITS, PASTE_REQUESTS, PASTE_STOP_MS, PASTE_TEXT_BYTES, pasteFragments } from "./paste-protocol.js";
5
5
  const live = new Set();
@@ -24,7 +24,7 @@ export type PasteSource = {
24
24
  };
25
25
  export interface PasteEvent {
26
26
  readonly request: number;
27
- readonly phase: "receipt" | "framing" | "admitted" | "predecessor" | "acquiring" | "acquired-text" | "acquired-image" | "classifying" | "path-fallback" | "prepared" | "inserting" | "settled" | "cleanup";
27
+ readonly phase: "receipt" | "shortcut-received" | "shortcut-matched" | "shortcut-admitted" | "pointer-admitted" | "framing" | "admitted" | "predecessor" | "acquiring" | "acquired-text" | "acquired-image" | "classifying" | "path-fallback" | "prepared" | "inserting" | "settled" | "cleanup";
28
28
  readonly atMs: number;
29
29
  readonly elapsedMs?: number;
30
30
  readonly pending: number;
@@ -1,4 +1,4 @@
1
- import type { PiShellClipboardContent, PiShellEditorTextRange } from "../components/index.js";
1
+ import type { PiShellClipboardContent, PiShellEditorTextRange } from "../components/shell-shared-facade.js";
2
2
  import type { PasteEvent, PasteSource } from "./paste-protocol.js";
3
3
  export interface PromptImageAttachment {
4
4
  readonly type: "image";
@@ -1,7 +1,7 @@
1
1
  import { randomBytes } from "node:crypto";
2
2
  import path from "node:path";
3
3
  import { canonicalizeClipboardImage } from "./clipboard-image.js";
4
- import { assertImageEncodedSize, assertPromptImages, ImageAttachmentError } from "../../../contracts/owned-ui/index.js";
4
+ import { assertImageEncodedSize, assertPromptImages, ImageAttachmentError } from "../../../contracts/owned-ui/image-attachments.js";
5
5
  import { ImagePreparationClient } from "./image-preparation-client.js";
6
6
  import { preparePasteText } from "./paste-text-preparation.js";
7
7
  import { pathChipTag } from "./path-chip-presentation.js";
@@ -1,4 +1,4 @@
1
- import { type SelectionCopySnapshot } from "../../../ui/components/index.js";
1
+ import { type SelectionCopySnapshot } from "../../../ui/components/selection-copy.js";
2
2
  import { type CopyResult, type ResponseCopyEvent } from "./response-copy-protocol.js";
3
3
  import type { ResponseCopyExecutor } from "./response-copy-transport.js";
4
4
  /** Owns one delivery and one newest pending copy, including expiry and side-effect fencing. */
@@ -1,4 +1,4 @@
1
- import { MAX_COPY_SOURCE_UNITS } from "../../../ui/components/index.js";
1
+ import { MAX_COPY_SOURCE_UNITS } from "../../../ui/components/selection-copy.js";
2
2
  import { COPY_CLEANUP_MS, COPY_DEADLINE_MS } from "./response-copy-protocol.js";
3
3
  /** Owns one delivery and one newest pending copy, including expiry and side-effect fencing. */
4
4
  export class ResponseCopyCoordinator {
@@ -1,4 +1,4 @@
1
- import type { SelectionCopySnapshot } from "../../../ui/components/index.js";
1
+ import type { SelectionCopySnapshot } from "../../../ui/components/selection-copy.js";
2
2
  import { type CopyResult } from "./response-copy-protocol.js";
3
3
  export interface ResponseCopyJob {
4
4
  readonly result: Promise<CopyResult>;
@@ -1,10 +1,12 @@
1
1
  import type { OwnedUiPromptSuggestionGeneratorPort, OwnedUiSessionViewModel, OwnedUiViewportSettings, OwnedUiViewportSettingsPort, SuggestionDecision, SuggestionDiagnosticObserver } from "../../../contracts/owned-ui/index.js";
2
- import type { PiTuiPointerSurface } from "../tui-runtime/index.js";
3
- import type { UiRouteHost } from "../../../ui/apps/index.js";
4
- import { type TranscriptViewportFrame, type TranscriptViewportFrameDescriptor } from "../../../ui/components/index.js";
5
- import { type PiEngineAdapter, type PiWorkflowMessage, type PiWorkflowResult } from "../engine/index.js";
6
- import { type PiShellClipboardContent, type PiShellComponentPort, type PiShellEditorPort, type PiShellExtensionRendererResolver, type PiShellHeaderOptions, type PiShellHeaderPort, type PiShellImageAssetResolver, type PiShellLoadedResourcesPort, type PiShellResourceEntry, type PiShellTranscriptComponentPort } from "../components/index.js";
7
- import { type PiTuiComponentPort, type PiTuiInputSurfaceKind, type PiTuiInputCoordinationScheduler, type PiTuiInputDiagnosticsEvent, type PiTuiLayoutNode, type PiTuiTerminalPort } from "../tui-runtime/index.js";
2
+ import type { PiTuiPointerSurface } from "../tui-runtime/contracts.js";
3
+ import type { UiRouteHost } from "../../../ui/apps/contracts.js";
4
+ import type { TranscriptViewportFrame, TranscriptViewportFrameDescriptor } from "../../../ui/components/transcript-viewport.js";
5
+ import type { PiEngineAdapter } from "../engine/adapter.js";
6
+ import type { PiWorkflowMessage, PiWorkflowResult } from "../engine/workflows.js";
7
+ import { type PiShellClipboardContent, type PiShellComponentPort, type PiShellEditorPort, type PiShellExtensionRendererResolver, type PiShellHeaderOptions, type PiShellHeaderPort, type PiShellImageAssetResolver, type PiShellLoadedResourcesPort, type PiShellResourceEntry, type PiShellTranscriptComponentPort } from "../components/shell-shared-facade.js";
8
+ import { type PiTuiInputCoordinationScheduler, type PiTuiInputSurfaceKind } from "../tui-runtime/input-presentation-coordinator.js";
9
+ import type { PiTuiComponentPort, PiTuiInputDiagnosticsEvent, PiTuiLayoutNode, PiTuiTerminalPort } from "../tui-runtime/contracts.js";
8
10
  import { type PreparedPrompt } from "./prompt-chips.js";
9
11
  import { type SessionViewportInputResult } from "./session-viewport-controller.js";
10
12
  import type { ResponseCopyExecutor } from "./response-copy-transport.js";
@@ -1,8 +1,20 @@
1
- import { acceptsTranscriptUpdate } from "../../../contracts/owned-ui/index.js";
2
- import { backgroundSgrSpan, caretCell, composeSubmittedPromptRows, PromptInput, promptArrow, displayWidth, faint, formatSubmittedPromptTime, heldNativeHyperlinkStyle, hyperlinkSgrSpan, nativeHyperlinkStyle, overlaySpan, progressStatusText, submittedPromptLayout, stripAnsi, } from "../../../ui/components/index.js";
3
- import { PINNED_PI_HIDDEN_COMMAND_NAMES, PINNED_PI_WORKFLOW_COMMAND_NAMES, } from "../engine/index.js";
4
- import { createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellCollapsedChangelog, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellOperationLoader, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellStatus, createPiShellTranscriptComponent, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, onPiThemeChange, isPiPromptStyleCompaction, piShellVisibleWidth, piShellTruncateToWidth, piTheme, renderPiShellCommandMessage, renderPiShellPackageUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, } from "../components/index.js";
5
- import { PiTuiRuntimeAdapter, classifyPiTuiInput, } from "../tui-runtime/index.js";
1
+ import { acceptsTranscriptUpdate } from "../../../contracts/owned-ui/transcript-lifecycle.js";
2
+ import { caretCell } from "../../../ui/components/line-input.js";
3
+ import { PromptInput, promptArrow } from "../../../ui/components/prompt-input.js";
4
+ import { composeSubmittedPromptRows, formatSubmittedPromptTime, submittedPromptLayout, } from "../../../ui/components/submitted-prompt.js";
5
+ import { backgroundSgrSpan, heldNativeHyperlinkStyle, hyperlinkSgrSpan, nativeHyperlinkStyle, overlaySpan, } from "../../../ui/components/spans.js";
6
+ import { progressStatusText } from "../../../ui/components/progress-status.js";
7
+ import { displayWidth, faint, stripAnsi } from "../../../ui/components/text.js";
8
+ import { PINNED_PI_HIDDEN_COMMAND_NAMES, PINNED_PI_WORKFLOW_COMMAND_NAMES } from "../engine/workflows.js";
9
+ import { createPiExtensionUiBridge } from "../components/shell-extension-ui.js";
10
+ import { createPiShellEditor } from "../components/shell-editor-autocomplete.js";
11
+ import { createPiQueuedInputStatus, createPiShellFooter, createPiShellHeader, createPiShellLoadedResources, createPiShellStatus, } from "../components/shell-footer-status.js";
12
+ import { createPiShellArmin, createPiShellAuthProviderSelector, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellExtensionSelector, createPiShellLoginDialog, createPiShellModelSelector, createPiShellOperationLoader, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, } from "../components/shell-selectors-dialogs.js";
13
+ import { createPiShellChangelog, createPiShellCollapsedChangelog, createPiShellHotkeys, createPiShellSessionInfo, renderPiShellCommandMessage, renderPiShellStatusText, } from "../components/shell-presenters-info.js";
14
+ import { createPiShellTranscriptComponent, isPiPromptStyleCompaction, paintPiSubmittedPromptTimestamp, renderPiShellPackageUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellTranscriptBlock, } from "../components/shell-presenters-transcript.js";
15
+ import { onPiThemeChange, piTheme } from "../components/upstream/theme/theme.js";
16
+ import { piShellTruncateToWidth, piShellVisibleWidth, } from "../components/shell-shared-facade.js";
17
+ import { classifyPiTuiInput, } from "../tui-runtime/input-presentation-coordinator.js";
6
18
  import { PromptChipStore } from "./prompt-chips.js";
7
19
  import { EditorHyperlinkBudget } from "./editor-hyperlink-budget.js";
8
20
  import { SessionViewportController } from "./session-viewport-controller.js";
@@ -28,7 +40,8 @@ export class OwnedUiSessionShellRoot {
28
40
  #imageAssets;
29
41
  #promptChips;
30
42
  #editorHyperlinks = new EditorHyperlinkBudget();
31
- #pasteFramingId = 0;
43
+ #pasteDiagnosticId = 0;
44
+ #terminalPasteDiagnosticRequest;
32
45
  #customViewport;
33
46
  #submittedPromptComposer;
34
47
  #viewportController;
@@ -107,9 +120,15 @@ export class OwnedUiSessionShellRoot {
107
120
  },
108
121
  ...(this.#customViewport ? {
109
122
  beginClipboardPaste: () => this.#promptChips.beginPaste(this.editor.getText(), handlers.captureClipboardPaste?.() ?? { kind: "provided", read: signal => handlers.readClipboardContent?.(signal) ?? Promise.resolve(null) }, error => handlers.onPasteRejected?.(error), () => handlers.requestRender()),
110
- onPasteInput: bytes => {
123
+ onPasteInput: (bytes, phase) => {
111
124
  try {
112
- handlers.pasteDiagnostics?.({ request: --this.#pasteFramingId, phase: "framing", bytes, atMs: performance.now(), pending: 0, transport: "terminal" });
125
+ if (phase === "framing")
126
+ this.#terminalPasteDiagnosticRequest = --this.#pasteDiagnosticId;
127
+ const request = this.#terminalPasteDiagnosticRequest ?? --this.#pasteDiagnosticId;
128
+ handlers.pasteDiagnostics?.({ request, phase, bytes, atMs: performance.now(), pending: 0, transport: "terminal",
129
+ ...(phase === "settled" ? { outcome: "ready" } : {}) });
130
+ if (phase === "settled")
131
+ this.#terminalPasteDiagnosticRequest = undefined;
113
132
  }
114
133
  catch { /* Invariant: payload-free diagnostics cannot interfere with the input path. */ }
115
134
  },
@@ -165,6 +184,8 @@ export class OwnedUiSessionShellRoot {
165
184
  requestRender: force => this.#componentRuntime.requestRender(force),
166
185
  requestHyperlinkCleanup: rows => handlers.requestHyperlinkCleanup?.(rows),
167
186
  hasEditorLinks: () => this.#promptChips.hyperlinkRanges(this.editor.getText()).length > 0,
187
+ ...(handlers.pasteDiagnostics === undefined ? {} : { pasteDiagnostics: handlers.pasteDiagnostics }),
188
+ nextPasteDiagnosticRequest: () => --this.#pasteDiagnosticId,
168
189
  });
169
190
  // Performance: stable painter identities let the neutral viewport retain row-level
170
191
  // selection variants while each callback still resolves the live Pi theme.
@@ -1122,7 +1143,7 @@ function nativeTranscriptLinkColor(text, target) {
1122
1143
  function withoutTerminalBackground(text) {
1123
1144
  return text.replace(TERMINAL_BACKGROUND, "");
1124
1145
  }
1125
- /** Preserve the established prompt foreground for quiet and hovered pinned timestamps. */
1146
+ /** Preserve the stable metadata-grey foreground for every pinned timestamp state. */
1126
1147
  function pinnedPromptSourceRow(block, sourceRow, width) {
1127
1148
  if (typeof block.payload !== "object" || block.payload === null)
1128
1149
  return sourceRow;
@@ -1136,7 +1157,7 @@ function pinnedPromptSourceRow(block, sourceRow, width) {
1136
1157
  const timestampWidth = displayWidth(timestamp);
1137
1158
  if (rowWidth < timestampWidth)
1138
1159
  return sourceRow;
1139
- return overlaySpan(sourceRow, rowWidth - timestampWidth, rowWidth, piTheme().fg("userMessageText", timestamp));
1160
+ return overlaySpan(sourceRow, rowWidth - timestampWidth, rowWidth, paintPiSubmittedPromptTimestamp(timestamp));
1140
1161
  }
1141
1162
  function layoutPort(render, invalidate, handleInput) {
1142
1163
  return {
@@ -1,7 +1,10 @@
1
1
  import type { OwnedUiSessionViewModel, OwnedUiThinkingLevel } from "../../../contracts/owned-ui/index.js";
2
- import { type AdapterCommandResult, type PiWorkflowRequest } from "../engine/index.js";
3
- import { type PiShellSelectorOption } from "../components/index.js";
4
- import { PiTuiRuntimeAdapter, type PiTuiDamageDecision, type PiTuiOverlayHandle } from "../tui-runtime/index.js";
2
+ import type { AdapterCommandResult } from "../engine/adapter.js";
3
+ import type { PiWorkflowRequest } from "../engine/workflows.js";
4
+ import type { PiShellSelectorOption } from "../components/shell-shared-facade.js";
5
+ import { type PiTuiDamageDecision } from "../tui-runtime/damage-aware-terminal.js";
6
+ import { PiTuiRuntimeAdapter } from "../tui-runtime/adapter.js";
7
+ import type { PiTuiOverlayHandle } from "../tui-runtime/contracts.js";
5
8
  import { OwnedUiSessionShellRoot, type OwnedUiBackendPort, type OwnedUiSessionShellOptions } from "./session-shell-root.js";
6
9
  export { OwnedUiSessionShellRoot, type OwnedUiSessionShellOptions } from "./session-shell-root.js";
7
10
  /** Coordinates backend, owned presentation, and Pi TUI lifecycles for one interactive session. */
@@ -3,13 +3,23 @@ import { createResponseCopyExecutor, hasAsyncClipboardOutput, responseCopyDestin
3
3
  import { MAX_COPY_CONTROL_BYTES } from "./response-copy-protocol.js";
4
4
  import { PromptHistoryController } from "./prompt-history-controller.js";
5
5
  import { PRODUCT_TEXT } from "../../../product-identity.js";
6
- import { boundedCleanup } from "../../../foundation/terminal-cleanup/index.js";
7
- import { assertOwnedUiCommand, assertPromptImages, ImageAttachmentError } from "../../../contracts/owned-ui/index.js";
6
+ import { boundedCleanup } from "../../../foundation/terminal-cleanup/terminal-reset.js";
7
+ import { assertOwnedUiCommand } from "../../../contracts/owned-ui/validation.js";
8
+ import { assertPromptImages, ImageAttachmentError } from "../../../contracts/owned-ui/image-attachments.js";
8
9
  import { ContextualPromptSuggestionController } from "./prompt-suggestion-controller.js";
9
- import { MOUSE_TRACKING_OFF, MOUSE_TRACKING_ON, parseMouseInput, readVisibleHyperlinks } from "../../../ui/components/index.js";
10
- import { PINNED_PI_HIDDEN_COMMAND_NAMES, PINNED_PI_WORKFLOW_COMMAND_NAMES, } from "../engine/index.js";
11
- import { createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellOperationLoader, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellStatus, createPiShellTranscriptComponent, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, onPiThemeChange, piTheme, renderPiShellPackageUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, } from "../components/index.js";
12
- import { DamageAwareTerminalAdapter, PiTuiRuntimeAdapter, classifyPiTuiInput, } from "../tui-runtime/index.js";
10
+ import { MOUSE_TRACKING_OFF, MOUSE_TRACKING_ON, parseMouseInput } from "../../../ui/components/mouse.js";
11
+ import { readVisibleHyperlinks } from "../../../ui/components/visible-hyperlinks.js";
12
+ import { PINNED_PI_HIDDEN_COMMAND_NAMES, PINNED_PI_WORKFLOW_COMMAND_NAMES } from "../engine/workflows.js";
13
+ import { createPiExtensionUiBridge } from "../components/shell-extension-ui.js";
14
+ import { createPiShellEditor } from "../components/shell-editor-autocomplete.js";
15
+ import { createPiQueuedInputStatus, createPiShellFooter, createPiShellHeader, createPiShellLoadedResources, createPiShellStatus, } from "../components/shell-footer-status.js";
16
+ import { createPiShellArmin, createPiShellAuthProviderSelector, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellExtensionSelector, createPiShellLoginDialog, createPiShellModelSelector, createPiShellOperationLoader, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, } from "../components/shell-selectors-dialogs.js";
17
+ import { createPiShellChangelog, createPiShellHotkeys, createPiShellSessionInfo, renderPiShellStatusText, } from "../components/shell-presenters-info.js";
18
+ import { createPiShellTranscriptComponent, renderPiShellPackageUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellTranscriptBlock, } from "../components/shell-presenters-transcript.js";
19
+ import { onPiThemeChange, piTheme } from "../components/upstream/theme/theme.js";
20
+ import { DamageAwareTerminalAdapter } from "../tui-runtime/damage-aware-terminal.js";
21
+ import { PiTuiRuntimeAdapter } from "../tui-runtime/adapter.js";
22
+ import { classifyPiTuiInput } from "../tui-runtime/input-presentation-coordinator.js";
13
23
  import { runImageWorker } from "./image-preparation-client.js";
14
24
  import { STREAM_PRESENTATION_INTERVAL_MS, StreamPresentationCoalescer, } from "./stream-presentation-coalescer.js";
15
25
  import { writeSystemClipboardText, } from "./system-clipboard.js";
@@ -38,6 +48,8 @@ export class OwnedUiSessionShell {
38
48
  #editorRevision = 0;
39
49
  #started = false;
40
50
  #disposed = false;
51
+ #shutdownPromise;
52
+ #disposePromise;
41
53
  #pointerReporting = false;
42
54
  #customViewport;
43
55
  #responseCopy;
@@ -481,7 +493,7 @@ export class OwnedUiSessionShell {
481
493
  if (view.lifecycle === "ready" && this.#compactionQueue.length > 0)
482
494
  void this.#flushCompactionQueue();
483
495
  if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
484
- this.#resolveStopped?.();
496
+ this.#settleStoppedLifecycle();
485
497
  });
486
498
  this.#unbindClipboardWriter = this.#responseCopy === null ? () => { } : this.backend.bindClipboardWriter(async (text) => {
487
499
  const result = await this.#responseCopy.submitText(text);
@@ -1068,10 +1080,23 @@ export class OwnedUiSessionShell {
1068
1080
  this.root.setInputSurface(component);
1069
1081
  this.runtime.requestRender();
1070
1082
  }
1071
- async shutdown() {
1072
- return this.runWorkflow({ command: "quit", argument: "" });
1083
+ shutdown() {
1084
+ this.#shutdownPromise ??= this.#shutdown();
1085
+ return this.#shutdownPromise;
1086
+ }
1087
+ async #shutdown() {
1088
+ try {
1089
+ const result = await this.backend.executeWorkflow({ command: "quit", argument: "" });
1090
+ await this.dispose();
1091
+ return workflowAdapterResult(result);
1092
+ }
1093
+ finally {
1094
+ this.#resolveStoppedLifecycle();
1095
+ }
1073
1096
  }
1074
1097
  async runWorkflow(request) {
1098
+ if (request.command === "quit")
1099
+ return this.shutdown();
1075
1100
  const copyGeneration = request.command === "copy" ? this.backend.sessionBindingGeneration : undefined;
1076
1101
  if (request.command === "login" && request.selection !== undefined) {
1077
1102
  const setup = this.backend.pinnedAmbientAuthentication(request.selection);
@@ -1311,9 +1336,19 @@ export class OwnedUiSessionShell {
1311
1336
  return;
1312
1337
  this.runtime.writeControl(effective ? MOUSE_TRACKING_ON : MOUSE_TRACKING_OFF);
1313
1338
  }
1314
- async dispose() {
1339
+ dispose() {
1340
+ if (this.#disposePromise !== undefined)
1341
+ return this.#disposePromise;
1315
1342
  if (this.#disposed)
1316
- return;
1343
+ return Promise.resolve();
1344
+ const pending = Promise.resolve().then(() => this.#dispose());
1345
+ this.#disposePromise = pending;
1346
+ const clear = () => { if (this.#disposePromise === pending)
1347
+ this.#disposePromise = undefined; };
1348
+ void pending.then(clear, clear);
1349
+ return pending;
1350
+ }
1351
+ async #dispose() {
1317
1352
  this.#disposed = true;
1318
1353
  this.#responseCopy?.dispose();
1319
1354
  this.#cancelWaitingImages();
@@ -1361,6 +1396,14 @@ export class OwnedUiSessionShell {
1361
1396
  if (fullscreenExitText.length > 0)
1362
1397
  this.runtime.writeAfterStop(`${fullscreenExitText}\n`);
1363
1398
  }
1399
+ #settleStoppedLifecycle() {
1400
+ void this.dispose().then(() => this.#resolveStoppedLifecycle(), () => this.#resolveStoppedLifecycle());
1401
+ }
1402
+ #resolveStoppedLifecycle() {
1403
+ const resolve = this.#resolveStopped;
1404
+ this.#resolveStopped = undefined;
1405
+ resolve?.();
1406
+ }
1364
1407
  // Invariant: incremental block updates notify listeners with the same complete view contract.
1365
1408
  #syncBlock(block) {
1366
1409
  this.root.applyTranscriptBlock(block);
@@ -1,7 +1,9 @@
1
- import { type PiTuiPointerSurface } from "../tui-runtime/index.js";
1
+ import type { PiTuiPointerSurface } from "../tui-runtime/contracts.js";
2
2
  import type { OwnedUiViewportSettings } from "../../../contracts/owned-ui/index.js";
3
- import { type SelectionCopySnapshot, type TranscriptViewportFrame, type TranscriptViewportFrameInput } from "../../../ui/components/index.js";
4
- import type { PiShellEditorPort } from "../components/index.js";
3
+ import { type TranscriptViewportFrame, type TranscriptViewportFrameInput } from "../../../ui/components/transcript-viewport.js";
4
+ import type { SelectionCopySnapshot } from "../../../ui/components/selection-copy.js";
5
+ import type { PiShellEditorPort } from "../components/shell-shared-facade.js";
6
+ import type { PasteEvent } from "./paste-protocol.js";
5
7
  export interface SessionViewportControllerOptions {
6
8
  readonly enabled: boolean;
7
9
  readonly editor: PiShellEditorPort;
@@ -9,6 +11,9 @@ export interface SessionViewportControllerOptions {
9
11
  readonly requestHyperlinkCleanup?: (rows?: readonly number[]) => void;
10
12
  /** Whether mutable editor URL chips need targeted link-cell cleanup on deletion. */
11
13
  readonly hasEditorLinks?: () => boolean;
14
+ /** Payload-free first-use paste routing observations. */
15
+ readonly pasteDiagnostics?: (event: PasteEvent) => void;
16
+ readonly nextPasteDiagnosticRequest?: () => number;
12
17
  }
13
18
  export interface SessionViewportInputResult {
14
19
  readonly data: string;
@@ -1,5 +1,8 @@
1
- import { samePointerSurfaces } from "../tui-runtime/index.js";
2
- import { TranscriptViewport, readVisibleHyperlinks, routeMouseInput, scrollForTrackPage, scrollForThumbRow, scrollbarSelectionRows, scrollbarWheelRows, } from "../../../ui/components/index.js";
1
+ import { samePointerSurfaces } from "../tui-runtime/overlay-geometry.js";
2
+ import { TranscriptViewport } from "../../../ui/components/transcript-viewport.js";
3
+ import { readVisibleHyperlinks } from "../../../ui/components/visible-hyperlinks.js";
4
+ import { routeMouseInput } from "../../../ui/components/mouse.js";
5
+ import { scrollForTrackPage, scrollForThumbRow, scrollbarSelectionRows, scrollbarWheelRows } from "../../../ui/components/scrollbar.js";
3
6
  /**
4
7
  * Owns the stateful interaction policy of the bare-A1 session viewport. The
5
8
  * shell root supplies semantic rows and dock geometry; this controller owns
@@ -11,6 +14,9 @@ export class SessionViewportController {
11
14
  #requestRender;
12
15
  #hasEditorLinks;
13
16
  #requestHyperlinkCleanup;
17
+ #pasteDiagnostics;
18
+ #nextPasteDiagnosticRequest;
19
+ #pasteDiagnosticRequest = 0;
14
20
  #viewport = new TranscriptViewport();
15
21
  #config = {
16
22
  scrollbarAppearance: "auto",
@@ -46,6 +52,8 @@ export class SessionViewportController {
46
52
  };
47
53
  this.#hasEditorLinks = options.hasEditorLinks ?? (() => false);
48
54
  this.#requestHyperlinkCleanup = options.requestHyperlinkCleanup ?? (() => { });
55
+ this.#pasteDiagnostics = options.pasteDiagnostics;
56
+ this.#nextPasteDiagnosticRequest = options.nextPasteDiagnosticRequest ?? (() => --this.#pasteDiagnosticRequest);
49
57
  }
50
58
  get config() {
51
59
  return this.#config;
@@ -183,6 +191,12 @@ export class SessionViewportController {
183
191
  this.#viewport.clearTransient();
184
192
  this.#pointerOwner = undefined;
185
193
  }
194
+ #emitPasteRoute(request, phase) {
195
+ try {
196
+ this.#pasteDiagnostics?.({ request, phase, atMs: performance.now(), pending: 0 });
197
+ }
198
+ catch { /* Invariant: payload-free diagnostics cannot interfere with input routing. */ }
199
+ }
186
200
  #cancelGesture() {
187
201
  const held = this.#pointerOwner !== undefined || this.#viewport.selectionActive || this.#editorPointerSelecting;
188
202
  const repaint = this.#viewport.hasSelection || held;
@@ -199,6 +213,11 @@ export class SessionViewportController {
199
213
  handlePreInput(data, allowWheel = true, now = Date.now(), editorActive = true) {
200
214
  if (!this.#enabled)
201
215
  return { data, consumed: false };
216
+ let pasteRequest;
217
+ if (editorActive && data === "\u0016") {
218
+ pasteRequest = this.#nextPasteDiagnosticRequest();
219
+ this.#emitPasteRoute(pasteRequest, "shortcut-received");
220
+ }
202
221
  // Compatibility: Pi components share one keybinding manager. Restore bare A1's aliases
203
222
  // before the focused vanilla editor handles this input.
204
223
  if (editorActive)
@@ -208,8 +227,15 @@ export class SessionViewportController {
208
227
  return { data, consumed: false };
209
228
  // Platform: handle the physical paste chord at the pre-input boundary. Windows
210
229
  // terminals vary between forwarding Ctrl+V and terminal-owned bracketed paste.
211
- if (editorActive && this.#editor.matchesTerminalKey(data, "ctrl+v") && this.#editor.pasteClipboard()) {
212
- return { data: "", consumed: true };
230
+ if (editorActive && this.#editor.matchesTerminalKey(data, "ctrl+v")) {
231
+ pasteRequest ??= this.#nextPasteDiagnosticRequest();
232
+ if (data !== "\u0016")
233
+ this.#emitPasteRoute(pasteRequest, "shortcut-received");
234
+ this.#emitPasteRoute(pasteRequest, "shortcut-matched");
235
+ if (this.#editor.pasteClipboard()) {
236
+ this.#emitPasteRoute(pasteRequest, "shortcut-admitted");
237
+ return { data: "", consumed: true };
238
+ }
213
239
  }
214
240
  // Platform: URL chip deletion must overwrite terminal link cells in the same frame.
215
241
  if (editorActive && EDITOR_LINK_DELETION_INPUTS.has(data) && this.#hasEditorLinks()) {
@@ -378,7 +404,9 @@ export class SessionViewportController {
378
404
  this.#stopSelectionAutoScroll();
379
405
  if (this.#viewport.clearSelection())
380
406
  repaint = true;
381
- this.#editor.pasteClipboard();
407
+ const request = this.#nextPasteDiagnosticRequest();
408
+ if (this.#editor.pasteClipboard())
409
+ this.#emitPasteRoute(request, "pointer-admitted");
382
410
  this.#dockPointerSuppressed = true;
383
411
  repaint = true;
384
412
  return true;
@@ -1,4 +1,4 @@
1
- import type { PiShellClipboardContent } from "../components/index.js";
1
+ import type { PiShellClipboardContent } from "../components/shell-shared-facade.js";
2
2
  export interface SystemClipboardImageReader {
3
3
  hasImage(): boolean;
4
4
  getImageBinary?(): Promise<readonly number[]>;
@@ -1,6 +1,6 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { canonicalizeClipboardImage } from "./clipboard-image.js";
3
- import { ImageAttachmentError } from "../../../contracts/owned-ui/index.js";
3
+ import { ImageAttachmentError } from "../../../contracts/owned-ui/image-attachments.js";
4
4
  import { assertSourceBytes } from "./image-source.js";
5
5
  const MAX_CLIPBOARD_BYTES = 16 * 1024 * 1024;
6
6
  let nativeClipboardPromise;
@@ -85,8 +85,9 @@ export async function readSystemClipboardText(signal, strict = false) {
85
85
  const text = await native.getText();
86
86
  if (text.length > 0)
87
87
  return text;
88
- if (strict)
89
- return null;
88
+ // Compatibility: a cold native adapter can report empty before the platform
89
+ // command can observe the existing clipboard. Treat empty as inconclusive
90
+ // and continue within this request's existing abort/deadline boundary.
90
91
  }
91
92
  catch {
92
93
  // Compatibility: fall through to the platform command.
@@ -105,7 +106,9 @@ export async function readSystemClipboardText(signal, strict = false) {
105
106
  return execClipboard("pbpaste", [], signal, strict);
106
107
  try {
107
108
  const value = await execClipboard("wl-paste", ["--no-newline", "--type", "text"], signal, strict);
108
- if (strict || value !== null)
109
+ // Compatibility: an empty Wayland result does not prove that the X11
110
+ // clipboard is empty on mixed sessions. Let the existing fallback decide.
111
+ if (value !== null)
109
112
  return value;
110
113
  }
111
114
  catch { /* Compatibility: X11 may be available when the Wayland command is not. */ }
@@ -0,0 +1,2 @@
1
+ export { ArminComponent, AssistantMessageComponent, BashExecutionComponent, BorderedLoader, CompactionSummaryMessageComponent, CredentialSynchronizationError, CustomMessageComponent, DefaultPackageManager, DynamicBorder, ExtensionInputComponent, ExtensionSelectorComponent, LoginDialogComponent, ModelRuntime, ModelSelectorComponent, OAuthSelectorComponent, ProjectTrustStore, SessionManager, SettingsManager, SettingsSelectorComponent, ShowImagesSelectorComponent, Theme, ThemeSelectorComponent, ThinkingSelectorComponent, ToolExecutionComponent, UserMessageComponent, UserMessageSelectorComponent, VERSION, convertToPng, copyToClipboard, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, createBashToolDefinition, createEditToolDefinition, createFindToolDefinition, createGrepToolDefinition, createLsToolDefinition, createReadToolDefinition, createWriteToolDefinition, getAgentDir, getMarkdownTheme, getSelectListTheme, hasTrustRequiringProjectResources, initTheme, isBashToolResult, isEditToolResult, isWriteToolResult, keyHint, keyText, parseSkillBlock, rawKeyHint, resolveModelScopeWithDiagnostics, } from "@earendil-works/pi-coding-agent";
2
+ export type * from "@earendil-works/pi-coding-agent";