@timurproko/a1 0.2.1 → 0.2.2

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 (67) hide show
  1. package/README.md +16 -8
  2. package/bin/pinned-pi-public.js +11 -4
  3. package/dist/app/session-shell/index.d.ts +1 -1
  4. package/dist/app/session-shell/paste-executor.js +6 -1
  5. package/dist/app/session-shell/prompt-chips.d.ts +8 -0
  6. package/dist/app/session-shell/prompt-chips.js +58 -13
  7. package/dist/app/session-shell/session-shell-root.d.ts +21 -3
  8. package/dist/app/session-shell/session-shell-root.js +110 -17
  9. package/dist/app/session-shell/session-shell.d.ts +1 -1
  10. package/dist/app/session-shell/session-shell.js +76 -31
  11. package/dist/app/session-shell/session-viewport-controller.d.ts +13 -0
  12. package/dist/app/session-shell/session-viewport-controller.js +28 -1
  13. package/dist/cli/version-stats.js +4 -7
  14. package/dist/composition/owned-ui.d.ts +7 -0
  15. package/dist/composition/owned-ui.js +71 -3
  16. package/dist/contracts/owned-ui/image-attachments.d.ts +7 -4
  17. package/dist/contracts/owned-ui/image-attachments.js +20 -7
  18. package/dist/contracts/owned-ui/index.d.ts +1 -1
  19. package/dist/contracts/owned-ui/index.js +1 -1
  20. package/dist/contracts/owned-ui/prompt-chips.d.ts +2 -2
  21. package/dist/contracts/owned-ui/prompt-chips.js +9 -6
  22. package/dist/features/owned-ui/project-trust-prompt.js +39 -3
  23. package/dist/features/owned-ui/release-note-state.d.ts +13 -0
  24. package/dist/features/owned-ui/release-note-state.js +109 -0
  25. package/dist/features/owned-ui/release-notes.d.ts +10 -0
  26. package/dist/features/owned-ui/release-notes.js +73 -0
  27. package/dist/features/owned-ui/resources/release-notes.json +9 -0
  28. package/dist/foundation/release/latest-release.d.ts +55 -0
  29. package/dist/foundation/release/latest-release.js +166 -0
  30. package/dist/foundation/release/update.js +9 -0
  31. package/dist/integrations/pi/components/index.d.ts +1 -1
  32. package/dist/integrations/pi/components/index.js +1 -1
  33. package/dist/integrations/pi/components/prompt-chip-presentation.d.ts +3 -0
  34. package/dist/integrations/pi/components/prompt-chip-presentation.js +14 -0
  35. package/dist/integrations/pi/components/shell-footer-status.js +30 -9
  36. package/dist/integrations/pi/components/shell-presenters-info.d.ts +36 -0
  37. package/dist/integrations/pi/components/shell-presenters-info.js +77 -1
  38. package/dist/integrations/pi/components/shell-presenters-transcript.d.ts +0 -6
  39. package/dist/integrations/pi/components/shell-presenters-transcript.js +0 -19
  40. package/dist/integrations/pi/components/shell-shared-facade.d.ts +2 -1
  41. package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +1 -1
  42. package/dist/integrations/pi/components/submitted-prompt-adapter.js +13 -4
  43. package/dist/integrations/pi/engine/adapter.d.ts +12 -0
  44. package/dist/integrations/pi/engine/adapter.js +13 -0
  45. package/dist/integrations/pi/engine/session-runtime.d.ts +1 -0
  46. package/dist/integrations/pi/engine/session-runtime.js +2 -1
  47. package/dist/native/darwin-arm64/manifest.json +1 -1
  48. package/dist/native/linux-x64/manifest.json +1 -1
  49. package/dist/native/win32-x64/manifest.json +2 -2
  50. package/dist/native/win32-x64/process-guardian.exe +0 -0
  51. package/dist/product-identity.d.ts +1 -1
  52. package/dist/product-identity.js +1 -1
  53. package/dist/product-identity.json +1 -0
  54. package/dist/ui/settings/declarations.d.ts +25 -1
  55. package/dist/ui/settings/declarations.js +19 -1
  56. package/dist/ui/settings/migrations.js +14 -0
  57. package/docs/architecture/internal-naming.md +2 -2
  58. package/docs/architecture/resource-and-data-policy.md +11 -0
  59. package/docs/architecture/toolchain.md +1 -1
  60. package/docs/architecture/ui-reference-provenance.md +1 -0
  61. package/docs/ci-release-runbook.md +154 -70
  62. package/docs/local-worktree-cleanup.md +21 -4
  63. package/docs/manual-owned-ui-checkpoint.md +1 -0
  64. package/docs/openspec-archive-automation.md +1 -1
  65. package/docs/releases/0.2.2.md +47 -0
  66. package/docs/validation.md +13 -3
  67. package/package.json +3 -3
@@ -5,7 +5,6 @@ import { piToolArguments as toolArguments, updatePiToolResult as updateToolResul
5
5
  import { createTranscriptImageResolver } from "./transcript-image-resolver.js";
6
6
  import { createMermaidMarkdownTransformer } from "./upstream/components/mermaid.js";
7
7
  import { Container, Image, Spacer, Text, } from "@earendil-works/pi-tui";
8
- import { PRODUCT_TEXT } from "../../../product-identity.js";
9
8
  import { createPiSubmittedPromptComponent, isPiPromptStyleCompaction, } from "./submitted-prompt-adapter.js";
10
9
  export { isPiPromptStyleCompaction, paintPiSubmittedPromptTimestamp } from "./submitted-prompt-adapter.js";
11
10
  import { PINNED_PI_LAYOUT, piTheme, } from "./theme.js";
@@ -170,24 +169,6 @@ export function renderPiShellStartupDiagnostic(diagnostic, width) {
170
169
  : { open: `${escape}[2m`, close: `${escape}[22m`, prefix: "" };
171
170
  return new Text(`${chalk.open}${chalk.prefix}${diagnostic.message}${chalk.close}`, 0, 0).render(width);
172
171
  }
173
- /**
174
- * Pinned Pi's `showPackageUpdateNotification` banner: warning-coloured dynamic
175
- * borders around a bold warning title, the muted update instruction with the
176
- * accent command, and the package list.
177
- */
178
- export function renderPiShellPackageUpdateNotice(packages, width) {
179
- ensureTheme();
180
- const theme = piTheme();
181
- const container = new Container();
182
- container.addChild(new Spacer(1));
183
- container.addChild(new DynamicBorder(text => theme.fg("warning", text)));
184
- container.addChild(new Text(`${theme.bold(theme.fg("warning", "Package Updates Available"))}\n`
185
- + `${theme.fg("muted", "Package updates are available. Run ")}${theme.fg("accent", `${PRODUCT_TEXT.commandName} pi update --extensions`)}\n`
186
- + `${theme.fg("muted", "Packages:")}\n`
187
- + packages.map(name => `- ${name}`).join("\n"), 1, 0));
188
- container.addChild(new DynamicBorder(text => theme.fg("warning", text)));
189
- return container.render(width);
190
- }
191
172
  function transcriptComponent(block, cwd, expanded, extensions, submittedPrompt, outputPad, hideThinkingBlock, mermaidRenderingMode, showImages, imageWidthCells, imageAssets, tui) {
192
173
  switch (block.kind) {
193
174
  case "user": {
@@ -89,7 +89,8 @@ export interface PiShellProgressStatusPresentation {
89
89
  }) => string;
90
90
  }
91
91
  export interface PiShellStatusPort extends PiShellViewComponentPort {
92
- setWorkingOverride(message: string | undefined): void;
92
+ /** `active` owns a live operation before the engine lifecycle itself becomes busy. */
93
+ setWorkingOverride(message: string | undefined, active?: boolean): void;
93
94
  setOutputPad(padding: 0 | 1): void;
94
95
  /** Bare A1 shows engine-measured progress beside the working word; the pinned route keeps the bare word. */
95
96
  setProgressPresentation(presentation: PiShellProgressPresentationMode): void;
@@ -1,5 +1,5 @@
1
1
  import { type Component } from "@earendil-works/pi-tui";
2
- import { type OwnedUiTranscriptBlock } from "../../../contracts/owned-ui/index.js";
2
+ import type { OwnedUiTranscriptBlock } from "../../../contracts/owned-ui/index.js";
3
3
  export interface PiShellSubmittedPromptComposer {
4
4
  readonly layout: (width: number, source?: Date | number | null) => {
5
5
  readonly contentWidth: number;
@@ -1,6 +1,6 @@
1
1
  import { getMarkdownTheme } from "../startup-public.js";
2
2
  import { Box, Markdown, Text } from "@earendil-works/pi-tui";
3
- import { protectPromptChipWrapping } from "../../../contracts/owned-ui/index.js";
3
+ import { protectPiPromptChipPresentation } from "./prompt-chip-presentation.js";
4
4
  import { piTheme } from "./theme.js";
5
5
  /** Branch summaries share the block kind but do not participate in prompt navigation. */
6
6
  export function isPiPromptStyleCompaction(block) {
@@ -19,13 +19,22 @@ export function createPiSubmittedPromptComponent(block, composer, heading) {
19
19
  const timestamp = numericTimestamp(block);
20
20
  // Invariant: presentation-only chrome stays outside the summary's Markdown parser and stored text.
21
21
  const header = heading === undefined ? undefined : new Text(heading, 0, 0);
22
- const chipWrapping = block.kind === "user" ? protectPromptChipWrapping(block.text) : undefined;
23
- const markdown = new Markdown(chipWrapping?.text ?? block.text, 0, 0, getMarkdownTheme(), { color: content => piTheme().fg("userMessageText", content) }, { preserveOrderedListMarkers: true, preserveBackslashEscapes: true });
22
+ let chipWrapping;
23
+ const markdown = new Markdown(block.text, 0, 0, getMarkdownTheme(), { color: content => piTheme().fg("userMessageText", content) }, {
24
+ preserveOrderedListMarkers: true,
25
+ preserveBackslashEscapes: true,
26
+ ...(block.kind === "user" ? { transform: (text, width) => {
27
+ const wrapping = protectPiPromptChipPresentation(text, width);
28
+ chipWrapping = wrapping;
29
+ return wrapping.text;
30
+ } } : {}),
31
+ });
24
32
  const content = {
25
33
  render(width) {
26
34
  const layout = composer.layout(width, timestamp);
27
35
  const renderedBodyRows = markdown.render(layout.contentWidth);
28
- const bodyRows = chipWrapping === undefined ? renderedBodyRows : renderedBodyRows.map(row => chipWrapping.restore(row));
36
+ const wrapping = chipWrapping;
37
+ const bodyRows = wrapping === undefined ? renderedBodyRows : renderedBodyRows.map(row => wrapping.restore(row));
29
38
  const rows = header === undefined ? bodyRows : [
30
39
  ...header.render(layout.contentWidth).map(row => piTheme().fg("userMessageText", row)),
31
40
  ...(bodyRows.length === 0 ? [] : ["", ...bodyRows]),
@@ -41,6 +41,8 @@ export interface PiEngineAdapterOptions {
41
41
  * mode. Returns display names of packages with updates available.
42
42
  */
43
43
  readonly checkPackageUpdates?: PiEnginePackageUpdateProbe;
44
+ /** Comparison profiles preserve Pi's startup changelog; bare A1 owns release-note startup. */
45
+ readonly announceStartupChangelog?: boolean;
44
46
  readonly repositoryContextReader?: PiRepositoryContextReader;
45
47
  }
46
48
  /** Owns the pinned Pi session lifecycle and translates its events into the neutral agent-engine contract. */
@@ -58,6 +60,16 @@ export declare class PiEngineAdapter implements OwnedUiPromptSuggestionGenerator
58
60
  currentSessionFile(): string | null;
59
61
  currentSessionResumeMetadata(): PiSessionResumeMetadata | null;
60
62
  get disposed(): boolean;
63
+ /**
64
+ * Report a newer A1 release found by the startup check. The shell renders the diagnostic as
65
+ * pinned Pi's `Update Available` notice; it arrives whenever the check resolves, so a late
66
+ * result is appended to the transcript like Pi's own fire-and-forget version check.
67
+ */
68
+ announceReleaseUpdate(release: {
69
+ readonly version: string;
70
+ readonly command: string;
71
+ readonly changelogUrl: string | null;
72
+ }): void;
61
73
  suggestionReasoningPolicy(): OwnedUiPromptSuggestionReasoning;
62
74
  generate(request: OwnedUiPromptSuggestionRequest): Promise<OwnedUiPromptSuggestionResult>;
63
75
  start(): Promise<OwnedUiSessionViewModel>;
@@ -133,6 +133,7 @@ export class PiEngineAdapter {
133
133
  projectTrustPrompt: options.projectTrustPrompt,
134
134
  createRuntime: options.createRuntime,
135
135
  checkPackageUpdates: options.checkPackageUpdates,
136
+ ...(options.announceStartupChangelog === undefined ? {} : { announceStartupChangelog: options.announceStartupChangelog }),
136
137
  ...(options.repositoryContextReader === undefined ? {} : { repositoryContextReader: options.repositoryContextReader }),
137
138
  host: this.#workflowHost,
138
139
  }, {
@@ -241,6 +242,18 @@ export class PiEngineAdapter {
241
242
  get disposed() {
242
243
  return this.#disposed;
243
244
  }
245
+ /**
246
+ * Report a newer A1 release found by the startup check. The shell renders the diagnostic as
247
+ * pinned Pi's `Update Available` notice; it arrives whenever the check resolves, so a late
248
+ * result is appended to the transcript like Pi's own fire-and-forget version check.
249
+ */
250
+ announceReleaseUpdate(release) {
251
+ if (this.#disposed)
252
+ return;
253
+ const changelog = release.changelogUrl === null ? "" : `\nChangelog: ${release.changelogUrl}`;
254
+ this.#addDiagnostic("info", "release-update", `New version ${release.version} is available. Run ${release.command}${changelog}`, true);
255
+ this.#emitView();
256
+ }
244
257
  suggestionReasoningPolicy() {
245
258
  return this.#suggestions.reasoningPolicy();
246
259
  }
@@ -32,6 +32,7 @@ export interface PiEngineRuntimeOptions {
32
32
  readonly projectTrustPrompt: PiProjectTrustPreflightPrompt | undefined;
33
33
  readonly createRuntime: PiEngineRuntimeFactory | undefined;
34
34
  readonly checkPackageUpdates: PiEnginePackageUpdateProbe | undefined;
35
+ readonly announceStartupChangelog?: boolean;
35
36
  readonly pullRequestProbe?: PiPullRequestProbe;
36
37
  readonly pullRequestRefreshMs?: number;
37
38
  readonly repositoryContextPollMs?: number;
@@ -122,7 +122,8 @@ export class PiEngineRuntime {
122
122
  this.#ports.diagnostic(diagnostic.type === "error" ? "error" : diagnostic.type === "warning" ? "warning" : "info", code, diagnostic.message, diagnostic.type !== "error");
123
123
  }
124
124
  this.bindSession(runtime.session);
125
- await this.#announceChangelog(runtime.services.settingsManager);
125
+ if (this.#options.announceStartupChangelog !== false)
126
+ await this.#announceChangelog(runtime.services.settingsManager);
126
127
  this.#repositoryRefreshEnabled = true;
127
128
  this.#startRepositoryRefresh();
128
129
  return runtime;
@@ -5,7 +5,7 @@
5
5
  "platform": "darwin",
6
6
  "architecture": "arm64",
7
7
  "capability": "supported",
8
- "builtAt": "2026-09-28T08:09:05.323Z",
8
+ "builtAt": "2026-09-30T15:11:14.553Z",
9
9
  "artifact": {
10
10
  "filename": "process-guardian",
11
11
  "sha256": "9db1726bbe3fc2e8292f2ead1e7e9d0fd4d7d0dc9217b372582bf354b0f565dc",
@@ -5,7 +5,7 @@
5
5
  "platform": "linux",
6
6
  "architecture": "x64",
7
7
  "capability": "supported",
8
- "builtAt": "2026-09-28T08:08:49.459Z",
8
+ "builtAt": "2026-09-30T15:11:06.077Z",
9
9
  "artifact": {
10
10
  "filename": "process-guardian",
11
11
  "sha256": "d8cda6b0c7cb36c0cc41e90802aceebf6c02eaebbc08a83d7d963d2e918dbd7a",
@@ -5,10 +5,10 @@
5
5
  "platform": "win32",
6
6
  "architecture": "x64",
7
7
  "capability": "supported",
8
- "builtAt": "2026-09-28T08:09:42.804Z",
8
+ "builtAt": "2026-09-30T15:12:00.529Z",
9
9
  "artifact": {
10
10
  "filename": "process-guardian.exe",
11
- "sha256": "9f36428f29224cc424dd262aa0495a075e915c9ecce6bdfcc45bd972270afdde",
11
+ "sha256": "48fa14151a68053140a6bd2e7cb17b28af573d97a1c386d3466ba3abf9076cd5",
12
12
  "size": 178176
13
13
  },
14
14
  "provenance": {
@@ -1,4 +1,4 @@
1
- declare const ENVIRONMENT_KEYS: readonly ["clipboardDiagnostics", "configDir", "dataDir", "databasePath", "developmentInstanceId", "developmentRoot", "endpoint", "paneId", "probeTrace", "processGuardianPath", "prFooterPreview", "profileHome", "runtimeDir", "startupTrace", "suggestionDiagnostics", "terminalSessionId"];
1
+ declare const ENVIRONMENT_KEYS: readonly ["clipboardDiagnostics", "configDir", "dataDir", "databasePath", "developmentInstanceId", "developmentRoot", "endpoint", "paneId", "probeTrace", "processGuardianPath", "prFooterPreview", "profileHome", "runtimeDir", "skipVersionCheck", "startupTrace", "suggestionDiagnostics", "terminalSessionId"];
2
2
  declare const FILESYSTEM_KEYS: readonly ["slug", "windowsDirectory", "unixDirectory", "temporaryPrefix"];
3
3
  declare const STATE_KEYS: readonly ["windowsControlDirectory", "unixControlDirectory", "developmentDirectory", "piAgentProfile", "piVanillaProfile", "sessionRepositoryDirectory"];
4
4
  declare const ENDPOINT_KEYS: readonly ["windowsPipeStem", "unixSocketFilename", "metadataFilename", "supervisorLogFilename", "databaseFilename"];
@@ -1,7 +1,7 @@
1
1
  import rawIdentity from "./product-identity.json" with { type: "json" };
2
2
  const ENVIRONMENT_KEYS = [
3
3
  "clipboardDiagnostics", "configDir", "dataDir", "databasePath", "developmentInstanceId", "developmentRoot", "endpoint",
4
- "paneId", "probeTrace", "processGuardianPath", "prFooterPreview", "profileHome", "runtimeDir", "startupTrace", "suggestionDiagnostics", "terminalSessionId",
4
+ "paneId", "probeTrace", "processGuardianPath", "prFooterPreview", "profileHome", "runtimeDir", "skipVersionCheck", "startupTrace", "suggestionDiagnostics", "terminalSessionId",
5
5
  ];
6
6
  const FILESYSTEM_KEYS = ["slug", "windowsDirectory", "unixDirectory", "temporaryPrefix"];
7
7
  const STATE_KEYS = ["windowsControlDirectory", "unixControlDirectory", "developmentDirectory", "piAgentProfile", "piVanillaProfile", "sessionRepositoryDirectory"];
@@ -23,6 +23,7 @@
23
23
  "prFooterPreview": "A1_PR_FOOTER_PREVIEW",
24
24
  "profileHome": "A1_PROFILE_HOME",
25
25
  "runtimeDir": "A1_RUNTIME_DIR",
26
+ "skipVersionCheck": "A1_SKIP_VERSION_CHECK",
26
27
  "startupTrace": "A1_STARTUP_TRACE",
27
28
  "suggestionDiagnostics": "A1_SUGGESTION_DIAGNOSTICS",
28
29
  "terminalSessionId": "A1_TERMINAL_SESSION_ID"
@@ -1,4 +1,4 @@
1
- export declare const OWNED_UI_SETTINGS_VERSION = 8;
1
+ export declare const OWNED_UI_SETTINGS_VERSION = 10;
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 updateCheck: Readonly<{
36
+ id: "updateCheck";
37
+ label: "Update check";
38
+ section: Readonly<{
39
+ id: "generic";
40
+ title: "Generic";
41
+ }>;
42
+ description: "Check once a day at startup whether a newer A1 release exists on this channel and show a notice. Uses the public npm registry; applies on next start.";
43
+ application: "restart";
44
+ defaultValue: true;
45
+ allowedValues: readonly [true, false];
46
+ }>;
35
47
  readonly scrollbarAppearance: Readonly<{
36
48
  id: "scrollbarAppearance";
37
49
  label: "Scrollbar mode";
@@ -116,6 +128,18 @@ export declare const OWNED_SETTING_DECLARATIONS: Readonly<{
116
128
  defaultValue: "collapse";
117
129
  allowedValues: readonly ["collapse", "expand"];
118
130
  }>;
131
+ readonly promptImageLimit: Readonly<{
132
+ id: "promptImageLimit";
133
+ label: "Prompt image limit";
134
+ section: Readonly<{
135
+ id: "agent";
136
+ title: "Agent";
137
+ }>;
138
+ description: "Maximum image attachments in one prompt. Providers may enforce a lower limit.";
139
+ application: "live";
140
+ defaultValue: 8;
141
+ allowedValues: readonly [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
142
+ }>;
119
143
  }>;
120
144
  export type OwnedSettingId = keyof typeof OWNED_SETTING_DECLARATIONS;
121
145
  /** The value type a setting's declaration allows: a literal union for a choice, `number` for a stepped range. */
@@ -1,4 +1,4 @@
1
- export const OWNED_UI_SETTINGS_VERSION = 8;
1
+ export const OWNED_UI_SETTINGS_VERSION = 10;
2
2
  const MAX_ID_LENGTH = 64;
3
3
  const ID_PATTERN = /^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$/;
4
4
  /** Declared first so the settings screen opens on it; sections follow first-declaration order. */
@@ -19,6 +19,15 @@ export const OWNED_SETTING_DECLARATIONS = Object.freeze({
19
19
  defaultValue: true,
20
20
  allowedValues: Object.freeze([true, false]),
21
21
  }),
22
+ updateCheck: Object.freeze({
23
+ id: "updateCheck",
24
+ label: "Update check",
25
+ section: GENERIC_SECTION,
26
+ description: "Check once a day at startup whether a newer A1 release exists on this channel and show a notice. Uses the public npm registry; applies on next start.",
27
+ application: "restart",
28
+ defaultValue: true,
29
+ allowedValues: Object.freeze([true, false]),
30
+ }),
22
31
  scrollbarAppearance: Object.freeze({
23
32
  id: "scrollbarAppearance",
24
33
  label: "Scrollbar mode",
@@ -82,6 +91,15 @@ export const OWNED_SETTING_DECLARATIONS = Object.freeze({
82
91
  defaultValue: "collapse",
83
92
  allowedValues: Object.freeze(["collapse", "expand"]),
84
93
  }),
94
+ promptImageLimit: Object.freeze({
95
+ id: "promptImageLimit",
96
+ label: "Prompt image limit",
97
+ section: AGENT_SECTION,
98
+ description: "Maximum image attachments in one prompt. Providers may enforce a lower limit.",
99
+ application: "live",
100
+ defaultValue: 8,
101
+ allowedValues: Object.freeze([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
102
+ }),
85
103
  });
86
104
  /** The declarations in declaration order, for resolution, persistence, and the settings screen. */
87
105
  export const OWNED_UI_SETTING_DECLARATIONS = Object.freeze(Object.values(OWNED_SETTING_DECLARATIONS));
@@ -67,6 +67,20 @@ export const OWNED_UI_SETTINGS_MIGRATIONS = Object.freeze([
67
67
  return { ...values };
68
68
  },
69
69
  }),
70
+ Object.freeze({
71
+ to: 9,
72
+ description: "Introduce the configurable prompt image limit with the eight-image default.",
73
+ migrate(values) {
74
+ return { ...values };
75
+ },
76
+ }),
77
+ Object.freeze({
78
+ to: 10,
79
+ description: "Introduce the startup update check with the enabled default.",
80
+ migrate(values) {
81
+ return { ...values };
82
+ },
83
+ }),
70
84
  ]);
71
85
  export function assertOwnedUiSettingsMigrations(migrations, currentVersion = OWNED_UI_SETTINGS_VERSION) {
72
86
  const firstProduced = currentVersion - migrations.length + 1;
@@ -6,7 +6,7 @@ Internal code names contain no case-insensitive `a1` substring. This includes co
6
6
 
7
7
  The required **Internal naming validation** job scans complete added, modified, copied, and renamed-to files at the exact PR head against the complete merge-base diff. It does not inspect only changed lines. Policy, exception, ownership, parser-dependency, and selection changes require a full audit and inspector regression tests. A stale, missing, failed, or unexpectedly skipped required result blocks the aggregate development check.
8
8
 
9
- The nightly release workflow runs `full-release`, including `naming-full`, against the entire tracked codebase at its selected source commit. It does not use PR changed-file selection, including when it verifies an already-published immutable package. Naming failure fails platform validation and blocks publication. `naming-selection.test.ts` locks down this nightly wiring and checks that unchanged source is audited.
9
+ The nightly publication workflow runs `full-release`, including `naming-full`, against the entire tracked codebase at its selected source commit. It does not use PR changed-file selection, including when it verifies an already-published immutable package. Naming failure fails platform validation and blocks publication. `naming-selection.test.ts` locks down this nightly wiring and checks that unchanged source is audited.
10
10
 
11
11
  - Full local audit: `npm run check:names` (tracked files, including staged new files).
12
12
  - Exact selected PR audit: `npm run check:names:changed` after producing `.artifacts/validation/impact.json`.
@@ -62,7 +62,7 @@ These names are already neutral; their definitions and consumers remain the auth
62
62
  - Development aggregate: `CHANGES_RESULT`, `DOCS_RESULT`, `DOCUMENTATION_RESULT`, `DOCUMENTATION_REQUIRED`, `VALIDATE_RESULT`, `CONTAINMENT_RESULT`, `STARTUP_RESULT`, `RENDERING_RESULT`, `RENDERING_TIER`, `DOCS_ONLY`, `VERSION_ONLY`, `OPENSPEC_TOUCHED`, `SELECTED_HEAD`, `EXPECTED_HEAD`, `EVENT_BASE_SHA`, `EVENT_HEAD_SHA`. The workflow produces these and `require-development-validation.mjs` or the selector consumes them.
63
63
  - Naming aggregate: `NAMING_RESULT`, `NAMING_REQUIRED`, `NAMING_HEAD`, produced by CI and consumed by the same required aggregate.
64
64
  - Validation: `VALIDATION_BUILD_READY`, `VALIDATION_CANDIDATE_TARBALL`, `VALIDATION_DOCUMENTATION_FULL_READY`, `VALIDATION_SELECTION_JSON`, `STARTUP_PERFORMANCE_RESULT`, owned by validation orchestration and exact-package fixtures.
65
- - Publication workflow-local handoffs: `BUILD`, `EVENT_NAME`, `EXISTS`, `EXPECTED_INTEGRITY`, `EXPECTED_REGISTRY_INTEGRITY`, `EXPECTED_REGISTRY_SHASUM`, `EXPECTED_SHASUM`, `MODE`, `PACKAGE`, `PLAN`, `PUBLISH`, `PULLS_PATH`, `PULL_REQUEST`, `REGISTRY_TARBALL`, `RELEASE_CHANNEL`, `RELEASE_VERSION`, `REQUESTED_CHANNEL`, `REQUESTED_SHA`, `SOURCE_SHA`, `VALIDATE`, `VERSION`, `WORK`, defined and consumed in `.github/workflows/release.yml`.
65
+ - Publication workflow-local handoffs: `BUILD`, `EVENT_NAME`, `EXISTS`, `EXPECTED_INTEGRITY`, `EXPECTED_REGISTRY_INTEGRITY`, `EXPECTED_REGISTRY_SHASUM`, `EXPECTED_SHASUM`, `MODE`, `PACKAGE`, `PLAN`, `PUBLISH`, `PULLS_PATH`, `PULL_REQUEST`, `REGISTRY_TARBALL`, `RELEASE_CHANNEL`, `RELEASE_VERSION`, `REQUESTED_CHANNEL`, `REQUESTED_SHA`, `SOURCE_SHA`, `VALIDATE`, `VERSION`, `WORK`, defined and consumed in `.github/workflows/publish.yml`.
66
66
  - Isolated fixture controls: `PROMPT_SUGGESTION_AGENT_DIR`, `RUN_PROMPT_SUGGESTION_PROVIDER_TEST`, `TEST_SUPERVISOR_SECRET`, owned by their specific provider/supervisor tests.
67
67
  - Host/tool integration: `CARGO`, `ZIG`, `PATH`, `HOME`, `USERPROFILE`, `APPDATA`, `LOCALAPPDATA`, XDG directory variables, `TERM`, `COLORTERM`, `TERM_PROGRAM`, `WT_SESSION`, `EXEPATH`, `MINGW_PREFIX`, `MSYSTEM`, and third-party `PI_*`, `GITHUB_*`, `GH_TOKEN`, and npm variables. Their external spellings and caller values are not private product naming targets. The forwarding of an arbitrary user's environment is distinct from defining an owned setting.
68
68
 
@@ -23,14 +23,25 @@ Budgets are minimum defaults, not promises of capacity. An implementation may lo
23
23
  | Scrollback per pane | Host-defined, always bounded | Compact from oldest data first without cross-pane mutation |
24
24
  | Proof evidence file | 16 MiB | Reject and request summarized evidence |
25
25
  | Diagnostic payload | 256 KiB | Redact, truncate, and retain enough evidence for the failed operation |
26
+ | Packaged release-note resource | 1 MiB total; 128 KiB per note | Reject the damaged resource and retain the note as unacknowledged |
27
+ | Release-note acknowledgement/claim | 4 KiB per profile; one claim; one-hour stale bound | Ignore malformed acknowledgement, recover stale claim, and never acknowledge implicitly |
26
28
 
27
29
  Every asynchronous consumer must implement a finite queue or window. Backpressure must isolate the offending agent/pane and must not block unrelated identities.
28
30
 
31
+ Stable release-note preparation generates Pi-style Markdown with a
32
+ `## [version] - YYYY-MM-DD` heading and applicable categorized `###` sections. Human
33
+ editing remains allowed. Approval normalizes and bounds the editable draft GitHub
34
+ Release body before hashing it; if that version/date heading remains, its version and
35
+ calendar date must be valid. Publication jobs consume only that immutable snapshot;
36
+ later draft edits cannot expand or replace the package candidate. The same per-note
37
+ and total catalog limits apply when the snapshot is combined with committed history.
38
+
29
39
  ## Data classification
30
40
 
31
41
  | Class | Examples | Storage policy |
32
42
  |---|---|---|
33
43
  | Workspace metadata | IDs, names, lifecycle, capability versions, topology revisions, recovery references | May persist in the control store |
44
+ | Release-note state | Last acknowledged stable A1 version and opaque bounded claim token/time | May persist atomically in profile-isolated A1 configuration; never stores note text or Pi settings |
34
45
  | Structured payloads | Messages, tool calls, snapshots, attachments | Bound and process; arbitrary payload persistence remains unsupported |
35
46
  | User-authored prompt recall | Canonical interactive input and bounded provenance | May persist only through the profile-isolated prompt-history policy below, never in the control store |
36
47
  | Terminal content | PTY bytes, scrollback, selection, rendered cells | Never persist in A1's control store or diagnostics |
@@ -81,7 +81,7 @@ Presentation acceptance is the reader comparing `a1 pi` with pinned Pi. `node sc
81
81
 
82
82
  ## Publication
83
83
 
84
- One workflow publishes both channels: `.github/workflows/release.yml`. Pushes do not publish. Nightly development verification runs at `03:17 UTC`; `npm run develop` explicitly requests a numbered preview and `npm run release -- patch` explicitly requests stable publication after its version pull request is manually merged; it promotes a development version to its stable core. The following development-version pull request also requires manual merge. A preview is stamped as `-dev.<merged pull-request number>` and uses npm `next` only as an internal dist-tag. New candidates pack the application and dependency-free installer once each and validate their exact bytes on Windows, Linux, and macOS; a repeated nightly verifies both immutable registry tarballs. All publication uses provenance from the `npm-publish` environment, a preview never changes `latest`, and the stable tag, GitHub Release, and `master` are written only after npm has both packages. One global non-cancelling concurrency group serializes the final registry check.
84
+ One reusable workflow publishes both npm channels: `.github/workflows/publish.yml`. Pushes do not publish. Nightly development verification runs at `03:17 UTC`; `npm run develop` dispatches the development wrapper for a numbered preview. `npm run release -- patch` generates a source-bound draft GitHub Release with a Pi-style version/date heading and categorized change sections, starts `.github/workflows/release-candidate.yml` to run the complete stable suite on that source, prints the run link, waits for it, and prints the draft editing link once only after it passes. Choosing native **Publish release** on the draft is the only stable npm trigger: GitHub creates the tag at the bound source, and the `release.published` workflow calls the default-branch publisher, which derives the authorized human actor, source, Release identity, normalized body, and digest, and requires the successful candidate run for that source and version. A preview is stamped as `-dev.<merged pull-request number>` and uses npm `next` only as an internal dist-tag. New candidates pack the application and dependency-free installer once each—including committed release history plus the approved current note snapshot—and validate their exact bytes on Windows, Linux, and macOS; after the click the published note is repacked and the exact-package gates run on the final bytes. A repeated nightly verifies both immutable registry tarballs. After npm verification, publication uploads the asset and fast-forwards `master`, then App-authenticated automation proposes one exact, manually merged reopening PR storing both next `-dev` versions and the note. A failure before either package reaches npm returns the Release to draft and deletes its unconsumed tag, the only tag deletion the release-automation App may perform; after npm, the same run's failed jobs are rerun. Tags are never moved or reused. All npm publication uses provenance from the `npm-publish` environment, a preview never changes `latest`, and one global non-cancelling concurrency group serializes the final registry check.
85
85
 
86
86
  `docs/ci-release-runbook.md` is the operational reference.
87
87
 
@@ -72,6 +72,7 @@ its own `core` facade layer; A1 is a product, so the port adapts imports and kee
72
72
  transcripts, widgets, pointer selection, and extension-editor restoration. Physical
73
73
  acceptance of the exact build remains required before merging the implementation.
74
74
  - **Owned in-session routes are overlays.** The A1 UI reference owns its surface and can switch screens; A1 renders in-session owned routes through the pinned Pi TUI as full-viewport overlays. The pre-resource trust selector is separate and uses a bounded alternate startup surface solely so every completion path can restore the untouched parent terminal before engine activation or a fail-closed diagnostic.
75
+ - **A1 release notes replace Pi startup changelog behavior only in bare A1.** Bare A1's `/changelog` screen reads the bounded packaged resource generated from reviewed `docs/releases/*.md` documents, and an exact stable current note may open in the same full-screen route after startup safety surfaces. Product-owned per-profile claim/acknowledgement state is written only after a rendered close. The `a1 pi` comparison profile retains Pi's pinned changelog data, settings, startup announcement, and in-feed command presentation. Evidence is in `test/features/owned-ui/release-notes.test.ts`, `release-note-state.test.ts`, `test/composition/settings-route-host.test.ts`, and `test/app/session-shell/session-shell-reference-screens.test.ts`.
75
76
  - **Colour is a port, not an import.** The reference takes a Pi `Theme` directly. A1 defines
76
77
  `UiTheme` so the component layer never imports a Pi adapter and can be rendered plainly in
77
78
  tests.