@timurproko/a1 0.2.7-dev.779 → 0.2.7-dev.792
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.
- package/dist/app/session-shell/session-shell-root.d.ts +0 -1
- package/dist/app/session-shell/session-shell-root.js +45 -18
- package/dist/app/session-shell/session-shell.js +10 -5
- package/dist/app/session-shell/session-viewport-controller.d.ts +2 -2
- package/dist/app/session-shell/session-viewport-controller.js +24 -12
- package/dist/app/session-shell/shell-host.d.ts +0 -2
- package/dist/app/session-shell/shell-host.js +3 -20
- package/dist/cli/tabs.js +15 -0
- package/dist/composition/owned-ui.d.ts +1 -1
- package/dist/composition/owned-ui.js +66 -32
- package/dist/contracts/owned-ui/index.d.ts +1 -1
- package/dist/contracts/owned-ui/model.d.ts +3 -0
- package/dist/contracts/owned-ui/session-workflows.d.ts +4 -1
- package/dist/features/owned-ui/settings-app.js +9 -6
- package/dist/features/resident-tab/auto-name.d.ts +2 -2
- package/dist/features/resident-tab/auto-name.js +7 -5
- package/dist/features/resident-tab/index.d.ts +4 -2
- package/dist/features/resident-tab/index.js +6 -2
- package/dist/features/resident-tab/shortcut-bindings-file.d.ts +8 -0
- package/dist/features/resident-tab/shortcut-bindings-file.js +40 -0
- package/dist/features/resident-tab/{shortcuts.d.ts → shortcut-declarations.d.ts} +5 -2
- package/dist/features/resident-tab/{shortcuts.js → shortcut-declarations.js} +5 -17
- package/dist/features/resident-tab/shortcut-projection.d.ts +29 -0
- package/dist/features/resident-tab/shortcut-projection.js +64 -0
- package/dist/foundation/release/bootstrap.js +1 -0
- package/dist/foundation/release/progress-palette.generated.d.ts +2 -2
- package/dist/foundation/release/progress-palette.generated.js +2 -2
- package/dist/foundation/resident-tabs/bridge-client.d.ts +5 -0
- package/dist/foundation/resident-tabs/bridge-client.js +17 -1
- package/dist/foundation/resident-tabs/prompt-journal.d.ts +0 -2
- package/dist/foundation/resident-tabs/prompt-journal.js +0 -1
- package/dist/foundation/startup/startup-descriptor.js +2 -2
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +2 -0
- package/dist/integrations/pi/components/owned-editor-ux.js +13 -0
- package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -2
- package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
- package/dist/integrations/pi/components/share-operation-dialog.d.ts +2 -0
- package/dist/integrations/pi/components/share-operation-dialog.js +2 -1
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +1 -0
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +1 -0
- package/dist/integrations/pi/components/shell-presenters-info.js +10 -30
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +1 -0
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +2 -0
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +1 -1
- package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
- package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/session-footer.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +3 -11
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.js +1 -1
- package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
- package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
- package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
- package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
- package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme.js +1 -1
- package/dist/integrations/pi/engine/pi-settings-metadata.json +12 -0
- package/dist/integrations/pi/engine/resources/changelog.json +4 -4
- package/dist/integrations/pi/engine/settings-bridge.js +2 -0
- package/dist/integrations/pi/engine/settings-port.js +10 -1
- package/dist/integrations/pi/engine/workflow-runner.js +64 -2
- package/dist/integrations/pi/engine/workflow-support.d.ts +12 -0
- package/dist/integrations/pi/engine/workflow-support.js +36 -0
- package/dist/integrations/pi/engine/workflows.d.ts +3 -1
- package/dist/integrations/pi/engine/workflows.js +1 -0
- package/dist/integrations/pi/startup-public.js +38 -35
- package/dist/integrations/pi/startup-public.manifest.json +110 -116
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +1 -1
- package/dist/native/darwin-arm64/a1_session_lock.node +0 -0
- package/dist/native/darwin-arm64/manifest.json +3 -2
- package/dist/native/darwin-arm64/terminal-host +0 -0
- package/dist/native/darwin-arm64/terminal-host.manifest.json +7 -6
- package/dist/native/darwin-x64/a1_session_lock.node +0 -0
- package/dist/native/darwin-x64/manifest.json +5 -4
- package/dist/native/darwin-x64/process-guardian +0 -0
- package/dist/native/darwin-x64/terminal-host +0 -0
- package/dist/native/darwin-x64/terminal-host.manifest.json +7 -6
- package/dist/native/linux-x64/a1_session_lock.node +0 -0
- package/dist/native/linux-x64/manifest.json +3 -2
- package/dist/native/linux-x64/terminal-host +0 -0
- package/dist/native/linux-x64/terminal-host.manifest.json +7 -6
- package/dist/native/win32-x64/a1_session_lock.node +0 -0
- package/dist/native/win32-x64/manifest.json +4 -3
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/native/win32-x64/terminal-host.exe +0 -0
- package/dist/native/win32-x64/terminal-host.manifest.json +6 -5
- package/dist/runtime-payload-inventory.json +4242 -3716
- package/dist/ui/components/index.d.ts +2 -2
- package/dist/ui/components/index.js +1 -1
- package/dist/ui/components/selection-copy.d.ts +2 -0
- package/dist/ui/components/selection-copy.js +13 -0
- package/dist/ui/components/submitted-prompt.d.ts +7 -4
- package/dist/ui/components/submitted-prompt.js +18 -10
- package/dist/ui/components/transcript-viewport.d.ts +10 -6
- package/dist/ui/components/transcript-viewport.js +28 -13
- package/dist/ui/settings/declarations.d.ts +13 -1
- package/dist/ui/settings/declarations.js +12 -1
- package/dist/ui/settings/migrations.js +7 -0
- package/docs/architecture/evidence/resident-tabs/macos-x64.md +1 -1
- package/docs/architecture/process-guardian-provenance.md +1 -1
- package/docs/architecture/project-structure.md +8 -0
- package/docs/architecture/resident-tabs.md +18 -2
- package/docs/architecture/terminal-host-provenance.md +1 -1
- package/docs/architecture/toolchain.md +2 -2
- package/docs/ci-release-runbook.md +2 -2
- package/docs/openspec-archive-automation.md +5 -5
- package/docs/validation.md +12 -4
- package/package.json +3 -3
|
@@ -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,
|
|
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,
|
|
7
|
-
export function formatSubmittedPromptTime(source) {
|
|
8
|
-
|
|
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
|
-
|
|
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(
|
|
180
|
+
selectedText(): string | null;
|
|
176
181
|
/** Captures visible selected text, not off-screen history. */
|
|
177
|
-
captureSelectedText(
|
|
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,
|
|
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
|
-
#
|
|
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(
|
|
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
|
-
||
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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(
|
|
210
|
-
if (
|
|
215
|
+
captureSelectedText() {
|
|
216
|
+
if (!this.#copyableSelection)
|
|
211
217
|
return null;
|
|
212
218
|
const started = performance.now();
|
|
213
|
-
let text = this.selectedText(
|
|
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.#
|
|
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.#
|
|
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,
|
|
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.#
|
|
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 =
|
|
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";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const OWNED_UI_SETTINGS_VERSION =
|
|
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
|
]);
|
|
@@ -25,6 +25,17 @@ export const OWNED_SETTING_DECLARATIONS = Object.freeze({
|
|
|
25
25
|
defaultValue: true,
|
|
26
26
|
allowedValues: Object.freeze([true, false]),
|
|
27
27
|
}),
|
|
28
|
+
timeFormat: Object.freeze({
|
|
29
|
+
id: "timeFormat",
|
|
30
|
+
label: "Time format",
|
|
31
|
+
section: GENERIC_SECTION,
|
|
32
|
+
description: "Format used by submitted-prompt timestamps and the resident tab clock.",
|
|
33
|
+
application: "live",
|
|
34
|
+
defaultValue: "8:00 PM",
|
|
35
|
+
allowedValues: Object.freeze([
|
|
36
|
+
"20:00", "8:00 PM",
|
|
37
|
+
]),
|
|
38
|
+
}),
|
|
28
39
|
accentColor: Object.freeze({
|
|
29
40
|
id: "accentColor",
|
|
30
41
|
label: "Accent color",
|
|
@@ -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) {
|
|
@@ -15,7 +15,7 @@ Physical acceptance against a published candidate package is pending; the operat
|
|
|
15
15
|
|
|
16
16
|
## Automated evidence
|
|
17
17
|
|
|
18
|
-
- Publication `terminal_hosts` and `guardians` jobs on `macos-15
|
|
18
|
+
- Publication `terminal_hosts` and `guardians` jobs on `macos-15` (arm64): the release terminal host and process guardian are cross-compiled for Intel macOS with `--target x86_64-apple-darwin`, the host's `--version` identity is checked through Rosetta 2 when the runner can execute it (otherwise the manifest records a Mach-O architecture check), and packing refuses a missing or altered artifact. Before 2026-10-16 the same builds ran natively on `macos-15-intel`.
|
|
19
19
|
- Known gap: the pull-request `terminal-host` and `resident-chaos` suites run on macOS arm64 only, because modular validation outcomes are keyed by platform without architecture. Intel macOS has build and identity evidence but no automated behavior suite of its own.
|
|
20
20
|
|
|
21
21
|
## Physical verdicts
|
|
@@ -21,7 +21,7 @@ dist/native/darwin-x64/process-guardian
|
|
|
21
21
|
dist/native/darwin-arm64/process-guardian
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
The publication `guardians` job builds them on `windows-2025`, `ubuntu-24.04`, `macos-15` (arm64)
|
|
24
|
+
The publication `guardians` job builds them on `windows-2025`, `ubuntu-24.04`, and `macos-15` (arm64); the macOS arm64 job also cross-compiles the x64 guardian with `--target x86_64-apple-darwin`, and its manifest records whether the identity was observed by execution or only from the Mach-O header.
|
|
25
25
|
|
|
26
26
|
Each supported artifact must be named in the release integrity manifest with target triple, crate version, guardian protocol version, SHA-256, byte size, build provenance, and signature/attestation status. The build marks a platform supported only after its native containment integration runs on that platform. A missing, altered, incompatible, unsupported, or wrong-platform artifact is a concise containment launch error; A1 never silently falls back to PID-only cleanup.
|
|
27
27
|
|
|
@@ -103,6 +103,14 @@ a1 session link-worktree <absolute-worktree>
|
|
|
103
103
|
git -C .worktrees/<task-id> status
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
+
Claude Code sessions have no A1 shell-tool session, so they link with Claude Code's `EnterWorktree` tool by task name. The tracked `.claude/settings.json` wires a `WorktreeCreate` hook, `scripts/governance/claude-worktree-create.mjs`, that creates `.worktrees/<task-id>` detached at fresh `origin/develop`, or returns it when it is already registered, so Claude Code anchors the session there without an approval prompt. The agent then creates the task branch inside it:
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
git -C .worktrees/<task-id> switch -c <type>/<short-description>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Passing an absolute `path` to `EnterWorktree` is reserved for a worktree created by hand, from the primary checkout, before any shell command in that session; Claude Code otherwise keeps its shell tools anchored to the primary checkout and refuses their commands. The matching `WorktreeRemove` hook declines removal, so sessions leave with `ExitWorktree` `keep` and worktrees are removed only by the cleanup tool.
|
|
113
|
+
|
|
106
114
|
Inventory is read-only and advisory because another runtime may win a later race. A successful link response confirming the exact canonical worktree is required before planning, implementation, test, or delivery-documentation edits. If inventory or linking fails, reports a live/unverifiable owner, loses a race, or confirms another path, stop task edits and report the blocker; use a separate fresh worktree rather than overriding, unlinking, or recovering that owner. A session resuming an existing delivery or switching streams atomically claims and links the exact worktree before editing it.
|
|
107
115
|
|
|
108
116
|
The link acquires a cooperative live-session editing claim and switches bare A1's footer repository context and pull-request discovery. It does not change process or tool cwd, create a Git worktree lock, or register, release, or authorize cleanup. Clean unlink/disposal releases live editing authority; a crashed owner becomes reusable only after exact process death is verified. Repository commands therefore keep an explicit worktree path. The primary worktree stays on `develop` for integration and must not be used for task edits. Do not edit, adopt, move, or remove another session's worktree.
|
|
@@ -238,6 +238,18 @@ The channels carry bounded generation-1 frames: a u32 little-endian length follo
|
|
|
238
238
|
- Image protocols are not forwarded in the first version; the terminal identity the child sees disables them and existing text fallback applies. Extension parity is claimed only for the certified text-terminal contract.
|
|
239
239
|
- **Detach.** On detach the client restores the outer terminal's keyboard and mouse modes exactly. Enhanced keyboard sequences must not leak into the parent shell (herdr CHANGELOG lesson). Preserve A1's surviving-owner restoration for a killed attach process; an in-process panic/fatal hook cannot run after forced termination. The outer bootstrap/exit-notice owner performs bounded emergency restoration without giving either guardian terminal-byte relay authority.
|
|
240
240
|
|
|
241
|
+
### 6a. Solo interaction parity (2026-10-17)
|
|
242
|
+
|
|
243
|
+
Direct `a1 solo` is the behavioural oracle for every viewed resident child. Only the tab strip row and its tab actions, detach instead of exit, the hidden session name, process residency, and the text fallback for unsupported image protocols may differ.
|
|
244
|
+
|
|
245
|
+
- **Semantic input.** Attach resolves tab actions first, then names every other outer event as a bounded generation-1 `input.event`: key identity from the libghostty key table, `MOD_*` modifiers, produced text, repeat, focus, or a pointer gesture already translated to child rows. The server validates and fences it like byte input. The holder encodes it with libghostty against the child's live key, mouse, focus, and bracketed-paste modes, and falls back to the CSI u bytes direct terminals send for modified Enter, Tab, Backspace, and Escape. Double `Ctrl+C` is recognized from the key identity before any encoding; a paste or pointer activation completes another input sequence and resets the chord.
|
|
246
|
+
- **Compatibility.** `semantic-input` and `terminal-effects` are advertised features. A same-generation holder without semantic encoding answers `legacy-holder`; attach re-sends the refused event as bytes and keeps the byte path. That fallback is not certified against the parity contract.
|
|
247
|
+
- **Typed effects.** The holder registers libghostty's clipboard-write callback, which normalizes OSC 52 and OSC 1337. A write from the viewed tab crosses as one bounded `terminal.effect`; attach writes one OSC 52 for it. A hidden tab's write is dropped, never replayed into a later view. Payloads are never logged.
|
|
248
|
+
- **Modes and cursor.** Each surface carries the child's cursor cell and modes. Attach mirrors a cursor shape the child chose and resets it on detach or failure; a default block cursor is left to the outer terminal, as direct A1 leaves it.
|
|
249
|
+
- **Shortcut projection.** The owned child projects the effective A1 keybindings plus `keybindings.json` into one assignment per tab action: a key an A1 action holds never becomes a tab shortcut, and the earlier declaration keeps a duplicated key. It publishes the projection as `bridge.shortcuts`; the server relays it as `tabs.shortcuts`, and attach dispatches and labels exactly that projection. `/hotkeys` renders the same projection. A shared case file is replayed by both resolvers.
|
|
250
|
+
- **Committed presentation.** A requested view commits only with a topology that lists it and a complete target surface. Surfaces of the committed view apply in revision order, and revisions rise across holder incarnations. A retained re-offer is marked stale and parks for at most 120 ms while the fresh frame arrives. One compositor writes strip, body, overlay, and final cursor inside a single synchronized update, and refuses clear-only, blank, and cursor-less strip-only frames. Clock, hover, and title-animation damage repaints only the strip and restores the child's cursor.
|
|
251
|
+
- **Evidence.** One interaction matrix drives three layers: an owned-shell oracle that records content-free observations, role fixtures that drive real server, holder, and attach processes with a certified parity child, and an exact-artifact harness, `verify-interaction-parity.mjs`, that compares the bytes the same child observes directly and through the built host on each platform. Observations carry digests and lengths, never content. Each platform's verdict stands alone.
|
|
252
|
+
|
|
241
253
|
### 7. Status and attention come from the tab bridge
|
|
242
254
|
|
|
243
255
|
Tab status is an A1-owned state machine fed by `bridge.status`:
|
|
@@ -278,7 +290,7 @@ Tab status is an A1-owned state machine fed by `bridge.status`:
|
|
|
278
290
|
- `registryRevision`, `epoch`, and `bootId`
|
|
279
291
|
- **No per-tab credential is persisted in the registry.** The owner-only profile secret is stored separately and derives per-tab/per-incarnation credentials from recorded non-secret identities. The environment sent with `tab.create` is kept in holder memory only; a tab restarted after a crash reuses its holder's environment.
|
|
280
292
|
- **Session-writer lease.** All A1-owned session writers (resident, solo/fallback, and Pi-comparison) on the supported platforms use one profile-neutral native lock primitive before opening a session for writing, independent of launch mode. It does not start a host, holder, or bridge for direct modes. The primitive is an OS lock held by the writer process itself (`LockFileEx` on Windows, an open-file-description `fcntl` lock on Linux, `flock` on macOS), so the kernel releases it only when the writer is gone. Node writers take it in-process through a Node-API 9 artifact produced by the terminal-host Cargo package from the same lock implementation; a helper process cannot hold a lock on their behalf. Existing files are opened, identified by stable volume/device plus file identity, locked through that identity, and revalidated so case, junction/symlink, and hard-link aliases converge. A new file first holds a canonical-parent/name reservation, creates/opens without writing session content, acquires and revalidates file-identity authority while the reservation remains held, and only then admits writing; losing that race writes nothing. The writer routes include startup, `--session`, in-runtime switches, fork, import, new session, and the picker rename. The registry and holder coordinate admission, but a holder-only lock is insufficient: native lease custody must remain valid for the actual writer's lifetime, including any interval after holder death. Pin and prove the writer-bound lock/handle design on each platform in milestone 1; do not infer child death from pseudoterminal loss. Replacement requires lease acquisition and verified prior-writer/tree exit; uncertainty blocks it. Session switching acquires the target before relinquishing the old writer lease, and failed switches preserve the original session. Resident selection focuses an existing tab; direct-mode conflicts fail safely or offer an explicit fork, never silently attach or overwrite. Unmodified external Pi, older nonparticipating builds, and arbitrary file writers are outside this cooperative guarantee; document that limitation rather than claiming an OS sandbox.
|
|
281
|
-
- **Prompt journal.** `<dataDir>/tabs/<profile-token>/<tabId>/journal.jsonl` is an owner-only child-owned recovery journal, separate from asynchronous prompt history. Each submission has a stable ID and session/incarnation identity. Admission
|
|
293
|
+
- **Prompt journal.** `<dataDir>/tabs/<profile-token>/<tabId>/journal.jsonl` is an owner-only child-owned recovery journal, separate from asynchronous prompt history. Each submission has a stable ID and session/incarnation identity. Admission durably records bounded identity and recoverable editor text, never duplicate attachment payload bytes, before dispatch; timeout/failure leaves the prompt in the editor with a visible failure and dispatches nothing. The actual engine command retains every validated attachment. Correlate the record with the committed session entry, and retire it only after the corresponding session data is synchronized, including when command completion observes that the lifecycle already returned to ready; a settled turn's durable completion also records its submission ID so recovery never offers a completed prompt as unfinished. Recovery merges journal/session evidence by identity and never automatically resends, including when a crash occurs between dispatch, session append, sync, and journal retirement. It rehydrates image chips only from validated profile sidecars and removes unavailable tokens rather than presenting inert attachment labels. Preserve the first-turn journal and reserved session identity if Pi has not created its file yet; distinguish that from an unexpectedly missing existing transcript.
|
|
282
294
|
- **Draft checkpoint.** Use a periodic dirty checkpoint with a maximum one-second dirty interval while storage is healthy, including uninterrupted typing, rather than inactivity-only debounce. Expose failed/late checkpoints as degraded recovery; never continue claiming the one-second bound during a blocked disk or event-loop stall. Drafts and submitted prompts have different guarantees.
|
|
283
295
|
|
|
284
296
|
### 9. Failure and recovery
|
|
@@ -389,7 +401,7 @@ Every queue, buffer, file, and collection the resident roles keep has a declared
|
|
|
389
401
|
| Diagnostic logs | 5 MiB × 3 generations per role | `roles/diagnostics.rs` | `logs_rotate_at_their_cap_and_keep_a_bounded_number_of_generations` |
|
|
390
402
|
| Crash records | 64 KiB each, 50 records, 30 days | `roles/diagnostics.rs`, `shell/watchdog.rs` | `crash_records_are_distinct_bounded_and_allowlisted`, `crash_record_is_bounded_and_owner_only` |
|
|
391
403
|
| Last screen and private stderr sink | 2 MiB; 5 MiB × 3 generations, 7 days | `roles/recovery_artifacts.rs` | `recovery_files_are_plain_bounded_private_and_rotated`, `fixture_stderr_sink_caps_content` |
|
|
392
|
-
| Prompt journal | 8 MiB, 2 MiB per record | `src/foundation/resident-tabs/prompt-journal.ts` | `bounds append size` |
|
|
404
|
+
| Prompt journal | 8 MiB, 2 MiB per bounded metadata/text record; attachment payloads excluded | `src/foundation/resident-tabs/prompt-journal.ts` | `bounds append size`; `keeps a legal multi-image payload out of bounded journal admission and sends every image` |
|
|
393
405
|
| Session reconciliation read | 64 MiB | `src/foundation/resident-tabs/recovery.ts` | `refuses to scan a session past the 64 MiB reconciliation cap` |
|
|
394
406
|
| Release-hold report | 32 uncertainty reasons; 1 MiB read | `roles/release_holds.rs`, `release-holds.ts`, `bounded-host-command.ts` | `uncertainty_reasons_stay_within_their_cap`; `fails a release-hold report that pushes past its byte cap without returning a prefix` |
|
|
395
407
|
| Maintenance exchange | 5 s reads, 60 s stops, 4 MiB report | `roles/maintain.rs`, `maintenance.ts`, `bounded-host-command.ts` | `fails a maintenance report that pushes past its byte cap without returning a prefix`, `kills and rejects a command that outlives its deadline` |
|
|
@@ -570,6 +582,10 @@ The user made these decisions on 2026-09-24:
|
|
|
570
582
|
- `Ctrl+C` twice leaves `a1` from any tab while tabs keep running. There is no separate detach key.
|
|
571
583
|
- Reliability is a first-class, release-gating requirement (Decision 16).
|
|
572
584
|
|
|
585
|
+
On 2026-10-16 the `ci-critical-path` change replaced the Intel runner for the release builds:
|
|
586
|
+
|
|
587
|
+
- The macOS x64 process guardian and terminal host are cross-compiled on the `macos-15` arm64 runner (`npm run build:terminal-host -- --target x86_64-apple-darwin`, same for the guardian) and uploaded beside the arm64 artifacts; the Intel runner took 6 to 11 minutes for builds the arm64 runner finishes in about 4, and it gated packing in every publication. The x64 executable's `--version` identity is read by executing it through Rosetta 2 when the runner can; otherwise the manifest records a Mach-O architecture check as `provenance.identityCheck: "mach-o-header"` instead of a report nobody observed. Intel macOS stays certified separately and its physical acceptance record is unchanged; no publication lane ran the x64 bytes beyond that identity check before either, because the published-pair smoke matrix has no Intel lane.
|
|
588
|
+
|
|
573
589
|
On 2026-10-14 the user resolved the milestone-6 `darwin-x64` question:
|
|
574
590
|
|
|
575
591
|
- Add an Intel macOS runner (`macos-15-intel`) for both the process guardian and the terminal host, so every release carries `darwin-x64` binaries beside `darwin-arm64`. Intel macOS is certified separately from Apple silicon: it needs its own physical acceptance record, and the chaos group runs on macOS arm64 only.
|
|
@@ -53,7 +53,7 @@ The console proof requires:
|
|
|
53
53
|
- Rust/Cargo for the A1 terminal host;
|
|
54
54
|
- Zig `0.15.x` with patch `>= 0.15.2` to build `libghostty-vt`;
|
|
55
55
|
- the platform C/C++ build toolchain required by Rust and the PTY/input crates (Visual Studio 2022 Build Tools/MSVC on Windows, the runner image's Xcode Clang on macOS, GCC on Linux);
|
|
56
|
-
- release builds on `windows-2025`, `ubuntu-24.04`, `macos-15` (arm64
|
|
56
|
+
- release builds on `windows-2025`, `ubuntu-24.04`, and `macos-15` (arm64, which also cross-compiles the x64 artifact with `--target x86_64-apple-darwin`);
|
|
57
57
|
- an existing terminal emulator for manual validation;
|
|
58
58
|
- an isolated disposable worker for automated physical validation.
|
|
59
59
|
|
|
@@ -36,7 +36,7 @@ It contains no PTY, terminal emulator, browser/desktop GUI, custom renderer, inp
|
|
|
36
36
|
|
|
37
37
|
`npm run doctor` reports this contract against the current machine—Node range, npm major, git, the GitHub CLI, Rust/Cargo, and whether `node_modules` matches the lockfile—and names the install command for anything missing. `npm run build` runs the same check as its first step, so an unmet prerequisite fails by name rather than inside a module resolver or Cargo. Unmet tool prerequisites block; a Node or npm version outside the declared contract is reported as an advisory without failing the build.
|
|
38
38
|
|
|
39
|
-
Source builds require Rust/Cargo 1.85 or newer. `npm run build` compiles the standalone `native/process-guardian` crate for the host platform, places it under `dist/native/<platform>-<architecture>/`, and writes an integrity manifest. Preview and stable candidate workflows build platform artifacts on isolated Windows, Linux, macOS arm64,
|
|
39
|
+
Source builds require Rust/Cargo 1.85 or newer; `rust-toolchain.toml` pins the exact version CI and publication install through `scripts/development/prepare-ci-rust.sh`, and rustup selects that version for Cargo commands inside the repository, installing it on first use. The Zig cache (`mlugg/setup-zig`, one entry per workflow and platform per run, bounded to 512 MiB) stays enabled: measured on 2026-10-16, a cold Zig build of `libghostty-vt` added about 40 to 60 seconds to a terminal-host test build (Linux 2m21s cold against 1m20s warm, Windows 2m05s against 1m26s), which the cache saves on every warm run. `npm run build` compiles the standalone `native/process-guardian` crate for the host platform, places it under `dist/native/<platform>-<architecture>/`, and writes an integrity manifest. Preview and stable candidate workflows build platform artifacts on isolated Windows, Linux, and macOS arm64 runners, cross-compile the macOS x64 artifacts on the arm64 runner with `--target x86_64-apple-darwin`, and assemble them before packing. The same runners build the release terminal host and its session-writer lock with `npm run build:terminal-host`; the local `npm run build` does not, because the Zig fetch for `libghostty-vt` is quarantined by workstation antivirus on Windows (see [`terminal-host-provenance.md`](terminal-host-provenance.md)). macOS remains explicitly unsupported until its exact containment adapter is certified; the package must fail before runtime startup rather than use PID-only cleanup.
|
|
40
40
|
|
|
41
41
|
The process guardian inherits terminal handles but transports no terminal bytes. See [`process-guardian-provenance.md`](process-guardian-provenance.md).
|
|
42
42
|
|
|
@@ -71,7 +71,7 @@ This optional, mutating presentation-maintenance workflow regenerates component
|
|
|
71
71
|
|
|
72
72
|
`node scripts/pi/sync-pi-inventories.mjs` re-resolves `modal-surface-inventory.json`, `presenter-ownership-inventory.json`, and `pinned-pi-interactive-baseline.json` against the installed Pi packages: anchors that still match stay, anchors that match only ignoring whitespace are rewritten, anchors that match nowhere mark their entry `orphaned`, behavior line ranges that lost their anchors move to their symbols' span, hashes and manifests are regenerated, and interactive components the modal graph has never recorded are reported as unmapped. `--check` reports without writing; `--commit <sha>` records a new version's upstream commit; `--report <path>` writes the resolution report.
|
|
73
73
|
|
|
74
|
-
`node scripts/pi/propose-pi-upgrade.mjs [--version <v>] [--commit <sha>] [--skip <v>...] [--refresh] [--output <dir>]` proposes a Pi upgrade in the working tree: it captures the old upstream sources, pins both packages at the target (by default the newest published version newer than the pin that is not skipped; `--version` ignores skips), evaluates the candidate through `pi-candidate-evaluator.mjs` and keeps the complete compile output in the artifact (summarized per file in the
|
|
74
|
+
`node scripts/pi/propose-pi-upgrade.mjs [--version <v>] [--commit <sha>] [--skip <v>...] [--refresh] [--output <dir>]` proposes a Pi upgrade in the working tree: it captures the old upstream sources, pins both packages at the target (by default the newest published version newer than the pin that is not skipped; `--version` ignores skips), evaluates the candidate through `pi-candidate-evaluator.mjs` and keeps the complete compile output in the artifact (summarized per file in the sync report), installs and builds, three-way merges each vendored copy under `src/integrations/pi/components/upstream/` whose ledger record says `upgradeStrategy: three-way` (`git merge-file --diff3` of the A1 copy, the old upstream, and the new upstream; conflict markers stay in the file as review items) and, for a `keep-owned` copy, leaves the file alone and writes the upstream delta to `kept/<record>.diff` in the artifact, regenerates the ledger and headers, re-resolves the inventories, refreshes the public API baseline (listing removed or changed exports with their A1 consumers as adoption items) and the feature adoption matrix (listing new upstream rows as pending), re-pins the startup graph, refreshes parity evidence, runs the type, architecture, engine-conformance, and parity gates, scaffolds `openspec/changes/pi-upgrade-<version>/` with the pin moved in the requirement that names it (only when the change directory is absent), and writes `report.json`, the pull-request `body.md` in the ordinary delivery layout with its generated implementation and acceptance outcomes, and the sync report `comment.md` carrying the version delta, changelog excerpt, verdicts, and review items. A failed step is recorded and the run continues; while conflict markers remain in any copy, the gates that compile the tree (`startup-graph`, `parity`, `typecheck`, `architecture`, `parity-suites`) are recorded as `blocked` by those copies instead of running to fail, and the isolated evaluation and engine conformance still report the candidate's verdicts. `--refresh` re-runs the derived steps and gates on the checked-out proposal branch without bumping, evaluating, installing, or merging, comparing against the pin of `--base` (`origin/develop`). `.github/workflows/pi-upstream-sync.yml` runs it nightly and opens the draft pull request `chore/pi-<version>` with the App identity and posts the sync report comment; every later run posts another comment and never edits the body, whose outcomes the reviewer checks, and a branch that carries commits the bot did not author is never pushed to. Closing a proposal with the `pi-upgrade-skipped` label skips its version; `PI_UPGRADE_FREEZE_UNTIL` silences the schedule until a date. A human resolves the review items and merges. The pinned identity every check compares itself to comes from `scripts/governance/pinned-pi-identity.mjs`: versions from the dependency authority, the commit from `pinned-pi-interactive-baseline.json`.
|
|
75
75
|
|
|
76
76
|
`node scripts/pi/update-pinned-pi-public-api.mjs [--check] [--packages-root <node_modules>] [--output <path>]` records `config/baselines/pinned-pi-public-api.json`, the package-root export surface of both pinned packages read from their declaration entries with the TypeScript compiler API: each export's kind, the hash of its normalized declaration, and the A1 modules under `src/` whose imports name it, directly or through a barrel such as `startup-public.ts`. The baseline is tooling evidence read by path, never a production import. `node scripts/pi/update-pi-feature-adoption-matrix.mjs [--check] [--packages-root <node_modules>] [--report <path>]` records `config/baselines/pi-feature-adoption-matrix.json`: one row per advertised and hidden command, TUI and app keybinding, session event, settings callback, presented setting, and stateful component from the interactive baseline's manifests and the engine's settings source, plus one row per changelog "New Features" entry newer than the matrix's `changelogSince`, each carrying A1's disposition: `pinned` (reused as is), `owned` (the behavior id and the test that proves it), `diverged` (the approved deviation id), `declined` (a reason), or `pending` (what the refresher writes for a new row). The refresher rewrites the upstream side only and marks a row upstream dropped `retired`; `test/repository-governance/pi-feature-adoption-matrix.test.ts` fails on a pending row, on missing evidence, and on a row whose feature upstream no longer presents unless it is retired. `node scripts/pi/update-startup-graph-baseline.mjs [--check]` re-pins the file and byte totals in `config/startup-graph-baseline.json` from the measured startup reachability and the manifest the last build wrote; optional modules and pinned dynamic imports stay reviewed.
|
|
77
77
|
|
|
@@ -88,7 +88,7 @@ effect of stable publication, not a trigger.
|
|
|
88
88
|
| Native **Publish release** on the prepared draft | GitHub creates the source-bound tag; `.github/workflows/release.yml` requires the successful candidate run, adopts the package pair it validated (replacing only the packaged release-note resource when the note was edited), proves npm trust, publishes both packages to npm `latest`, and proposes one reopening-and-note PR that auto-merges after required CI; a failure before npm returns the Release to draft |
|
|
89
89
|
| `.github/workflows/release-tag-cleanup.yml` | When a stable Release is deleted, or on dispatch with a version (`gh workflow run release-tag-cleanup.yml -f version=X.Y.Z`): the release-automation App deletes the leftover `vX.Y.Z` tag only while no Release uses it and npm serves neither package; a published version's tag is permanent |
|
|
90
90
|
| `.github/workflows/full-regression.yml` | Additional on-demand complete regression without publication authority |
|
|
91
|
-
| `.github/workflows/pi-upstream-sync.yml` | Nightly at `03:23 UTC`: when npm publishes a newer Pi than the pin that no closed proposal skipped, proposes the upgrade as a draft pull request with the vendored copies that follow upstream merged, the kept copies reported with their upstream delta, the ledger, headers, inventories, public API and feature baselines, startup graph, and parity evidence regenerated, and every gate verdict (passed, failed, or blocked by conflict markers) and review item
|
|
91
|
+
| `.github/workflows/pi-upstream-sync.yml` | Nightly at `03:23 UTC`: when npm publishes a newer Pi than the pin that no closed proposal skipped, proposes the upgrade as a draft pull request with the vendored copies that follow upstream merged, the kept copies reported with their upstream delta, the ledger, headers, inventories, public API and feature baselines, startup graph, and parity evidence regenerated, and the body in the ordinary delivery layout with its four implementation outcomes and one acceptance outcome generated, and posts a sync report comment carrying the version delta, changelog excerpt, every gate verdict (passed, failed, or blocked by conflict markers), and review item; every later run posts another comment and never edits the body; never merges and never replaces a proposal a human has continued |
|
|
92
92
|
| `.github/workflows/nightly-regression-triage.yml` | After every completed `Full regression` run on `develop` or scheduled `Publish` validation: judges the startup budget across the three most recent runs and, after a failure or a persistent overrun, opens `fix/nightly-regression-<date>` as a draft pull request in the ordinary delivery layout with its two implementation outcomes and one acceptance outcome generated, posts a triage comment carrying the failed commands per lane, their tests, a bounded log excerpt, and the `develop` commits since the last green run, and commits an OpenSpec fix scaffold, or refreshes the open candidate with the same failed scope set through another comment and design record; re-runs nothing, never writes `develop`, never merges |
|
|
93
93
|
|
|
94
94
|
## Impact-aware development validation
|
|
@@ -372,7 +372,7 @@ Rules that do not bend:
|
|
|
372
372
|
with another token.
|
|
373
373
|
- **Repository governance drifts:** run the read-only checker, review every reported
|
|
374
374
|
path, and use the confirmed apply mode only for an accepted mutable policy change.
|
|
375
|
-
- **A Pi upgrade proposal needs a re-run:** the sync never force-pushes over `chore/pi-<version>` once it carries a commit the bot did not author; a scheduled re-run posts its fresh verdicts as
|
|
375
|
+
- **A Pi upgrade proposal needs a re-run:** the sync never force-pushes over `chore/pi-<version>` once it carries a commit the bot did not author; a scheduled re-run posts its fresh verdicts as another sync report comment headed with the version and date and never edits the description. The description is the ordinary delivery layout: check each generated implementation outcome as its work completes, including one the report shows nothing for, never rewrite the generated items, and let trusted readiness promote the all-checked draft like any other. To re-run the derived steps and gates on the reviewer's head, dispatch the workflow with `refresh` and the `version`; it checks out the proposal branch, skips bump, evaluation, install, and merge, and reports without pushing. A branch whose commits are all the bot's is recreated from `develop` as before.
|
|
376
376
|
- **A Pi version should not be adopted:** close its proposal pull request with the `pi-upgrade-skipped` label (declared in `config/github-repository-governance.json`) and say why in the closing comment; the next run proposes the newest unskipped version newer than the pin, or nothing, and names the skipped versions in its log. A proposal closed without the label is proposed again the next night. Dispatching the workflow with a `version` ignores skips, which is how a skipped version is reconsidered. To silence the schedule through a release window, set the repository variable `PI_UPGRADE_FREEZE_UNTIL` to a date (`2026-10-01`); scheduled runs exit before proposing until it passes, manual dispatches still run.
|
|
377
377
|
- **Nightly documentation review fails:** inspect the reported paths and rules, identify the introducing merge from the nightly interval, and repair the invariant before unrelated work proceeds.
|
|
378
378
|
- **Development publication fails:** inspect both package versions and digests, fix the cause, and rerun `npm run develop`; an npm version that already exists is verified and never overwritten.
|
|
@@ -8,9 +8,9 @@ Version-1 and version-2 deliveries and their existing comments, acceptance PRs,
|
|
|
8
8
|
|
|
9
9
|
## Version-3 lifecycle
|
|
10
10
|
|
|
11
|
-
1. **Draft plan:** create one normally named branch/PR such as `feature/...`, `fix/...`, or `chore/...`. Start the body with `## Proposal`, use it for one or two sentences of intent, and follow it with two to ten unchecked, outcome-sized task items under `## Implementation`. Omit generic process tasks, quoted phase lines
|
|
12
|
-
2. **Same-PR implementation:** continue after explicit approval in the same worktree, branch, history, draft PR, and phase-free body. Check an Implementation item as soon as its associated
|
|
13
|
-
3. **Complete
|
|
11
|
+
1. **Draft plan:** create one normally named branch/PR such as `feature/...`, `fix/...`, or `chore/...`. Start the body with `## Proposal`, use it for one or two sentences of intent, and follow it with two to ten unchecked, outcome-sized task items under `## Implementation`. Each item names a delivered code outcome. Omit generic process tasks; run, verify, validate, evidence, or manual-test items; quoted phase lines; and routine validation command lists, and keep machine linkage under final collapsed `Automation`. Keep it draft and include only planning artifacts until the maintainer approves the plan and explicitly requests implementation.
|
|
12
|
+
2. **Same-PR implementation:** continue after explicit approval in the same worktree, branch, history, draft PR, and phase-free body. Check an Implementation item as soon as its associated code and tests are written and its detailed task bookkeeping is complete; an ordinary progress edit changes only `[ ]` to `[x]` and is not deferred until handoff. Adding, removing, reordering, or rewriting an item is a scope refinement requiring explicit approval and coherent planning updates, with affected scope left unchecked. Reconcile approved refinements before corresponding code edits.
|
|
13
|
+
3. **Complete implementation:** finish the code and its tests, substantive tasks, and explicit known-gap disposition. CI runs those tests after readiness; its success is objective evidence, not acceptance, and GitHub check counts are not Implementation task progress. Manual validation is the maintainer's optional choice before integrating and never blocks a checkbox, finalization, or merge.
|
|
14
14
|
4. **Plain acceptance list:** before checking the final item, keep the body phase-free and add final `## Acceptance` with one to ten concise implementation-specific behavior-and-result bullets. Do not use checkboxes, generic review/CI/approval/archive statements, angle-bracket placeholders or HTML, URLs, mentions, or automated-test inventory.
|
|
15
15
|
5. **Automatic readiness and finalization:** reconcile and push current `origin/develop`, run the [delivery body check](#delivery-body-check) on the intended final body, then check the final item. That checkbox update completes the agent-owned implementation job; agents never mark implementation PRs ready themselves. Trusted automation revalidates the exact fully complete version-3 task-list snapshot and all pre-finalization inputs, marks the PR ready, and then conservatively synchronizes all deltas, moves the active change into its dated archive, stages the conditional acceptance manifest, commits that to the same branch with the archive App identity, and writes the emitted paths into the body's implementation fence. It never checks tasks or infers completion. Running the [finalization command](#finalization-command) locally first is optional and yields the same bytes.
|
|
16
16
|
6. **Validate:** one normal exact-head workflow validates the finalized head: implementation, synchronized specs, archive, manifest, tasks/evidence, exact PR-body list, and every selected product/governance scope before emitting the stable protected aggregate. A new commit or acceptance-list change re-finalizes automatically when needed and requires full renewed validation; no lifecycle body edit or second workflow run is required.
|
|
@@ -50,7 +50,7 @@ Replace the multi-PR OpenSpec handoff with one manually merged development PR wh
|
|
|
50
50
|
</details>
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
Do not add a quoted phase line, generic CI/review/acceptance/merge/archive tasks, or a routine `Validation` section listing commands to an initial draft. Actual validation results belong in CI and the eventual implementation handoff. Continue with the same phase-free body after approval. Toggle only the exact marker when ordinary work completes; body history must not hide a scope change as progress. Historical version-3 bodies with only plain Implementation bullets remain readable, but new bodies use the task-list form. When implementation is complete and ready for required tests, use this visible order:
|
|
53
|
+
Do not add a quoted phase line, generic CI/review/acceptance/merge/archive tasks, run/verify/validate/evidence/manual-test items, or a routine `Validation` section listing commands to an initial draft. Actual validation results belong in CI and the eventual implementation handoff. Continue with the same phase-free body after approval. Toggle only the exact marker when ordinary work completes; body history must not hide a scope change as progress. Historical version-3 bodies with only plain Implementation bullets remain readable, but new bodies use the task-list form. When implementation is complete and ready for required tests, use this visible order:
|
|
54
54
|
|
|
55
55
|
```markdown
|
|
56
56
|
## Proposal
|
|
@@ -141,7 +141,7 @@ Use plain bullets:
|
|
|
141
141
|
- Finalized specs and archive match the implementation.
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
Each Implementation and Acceptance item is one line of 20 to 300 bytes. It must not contain angle-bracket text such as `<job>` or other HTML, URLs, or `@` mentions, and Acceptance items must not be checkboxes. Write a concrete example instead of a placeholder, such as `Develop / Build process guardian`.
|
|
144
|
+
Each Implementation and Acceptance item is one line of 20 to 300 bytes. Draft promotion and the delivery body check reject an Implementation item that starts with `Manually`, `Validate`, `Verify`, `Confirm`, `Prove`, `Run`, or `Test`, mentions manual testing, records or captures evidence, or delivers work "with" coverage, evidence, or validation (`implementation-progress-validation`); merged bodies keep their earlier wording. It must not contain angle-bracket text such as `<job>` or other HTML, URLs, or `@` mentions, and Acceptance items must not be checkboxes. Write a concrete example instead of a placeholder, such as `Develop / Build process guardian`.
|
|
145
145
|
|
|
146
146
|
### Delivery body check
|
|
147
147
|
|