@timurproko/a1 0.2.7-dev.788 → 0.2.7-dev.794

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 (135) hide show
  1. package/dist/app/session-shell/session-shell-root.d.ts +2 -1
  2. package/dist/app/session-shell/session-shell-root.js +41 -15
  3. package/dist/app/session-shell/session-shell.d.ts +1 -0
  4. package/dist/app/session-shell/session-shell.js +15 -4
  5. package/dist/app/session-shell/session-viewport-controller.d.ts +2 -2
  6. package/dist/app/session-shell/session-viewport-controller.js +24 -12
  7. package/dist/cli/tabs.js +1 -1
  8. package/dist/composition/owned-ui.d.ts +2 -0
  9. package/dist/composition/owned-ui.js +42 -4
  10. package/dist/contracts/owned-ui/index.d.ts +1 -1
  11. package/dist/contracts/owned-ui/model.d.ts +3 -0
  12. package/dist/features/owned-ui/settings-app.js +9 -6
  13. package/dist/features/resident-tab/index.d.ts +3 -1
  14. package/dist/features/resident-tab/index.js +5 -1
  15. package/dist/features/resident-tab/shortcut-bindings-file.d.ts +8 -0
  16. package/dist/features/resident-tab/shortcut-bindings-file.js +40 -0
  17. package/dist/features/resident-tab/shortcut-declarations.d.ts +13 -0
  18. package/dist/features/resident-tab/{shortcuts.js → shortcut-declarations.js} +6 -17
  19. package/dist/features/resident-tab/shortcut-projection.d.ts +29 -0
  20. package/dist/features/resident-tab/shortcut-projection.js +64 -0
  21. package/dist/foundation/launch-guardian/exit-watcher.d.ts +14 -0
  22. package/dist/foundation/launch-guardian/exit-watcher.js +94 -0
  23. package/dist/foundation/launch-guardian/main.d.ts +2 -1
  24. package/dist/foundation/launch-guardian/main.js +58 -6
  25. package/dist/foundation/process-containment/{native-guardian-containment.d.ts → addon-containment.d.ts} +7 -5
  26. package/dist/foundation/process-containment/addon-containment.js +139 -0
  27. package/dist/foundation/process-containment/addon-process-inspector.d.ts +11 -0
  28. package/dist/foundation/process-containment/addon-process-inspector.js +36 -0
  29. package/dist/foundation/process-containment/addon.d.ts +42 -0
  30. package/dist/foundation/process-containment/addon.js +57 -0
  31. package/dist/foundation/process-containment/artifact.d.ts +1 -1
  32. package/dist/foundation/process-containment/artifact.js +6 -5
  33. package/dist/foundation/process-containment/contracts.d.ts +2 -0
  34. package/dist/foundation/process-containment/index.d.ts +4 -4
  35. package/dist/foundation/process-containment/index.js +3 -3
  36. package/dist/foundation/process-containment/native-process-inspector.d.ts +2 -1
  37. package/dist/foundation/process-containment/native-process-inspector.js +10 -10
  38. package/dist/foundation/release/bootstrap.js +54 -16
  39. package/dist/foundation/release/index.d.ts +1 -1
  40. package/dist/foundation/release/index.js +1 -1
  41. package/dist/foundation/release/release-store.d.ts +12 -0
  42. package/dist/foundation/release/release-store.js +124 -2
  43. package/dist/foundation/resident-tabs/bounded-host-command.d.ts +3 -1
  44. package/dist/foundation/resident-tabs/bounded-host-command.js +6 -2
  45. package/dist/foundation/resident-tabs/bridge-client.d.ts +7 -0
  46. package/dist/foundation/resident-tabs/bridge-client.js +30 -1
  47. package/dist/foundation/resident-tabs/doctor.d.ts +0 -1
  48. package/dist/foundation/resident-tabs/doctor.js +4 -4
  49. package/dist/foundation/resident-tabs/ensure-terminal-host.d.ts +7 -2
  50. package/dist/foundation/resident-tabs/ensure-terminal-host.js +15 -11
  51. package/dist/foundation/resident-tabs/host-entry.d.ts +1 -0
  52. package/dist/foundation/resident-tabs/host-entry.js +17 -0
  53. package/dist/foundation/resident-tabs/index.d.ts +2 -2
  54. package/dist/foundation/resident-tabs/index.js +1 -1
  55. package/dist/foundation/resident-tabs/maintenance.d.ts +5 -4
  56. package/dist/foundation/resident-tabs/maintenance.js +32 -17
  57. package/dist/foundation/resident-tabs/prompt-journal.d.ts +0 -2
  58. package/dist/foundation/resident-tabs/prompt-journal.js +0 -1
  59. package/dist/foundation/resident-tabs/release-holds.d.ts +3 -2
  60. package/dist/foundation/resident-tabs/release-holds.js +16 -7
  61. package/dist/foundation/resident-tabs/settings.d.ts +0 -1
  62. package/dist/foundation/resident-tabs/settings.js +1 -7
  63. package/dist/foundation/resident-tabs/terminal-host-artifact.d.ts +11 -15
  64. package/dist/foundation/resident-tabs/terminal-host-artifact.js +57 -32
  65. package/dist/foundation/session-writer-lock/index.d.ts +1 -3
  66. package/dist/foundation/session-writer-lock/index.js +8 -6
  67. package/dist/integrations/pi/components/owned-editor-ux.d.ts +2 -0
  68. package/dist/integrations/pi/components/owned-editor-ux.js +13 -0
  69. package/dist/integrations/pi/components/shell-editor-autocomplete.js +3 -1
  70. package/dist/integrations/pi/components/shell-presenters-info.d.ts +1 -0
  71. package/dist/integrations/pi/components/shell-presenters-info.js +10 -30
  72. package/dist/integrations/pi/components/shell-shared-facade.d.ts +4 -0
  73. package/dist/native/darwin-arm64/manifest.json +10 -7
  74. package/dist/native/darwin-arm64/process-guardian.node +0 -0
  75. package/dist/native/darwin-arm64/terminal-host-THIRD-PARTY-NOTICES.txt +1 -1
  76. package/dist/native/darwin-arm64/terminal-host.manifest.json +16 -14
  77. package/dist/native/darwin-arm64/terminal-host.node +0 -0
  78. package/dist/native/darwin-x64/manifest.json +10 -7
  79. package/dist/native/darwin-x64/process-guardian.node +0 -0
  80. package/dist/native/darwin-x64/terminal-host-THIRD-PARTY-NOTICES.txt +1 -1
  81. package/dist/native/darwin-x64/terminal-host.manifest.json +16 -14
  82. package/dist/native/darwin-x64/terminal-host.node +0 -0
  83. package/dist/native/linux-x64/manifest.json +10 -7
  84. package/dist/native/linux-x64/process-guardian.node +0 -0
  85. package/dist/native/linux-x64/terminal-host-THIRD-PARTY-NOTICES.txt +1 -1
  86. package/dist/native/linux-x64/terminal-host.manifest.json +16 -14
  87. package/dist/native/linux-x64/terminal-host.node +0 -0
  88. package/dist/native/win32-x64/manifest.json +10 -7
  89. package/dist/native/win32-x64/process-guardian.node +0 -0
  90. package/dist/native/win32-x64/terminal-host-THIRD-PARTY-NOTICES.txt +1 -1
  91. package/dist/native/win32-x64/terminal-host.manifest.json +16 -14
  92. package/dist/native/win32-x64/terminal-host.node +0 -0
  93. package/dist/product-identity.d.ts +1 -1
  94. package/dist/product-identity.js +1 -1
  95. package/dist/product-identity.json +3 -2
  96. package/dist/runtime-payload-inventory.json +1 -0
  97. package/dist/ui/components/index.d.ts +2 -2
  98. package/dist/ui/components/index.js +1 -1
  99. package/dist/ui/components/selection-copy.d.ts +2 -0
  100. package/dist/ui/components/selection-copy.js +13 -0
  101. package/dist/ui/components/submitted-prompt.d.ts +7 -4
  102. package/dist/ui/components/submitted-prompt.js +18 -10
  103. package/dist/ui/components/transcript-viewport.d.ts +10 -6
  104. package/dist/ui/components/transcript-viewport.js +28 -13
  105. package/dist/ui/settings/declarations.d.ts +13 -13
  106. package/dist/ui/settings/declarations.js +12 -11
  107. package/dist/ui/settings/migrations.js +7 -0
  108. package/docs/architecture/boundaries.md +10 -9
  109. package/docs/architecture/evidence/resident-tabs/macos-x64.md +1 -1
  110. package/docs/architecture/process-guardian-provenance.md +17 -11
  111. package/docs/architecture/project-structure.md +8 -0
  112. package/docs/architecture/resident-tabs.md +54 -36
  113. package/docs/architecture/terminal-host-provenance.md +6 -4
  114. package/docs/architecture/toolchain.md +6 -6
  115. package/docs/openspec-archive-automation.md +3 -3
  116. package/docs/validation.md +7 -3
  117. package/package.json +1 -1
  118. package/dist/features/resident-tab/shortcuts.d.ts +0 -10
  119. package/dist/foundation/process-containment/darwin-process-inspector.d.ts +0 -5
  120. package/dist/foundation/process-containment/darwin-process-inspector.js +0 -7
  121. package/dist/foundation/process-containment/native-guardian-containment.js +0 -152
  122. package/dist/foundation/process-containment/windows-process-inspector.d.ts +0 -19
  123. package/dist/foundation/process-containment/windows-process-inspector.js +0 -56
  124. package/dist/native/darwin-arm64/a1_session_lock.node +0 -0
  125. package/dist/native/darwin-arm64/process-guardian +0 -0
  126. package/dist/native/darwin-arm64/terminal-host +0 -0
  127. package/dist/native/darwin-x64/a1_session_lock.node +0 -0
  128. package/dist/native/darwin-x64/process-guardian +0 -0
  129. package/dist/native/darwin-x64/terminal-host +0 -0
  130. package/dist/native/linux-x64/a1_session_lock.node +0 -0
  131. package/dist/native/linux-x64/process-guardian +0 -0
  132. package/dist/native/linux-x64/terminal-host +0 -0
  133. package/dist/native/win32-x64/a1_session_lock.node +0 -0
  134. package/dist/native/win32-x64/process-guardian.exe +0 -0
  135. package/dist/native/win32-x64/terminal-host.exe +0 -0
@@ -1,20 +1,23 @@
1
1
  {
2
- "schema": "a1-process-guardian-artifact-v1",
3
- "protocolVersion": 1,
2
+ "schema": "a1-process-guardian-artifact-v2",
3
+ "kind": "node-addon",
4
+ "nodeApi": 9,
5
+ "protocolVersion": 2,
4
6
  "crateVersion": "0.1.0-dev",
5
7
  "platform": "win32",
6
8
  "architecture": "x64",
7
9
  "capability": "supported",
8
- "builtAt": "2026-10-16T17:09:00.247Z",
10
+ "builtAt": "2026-10-18T08:41:31.607Z",
9
11
  "artifact": {
10
- "filename": "process-guardian.exe",
11
- "sha256": "22cad9088f307ea7c98eb992e56f0a9bda111ea14d42d478f1a6ec0216da75d4",
12
- "size": 288256
12
+ "filename": "process-guardian.node",
13
+ "sha256": "6299956800f1ab62f2e5bb4a1e4d61dbd45ce70a7711cbb9aca8f23033bdbbaf",
14
+ "size": 402432
13
15
  },
14
16
  "provenance": {
15
17
  "language": "Rust",
16
18
  "cargoLock": "native/process-guardian/Cargo.lock",
17
19
  "sourceRoot": "native/process-guardian",
18
- "signatureStatus": "ci-attestation-required"
20
+ "signatureStatus": "ci-attestation-required",
21
+ "identityCheck": "executed"
19
22
  }
20
23
  }
@@ -1,6 +1,6 @@
1
1
  Third-party notices for the A1 terminal host
2
2
 
3
- The terminal-host executable and its session-writer lock include the following components.
3
+ The terminal-host Node-API addon includes the following components.
4
4
 
5
5
  ==============================================================================
6
6
  anyhow 1.0.104
@@ -1,5 +1,7 @@
1
1
  {
2
- "schema": "a1-terminal-host-artifact-v1",
2
+ "schema": "a1-terminal-host-artifact-v2",
3
+ "kind": "node-addon",
4
+ "nodeApi": 9,
3
5
  "protocolVersion": 1,
4
6
  "generation": 1,
5
7
  "crateVersion": "0.1.0-dev",
@@ -7,21 +9,21 @@
7
9
  "architecture": "x64",
8
10
  "target": "x86_64-pc-windows-msvc",
9
11
  "capability": "supported",
10
- "builtAt": "2026-10-16T17:13:44.310Z",
12
+ "builtAt": "2026-10-18T08:44:54.428Z",
11
13
  "artifact": {
12
- "filename": "terminal-host.exe",
13
- "sha256": "8a75c5c5d1ca1b7e5d1e42eef4342f76037fc6d2962c2ca6f00c78abb6a7693e",
14
- "size": 5219840
14
+ "filename": "terminal-host.node",
15
+ "sha256": "de82227898a90a6ec6bda0c8b503148388d3769ef4ab7f1176e56c8472b76232",
16
+ "size": 5617664
15
17
  },
16
- "sessionLock": {
17
- "filename": "a1_session_lock.node",
18
- "sha256": "41e23a5a2d65943bfc82fca6f9f3eb0b3169dcbe7181dbc848de015675639790",
19
- "size": 1996288
18
+ "entry": {
19
+ "filename": "dist/foundation/resident-tabs/host-entry.js",
20
+ "sha256": "4b1f702cc9980ffa531cf3e9963b884eaa35120d04d5c195ea3308f501d8d557",
21
+ "size": 1315
20
22
  },
21
23
  "notices": {
22
24
  "filename": "terminal-host-THIRD-PARTY-NOTICES.txt",
23
- "sha256": "9e80136b62106ac672162dacbd0d6eb2a94b3318e597e40dfcf70c4920c34b00",
24
- "size": 555140
25
+ "sha256": "127b8634dc7f47d9b8c250ff281e028daeac7729290da4f41cf1a1eeafdb76ca",
26
+ "size": 555117
25
27
  },
26
28
  "provenance": {
27
29
  "language": "Rust",
@@ -34,11 +36,11 @@
34
36
  "zigVersion": "0.15.2",
35
37
  "rustVersion": "rustc 1.99.1 (58cf8f9c3 2026-10-13)",
36
38
  "features": {
37
- "executable": [],
38
- "sessionLock": [
39
+ "addon": [
39
40
  "node-addon"
40
41
  ]
41
42
  },
42
- "signatureStatus": "ci-attestation-required"
43
+ "signatureStatus": "ci-attestation-required",
44
+ "identityCheck": "executed"
43
45
  }
44
46
  }
@@ -5,7 +5,7 @@ declare const ENDPOINT_KEYS: readonly ["windowsPipeStem", "unixSocketFilename",
5
5
  declare const MANIFEST_KEYS: readonly ["releaseFilename", "packageFilename"];
6
6
  declare const PROTOCOL_KEYS: readonly ["namespace", "controlEnvelope", "supervisorSchema", "nativeHostSchema", "structuredAgentSchema", "controlStoreSchema", "promptHistorySchema", "releaseCohortSchema", "updateJournalSchema"];
7
7
  declare const EVIDENCE_KEYS: readonly ["nativeSpikeSchema", "terminalProvenanceSchema", "terminalProofSchema", "stableReleaseSchema", "previewReleaseSchema", "releaseCertificationSchema", "previewPlatformVerdictSchema", "piSourceLedgerSchema", "piComponentParitySchema", "piEventFrameParitySchema", "startupTraceSchema", "dependencyLayerSchema", "dependencyLayerCertificationSchema", "runtimePayloadSchema"];
8
- declare const ARTIFACT_KEYS: readonly ["cliEntry", "supervisorEntry", "guardianEntry", "uiEntry", "nativeExecutable", "nativeCrate", "processGuardianExecutable", "releaseTarballStem", "diagnosticStem"];
8
+ declare const ARTIFACT_KEYS: readonly ["cliEntry", "supervisorEntry", "guardianEntry", "uiEntry", "terminalHostAddon", "terminalHostEntry", "nativeCrate", "processGuardianAddon", "releaseTarballStem", "diagnosticStem"];
9
9
  type StringRecord<Keys extends readonly string[]> = {
10
10
  readonly [Key in Keys[number]]: string;
11
11
  };
@@ -9,7 +9,7 @@ const ENDPOINT_KEYS = ["windowsPipeStem", "unixSocketFilename", "metadataFilenam
9
9
  const MANIFEST_KEYS = ["releaseFilename", "packageFilename"];
10
10
  const PROTOCOL_KEYS = ["namespace", "controlEnvelope", "supervisorSchema", "nativeHostSchema", "structuredAgentSchema", "controlStoreSchema", "promptHistorySchema", "releaseCohortSchema", "updateJournalSchema"];
11
11
  const EVIDENCE_KEYS = ["nativeSpikeSchema", "terminalProvenanceSchema", "terminalProofSchema", "stableReleaseSchema", "previewReleaseSchema", "releaseCertificationSchema", "previewPlatformVerdictSchema", "piSourceLedgerSchema", "piComponentParitySchema", "piEventFrameParitySchema", "startupTraceSchema", "dependencyLayerSchema", "dependencyLayerCertificationSchema", "runtimePayloadSchema"];
12
- const ARTIFACT_KEYS = ["cliEntry", "supervisorEntry", "guardianEntry", "uiEntry", "nativeExecutable", "nativeCrate", "processGuardianExecutable", "releaseTarballStem", "diagnosticStem"];
12
+ const ARTIFACT_KEYS = ["cliEntry", "supervisorEntry", "guardianEntry", "uiEntry", "terminalHostAddon", "terminalHostEntry", "nativeCrate", "processGuardianAddon", "releaseTarballStem", "diagnosticStem"];
13
13
  const ROOT_KEYS = ["schema", "displayName", "commandName", "packageName", "filesystem", "environment", "state", "endpoint", "manifest", "protocol", "evidence", "artifacts"];
14
14
  export function validateProductIdentity(value) {
15
15
  const root = exactObject(value, ROOT_KEYS, "product identity");
@@ -87,9 +87,10 @@
87
87
  "supervisorEntry": "bin/supervisor.js",
88
88
  "guardianEntry": "bin/guardian.js",
89
89
  "uiEntry": "bin/ui.js",
90
- "nativeExecutable": "terminal-host",
90
+ "terminalHostAddon": "terminal-host",
91
+ "terminalHostEntry": "host-entry",
91
92
  "nativeCrate": "terminal-host",
92
- "processGuardianExecutable": "process-guardian",
93
+ "processGuardianAddon": "process-guardian",
93
94
  "releaseTarballStem": "timurproko-a1",
94
95
  "diagnosticStem": "a1"
95
96
  }
@@ -8,6 +8,7 @@
8
8
  "bin/ui.js",
9
9
  "bin/update-recovery.js",
10
10
  "bin/warmup.js",
11
+ "dist/foundation/launch-guardian/exit-watcher.js",
11
12
  "dist/foundation/startup/startup-descriptor.js",
12
13
  "dist/integrations/pi/startup-public.js"
13
14
  ],
@@ -32,8 +32,8 @@ export { readVisibleHyperlinks } from "./visible-hyperlinks.js";
32
32
  export type { VisibleHyperlinkRange, VisibleHyperlinkRow } from "./visible-hyperlinks.js";
33
33
  export { renderStatusLine, statusText } from "./status-line.js";
34
34
  export type { StatusLineInput } from "./status-line.js";
35
- export { SUBMITTED_PROMPT_PREFIX_WIDTH, composeSubmittedPromptRows, formatSubmittedPromptTime, submittedPromptLayout } from "./submitted-prompt.js";
36
- export type { SubmittedPromptLayout, SubmittedPromptStyle } from "./submitted-prompt.js";
35
+ export { SUBMITTED_PROMPT_PREFIX_WIDTH, composeSubmittedPromptRows, formatLocalTime, formatSubmittedPromptTime, submittedPromptLayout } from "./submitted-prompt.js";
36
+ export type { SubmittedPromptLayout, SubmittedPromptStyle, UiTimeFormat } from "./submitted-prompt.js";
37
37
  export { numericValues, steppedValue, stepperEnds } from "./stepper.js";
38
38
  export type { NumericRange } from "./stepper.js";
39
39
  export { TranscriptViewport, assertTranscriptViewportFrameDescriptor } from "./transcript-viewport.js";
@@ -16,7 +16,7 @@ export { GLOBAL_SCOPE, ShortcutRegistry, assembleShortcuts, assertNoShortcutConf
16
16
  export { backgroundSgrSpan, heldNativeHyperlinkStyle, hyperlinkSgrSpan, hyperlinkTargetAtColumn, nativeHyperlinkStyle, overlaySpan } from "./spans.js";
17
17
  export { readVisibleHyperlinks } from "./visible-hyperlinks.js";
18
18
  export { renderStatusLine, statusText } from "./status-line.js";
19
- export { SUBMITTED_PROMPT_PREFIX_WIDTH, composeSubmittedPromptRows, formatSubmittedPromptTime, submittedPromptLayout } from "./submitted-prompt.js";
19
+ export { SUBMITTED_PROMPT_PREFIX_WIDTH, composeSubmittedPromptRows, formatLocalTime, formatSubmittedPromptTime, submittedPromptLayout } from "./submitted-prompt.js";
20
20
  export { numericValues, steppedValue, stepperEnds } from "./stepper.js";
21
21
  export { TranscriptViewport, assertTranscriptViewportFrameDescriptor } from "./transcript-viewport.js";
22
22
  export { RAIL_COLUMNS, renderEmptyState, withScrollbarRail } from "./surface.js";
@@ -20,5 +20,7 @@ export interface SelectionCopySnapshot {
20
20
  }
21
21
  /** Shares the viewport's semantic chrome exclusions with isolated copy preparation. */
22
22
  export declare function selectionCopyLineContent(text: string, prompt: SelectionCopyPrompt): TextSelectionLineContent;
23
+ /** Builds an immutable exact-text snapshot without changing editor-owned selection state. */
24
+ export declare function literalSelectionCopySnapshot(text: string, revision?: number): SelectionCopySnapshot | null;
23
25
  /** Extracts one snapshot row with the existing grapheme/newline policy; run expensive rows off-thread. */
24
26
  export declare function selectionCopyRowText(snapshot: Pick<SelectionCopySnapshot, "selection" | "literal">, row: SelectionCopyRow, index: number): string;
@@ -19,6 +19,19 @@ export function selectionCopyLineContent(text, prompt) {
19
19
  return { from, to: from + 1 };
20
20
  return usefulTextLineContent(plain, from);
21
21
  }
22
+ /** Builds an immutable exact-text snapshot without changing editor-owned selection state. */
23
+ export function literalSelectionCopySnapshot(text, revision = 0) {
24
+ if (text.trim().length === 0)
25
+ return null;
26
+ const selection = {
27
+ start: { line: 0, column: 0 },
28
+ end: { line: 0, column: Number.MAX_SAFE_INTEGER },
29
+ };
30
+ if (text.length > MAX_COPY_SOURCE_UNITS) {
31
+ return { literal: true, selection, revision, rows: [], sourceUnits: 0, rejected: "size" };
32
+ }
33
+ return { literal: true, selection, revision, rows: [{ text }], sourceUnits: text.length };
34
+ }
22
35
  /** Extracts one snapshot row with the existing grapheme/newline policy; run expensive rows off-thread. */
23
36
  export function selectionCopyRowText(snapshot, row, index) {
24
37
  if (snapshot.literal)
@@ -1,3 +1,6 @@
1
+ export type UiTimeFormat = "20:00" | "8:00 PM";
2
+ /** Deterministic local hour/minute presentation shared by A1-owned time labels. */
3
+ export declare function formatLocalTime(source: Date | number, format?: UiTimeFormat): string | null;
1
4
  /** Visible width of the submitted-prompt prefix (`❯ `). */
2
5
  export declare const SUBMITTED_PROMPT_PREFIX_WIDTH = 2;
3
6
  export interface SubmittedPromptStyle {
@@ -8,16 +11,16 @@ export interface SubmittedPromptLayout {
8
11
  readonly contentWidth: number;
9
12
  readonly timestamp: string | null;
10
13
  }
11
- /** Formats transcript metadata, never render time, as local 24-hour HH:mm. */
12
- export declare function formatSubmittedPromptTime(source: Date | number): string | null;
14
+ /** Formats transcript metadata, never render time, in the active A1 time format. */
15
+ export declare function formatSubmittedPromptTime(source: Date | number, format?: UiTimeFormat): string | null;
13
16
  /**
14
17
  * Computes the width at which the prompt's Markdown body must be rendered.
15
18
  * The timestamp is omitted rather than allowing it to crowd useful content.
16
19
  */
17
- export declare function submittedPromptLayout(width: number, source?: Date | number | null): SubmittedPromptLayout;
20
+ export declare function submittedPromptLayout(width: number, source?: Date | number | null, format?: UiTimeFormat): SubmittedPromptLayout;
18
21
  /**
19
22
  * Composes already-rendered prompt content into the compact submitted bar.
20
23
  * Continuations align below the content, not below the prefix, and no row can
21
24
  * exceed the supplied terminal width even when the content renderer misbehaves.
22
25
  */
23
- export declare function composeSubmittedPromptRows(contentRows: readonly string[], width: number, source?: Date | number | null, style?: SubmittedPromptStyle): readonly string[];
26
+ export declare function composeSubmittedPromptRows(contentRows: readonly string[], width: number, source?: Date | number | null, style?: SubmittedPromptStyle, format?: UiTimeFormat): readonly string[];
@@ -1,22 +1,30 @@
1
1
  import { displayWidth, truncateToWidth } from "./text.js";
2
+ /** Deterministic local hour/minute presentation shared by A1-owned time labels. */
3
+ export function formatLocalTime(source, format = "8:00 PM") {
4
+ const date = source instanceof Date ? source : new Date(source);
5
+ if (!Number.isFinite(date.getTime()))
6
+ return null;
7
+ const hour = date.getHours();
8
+ const minute = String(date.getMinutes()).padStart(2, "0");
9
+ if (format === "20:00")
10
+ return `${String(hour).padStart(2, "0")}:${minute}`;
11
+ return `${hour % 12 || 12}:${minute} ${hour < 12 ? "AM" : "PM"}`;
12
+ }
2
13
  /** Visible width of the submitted-prompt prefix (`❯ `). */
3
14
  export const SUBMITTED_PROMPT_PREFIX_WIDTH = 2;
4
15
  const TIMESTAMP_MARGIN = 3;
5
16
  const MIN_USEFUL_CONTENT_WIDTH = 8;
6
- /** Formats transcript metadata, never render time, as local 24-hour HH:mm. */
7
- export function formatSubmittedPromptTime(source) {
8
- const date = source instanceof Date ? source : new Date(source);
9
- if (!Number.isFinite(date.getTime()))
10
- return null;
11
- return `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
17
+ /** Formats transcript metadata, never render time, in the active A1 time format. */
18
+ export function formatSubmittedPromptTime(source, format = "8:00 PM") {
19
+ return formatLocalTime(source, format);
12
20
  }
13
21
  /**
14
22
  * Computes the width at which the prompt's Markdown body must be rendered.
15
23
  * The timestamp is omitted rather than allowing it to crowd useful content.
16
24
  */
17
- export function submittedPromptLayout(width, source) {
25
+ export function submittedPromptLayout(width, source, format = "8:00 PM") {
18
26
  const boundedWidth = Math.max(1, width);
19
- const timestamp = source === undefined || source === null ? null : formatSubmittedPromptTime(source);
27
+ const timestamp = source === undefined || source === null ? null : formatSubmittedPromptTime(source, format);
20
28
  const timestampReserve = timestamp === null ? 0 : displayWidth(timestamp) + TIMESTAMP_MARGIN;
21
29
  const canShowTimestamp = timestamp !== null
22
30
  && boundedWidth - SUBMITTED_PROMPT_PREFIX_WIDTH - timestampReserve >= MIN_USEFUL_CONTENT_WIDTH;
@@ -30,10 +38,10 @@ export function submittedPromptLayout(width, source) {
30
38
  * Continuations align below the content, not below the prefix, and no row can
31
39
  * exceed the supplied terminal width even when the content renderer misbehaves.
32
40
  */
33
- export function composeSubmittedPromptRows(contentRows, width, source, style = {}) {
41
+ export function composeSubmittedPromptRows(contentRows, width, source, style = {}, format = "8:00 PM") {
34
42
  if (width <= 0)
35
43
  return [];
36
- const layout = submittedPromptLayout(width, source);
44
+ const layout = submittedPromptLayout(width, source, format);
37
45
  const prefix = (style.prefix ?? identity)("❯ ");
38
46
  const rows = (contentRows.length === 0 ? [""] : contentRows).map((row, index) => {
39
47
  const content = truncateToWidth(row, layout.contentWidth);
@@ -6,6 +6,8 @@ export interface TranscriptPromptAnchor {
6
6
  readonly lastRow: number;
7
7
  /** The source first row, including its submitted-prompt styling and timestamp. */
8
8
  readonly sourceRow: string;
9
+ /** Right-edge metadata cells omitted from semantic prompt copies. */
10
+ readonly copySuffixWidth?: number;
9
11
  /** Optional source-styled row used only while prominent and not hovered. */
10
12
  readonly prominentSourceRow?: string;
11
13
  }
@@ -36,7 +38,11 @@ export interface TranscriptViewportFrameInput {
36
38
  /** Final transient rows to bottom-align with unused viewport space while content fits. */
37
39
  readonly bottomAlignedTailRowCount?: number;
38
40
  readonly dockRows: readonly string[];
39
- readonly explicitCopyDockRows?: number;
41
+ /** Zero-based dock rows admitted to frame copying, classified before dock composition. */
42
+ readonly copyableDockRows?: readonly {
43
+ readonly row: number;
44
+ readonly prompt?: "first" | "continuation";
45
+ }[];
40
46
  readonly promptAnchors: readonly TranscriptPromptAnchor[];
41
47
  readonly width: number;
42
48
  readonly height: number;
@@ -142,7 +148,6 @@ export interface TranscriptViewportFrame {
142
148
  readonly cacheEntries: number;
143
149
  };
144
150
  }
145
- type SelectionCopyIntent = "automatic" | "explicit";
146
151
  /**
147
152
  * A1-owned viewport state. It knows only rows and semantic prompt anchors; Pi
148
153
  * components and transcript payloads remain outside this neutral boundary.
@@ -172,9 +177,9 @@ export declare class TranscriptViewport {
172
177
  extendSelection(column: number, frameRow: number, now?: number, autoScroll?: boolean): boolean;
173
178
  releaseSelection(): boolean;
174
179
  clearSelection(): boolean;
175
- selectedText(intent?: SelectionCopyIntent): string | null;
180
+ selectedText(): string | null;
176
181
  /** Captures visible selected text, not off-screen history. */
177
- captureSelectedText(intent?: SelectionCopyIntent): SelectionCopySnapshot | null;
182
+ captureSelectedText(): SelectionCopySnapshot | null;
178
183
  scrollBy(lines: number, now?: number): boolean;
179
184
  scrollTo(position: number, now?: number): boolean;
180
185
  scrollToEnd(now?: number): boolean;
@@ -186,7 +191,6 @@ export declare class TranscriptViewport {
186
191
  clearTransient(): void;
187
192
  compose(input: TranscriptViewportFrameInput): TranscriptViewportFrame;
188
193
  /** Reuses an established transcript frame when only same-height dock rows changed. */
189
- composeDockOnly(dockRows: readonly string[], width: number, height: number, explicitCopyDockRows?: number): TranscriptViewportFrame | null;
194
+ composeDockOnly(dockRows: readonly string[], width: number, height: number, copyableDockRows?: TranscriptViewportFrameInput["copyableDockRows"]): TranscriptViewportFrame | null;
190
195
  }
191
196
  export declare function assertTranscriptViewportFrameDescriptor(descriptor: TranscriptViewportFrameDescriptor): void;
192
- export {};
@@ -63,7 +63,7 @@ export class TranscriptViewport {
63
63
  #contentWidth = 0;
64
64
  #selectionWidth = 0;
65
65
  #viewportHeight = 0;
66
- #explicitCopyDockRows = 0;
66
+ #copyableDockRows = new Map();
67
67
  #firstSelectableRow = 0;
68
68
  #selectionRowAnchors = [];
69
69
  #frameId = 0;
@@ -179,14 +179,14 @@ export class TranscriptViewport {
179
179
  this.#selectionRevision += 1;
180
180
  return true;
181
181
  }
182
- selectedText(intent = "automatic") {
182
+ selectedText() {
183
183
  const selection = this.#visibleSelection();
184
184
  if (selection === undefined)
185
185
  return null;
186
186
  const copiedLines = Array.from({ length: Math.max(0, selection.end.line - selection.start.line + 1) }, (_value, index) => selection.start.line + index).filter(line => {
187
187
  const anchor = this.#selectionRowAnchors[line];
188
188
  return anchor?.kind === "document" && anchor.row < this.#selectableDocumentRowCount
189
- || intent === "explicit" && anchor?.kind === "dock" && anchor.fromBottom < this.#explicitCopyDockRows;
189
+ || anchor?.kind === "dock" && this.#copyableDockRows.has(anchor.fromBottom);
190
190
  });
191
191
  if (copiedLines.length === 0)
192
192
  return null;
@@ -199,18 +199,24 @@ export class TranscriptViewport {
199
199
  const text = textSelectionText(selection, this.#selectionRows, line => {
200
200
  const row = this.#selectionRows[line] ?? "";
201
201
  const anchor = this.#selectionRowAnchors[line];
202
- return prompt !== undefined && anchor?.kind === "document"
203
- ? selectionCopyLineContent(row, anchor.row === prompt.firstRow ? "first" : "continuation")
204
- : usefulTextLineContent(row);
202
+ const dock = anchor?.kind === "dock" ? this.#copyableDockRows.get(anchor.fromBottom) : undefined;
203
+ if (prompt !== undefined && anchor?.kind === "document") {
204
+ const first = anchor.row === prompt.firstRow;
205
+ const copyRow = first && (prompt.copySuffixWidth ?? 0) > 0
206
+ ? truncateToWidth(row, Math.max(0, displayWidth(row) - (prompt.copySuffixWidth ?? 0)))
207
+ : row;
208
+ return selectionCopyLineContent(copyRow, first ? "first" : "continuation");
209
+ }
210
+ return dock?.prompt !== undefined ? selectionCopyLineContent(row, dock.prompt) : usefulTextLineContent(row);
205
211
  }, line => included.has(line));
206
212
  return text.length === 0 ? null : text;
207
213
  }
208
214
  /** Captures visible selected text, not off-screen history. */
209
- captureSelectedText(intent = "automatic") {
210
- if (intent === "automatic" && !this.#copyableSelection)
215
+ captureSelectedText() {
216
+ if (!this.#copyableSelection)
211
217
  return null;
212
218
  const started = performance.now();
213
- let text = this.selectedText(intent);
219
+ let text = this.selectedText();
214
220
  if (text === null)
215
221
  return null;
216
222
  text = text.trim();
@@ -313,7 +319,7 @@ export class TranscriptViewport {
313
319
  this.#contentWidth = 0;
314
320
  this.#selectionWidth = 0;
315
321
  this.#viewportHeight = 0;
316
- this.#explicitCopyDockRows = 0;
322
+ this.#copyableDockRows.clear();
317
323
  this.clearTransient();
318
324
  this.#frame = null;
319
325
  }
@@ -329,7 +335,7 @@ export class TranscriptViewport {
329
335
  const theme = input.theme ?? PLAIN_THEME;
330
336
  const previousDescriptor = this.#frame?.descriptor ?? null;
331
337
  const dock = input.dockRows.length > height ? input.dockRows.slice(-height) : [...input.dockRows];
332
- this.#explicitCopyDockRows = clamp(input.explicitCopyDockRows ?? 0, 0, dock.length);
338
+ this.#copyableDockRows = copyableDockRowsBySuffix(input.dockRows, input.copyableDockRows);
333
339
  const viewportHeight = Math.max(0, height - dock.length);
334
340
  const bottomAlignedTailRowCount = clamp(input.bottomAlignedTailRowCount ?? 0, 0, input.documentRows.length);
335
341
  const transientAlignmentGapRows = bottomAlignedTailRowCount > 0
@@ -606,7 +612,7 @@ export class TranscriptViewport {
606
612
  return frame;
607
613
  }
608
614
  /** Reuses an established transcript frame when only same-height dock rows changed. */
609
- composeDockOnly(dockRows, width, height, explicitCopyDockRows = 0) {
615
+ composeDockOnly(dockRows, width, height, copyableDockRows = []) {
610
616
  const previous = this.#frame;
611
617
  const boundedWidth = Math.max(1, width);
612
618
  const boundedHeight = Math.max(0, height);
@@ -642,7 +648,7 @@ export class TranscriptViewport {
642
648
  };
643
649
  assertTranscriptViewportFrameDescriptor(descriptor);
644
650
  this.#selectionRows = [...this.#selectionRows.slice(0, viewportHeight), ...dock].slice(0, boundedHeight);
645
- this.#explicitCopyDockRows = clamp(explicitCopyDockRows, 0, dock.length);
651
+ this.#copyableDockRows = copyableDockRowsBySuffix(dockRows, copyableDockRows);
646
652
  const frame = {
647
653
  rows: [...previous.rows.slice(0, viewportHeight), ...dock].slice(0, boundedHeight),
648
654
  contentWidth: previous.contentWidth,
@@ -961,6 +967,15 @@ function assertDocumentRange(range, label) {
961
967
  function sameRectangle(left, right) {
962
968
  return left === null ? right === null : right !== null && left.rowStart === right.rowStart && left.rowEnd === right.rowEnd;
963
969
  }
970
+ function copyableDockRowsBySuffix(dockRows, declarations) {
971
+ const result = new Map();
972
+ for (const declaration of declarations ?? []) {
973
+ if (!Number.isSafeInteger(declaration.row) || declaration.row < 0 || declaration.row >= dockRows.length)
974
+ continue;
975
+ result.set(dockRows.length - declaration.row - 1, declaration.prompt === undefined ? {} : { prompt: declaration.prompt });
976
+ }
977
+ return result;
978
+ }
964
979
  function clamp(value, minimum, maximum) {
965
980
  return Math.min(Math.max(value, minimum), maximum);
966
981
  }
@@ -1,4 +1,4 @@
1
- export declare const OWNED_UI_SETTINGS_VERSION = 16;
1
+ export declare const OWNED_UI_SETTINGS_VERSION = 17;
2
2
  export type OwnedUiSettingValue = string | number | boolean;
3
3
  export type OwnedUiSettingApplication = "live" | "restart";
4
4
  export interface OwnedUiSettingDeclaration {
@@ -32,6 +32,18 @@ export declare const OWNED_SETTING_DECLARATIONS: Readonly<{
32
32
  defaultValue: true;
33
33
  allowedValues: readonly [true, false];
34
34
  }>;
35
+ readonly timeFormat: Readonly<{
36
+ id: "timeFormat";
37
+ label: "Time format";
38
+ section: Readonly<{
39
+ id: "generic";
40
+ title: "Generic";
41
+ }>;
42
+ description: "Format used by submitted-prompt timestamps and the resident tab clock.";
43
+ application: "live";
44
+ defaultValue: "8:00 PM";
45
+ allowedValues: readonly ["20:00", "8:00 PM"];
46
+ }>;
35
47
  readonly accentColor: Readonly<{
36
48
  id: "accentColor";
37
49
  label: "Accent color";
@@ -164,18 +176,6 @@ export declare const OWNED_SETTING_DECLARATIONS: Readonly<{
164
176
  defaultValue: 8;
165
177
  allowedValues: readonly [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
166
178
  }>;
167
- readonly tabsMax: Readonly<{
168
- id: "tabsMax";
169
- label: "Maximum tabs";
170
- section: Readonly<{
171
- id: "tabs";
172
- title: "Tabs";
173
- }>;
174
- description: "Maximum resident A1 tabs kept in the shared strip.";
175
- application: "live";
176
- defaultValue: 10;
177
- allowedValues: readonly number[];
178
- }>;
179
179
  readonly tabsAutoName: Readonly<{
180
180
  id: "tabsAutoName";
181
181
  label: "Auto name";
@@ -1,4 +1,4 @@
1
- export const OWNED_UI_SETTINGS_VERSION = 16;
1
+ export const OWNED_UI_SETTINGS_VERSION = 17;
2
2
  const UI_ACCENT_COLOR_CHOICES = Object.freeze([
3
3
  "purple", "blue", "cyan", "green", "orange", "pink",
4
4
  ]);
@@ -10,7 +10,6 @@ const APPEARANCE_SECTION = Object.freeze({ id: "appearance", title: "Appearance"
10
10
  const SCROLL_SECTION = Object.freeze({ id: "scroll", title: "Scroll" });
11
11
  const AGENT_SECTION = Object.freeze({ id: "agent", title: "Agent" });
12
12
  const TABS_SECTION = Object.freeze({ id: "tabs", title: "Tabs" });
13
- const TABS_MAX_CHOICES = Object.freeze(Array.from({ length: 50 }, (_, index) => index + 1));
14
13
  /**
15
14
  * Every A1 setting, keyed by its id. The table is the one declaration: ids, defaults, and allowed
16
15
  * values are read from it, and `OwnedSettingValueOf` derives each getter's type from it.
@@ -25,6 +24,17 @@ export const OWNED_SETTING_DECLARATIONS = Object.freeze({
25
24
  defaultValue: true,
26
25
  allowedValues: Object.freeze([true, false]),
27
26
  }),
27
+ timeFormat: Object.freeze({
28
+ id: "timeFormat",
29
+ label: "Time format",
30
+ section: GENERIC_SECTION,
31
+ description: "Format used by submitted-prompt timestamps and the resident tab clock.",
32
+ application: "live",
33
+ defaultValue: "8:00 PM",
34
+ allowedValues: Object.freeze([
35
+ "20:00", "8:00 PM",
36
+ ]),
37
+ }),
28
38
  accentColor: Object.freeze({
29
39
  id: "accentColor",
30
40
  label: "Accent color",
@@ -126,15 +136,6 @@ export const OWNED_SETTING_DECLARATIONS = Object.freeze({
126
136
  defaultValue: 8,
127
137
  allowedValues: Object.freeze([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
128
138
  }),
129
- tabsMax: Object.freeze({
130
- id: "tabsMax",
131
- label: "Maximum tabs",
132
- section: TABS_SECTION,
133
- description: "Maximum resident A1 tabs kept in the shared strip.",
134
- application: "live",
135
- defaultValue: 10,
136
- allowedValues: TABS_MAX_CHOICES,
137
- }),
138
139
  tabsAutoName: Object.freeze({
139
140
  id: "tabsAutoName",
140
141
  label: "Auto name",
@@ -130,6 +130,13 @@ export const OWNED_UI_SETTINGS_MIGRATIONS = Object.freeze([
130
130
  return migrated;
131
131
  },
132
132
  }),
133
+ Object.freeze({
134
+ to: 17,
135
+ description: "Introduce the shared twelve-hour time format default.",
136
+ migrate(values) {
137
+ return { ...values };
138
+ },
139
+ }),
133
140
  ]);
134
141
  /** Shape-selected compatibility for the metadata-free product object. */
135
142
  export function normalizeOwnedUiSettingsValues(source) {
@@ -7,23 +7,24 @@ Every interactive command uses this profile-neutral lifecycle path:
7
7
  ```text
8
8
  mutable a1 entry
9
9
  -> verified immutable release
10
- -> Node launch guardian and authenticated launch-instance registration
11
- -> native process guardian and per-instance containment
12
- -> profile-aware owned-UI runtime selection
10
+ -> Node launch guardian loading the verified process-guardian addon
11
+ -> addon-held per-instance containment and profile-aware runtime selection
13
12
  -> owned Pi-backed composition, with A1 surfaces enabled only for bare a1
14
13
  ```
15
14
 
16
15
  Launch-instance ownership is plural. The supervisor tracks any number of independently authenticated `a1` and `a1 pi` instances and never uses one product-wide foreground mutex. Closing one instance closes only its verified process tree. Persisted rows alone do not prove liveness, and uncertainty never authorizes terminating an unrelated process.
17
16
 
18
- Neither guardian reads ordinary terminal input, parses or relays runtime output, renders cells, infers frames, synthesizes terminal responses, or emits display control. Both profiles use the same owned rendering and input pipeline. Bare `a1` exposes A1-owned surfaces; `a1 pi` withholds those surfaces and uses Pi's ordinary profile root. The private guardian boundary carries only bounded identity, readiness, stop, and outcome data.
17
+ The launch guardian and process-guardian addon do not read ordinary terminal input, parse or relay runtime output, render cells, infer frames, or synthesize terminal responses. Their only terminal output is the bounded reset and sanitized armed exit notice after runtime failure. Both profiles use the same owned rendering and input pipeline. Bare `a1` exposes A1-owned surfaces; `a1 pi` withholds those surfaces and uses Pi's ordinary profile root. The containment boundary carries only bounded identity, readiness, stop, and outcome data.
18
+
19
+ A detached Node exit watcher sits outside the launch guardian's containment. It waits for the guardian, performs bounded Unix process-group cleanup, and may deliver the same claimed exit notice. A kill aimed at every Node runtime also kills this watcher; the accepted loss of the notice and Unix fallback cleanup in that case is documented in [`process-guardian-provenance.md`](process-guardian-provenance.md), and A1 starts no native executable to close that gap.
19
20
 
20
21
  The owned Pi-backed surface is not an arbitrary-CLI terminal multiplexer. A feature that requires resident arbitrary CLI sessions, internal tabs, terminal-state reconnection, or A1-authoritative scrollback must introduce and certify the separate composed-terminal authority rather than reactivating the retired transparent attachment path.
21
22
 
22
23
  ## Current module responsibilities
23
24
 
24
25
  - `lifecycle`: dependency-free launch-instance, process identity, state transition, outcome, and control-command contracts.
25
- - `process-containment`: artifact verification, OS-verifiable process inspection, containment adapters, and bounded graceful/forced cleanup; it owns no terminal content.
26
- - `launch-guardian`: one profile-neutral instance coordinator above runtime selection.
26
+ - `process-containment`: process-guardian addon loading and artifact verification, OS-verifiable process inspection, in-process containment adapters, and bounded graceful/forced cleanup; it owns no terminal content.
27
+ - `launch-guardian`: one profile-neutral Node instance coordinator above runtime selection, plus the fixed Node exit-watcher entry used only for owner-death cleanup and the armed notice.
27
28
  - `protocol`: additive control handshake, bounded line framing, authenticated launch-instance commands, typed stop intent, snapshots, and command results.
28
29
  - `launch`: resolves the effective profile home and the history-specific data root. Composition uses its public path resolver to select `~/.a1/data` for history unless `A1_DATA_DIR` is explicit; global control/release/runtime/cache paths stay unchanged.
29
30
  - `prompt-history`: narrowly typed user-input retention in separate profile-owned databases under `~/.a1/data/history` (or `<A1_DATA_DIR>/history`), with bounded worker queues and no supervisor/control-store payloads. It receives a resolved root rather than importing launch-feature internals; it never probes, imports, or deletes the former platform-default history. The editor's owned history state machine remains inside the Pi component boundary; the session UI only coordinates snapshots and classified submissions.
@@ -32,14 +33,14 @@ The owned Pi-backed surface is not an arbitrary-CLI terminal multiplexer. A feat
32
33
  - `supervisor`: endpoint identity, plural cohort ownership, per-instance reconciliation, and aggregate release shutdown coordination. It owns no terminal surface.
33
34
  - `pi-engine-adapter`, `pi-component-adapter`, and `pi-tui-runtime-adapter`: isolate pinned Pi engine and presentation knowledge behind neutral contracts; product features do not import them directly. Inside the engine adapter, one process-level engine host owns what is process-wide (the HTTP dispatcher, the theme singletons, the one-time changelog and package-update announcements, the startup trace) and is the only place sessions are created, so every session id is unique per process.
34
35
  - `session-shell` (`src/app/session-shell`): the application layer that composes the feature owners, the UI foundations, and the three Pi adapters into the interactive session; only composition imports it. Its render root assembles semantic document and dock rows, while its focused viewport controller owns follow state, pointer routing, selection, and interaction timers. Owned-app route lifecycle belongs to the neutral `ui-apps` owner and is only hosted by the session shell.
35
- - release/update/bootstrap: package-derived immutable release identity, process-guardian integrity, cohort selection, durable update transactions, rollback, and dependency-light command entry. After an unsuccessful bare-A1 child exit, the bootstrap restores owned terminal modes; neither guardian emits terminal controls.
36
+ - release/update/bootstrap: package-derived immutable release identity, native-addon integrity, cohort selection, durable update transactions, rollback, and dependency-light command entry. Before certified fast-path reuse it checks every recorded product file is present; a missing or altered file is replaced only from the matching installed package when its size and digest reproduce the approved release, followed by full verification. Dependency layers keep their separate verification and repair policy. After an unsuccessful bare-A1 child exit, the launch owner or its Node watcher restores owned terminal modes and emits only the armed bounded notice.
36
37
  - `terminal-cleanup`: bounded, idempotent emergency restoration and fatal-exit diagnostics for an explicitly owned terminal. It does not inspect commands, relay terminal input/output, or emulate terminal state. The owned UI installs its fatal boundary before terminal activation; packaged bootstrap and checkout launch provide the surviving-owner fallback. Fatal records retain at most ten 16 KiB records with trusted classifications and code locations, never prompts, attachments, raw input, credentials, or arbitrary exception messages.
37
38
 
38
39
  ## Dependency direction
39
40
 
40
41
  Terminal boundaries are application-agnostic. They may not select behavior from executable names, arguments, CLI-specific environment variables, or visible text. Production code may not import private Pi distribution APIs or use a Pi-specific terminal workaround.
41
42
 
42
- The JavaScript product path has no PTY or terminal-emulator dependency. Reintroducing `node-pty`, xterm state, custom input encoders, mode/query trackers, cadence-derived frame inference, or renderer/projection code requires an approved capability change and cannot become a second terminal authority. The Rust process guardian is a lifecycle-only native boundary and is independent from the held composed terminal host.
43
+ The JavaScript product path has no PTY or terminal-emulator dependency. Reintroducing `node-pty`, xterm state, custom input encoders, mode/query trackers, cadence-derived frame inference, or renderer/projection code requires an approved capability change and cannot become a second terminal authority. The Rust process guardian is a lifecycle-only Node-API addon loaded by the launch guardian and is independent from the terminal-host Node-API addon. No A1-built executable is part of the production process surface.
43
44
 
44
45
  `scripts/governance/check-architecture.mjs` enforces the structural parts of these boundaries. Cross-cutting rationale belongs here; implementation history belongs in Git and archived OpenSpec changes.
45
46
 
@@ -61,7 +62,7 @@ Default future agents and composed hosts are children of the originating bare-`a
61
62
 
62
63
  The structured-agent runtime uses a versioned adapter hello and feature negotiation before readiness. Runtime state must use typed events, commands, snapshots, cancellation, and recovery evidence. It must not infer structured semantics from terminal text, terminal timing, or visual content and must not own pseudoterminals or renderer state.
63
64
 
64
- The terminal-host protocol boundary may carry only bounded typed control and semantic lifecycle messages. Pseudoterminal bytes, per-event child input, rendered cells, cell grids, framebuffers, and screen buffers are forbidden across it. Console host executables and packaging live outside the current JavaScript production owners and remain unavailable until the isolated in-terminal proof passes; replacing them with a lightweight custom parser/renderer is forbidden. A desktop-native window and GPU application shell are postponed and are not required for the terminal-hosted product.
65
+ The JavaScript-to-native terminal-host boundary carries only the fixed role arguments, host command, return code, session-lock calls, and typed semantic bridge data. `host-entry.js` does not touch Node's stdin/stdout streams; pseudoterminal bytes, per-event child input, rendered cells, cell grids, framebuffers, and screen buffers remain inside the addon's native roles and their bounded native IPC. The verified addon and fixed entry are the packaged production host; no console host executable exists. Replacing libghostty-vt with a lightweight custom parser/renderer is forbidden. A desktop-native window and GPU application shell are postponed and are not required for the terminal-hosted product.
65
66
 
66
67
  Resource queues, retained state, evidence, logs, and diagnostics follow `docs/architecture/resource-and-data-policy.md`. Terminal content and authentication material are never control-store records. Unknown data is potentially sensitive by default and must be rejected or redacted before persistence.
67
68