@timurproko/a1 0.1.8-dev.182 → 0.1.8-dev.214

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 (142) hide show
  1. package/bin/cli.js +2 -2
  2. package/bin/sync-pi-tui-proxy.js +1 -1
  3. package/bin/ui.js +1 -1
  4. package/dist/cli/dispatch.js +3 -3
  5. package/dist/cli/packages.js +1 -1
  6. package/dist/cli/version-stats.js +3 -3
  7. package/dist/composition/owned-ui.js +1 -1
  8. package/dist/composition/settings-route-host.js +6 -4
  9. package/dist/features/launch/development-launch.js +1 -1
  10. package/dist/features/owned-ui/customization.d.ts +2 -0
  11. package/dist/features/owned-ui/customization.js +2 -0
  12. package/dist/features/owned-ui/diagnostics.d.ts +1 -0
  13. package/dist/features/owned-ui/diagnostics.js +1 -0
  14. package/dist/features/owned-ui/project-trust-prompt.d.ts +11 -6
  15. package/dist/features/owned-ui/project-trust-prompt.js +134 -17
  16. package/dist/features/owned-ui/settings-app.js +47 -50
  17. package/dist/features/workspace/reducer.d.ts +1 -0
  18. package/dist/features/workspace/reducer.js +1 -0
  19. package/dist/features/workspace/router.d.ts +1 -0
  20. package/dist/features/workspace/router.js +1 -0
  21. package/dist/features/workspace/store.d.ts +1 -0
  22. package/dist/features/workspace/store.js +1 -0
  23. package/dist/foundation/launch-guardian/main.js +1 -1
  24. package/dist/foundation/native-host-protocol/codec.d.ts +2 -0
  25. package/dist/foundation/native-host-protocol/codec.js +2 -0
  26. package/dist/foundation/process-containment/linux-process-inspector.d.ts +1 -0
  27. package/dist/foundation/process-containment/linux-process-inspector.js +1 -0
  28. package/dist/foundation/process-containment/native-guardian-containment.d.ts +1 -0
  29. package/dist/foundation/process-containment/native-guardian-containment.js +1 -0
  30. package/dist/foundation/process-containment/windows-process-inspector.d.ts +1 -0
  31. package/dist/foundation/process-containment/windows-process-inspector.js +1 -0
  32. package/dist/foundation/protocol/client.d.ts +1 -0
  33. package/dist/foundation/protocol/client.js +1 -0
  34. package/dist/foundation/protocol/messages.d.ts +1 -0
  35. package/dist/foundation/protocol/messages.js +1 -0
  36. package/dist/foundation/release/bootstrap.js +6 -6
  37. package/dist/foundation/release/cohort-state.d.ts +1 -0
  38. package/dist/foundation/release/cohort-state.js +1 -0
  39. package/dist/foundation/release/release-gc.js +1 -1
  40. package/dist/foundation/release/release.js +1 -1
  41. package/dist/foundation/release/update-transaction.d.ts +1 -0
  42. package/dist/foundation/release/update-transaction.js +1 -0
  43. package/dist/foundation/release/update.js +12 -12
  44. package/dist/foundation/storage/control-store.d.ts +1 -0
  45. package/dist/foundation/storage/control-store.js +1 -0
  46. package/dist/foundation/structured-agent-runtime/backpressure.d.ts +1 -0
  47. package/dist/foundation/structured-agent-runtime/backpressure.js +1 -0
  48. package/dist/foundation/structured-agent-runtime/commands.d.ts +1 -0
  49. package/dist/foundation/structured-agent-runtime/commands.js +1 -0
  50. package/dist/foundation/structured-agent-runtime/reconnection.d.ts +1 -0
  51. package/dist/foundation/structured-agent-runtime/reconnection.js +1 -0
  52. package/dist/foundation/structured-agent-runtime/state.d.ts +1 -0
  53. package/dist/foundation/structured-agent-runtime/state.js +1 -0
  54. package/dist/foundation/supervision/main.js +1 -1
  55. package/dist/foundation/supervision/server.d.ts +1 -0
  56. package/dist/foundation/supervision/server.js +4 -6
  57. package/dist/integrations/pi/components/conformance.d.ts +1 -0
  58. package/dist/integrations/pi/components/conformance.js +1 -0
  59. package/dist/integrations/pi/components/shell-footer-status.d.ts +1 -1
  60. package/dist/integrations/pi/components/shell-footer-status.js +8 -7
  61. package/dist/integrations/pi/components/shell-shared-facade.js +1 -1
  62. package/dist/integrations/pi/engine/adapter.d.ts +7 -0
  63. package/dist/integrations/pi/engine/adapter.js +37 -35
  64. package/dist/integrations/pi/engine/conformance.d.ts +2 -0
  65. package/dist/integrations/pi/engine/conformance.js +2 -0
  66. package/dist/integrations/pi/engine/http-dispatcher.js +1 -1
  67. package/dist/integrations/pi/engine/model-auth-integration.d.ts +1 -0
  68. package/dist/integrations/pi/engine/model-auth-integration.js +1 -0
  69. package/dist/integrations/pi/engine/package-integration.js +1 -1
  70. package/dist/integrations/pi/engine/project-trust-preflight.js +1 -1
  71. package/dist/integrations/pi/engine/resource-extension-integration.d.ts +1 -0
  72. package/dist/integrations/pi/engine/resource-extension-integration.js +1 -0
  73. package/dist/integrations/pi/engine/session-integration.d.ts +1 -0
  74. package/dist/integrations/pi/engine/session-integration.js +2 -1
  75. package/dist/integrations/pi/engine/settings-effects.d.ts +13 -2
  76. package/dist/integrations/pi/engine/settings-effects.js +62 -42
  77. package/dist/integrations/pi/engine/settings-integration.js +4 -4
  78. package/dist/integrations/pi/engine/workflow-controllers.d.ts +1 -0
  79. package/dist/integrations/pi/engine/workflow-controllers.js +1 -0
  80. package/dist/integrations/pi/session-ui/index.d.ts +1 -0
  81. package/dist/integrations/pi/session-ui/index.js +1 -0
  82. package/dist/integrations/pi/session-ui/prompt-chips.js +1 -1
  83. package/dist/integrations/pi/session-ui/session-shell-root.d.ts +30 -2
  84. package/dist/integrations/pi/session-ui/session-shell-root.js +133 -72
  85. package/dist/integrations/pi/session-ui/session-shell.d.ts +9 -2
  86. package/dist/integrations/pi/session-ui/session-shell.js +112 -37
  87. package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +5 -0
  88. package/dist/integrations/pi/session-ui/session-viewport-controller.js +44 -11
  89. package/dist/integrations/pi/session-ui/stream-presentation-coalescer.d.ts +29 -0
  90. package/dist/integrations/pi/session-ui/stream-presentation-coalescer.js +79 -0
  91. package/dist/integrations/pi/session-ui/system-clipboard.js +6 -6
  92. package/dist/integrations/pi/tui-runtime/adapter.d.ts +2 -0
  93. package/dist/integrations/pi/tui-runtime/adapter.js +138 -8
  94. package/dist/integrations/pi/tui-runtime/contracts.d.ts +25 -0
  95. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +63 -0
  96. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +240 -0
  97. package/dist/integrations/pi/tui-runtime/index.d.ts +2 -0
  98. package/dist/integrations/pi/tui-runtime/index.js +2 -0
  99. package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +39 -0
  100. package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.js +139 -0
  101. package/dist/native/darwin-arm64/manifest.json +1 -1
  102. package/dist/native/linux-x64/manifest.json +1 -1
  103. package/dist/native/win32-x64/manifest.json +2 -2
  104. package/dist/native/win32-x64/process-guardian.exe +0 -0
  105. package/dist/ui/apps/host.js +5 -9
  106. package/dist/ui/apps/registry.d.ts +1 -0
  107. package/dist/ui/apps/registry.js +1 -0
  108. package/dist/ui/components/dialog-panel.js +5 -3
  109. package/dist/ui/components/frame.d.ts +1 -0
  110. package/dist/ui/components/frame.js +1 -0
  111. package/dist/ui/components/index.d.ts +1 -0
  112. package/dist/ui/components/index.js +1 -0
  113. package/dist/ui/components/line-input.d.ts +1 -6
  114. package/dist/ui/components/line-input.js +4 -9
  115. package/dist/ui/components/list-view.d.ts +0 -6
  116. package/dist/ui/components/list-view.js +14 -7
  117. package/dist/ui/components/progress-status.d.ts +2 -0
  118. package/dist/ui/components/progress-status.js +4 -0
  119. package/dist/ui/components/scrollbar.js +1 -1
  120. package/dist/ui/components/shortcuts.d.ts +1 -0
  121. package/dist/ui/components/shortcuts.js +1 -0
  122. package/dist/ui/components/spans.d.ts +0 -5
  123. package/dist/ui/components/spans.js +3 -8
  124. package/dist/ui/components/surface.d.ts +0 -5
  125. package/dist/ui/components/surface.js +1 -5
  126. package/dist/ui/components/text-selection.d.ts +10 -1
  127. package/dist/ui/components/text-selection.js +96 -29
  128. package/dist/ui/components/text.js +3 -3
  129. package/dist/ui/components/transcript-viewport.d.ts +42 -0
  130. package/dist/ui/components/transcript-viewport.js +287 -39
  131. package/dist/ui/settings/sections.d.ts +0 -2
  132. package/dist/ui/settings/sections.js +10 -16
  133. package/dist/ui/settings/session.js +5 -4
  134. package/dist/ui/settings/store.d.ts +1 -0
  135. package/dist/ui/settings/store.js +2 -1
  136. package/docs/architecture/code-documentation.md +77 -0
  137. package/docs/architecture/project-structure.md +1 -1
  138. package/docs/architecture/ui-reference-provenance.md +23 -3
  139. package/docs/ci-release-runbook.md +30 -4
  140. package/docs/manual-owned-ui-checkpoint.md +28 -1
  141. package/docs/manual-terminal-colour-check.md +4 -3
  142. package/package.json +7 -2
@@ -96,18 +96,18 @@ export function createUpdateLifecycleCoordinator(environment = process.env, file
96
96
  await removeEndpointArtifacts(owner.paths.endpointMetadataPath, owner.paths.endpoint);
97
97
  return { priorActiveVersion };
98
98
  }
99
- // Leaving sessions alone is the expected outcome, and saying so mid-update tears
99
+ // Rationale: leaving sessions alone is the expected outcome, and saying so mid-update tears
100
100
  // the progress bar; only ending a session (below) is worth interrupting it for.
101
101
  if (plan === "leave-running")
102
102
  return { priorActiveVersion };
103
- // Say whose work is ending before it ends.
103
+ // Rationale: say whose work is ending before it ends.
104
104
  const live = endpoint.ownership.liveInstanceIds.length;
105
105
  if (live > 0) {
106
106
  output.stderr(`${PRODUCT_TEXT.diagnostic(`ending ${live === 1 ? "one session" : `${live} sessions`} that run from the installation being replaced; a session started by an installed release would have been left alone.`)}\n`);
107
107
  }
108
108
  const identity = await requestUpdateShutdown(endpoint, targetVersion, 2_000);
109
109
  if (!identity.accepted && processIsAlive(endpoint.pid)) {
110
- // Explicit update consent permits bounded cleanup of an authenticated
110
+ // Security: explicit update consent permits bounded cleanup of an authenticated
111
111
  // older owner that predates the update-shutdown message.
112
112
  const cleanup = await cleanupVerifiedOwner(endpoint, { allowLiveInstances: true, reason: "legacy-mutable-install" });
113
113
  if (!cleanup.terminated)
@@ -133,7 +133,7 @@ export function createUpdateLifecycleCoordinator(environment = process.env, file
133
133
  await rename(probe, packageRoot);
134
134
  }
135
135
  catch (error) {
136
- // Best-effort rollback if the first rename succeeded and the second did not.
136
+ // Invariant: best-effort rollback runs if the first rename succeeded and the second did not.
137
137
  await rename(probe, packageRoot).catch(() => { });
138
138
  throw new Error(PRODUCT_TEXT.diagnostic(`package remains locked after verified shutdown: ${errorMessage(error)}`));
139
139
  }
@@ -214,7 +214,7 @@ function createUpdateProgress(output, enabled) {
214
214
  draw();
215
215
  if (creepTo <= current)
216
216
  return;
217
- // Creep asymptotically toward (but never reach) the next milestone so
217
+ // Rationale: creep asymptotically toward (but never reach) the next milestone so
218
218
  // long opaque phases such as npm install still show visible motion. The
219
219
  // ceiling stays a whole point below the milestone: settling on `creepTo`
220
220
  // itself would render as that milestone and make arriving at it invisible,
@@ -225,7 +225,7 @@ function createUpdateProgress(output, enabled) {
225
225
  }, PROGRESS_TICK_MS);
226
226
  timer.unref?.();
227
227
  },
228
- // The bar exists to say the update is still moving. Once it has finished
228
+ // Rationale: the bar exists to say the update is still moving. Once it has finished
229
229
  // there is a better line to occupy that row — the one naming what is now
230
230
  // installed — so the bar gives the row back rather than leaving a full
231
231
  // meter above a message that already implies it.
@@ -283,7 +283,7 @@ async function resolveRequestedPreview(runner, requested, output) {
283
283
  const versions = (Array.isArray(published) ? published : [published]).filter((value) => typeof value === "string");
284
284
  const exact = versions.find(version => version === requested);
285
285
  if (exact !== undefined) {
286
- // Naming a release here would install it through the preview path, which is a
286
+ // Rationale: naming a release here would install it through the preview path, which is a
287
287
  // different command with a different meaning.
288
288
  if (!exact.includes("-dev.")) {
289
289
  output.stderr(`${PRODUCT_TEXT.diagnostic(`${exact} is a release, not a preview; run ${PRODUCT_TEXT.commandName} update to move to the current release.`)}\n`);
@@ -336,7 +336,7 @@ export async function runSelfUpdate(options) {
336
336
  if (resolved.version === null)
337
337
  return resolved.exitCode;
338
338
  const targetVersion = resolved.version;
339
- // No full stop after a version: it already ends in a dot-separated identifier,
339
+ // Rationale: no full stop after a version: it already ends in a dot-separated identifier,
340
340
  // and a trailing one reads as part of the version rather than as punctuation.
341
341
  output.stdout(`${PRODUCT_TEXT.commandName} update: ${runningVersion} → ${targetVersion}\n`);
342
342
  const progress = createUpdateProgress(output, options.progress ?? (options.output === undefined && process.stdout.isTTY === true));
@@ -375,7 +375,7 @@ export async function runSelfUpdate(options) {
375
375
  output.stdout(`${PRODUCT_TEXT.commandName} is up to date — no update needed.\n`);
376
376
  return 0;
377
377
  }
378
- // The bar first appears here so a no-change run never flashes it.
378
+ // Rationale: the bar first appears here so a no-change run never flashes it.
379
379
  progress.set(3, 15);
380
380
  const cohortState = await new CohortStateStore(paths.dataDir).read();
381
381
  transaction = await transactionStore.begin({
@@ -403,7 +403,7 @@ export async function runSelfUpdate(options) {
403
403
  }
404
404
  transaction = await transactionStore.advance("package-installed");
405
405
  }
406
- // npm 12 blocks install scripts unless allowScripts covers the package, so
406
+ // Compatibility: npm 12 blocks install scripts unless allowScripts covers the package, so
407
407
  // the postinstall that points the #pi-tui proxy at the tree npm just built
408
408
  // may never have run. Run the shipped script directly: the proxy must be
409
409
  // correct before the release store copies this tree. A failure is reported
@@ -417,7 +417,7 @@ export async function runSelfUpdate(options) {
417
417
  output.stderr(`${PRODUCT_TEXT.diagnostic(`could not point the #pi-tui proxy at the installed tree: ${errorMessage(error)}`)}\n`);
418
418
  }
419
419
  progress.set(70, 75);
420
- // Ownership can be reacquired after an interrupted installation (for
420
+ // Concurrency: ownership can be reacquired after an interrupted installation (for
421
421
  // example, if bare A1 is launched before the update is resumed). Recheck
422
422
  // immediately before activation so recovery cannot start a second cohort.
423
423
  await measure("ownership-release", async () => { await lifecycle.shutdownVerifiedOwners(targetVersion); });
@@ -530,7 +530,7 @@ async function rollbackPriorCohort(dataDir, environment, priorReleaseId) {
530
530
  }
531
531
  const release = await readMaterializedRelease(prior.releaseRoot);
532
532
  const paths = resolveProductPaths(environment);
533
- // Rollback re-points the active reference and starts the prior cohort on its own endpoint;
533
+ // Invariant: rollback re-points the active reference and starts the prior cohort on its own endpoint;
534
534
  // a cohort that survived the update keeps serving the work it already had.
535
535
  await startSupervisor(release, environment);
536
536
  await waitForVerifiedEndpoint(resolveCohortEndpoint(paths, release.releaseId, environment).endpointMetadataPath, release, 8_000);
@@ -14,6 +14,7 @@ export interface StoredWorkspaceAgent {
14
14
  readonly agent: ManagedAgentDescriptor;
15
15
  readonly presentation: WorkspaceAgentPresentation;
16
16
  }
17
+ /** Owns WAL-backed control persistence and reconciles prior-boot records before current use. */
17
18
  export declare class ControlStore {
18
19
  #private;
19
20
  readonly bootNonce: string | null;
@@ -6,6 +6,7 @@ import { assertManagedAgentDescriptor, assertRecoveryAuthority, assertTerminalSe
6
6
  import { assertLaunchInstance, assertLaunchInstanceOutcome, assertNativeProcessIdentity, assertProcessContainmentIdentity, } from "../lifecycle/index.js";
7
7
  export const DEFAULT_WORKSPACE_ID = "workspace-default";
8
8
  const INITIAL_WORKSPACE_ID = DEFAULT_WORKSPACE_ID;
9
+ /** Owns WAL-backed control persistence and reconciles prior-boot records before current use. */
9
10
  export class ControlStore {
10
11
  bootNonce;
11
12
  database;
@@ -33,6 +33,7 @@ export type StructuredBackpressureReleaseResult = {
33
33
  readonly code: "unknown-lease" | "invalid-request";
34
34
  readonly diagnostic: string;
35
35
  };
36
+ /** Issues bounded resource leases and selects the negotiated backpressure action on exhaustion. */
36
37
  export declare class StructuredBackpressureController {
37
38
  #private;
38
39
  readonly adapterId: string;
@@ -1,4 +1,5 @@
1
1
  import { assertStructuredCapability, } from "../../contracts/workspace/index.js";
2
+ /** Issues bounded resource leases and selects the negotiated backpressure action on exhaustion. */
2
3
  export class StructuredBackpressureController {
3
4
  adapterId;
4
5
  #budgets;
@@ -38,6 +38,7 @@ export type StructuredCommandOutcomeResult = {
38
38
  readonly code: string;
39
39
  readonly diagnostic: string;
40
40
  };
41
+ /** Tracks structured commands by correlation identity through one idempotent terminal outcome. */
41
42
  export declare class StructuredCommandTracker {
42
43
  #private;
43
44
  readonly agentId: string;
@@ -1,4 +1,5 @@
1
1
  import { assertStructuredCapability, assertWorkspaceCommand, } from "../../contracts/workspace/index.js";
2
+ /** Tracks structured commands by correlation identity through one idempotent terminal outcome. */
2
3
  export class StructuredCommandTracker {
3
4
  agentId;
4
5
  #capability;
@@ -30,6 +30,7 @@ export type StructuredReconnectionResult = {
30
30
  readonly code: string;
31
31
  readonly diagnostic: string;
32
32
  };
33
+ /** Accepts a recovery boundary once after validating negotiated identity, proof, and protocol continuity. */
33
34
  export declare class StructuredReconnectionManager {
34
35
  #private;
35
36
  constructor(capability: StructuredCapabilityContract);
@@ -1,5 +1,6 @@
1
1
  import { WORKSPACE_CONTRACT_VERSION, assertRecoveryAuthority, assertStructuredAgentSnapshot, assertStructuredCapability, } from "../../contracts/workspace/index.js";
2
2
  import { StructuredEventReducer } from "./state.js";
3
+ /** Accepts a recovery boundary once after validating negotiated identity, proof, and protocol continuity. */
3
4
  export class StructuredReconnectionManager {
4
5
  #capability;
5
6
  #acceptedBoundaries = new Set();
@@ -44,6 +44,7 @@ export type StructuredSnapshotApplyResult = {
44
44
  readonly code: string;
45
45
  readonly diagnostic: string;
46
46
  };
47
+ /** Applies ordered structured events and snapshots while exposing gaps as explicit resynchronization. */
47
48
  export declare class StructuredEventReducer {
48
49
  #private;
49
50
  readonly agentId: string;
@@ -1,4 +1,5 @@
1
1
  import { assertStructuredAgentSnapshot, assertStructuredCapability, assertWorkspaceEvent, } from "../../contracts/workspace/index.js";
2
+ /** Applies ordered structured events and snapshots while exposing gaps as explicit resynchronization. */
2
3
  export class StructuredEventReducer {
3
4
  agentId;
4
5
  #capability;
@@ -19,7 +19,7 @@ export async function runSupervisor() {
19
19
  throw new Error(PRODUCT_TEXT.diagnostic("supervisor must be launched from a verified immutable release"));
20
20
  const release = await readCertifiedReleaseManifest({ releaseRoot, releaseId, contentDigest }, resolve(paths.dataDir, "releases"));
21
21
  await assertImmutableExecutionRoot(release, paths.dataDir);
22
- // One endpoint per cohort: a superseded cohort keeps serving what it already has while the
22
+ // Protocol: one endpoint per cohort: a superseded cohort keeps serving what it already has while the
23
23
  // installed release listens on its own address.
24
24
  paths = { ...productPaths, ...resolveCohortEndpoint(productPaths, release.releaseId) };
25
25
  const bootNonce = randomUUID();
@@ -2,6 +2,7 @@ import { type SupervisorSnapshot } from "../lifecycle/index.js";
2
2
  import { type MaterializedRelease } from "../release/index.js";
3
3
  import { ControlStore } from "../storage/index.js";
4
4
  import { type ProductPaths } from "./paths.js";
5
+ /** Owns one release-cohort endpoint and the authenticated launch instances registered through it. */
5
6
  export declare class SupervisorServer {
6
7
  #private;
7
8
  readonly store: ControlStore;
@@ -8,6 +8,7 @@ import { processIsAlive } from "../release/index.js";
8
8
  import { ControlStore } from "../storage/index.js";
9
9
  import { resolveProductPaths } from "./paths.js";
10
10
  import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../../product-identity.js";
11
+ /** Owns one release-cohort endpoint and the authenticated launch instances registered through it. */
11
12
  export class SupervisorServer {
12
13
  store;
13
14
  release;
@@ -90,10 +91,7 @@ export class SupervisorServer {
90
91
  this.#supersededPoll = poll;
91
92
  }
92
93
  }
93
- /**
94
- * Notices that another release has become the one new sessions start on. Nothing is
95
- * interrupted by that: this cohort finishes what it is holding and then leaves.
96
- */
94
+ // Invariant: superseding a cohort never interrupts its held instances; it retires only when empty.
97
95
  async #refreshCohortRole() {
98
96
  if (this.#closing || !this.readActiveReleaseId)
99
97
  return;
@@ -327,7 +325,7 @@ export class SupervisorServer {
327
325
  this.#uncertainInstances.delete(stored.id);
328
326
  this.#unbindOwner(stored.id, socket);
329
327
  this.#mutated();
330
- // The last session on a superseded cohort has left; there is nothing here to keep.
328
+ // Invariant: the last session on a superseded cohort has left; there is nothing here to keep.
331
329
  if (this.#superseded && this.#instances.size === 0)
332
330
  void this.retire();
333
331
  }
@@ -421,7 +419,7 @@ export class SupervisorServer {
421
419
  const deadline = Date.now() + timeoutMs;
422
420
  while (Date.now() < deadline) {
423
421
  if (this.#instances.size === 0) {
424
- // Let the terminal command result flush before closing owner sockets.
422
+ // Concurrency: allow the terminal command result to flush before closing owner sockets.
425
423
  await new Promise(resolvePromise => setTimeout(resolvePromise, 25));
426
424
  return this.#instances.size === 0;
427
425
  }
@@ -10,6 +10,7 @@ export interface PiComponentConformanceReport {
10
10
  readonly componentResults: readonly PiComponentConformanceResult[];
11
11
  readonly componentFamilies: readonly string[];
12
12
  }
13
+ /** Identifies the Pi presentation-conformance stage that failed against the pinned component surface. */
13
14
  export declare class PiComponentConformanceError extends Error {
14
15
  readonly stage: "theme" | "components";
15
16
  constructor(stage: "theme" | "components", cause: unknown);
@@ -5,6 +5,7 @@ import { AssistantMessageComponent, ExtensionSelectorComponent, initTheme, Login
5
5
  import { OWNED_UI_CONTRACT_VERSION } from "../../../contracts/owned-ui/index.js";
6
6
  import { createTuiFacade, validatedAssistantMessage } from "./shell-components.js";
7
7
  import { PRODUCT_IDENTITY } from "../../../product-identity.js";
8
+ /** Identifies the Pi presentation-conformance stage that failed against the pinned component surface. */
8
9
  export class PiComponentConformanceError extends Error {
9
10
  stage;
10
11
  constructor(stage, cause) {
@@ -2,6 +2,6 @@ import type { OwnedUiSessionViewModel } from "../../../contracts/owned-ui/index.
2
2
  import { type PiShellViewComponentPort, type PiShellStatusPort, type PiShellQueuedInputPort, type PiShellHeaderPort, type PiShellResourceEntry, type PiShellLoadedResourcesPort, type PiShellHeaderOptions, type PiShellEditorOptions } from "./shell-shared-facade.js";
3
3
  export declare function createPiShellHeader(options?: PiShellHeaderOptions): PiShellHeaderPort;
4
4
  export declare function createPiShellLoadedResources(resources: readonly PiShellResourceEntry[], initialExpanded?: boolean): PiShellLoadedResourcesPort;
5
- export declare function createPiShellStatus(view: OwnedUiSessionViewModel, runtime?: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">): PiShellStatusPort;
5
+ export declare function createPiShellStatus(view: OwnedUiSessionViewModel, formatProgressStatus: (message: string) => string, runtime?: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">): PiShellStatusPort;
6
6
  export declare function createPiShellFooter(view: OwnedUiSessionViewModel, cwd: string): PiShellViewComponentPort;
7
7
  export declare function createPiQueuedInputStatus(submissions: readonly string[], presentation?: "pinned" | "custom-viewport"): PiShellQueuedInputPort;
@@ -67,12 +67,12 @@ export function createPiShellLoadedResources(resources, initialExpanded = false)
67
67
  invalidate() { },
68
68
  };
69
69
  }
70
- export function createPiShellStatus(view, runtime) {
70
+ export function createPiShellStatus(view, formatProgressStatus, runtime) {
71
71
  ensureTheme();
72
72
  const statusUi = createTuiFacade(runtime ?? { getColumns: () => 80, getRows: () => 24, requestRender() { } });
73
73
  let workingOverride;
74
74
  let outputPad = PINNED_PI_LAYOUT.outputPad;
75
- let component = statusComponent(view, statusUi, workingOverride, outputPad);
75
+ let component = statusComponent(view, statusUi, workingOverride, outputPad, formatProgressStatus);
76
76
  let signature = statusSignature(view, workingOverride, outputPad);
77
77
  const rebuild = () => {
78
78
  const nextSignature = statusSignature(view, workingOverride, outputPad);
@@ -81,7 +81,7 @@ export function createPiShellStatus(view, runtime) {
81
81
  if (component !== undefined && "dispose" in component && typeof component.dispose === "function")
82
82
  component.dispose();
83
83
  signature = nextSignature;
84
- component = statusComponent(view, statusUi, workingOverride, outputPad);
84
+ component = statusComponent(view, statusUi, workingOverride, outputPad, formatProgressStatus);
85
85
  };
86
86
  return {
87
87
  render: width => component?.render(width) ?? [],
@@ -126,9 +126,10 @@ export function createPiQueuedInputStatus(submissions, presentation = "pinned")
126
126
  },
127
127
  };
128
128
  }
129
- function statusComponent(view, ui, workingOverride, outputPad) {
130
- if (view.lifecycle === "busy")
131
- return new WorkingStatusIndicator(ui, workingOverride ?? view.status.workingMessage ?? "Working...");
129
+ function statusComponent(view, ui, workingOverride, outputPad, formatProgressStatus) {
130
+ if (view.lifecycle === "busy") {
131
+ return new WorkingStatusIndicator(ui, formatProgressStatus(workingOverride ?? view.status.workingMessage ?? "Working"));
132
+ }
132
133
  if (view.lifecycle === "failed") {
133
134
  return new Text(piTheme().fg("error", view.status.diagnostics.at(-1) ?? "Session failed"), outputPad, 0);
134
135
  }
@@ -149,7 +150,7 @@ function queuedInputText(submissions, presentation) {
149
150
  }
150
151
  const messages = submissions.map(submission => theme.fg("dim", `Steering: ${submission.replaceAll("\n", " ⏎ ")}`));
151
152
  const dequeueHint = theme.fg("dim", "↳ Alt+Up to edit all queued messages");
152
- // The custom viewport matches Pi's interactive queue presentation while the
153
+ // Compatibility: the custom viewport matches Pi's interactive queue presentation while the
153
154
  // comparison shell remains byte-for-byte compatible with its pinned fixture.
154
155
  return ["", ...messages, dequeueHint].join("\n");
155
156
  }
@@ -3,7 +3,7 @@ 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. */
5
5
  export const piShellVisibleWidth = visibleWidth;
6
- // Pinned from packages/coding-agent/src/core/slash-commands.ts at 914cf14.
6
+ // Provenance: pinned from packages/coding-agent/src/core/slash-commands.ts at 914cf14.
7
7
  export function createTuiFacade(options) {
8
8
  const children = [];
9
9
  const terminal = {
@@ -46,6 +46,11 @@ export interface PiTreeSelectorContext {
46
46
  readonly skipSummaryPrompt: boolean;
47
47
  readonly appendLabelChange: (entryId: string, label: string | undefined) => void;
48
48
  }
49
+ export interface PiSessionResumeMetadata {
50
+ readonly sessionId: string;
51
+ readonly sessionDir: string;
52
+ readonly usesDefaultSessionDir: boolean;
53
+ }
49
54
  export interface PiSessionSelectorContext {
50
55
  readonly currentSessionFilePath: string | undefined;
51
56
  readonly loadCurrentSessions: (onProgress?: (loaded: number, total: number) => void) => Promise<SessionInfo[]>;
@@ -116,6 +121,7 @@ export interface AdapterCommandResult {
116
121
  readonly outcome: OwnedUiCommandOutcome;
117
122
  readonly diagnostic: string | null;
118
123
  }
124
+ /** Owns the pinned Pi session lifecycle and translates its events into the neutral agent-engine contract. */
119
125
  export declare class PiEngineAdapter {
120
126
  #private;
121
127
  constructor(options?: PiEngineAdapterOptions);
@@ -125,6 +131,7 @@ export declare class PiEngineAdapter {
125
131
  get agentDir(): string;
126
132
  resolveTranscriptImage(assetId: string): OwnedUiImageAttachment | null;
127
133
  currentSessionFile(): string | null;
134
+ currentSessionResumeMetadata(): PiSessionResumeMetadata | null;
128
135
  get disposed(): boolean;
129
136
  start(): Promise<OwnedUiSessionViewModel>;
130
137
  onEvent(listener: (event: OwnedUiEvent) => void): () => void;
@@ -18,7 +18,7 @@ const execFileAsync = promisify(execFile);
18
18
  * that a streaming burst never holds input, large enough that an ordinary turn is one
19
19
  * batch.
20
20
  */
21
- // Deliver at most one engine event per event-loop turn. Transcript updates can
21
+ // Performance: deliver at most one engine event per event-loop turn. Transcript updates can
22
22
  // be expensive in long sessions; a larger synchronous batch starves terminal
23
23
  // input and makes an in-progress mouse selection appear frozen.
24
24
  const EVENT_DELIVERY_BATCH = 1;
@@ -29,6 +29,7 @@ const DEFAULT_SURFACE = {
29
29
  focusedRegion: "editor",
30
30
  hardwareCursor: false,
31
31
  };
32
+ /** Owns the pinned Pi session lifecycle and translates its events into the neutral agent-engine contract. */
32
33
  export class PiEngineAdapter {
33
34
  #runtimeFactory;
34
35
  #checkPackageUpdates;
@@ -92,7 +93,6 @@ export class PiEngineAdapter {
92
93
  #projectTrustPrompt;
93
94
  #settingsIntegration;
94
95
  #settingsIntegrationManager;
95
- /** Lists the themes installed on this machine, when the caller supplies one. */
96
96
  #availableThemes;
97
97
  constructor(options = {}) {
98
98
  this.#cwd = options.cwd ?? process.cwd();
@@ -129,6 +129,22 @@ export class PiEngineAdapter {
129
129
  const value = this.#session?.sessionManager?.getSessionFile?.();
130
130
  return typeof value === "string" && value.length > 0 ? value : null;
131
131
  }
132
+ currentSessionResumeMetadata() {
133
+ const manager = this.#session?.sessionManager;
134
+ if (manager === undefined
135
+ || typeof manager.isPersisted !== "function"
136
+ || typeof manager.getSessionId !== "function"
137
+ || typeof manager.getSessionDir !== "function"
138
+ || typeof manager.usesDefaultSessionDir !== "function"
139
+ || manager.isPersisted() !== true
140
+ || this.currentSessionFile() === null)
141
+ return null;
142
+ const sessionId = manager.getSessionId();
143
+ const sessionDir = manager.getSessionDir();
144
+ if (!sessionId || !sessionDir)
145
+ return null;
146
+ return { sessionId, sessionDir, usesDefaultSessionDir: manager.usesDefaultSessionDir() };
147
+ }
132
148
  get disposed() {
133
149
  return this.#disposed;
134
150
  }
@@ -502,7 +518,7 @@ export class PiEngineAdapter {
502
518
  } },
503
519
  });
504
520
  this.#settingsIntegration.bindOwner("startup", {
505
- // Deferred application is the owner operation: the next preflight reads
521
+ // Invariant: deferred application is the owner operation: the next preflight reads
506
522
  // the persisted default before constructing project-backed services.
507
523
  defaultProjectTrust: { apply() { } },
508
524
  collapseChangelog: { apply() { } },
@@ -541,7 +557,7 @@ export class PiEngineAdapter {
541
557
  httpIdleTimeoutMs: { apply: value => {
542
558
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
543
559
  throw new TypeError("HTTP idle timeout is invalid");
544
- // Provider streaming reads the manager per request; global fetch uses
560
+ // Invariant: provider streaming reads the manager per request; global fetch uses
545
561
  // the matching owned dispatcher and zero maps to disabled semantics.
546
562
  configureOwnedHttpDispatcher(value);
547
563
  settings.setHttpIdleTimeoutMs(value);
@@ -1550,11 +1566,7 @@ export class PiEngineAdapter {
1550
1566
  this.#emitView();
1551
1567
  }
1552
1568
  }
1553
- /**
1554
- * Replaces the transcript and the index that finds a block by its identifier. Every
1555
- * lookup goes through the index, so streaming a chunk costs the same in a long session
1556
- * as in a new one.
1557
- */
1569
+ // Performance: replacing the transcript rebuilds its index so block lookup stays constant-time.
1558
1570
  #setTranscript(blocks) {
1559
1571
  this.#transcript = blocks;
1560
1572
  this.#transcriptIndex.clear();
@@ -1571,7 +1583,7 @@ export class PiEngineAdapter {
1571
1583
  const index = this.#transcriptIndex.get(id);
1572
1584
  return index === undefined ? undefined : this.#transcript[index];
1573
1585
  }
1574
- /** Shows the state named by `kind`, which becomes the state a later end can clear. */
1586
+ // Invariant: the named work state is the only state a matching end may clear.
1575
1587
  #enterWorkState(kind, message) {
1576
1588
  const wasBusy = this.#lifecycle === "busy";
1577
1589
  this.#statusKind = kind;
@@ -1581,21 +1593,16 @@ export class PiEngineAdapter {
1581
1593
  this.#emitEvent({ type: "session-lifecycle", lifecycle: "busy", reason: null });
1582
1594
  this.#emitEvent({ type: "status", status: this.#status });
1583
1595
  }
1584
- /**
1585
- * Ends one named state. A state the shell is not in is left alone, so a finished
1586
- * compaction or retry cannot clear the working state it never replaced. While the run
1587
- * continues, ending either of those returns to working rather than to idle.
1588
- */
1596
+ // Invariant: ending retry or compaction cannot clear a different active work state.
1589
1597
  #endWorkState(kind) {
1590
1598
  if (this.#statusKind !== kind)
1591
1599
  return;
1592
1600
  if (this.#agentRunActive) {
1593
- this.#enterWorkState("working", "Working...");
1601
+ this.#enterWorkState("working", "Working");
1594
1602
  return;
1595
1603
  }
1596
1604
  this.#leaveWorkStates();
1597
1605
  }
1598
- /** Leaves every work state and reports the session idle. */
1599
1606
  #leaveWorkStates() {
1600
1607
  this.#statusKind = null;
1601
1608
  this.#lifecycle = "ready";
@@ -1606,7 +1613,7 @@ export class PiEngineAdapter {
1606
1613
  #handlePiEvent(event) {
1607
1614
  if (!isRecord(event) || typeof event.type !== "string")
1608
1615
  return;
1609
- // Usage moves at message and lifecycle boundaries, not with stream chunks, so the
1616
+ // Invariant: usage moves at message and lifecycle boundaries, not with stream chunks, so the
1610
1617
  // two streaming event kinds keep the memo and everything else drops it.
1611
1618
  if (event.type !== "message_update" && event.type !== "tool_execution_update")
1612
1619
  this.#usageCache = undefined;
@@ -1614,7 +1621,7 @@ export class PiEngineAdapter {
1614
1621
  case "agent_start":
1615
1622
  this.#agentRunActive = true;
1616
1623
  this.#emitEvent({ type: "agent-run-started" });
1617
- this.#enterWorkState("working", "Working...");
1624
+ this.#enterWorkState("working", "Working");
1618
1625
  return;
1619
1626
  case "message_start":
1620
1627
  this.#upsertMessageBlock(event.message, "live");
@@ -1623,7 +1630,7 @@ export class PiEngineAdapter {
1623
1630
  const delta = isRecord(event.assistantMessageEvent) && typeof event.assistantMessageEvent.delta === "string"
1624
1631
  ? event.assistantMessageEvent.delta
1625
1632
  : undefined;
1626
- // The delta is folded in before the block is stored, so a chunk is one update to
1633
+ // Invariant: the delta is folded in before the block is stored, so a chunk is one update to
1627
1634
  // one block rather than a store without the delta followed by a store with it.
1628
1635
  const blocks = this.#messageBlocks(event.message, "live", this.#transcript.length);
1629
1636
  for (const [index, block] of blocks.entries()) {
@@ -1635,7 +1642,7 @@ export class PiEngineAdapter {
1635
1642
  }
1636
1643
  case "message_end":
1637
1644
  this.#upsertMessageBlock(event.message, "finalized");
1638
- // Preserve the same semantic boundary v2 counted. Transcript block
1645
+ // Compatibility: preserve the same semantic boundary v2 counted. Transcript block
1639
1646
  // finalization is intentionally not a substitute: rebuilds, retries,
1640
1647
  // thinking parts, and tool rows can all finalize independently.
1641
1648
  if (isRecord(event.message) && event.message.role === "assistant") {
@@ -1651,7 +1658,7 @@ export class PiEngineAdapter {
1651
1658
  return;
1652
1659
  case "tool_execution_start":
1653
1660
  case "tool_execution_end": {
1654
- // The end supersedes any update still waiting on the coalescing timer.
1661
+ // Concurrency: the end supersedes any update still waiting on the coalescing timer.
1655
1662
  const toolCallId = stringValue(event.toolCallId);
1656
1663
  if (toolCallId !== undefined)
1657
1664
  this.#pendingToolUpdates.delete(toolCallId);
@@ -1672,7 +1679,7 @@ export class PiEngineAdapter {
1672
1679
  this.#rebuildTranscript(finalMessages, "finalized");
1673
1680
  else
1674
1681
  this.#setTranscript(this.#transcript.map(block => block.status === "live" ? { ...block, status: "finalized" } : block));
1675
- // Ending a turn leaves the working state, as the recorded pinned baseline does, but
1682
+ // Compatibility: ending a turn leaves the working state, as the recorded pinned baseline does, but
1676
1683
  // it leaves only that state: a compaction or retry being shown outlives the turn
1677
1684
  // that ended under it. Settlement ends the run, and with it every state — the
1678
1685
  // engine ends a turn for each continuation it makes and settles once.
@@ -1698,13 +1705,13 @@ export class PiEngineAdapter {
1698
1705
  return;
1699
1706
  }
1700
1707
  case "auto_retry_start":
1701
- this.#enterWorkState("retry", "Retrying");
1708
+ this.#enterWorkState("retry", "Retrying");
1702
1709
  return;
1703
1710
  case "auto_retry_end":
1704
1711
  this.#endWorkState("retry");
1705
1712
  return;
1706
1713
  case "compaction_start":
1707
- this.#enterWorkState("compaction", "Compacting");
1714
+ this.#enterWorkState("compaction", "Compacting");
1708
1715
  return;
1709
1716
  case "compaction_end":
1710
1717
  this.#endWorkState("compaction");
@@ -1797,7 +1804,7 @@ export class PiEngineAdapter {
1797
1804
  }
1798
1805
  }
1799
1806
  }
1800
- // An authoritative rebuild restates most of what is already there. Reusing the block
1807
+ // Performance: an authoritative rebuild restates most of what is already there. Reusing the block
1801
1808
  // that already says it keeps its revision, and with it the rows the shell rendered for
1802
1809
  // it — otherwise every turn that ends re-renders the whole session.
1803
1810
  this.#setTranscript(blocks.map(block => {
@@ -1976,12 +1983,7 @@ export class PiEngineAdapter {
1976
1983
  }
1977
1984
  return references;
1978
1985
  }
1979
- /**
1980
- * A busy tool streams far more output chunks than a terminal frame can show, and every
1981
- * chunk restates the whole accumulated output. Keeping only the newest chunk per tool
1982
- * and applying it on a short timer bounds the per-command work by frames rather than
1983
- * by chunks, which is what keeps typed input and the spinner alive under the stream.
1984
- */
1986
+ // Performance: coalescing each tool to its newest chunk bounds work by frames, not stream events.
1985
1987
  #coalesceToolExecutionUpdate(event) {
1986
1988
  const toolCallId = stringValue(event.toolCallId);
1987
1989
  if (!toolCallId)
@@ -2024,7 +2026,7 @@ export class PiEngineAdapter {
2024
2026
  toolCallId,
2025
2027
  toolName: stringValue(event.toolName) ?? "unknown",
2026
2028
  arguments: jsonSummary(event.args),
2027
- // A partial result repeats the whole accumulated output on every chunk;
2029
+ // Performance: a partial result repeats the whole accumulated output on every chunk;
2028
2030
  // summarizing it each time would cost quadratic work over the stream.
2029
2031
  result: ended ? jsonSummary(source) : { summary: "", json: null },
2030
2032
  partialResult: event.type === "tool_execution_update",
@@ -2037,7 +2039,7 @@ export class PiEngineAdapter {
2037
2039
  const index = this.#transcriptIndex.get(block.id);
2038
2040
  if (index !== undefined) {
2039
2041
  const existing = this.#transcript[index];
2040
- // Nothing to tell the shell about a block that repeats itself, and keeping the
2042
+ // Performance: nothing is emitted for a block that repeats itself, and keeping the
2041
2043
  // revision keeps the rows it already rendered.
2042
2044
  if (existing !== undefined && sameBlockContent(existing, block))
2043
2045
  return;
@@ -2154,7 +2156,7 @@ export class PiEngineAdapter {
2154
2156
  }
2155
2157
  }
2156
2158
  deliveredSinceYield += 1;
2157
- // A microtask chain runs to exhaustion before the loop turns, so a streaming
2159
+ // Concurrency: a microtask chain runs to exhaustion before the loop turns, so a streaming
2158
2160
  // burst would hold typed input, pointer reports, and timed indicators until it
2159
2161
  // drained. Yielding on a macrotask hands those their turn between batches.
2160
2162
  if (deliveredSinceYield >= EVENT_DELIVERY_BATCH && this.#eventQueue.length > 0) {
@@ -13,6 +13,7 @@ export declare const REQUIRED_PI_CAPABILITY_OPERATIONS: Readonly<{
13
13
  readonly workflows: readonly ["workflow.route", "workflow.validate", "workflow.diagnostics"];
14
14
  readonly disposal: readonly ["subscription.dispose", "session.dispose", "services.cleanup"];
15
15
  }>;
16
+ /** Identifies one required Pi capability operation that differs from the accepted integration contract. */
16
17
  export declare class PiCapabilityCompatibilityError extends Error {
17
18
  readonly packageVersion: string;
18
19
  readonly capability: string;
@@ -29,6 +30,7 @@ export interface PiUpgradeConformanceReport {
29
30
  readonly commandSurface: readonly string[];
30
31
  readonly capabilities: readonly PiCapabilityConformanceResult[];
31
32
  }
33
+ /** Identifies the public Pi SDK stage that failed during upgrade conformance. */
32
34
  export declare class PiUpgradeConformanceError extends Error {
33
35
  readonly stage: "exports" | "services" | "session";
34
36
  constructor(stage: "exports" | "services" | "session", cause: unknown);
@@ -14,6 +14,7 @@ export const REQUIRED_PI_CAPABILITY_OPERATIONS = Object.freeze({
14
14
  workflows: ["workflow.route", "workflow.validate", "workflow.diagnostics"],
15
15
  disposal: ["subscription.dispose", "session.dispose", "services.cleanup"],
16
16
  });
17
+ /** Identifies one required Pi capability operation that differs from the accepted integration contract. */
17
18
  export class PiCapabilityCompatibilityError extends Error {
18
19
  packageVersion;
19
20
  capability;
@@ -26,6 +27,7 @@ export class PiCapabilityCompatibilityError extends Error {
26
27
  this.name = "PiCapabilityCompatibilityError";
27
28
  }
28
29
  }
30
+ /** Identifies the public Pi SDK stage that failed during upgrade conformance. */
29
31
  export class PiUpgradeConformanceError extends Error {
30
32
  stage;
31
33
  constructor(stage, cause) {
@@ -1,4 +1,4 @@
1
- // Mechanically adapted from Pi commit 914cf14
1
+ // Provenance: mechanically adapted from Pi commit 914cf14
2
2
  // packages/coding-agent/src/core/http-dispatcher.ts (MIT).
3
3
  // Local modifications: expose only A1's owned timeout seam and retain no private Pi imports.
4
4
  import { EnvHttpProxyAgent, install, setGlobalDispatcher } from "undici";
@@ -9,6 +9,7 @@ export interface PiModelAuthenticationOptions {
9
9
  readonly timeoutMs?: number;
10
10
  readonly scopedModelIds?: () => readonly string[] | undefined;
11
11
  }
12
+ /** Adapts the pinned model runtime to neutral model selection and authentication operations. */
12
13
  export declare class PiModelAuthenticationIntegration implements AgentModelPort, AgentAuthenticationPort {
13
14
  #private;
14
15
  private readonly options;