@gajae-code/coding-agent 0.12.4 → 0.12.6
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/CHANGELOG.md +36 -0
- package/README.md +4 -1
- package/dist/types/async/job-manager.d.ts +9 -1
- package/dist/types/eval/backend.d.ts +2 -2
- package/dist/types/exec/bash-executor.d.ts +10 -8
- package/dist/types/extensibility/extensions/runner.d.ts +9 -7
- package/dist/types/gjc-runtime/launch-tmux.d.ts +22 -3
- package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -0
- package/dist/types/gjc-runtime/team-launch.d.ts +3 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +14 -2
- package/dist/types/gjc-runtime/team-store.d.ts +0 -4
- package/dist/types/gjc-runtime/team-workers.d.ts +5 -0
- package/dist/types/gjc-runtime/tmux-common.d.ts +1 -0
- package/dist/types/gjc-runtime/tmux-provider-context.d.ts +57 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +8 -1
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +3 -0
- package/dist/types/gjc-runtime/ultragoal-review-source.d.ts +83 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +57 -4
- package/dist/types/internal-urls/registry-helpers.d.ts +18 -0
- package/dist/types/modes/components/gjc-bundle-settings.d.ts +1 -0
- package/dist/types/modes/components/plugin-settings.d.ts +2 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/sdk/broker/broker.d.ts +18 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +13 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +1 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +5 -2
- package/dist/types/sdk/bus/index.d.ts +4 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +7 -3
- package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -3
- package/dist/types/sdk/bus/topic-registry.d.ts +63 -3
- package/dist/types/sdk/host/host.d.ts +23 -2
- package/dist/types/sdk/host/reverse-leases.d.ts +7 -4
- package/dist/types/session/agent-session.d.ts +5 -4
- package/dist/types/session/artifacts.d.ts +8 -5
- package/dist/types/session/attempt-record-store.d.ts +19 -0
- package/dist/types/session/client-bridge.d.ts +14 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -23
- package/dist/types/session/messages.d.ts +4 -1
- package/dist/types/session/session-manager.d.ts +7 -5
- package/dist/types/session/session-storage.d.ts +8 -0
- package/dist/types/session/streaming-output.d.ts +32 -0
- package/dist/types/task/executor.d.ts +1 -1
- package/dist/types/task/index.d.ts +2 -1
- package/dist/types/task/receipt.d.ts +3 -0
- package/dist/types/task/types.d.ts +194 -0
- package/dist/types/task/worktree.d.ts +13 -6
- package/dist/types/tools/bash.d.ts +1 -1
- package/dist/types/tools/fetch.d.ts +3 -0
- package/dist/types/tools/output-meta.d.ts +37 -5
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/tools/tool-result.d.ts +1 -0
- package/dist/types/utils/artifact-id.d.ts +2 -0
- package/dist/types/utils/git.d.ts +1 -0
- package/package.json +8 -8
- package/scripts/capture-sticky-viewport-showcase.ts +131 -5
- package/scripts/verify-gjc-sdk-canonicalization.ts +128 -183
- package/scripts/verify-sticky-viewport-showcase.ts +620 -93
- package/src/async/job-manager.ts +13 -5
- package/src/config/model-profiles.ts +8 -0
- package/src/config/settings-schema.ts +17 -3
- package/src/cursor.ts +20 -13
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +5 -2
- package/src/eval/backend.ts +2 -2
- package/src/exec/bash-executor.ts +425 -151
- package/src/extensibility/extensions/runner.ts +80 -6
- package/src/extensibility/extensions/wrapper.ts +22 -15
- package/src/extensibility/runtime-skill-discovery.ts +4 -6
- package/src/gjc-runtime/launch-tmux.ts +309 -293
- package/src/gjc-runtime/managed-owner-supervisor.ts +6 -2
- package/src/gjc-runtime/psmux-detect.ts +52 -6
- package/src/gjc-runtime/team-launch.ts +50 -2
- package/src/gjc-runtime/team-runtime.ts +716 -251
- package/src/gjc-runtime/team-store.ts +25 -7
- package/src/gjc-runtime/team-workers.ts +161 -1
- package/src/gjc-runtime/tmux-common.ts +16 -4
- package/src/gjc-runtime/tmux-gc.ts +37 -5
- package/src/gjc-runtime/tmux-owner-isolation.ts +2 -0
- package/src/gjc-runtime/tmux-provider-context.ts +451 -0
- package/src/gjc-runtime/tmux-sessions.ts +409 -156
- package/src/gjc-runtime/ultragoal-change-set.ts +90 -44
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +7 -0
- package/src/gjc-runtime/ultragoal-review-source.ts +378 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +640 -159
- package/src/gjc-runtime/workflow-manifest.generated.json +40 -1
- package/src/gjc-runtime/workflow-manifest.ts +12 -0
- package/src/internal-urls/agent-protocol.ts +98 -38
- package/src/internal-urls/artifact-protocol.ts +28 -17
- package/src/internal-urls/docs-index.generated.ts +6 -6
- package/src/internal-urls/local-protocol.ts +39 -18
- package/src/internal-urls/registry-helpers.ts +62 -0
- package/src/modes/acp/acp-agent.ts +51 -13
- package/src/modes/acp/acp-client-bridge.ts +154 -11
- package/src/modes/components/gjc-bundle-settings.ts +2 -0
- package/src/modes/components/plugin-settings.ts +5 -0
- package/src/modes/components/settings-selector.ts +4 -0
- package/src/modes/controllers/selector-controller.ts +1 -0
- package/src/prompts/tools/bash.md +2 -2
- package/src/prompts/tools/monitor.md +4 -4
- package/src/sdk/acp/adapter.ts +200 -9
- package/src/sdk/broker/broker.ts +93 -10
- package/src/sdk/broker/lifecycle-ledger.ts +227 -11
- package/src/sdk/broker/lifecycle.ts +692 -98
- package/src/sdk/bus/chat-daemon-control.ts +33 -5
- package/src/sdk/bus/index.ts +347 -14
- package/src/sdk/bus/telegram-daemon-contract.ts +7 -3
- package/src/sdk/bus/telegram-daemon.ts +283 -44
- package/src/sdk/bus/topic-registry.ts +133 -10
- package/src/sdk/host/host.ts +187 -9
- package/src/sdk/host/reverse-leases.ts +249 -42
- package/src/sdk/session.ts +8 -6
- package/src/session/agent-session.ts +930 -354
- package/src/session/artifacts.ts +211 -74
- package/src/session/attempt-record-store.ts +106 -0
- package/src/session/client-bridge.ts +15 -0
- package/src/session/internal/managed-session-scope.ts +332 -198
- package/src/session/internal/managed-session-storage.ts +162 -450
- package/src/session/messages.ts +32 -7
- package/src/session/session-manager.ts +31 -28
- package/src/session/session-storage.ts +190 -53
- package/src/session/streaming-output.ts +198 -40
- package/src/task/executor.ts +5 -2
- package/src/task/index.ts +277 -64
- package/src/task/provider-retry-status.ts +4 -1
- package/src/task/receipt.ts +26 -2
- package/src/task/render.ts +42 -1
- package/src/task/types.ts +52 -0
- package/src/task/worktree.ts +122 -43
- package/src/tools/bash.ts +818 -239
- package/src/tools/eval.ts +99 -4
- package/src/tools/fetch.ts +77 -15
- package/src/tools/find.ts +7 -3
- package/src/tools/monitor.ts +7 -1
- package/src/tools/output-meta.ts +706 -116
- package/src/tools/search.ts +9 -4
- package/src/tools/subagent-render.ts +5 -2
- package/src/tools/subagent.ts +8 -0
- package/src/tools/tool-result.ts +1 -0
- package/src/utils/artifact-id.ts +6 -0
- package/src/utils/git.ts +2 -0
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
* Tools populate details.meta using the fluent OutputMetaBuilder.
|
|
5
5
|
* The tool wrapper automatically formats and appends notices at message boundary.
|
|
6
6
|
*/
|
|
7
|
-
import type { AgentTool } from "@gajae-code/agent-core";
|
|
7
|
+
import type { AgentTool, AgentToolContext, AgentToolResult } from "@gajae-code/agent-core";
|
|
8
8
|
import { type Settings } from "../config/settings";
|
|
9
9
|
import type { Theme } from "../modes/theme/theme";
|
|
10
10
|
import { type OutputSummary, type ReadWindow, type TruncationResult } from "../session/streaming-output";
|
|
11
|
+
export { isValidArtifactId } from "../utils/artifact-id";
|
|
11
12
|
/**
|
|
12
13
|
* Truncation metadata for the output notice.
|
|
13
14
|
*/
|
|
@@ -48,8 +49,16 @@ export interface TruncationMeta {
|
|
|
48
49
|
elidedLines?: number;
|
|
49
50
|
/** Artifact ID when output was persisted; completeness is tracked separately below. */
|
|
50
51
|
artifactId?: string;
|
|
52
|
+
/** Artifact existence was proven by a successful save or publisher receipt. */
|
|
53
|
+
artifactVerified?: boolean;
|
|
51
54
|
/** Bytes omitted from an artifact after its hard storage cap was reached. */
|
|
52
55
|
artifactTruncatedBytes?: number;
|
|
56
|
+
/** Bytes dropped before Bash received the native output stream. */
|
|
57
|
+
sourceTruncatedBytes?: number;
|
|
58
|
+
/** Exact source capture completeness could not be proven. */
|
|
59
|
+
sourceCaptureIncomplete?: boolean;
|
|
60
|
+
/** Bytes omitted from the visible output by per-line column capping. */
|
|
61
|
+
columnDroppedBytes?: number;
|
|
53
62
|
/** Bounded diagnostic when artifact writer creation, write, or finalization failed. */
|
|
54
63
|
artifactFailureDiagnostic?: string;
|
|
55
64
|
/** Next offset for pagination (head truncation only) */
|
|
@@ -103,12 +112,17 @@ export interface OutputMeta {
|
|
|
103
112
|
source?: SourceMeta;
|
|
104
113
|
diagnostics?: DiagnosticMeta;
|
|
105
114
|
limits?: LimitsMeta;
|
|
115
|
+
/** Diagnostics were omitted to preserve the configured inline byte cap. */
|
|
116
|
+
diagnosticsOmitted?: boolean;
|
|
106
117
|
}
|
|
107
118
|
export interface TruncationOptions {
|
|
108
119
|
direction: "head" | "tail" | "middle";
|
|
109
120
|
startLine?: number;
|
|
110
121
|
totalFileLines?: number;
|
|
111
122
|
artifactId?: string;
|
|
123
|
+
artifactVerified?: boolean;
|
|
124
|
+
artifactFailureDiagnostic?: string;
|
|
125
|
+
sourceCaptureIncomplete?: boolean;
|
|
112
126
|
maxBytes?: number;
|
|
113
127
|
noticeOwner?: "body";
|
|
114
128
|
}
|
|
@@ -124,6 +138,8 @@ export interface TruncationTextOptions {
|
|
|
124
138
|
totalBytes?: number;
|
|
125
139
|
maxBytes?: number;
|
|
126
140
|
artifactId?: string;
|
|
141
|
+
artifactVerified?: boolean;
|
|
142
|
+
sourceCaptureIncomplete?: boolean;
|
|
127
143
|
noticeOwner?: "body";
|
|
128
144
|
}
|
|
129
145
|
/**
|
|
@@ -145,6 +161,7 @@ export declare class OutputMetaBuilder {
|
|
|
145
161
|
/** Add metadata from the actual head/tail windows retained by middle truncation. */
|
|
146
162
|
truncationWindows(windows: ReadWindow, options?: {
|
|
147
163
|
artifactId?: string;
|
|
164
|
+
artifactVerified?: boolean;
|
|
148
165
|
noticeOwner?: "body";
|
|
149
166
|
maxBytes?: number;
|
|
150
167
|
rangeBase?: "file" | "window";
|
|
@@ -182,10 +199,24 @@ export declare class OutputMetaBuilder {
|
|
|
182
199
|
/** Create a new OutputMetaBuilder. */
|
|
183
200
|
export declare function outputMeta(): OutputMetaBuilder;
|
|
184
201
|
export declare function formatFullOutputReference(artifactId: string): string;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
202
|
+
export interface ArtifactFailurePreview {
|
|
203
|
+
text: string;
|
|
204
|
+
omittedBytes: number;
|
|
205
|
+
}
|
|
206
|
+
/** Build a bounded, UTF-8-safe preview when artifact storage cannot retain the full payload. */
|
|
207
|
+
export declare function createArtifactFailurePreview(fullText: string, maxInlineBytes: number | undefined, diagnostic: string): ArtifactFailurePreview;
|
|
208
|
+
/** Format an artifact reference without claiming completeness when capture or storage omitted bytes. */
|
|
209
|
+
export declare function formatArtifactReference(artifactId: string, artifactTruncatedBytes?: number, sourceTruncatedBytes?: number, sourceCaptureIncomplete?: boolean): string;
|
|
210
|
+
export interface ArtifactEvidence {
|
|
211
|
+
artifactId?: string;
|
|
212
|
+
artifactVerified?: boolean;
|
|
213
|
+
artifactTruncatedBytes?: number;
|
|
214
|
+
sourceTruncatedBytes?: number;
|
|
215
|
+
sourceCaptureIncomplete?: boolean;
|
|
216
|
+
artifactFailureDiagnostic?: string;
|
|
217
|
+
columnDroppedBytes?: number;
|
|
218
|
+
}
|
|
219
|
+
export declare function formatArtifactEvidenceNotice(evidence: ArtifactEvidence): string | undefined;
|
|
189
220
|
export declare function formatTruncationMetaNotice(truncation: TruncationMeta): string;
|
|
190
221
|
/**
|
|
191
222
|
* Format styled artifact reference with warning color and brackets.
|
|
@@ -238,6 +269,7 @@ export declare function resolveBashOutputSinkHeadBytes(s: Settings): number;
|
|
|
238
269
|
* line-buffer post-processing, so one setting controls both surfaces.
|
|
239
270
|
*/
|
|
240
271
|
export declare function resolveOutputMaxColumns(s: Settings | undefined): number;
|
|
272
|
+
export declare function finalizeToolResultForDelivery(result: AgentToolResult, toolName: string, context: AgentToolContext | undefined): Promise<AgentToolResult>;
|
|
241
273
|
/**
|
|
242
274
|
* Wrap a tool to:
|
|
243
275
|
* 1. Automatically append output notices based on details.meta
|
|
@@ -57,6 +57,8 @@ export interface SubagentSnapshot {
|
|
|
57
57
|
requestedModel?: string;
|
|
58
58
|
/** True when the requested model lacked credentials and fell back to the parent model. */
|
|
59
59
|
modelFellBack?: boolean;
|
|
60
|
+
/** True when the effective subagent provider is in fast mode. */
|
|
61
|
+
fastMode?: boolean;
|
|
60
62
|
}
|
|
61
63
|
export type SubagentAwaitOutcome = "completed" | "timed_out" | "interrupted";
|
|
62
64
|
export interface SubagentToolDetails {
|
|
@@ -14,6 +14,7 @@ export declare class ToolResultBuilder<TDetails extends DetailsWithMeta> {
|
|
|
14
14
|
truncation(result: TruncationResult, options: TruncationOptions): this;
|
|
15
15
|
truncationWindows(windows: ReadWindow, options?: {
|
|
16
16
|
artifactId?: string;
|
|
17
|
+
artifactVerified?: boolean;
|
|
17
18
|
noticeOwner?: "body";
|
|
18
19
|
maxBytes?: number;
|
|
19
20
|
rangeBase?: "file" | "window";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/coding-agent",
|
|
4
|
-
"version": "0.12.
|
|
4
|
+
"version": "0.12.6",
|
|
5
5
|
"description": "Gajae Code CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
7
7
|
"author": "Yeachan-Heo and Gajae Code Contributors",
|
|
@@ -53,13 +53,13 @@
|
|
|
53
53
|
"@agentclientprotocol/sdk": "1.3.0",
|
|
54
54
|
"@babel/parser": "^7.29.3",
|
|
55
55
|
"@mozilla/readability": "^0.6.0",
|
|
56
|
-
"@gajae-code/stats": "0.12.
|
|
57
|
-
"@gajae-code/agent-core": "0.12.
|
|
58
|
-
"@gajae-code/ai": "0.12.
|
|
59
|
-
"@gajae-code/bridge-client": "0.12.
|
|
60
|
-
"@gajae-code/natives": "0.12.
|
|
61
|
-
"@gajae-code/tui": "0.12.
|
|
62
|
-
"@gajae-code/utils": "0.12.
|
|
56
|
+
"@gajae-code/stats": "0.12.6",
|
|
57
|
+
"@gajae-code/agent-core": "0.12.6",
|
|
58
|
+
"@gajae-code/ai": "0.12.6",
|
|
59
|
+
"@gajae-code/bridge-client": "0.12.6",
|
|
60
|
+
"@gajae-code/natives": "0.12.6",
|
|
61
|
+
"@gajae-code/tui": "0.12.6",
|
|
62
|
+
"@gajae-code/utils": "0.12.6",
|
|
63
63
|
"@puppeteer/browsers": "^2.13.0",
|
|
64
64
|
"@types/turndown": "5.0.6",
|
|
65
65
|
"@xterm/headless": "^6.0.0",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
|
|
3
4
|
import {
|
|
4
5
|
renderStickyViewportShowcase,
|
|
5
6
|
STICKY_VIEWPORT_SHOWCASE_ENTRIES,
|
|
@@ -7,6 +8,10 @@ import {
|
|
|
7
8
|
type StickyViewportShowcaseEntry,
|
|
8
9
|
} from "../test/fixtures/tui/sticky-viewport-showcase";
|
|
9
10
|
|
|
11
|
+
export const REPOSITORY_ROOT = path.resolve(import.meta.dir, "../../..");
|
|
12
|
+
export const resolveRepositoryPath = (repositoryRelativePath: string): string =>
|
|
13
|
+
path.join(REPOSITORY_ROOT, repositoryRelativePath);
|
|
14
|
+
|
|
10
15
|
const COMMAND =
|
|
11
16
|
"bun packages/coding-agent/scripts/capture-sticky-viewport-showcase.ts --out .gjc/qa/sticky-viewport-<run>";
|
|
12
17
|
const REVISION = "sticky-viewport-showcase-v2";
|
|
@@ -168,17 +173,126 @@ export function ansiToHtml(value: string): string {
|
|
|
168
173
|
return `<!doctype html><html lang="en"><meta charset="utf-8"><title>Sticky viewport showcase</title><style>body{margin:0;background:#110b0b;color:#ffe7dc}pre{white-space:pre;font-family:ui-monospace,monospace}@keyframes blink{50%{visibility:hidden}}</style><pre>${body}</pre></html>\n`;
|
|
169
174
|
}
|
|
170
175
|
const json = (value: unknown) => `${JSON.stringify(value, null, 2)}\n`;
|
|
171
|
-
const hash = (value: string) => new Bun.CryptoHasher("sha256").update(value).digest("hex");
|
|
176
|
+
const hash = (value: string | Uint8Array) => new Bun.CryptoHasher("sha256").update(value).digest("hex");
|
|
177
|
+
const PROVENANCE_SOURCES = [
|
|
178
|
+
"packages/coding-agent/test/fixtures/tui/sticky-viewport-showcase.ts",
|
|
179
|
+
"packages/coding-agent/scripts/capture-sticky-viewport-showcase.ts",
|
|
180
|
+
"packages/coding-agent/scripts/verify-sticky-viewport-showcase.ts",
|
|
181
|
+
"packages/coding-agent/src/modes/interactive-mode.ts",
|
|
182
|
+
"packages/coding-agent/src/modes/components/irc-sidebar.ts",
|
|
183
|
+
"packages/tui/src/tui.ts",
|
|
184
|
+
] as const;
|
|
185
|
+
// Working-tree scope for `git_diff_binary_sha256`, persisted alongside the digest
|
|
186
|
+
// as `git_diff_scope` so a reviewer reads the covered surface off the bundle
|
|
187
|
+
// instead of inferring it.
|
|
188
|
+
//
|
|
189
|
+
// This digest used to hash `git diff --binary HEAD --` over the ENTIRE worktree.
|
|
190
|
+
// The verifier recomputes it live at verify time, so that coupled bundle validity
|
|
191
|
+
// to every tracked file in the repo: an unrelated edit anywhere — a doc typo,
|
|
192
|
+
// another package's test — retroactively made every already-captured bundle
|
|
193
|
+
// "stale". Those are false positives, and they are nondeterministic, because any
|
|
194
|
+
// write landing in the capture→verify window flips the digest mid-run and masks
|
|
195
|
+
// whichever guard was actually under test.
|
|
196
|
+
//
|
|
197
|
+
// The scope below is the transitive render-dependency closure of the fixture:
|
|
198
|
+
// every workspace package the capture reaches (coding-agent → agent, ai,
|
|
199
|
+
// bridge-client, natives, stats, tui, utils), the fixture plus the virtual
|
|
200
|
+
// terminal it paints into, both showcase scripts, and the lockfile pinning the
|
|
201
|
+
// installed dependency versions. Uncommitted edits inside this closure still
|
|
202
|
+
// invalidate a bundle — that is the property the staleness guard exists to
|
|
203
|
+
// enforce. Edits outside it no longer can, because they cannot change the paint.
|
|
204
|
+
export const PROVENANCE_DIFF_SCOPE = [
|
|
205
|
+
"Cargo.lock",
|
|
206
|
+
"Cargo.toml",
|
|
207
|
+
"bun.lock",
|
|
208
|
+
"crates",
|
|
209
|
+
|
|
210
|
+
"packages/agent/src",
|
|
211
|
+
"packages/ai/src",
|
|
212
|
+
"packages/bridge-client/src",
|
|
213
|
+
"packages/coding-agent/scripts/capture-sticky-viewport-showcase.ts",
|
|
214
|
+
"packages/coding-agent/scripts/verify-sticky-viewport-showcase.ts",
|
|
215
|
+
"packages/coding-agent/src",
|
|
216
|
+
"packages/coding-agent/test/fixtures/tui/sticky-viewport-showcase.ts",
|
|
217
|
+
"packages/natives/native",
|
|
218
|
+
"packages/stats/src",
|
|
219
|
+
"packages/tui/src",
|
|
220
|
+
"packages/tui/test/virtual-terminal.ts",
|
|
221
|
+
"packages/utils/src",
|
|
222
|
+
] as const;
|
|
223
|
+
async function git(args: string[]): Promise<Uint8Array> {
|
|
224
|
+
const result = Bun.spawn(["git", ...args], { cwd: REPOSITORY_ROOT, stdout: "pipe", stderr: "pipe" });
|
|
225
|
+
if ((await result.exited) !== 0)
|
|
226
|
+
throw new Error(`git ${args.join(" ")} failed: ${await new Response(result.stderr).text()}`);
|
|
227
|
+
return new Uint8Array(await new Response(result.stdout).arrayBuffer());
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Digest of a path's COMMITTED blob at a given commit, read straight out of the
|
|
231
|
+
// object database. This is the only provenance input a bundle author cannot
|
|
232
|
+
// restamp: `captureProvenance()` hashes the worktree, so mutating an oracle file
|
|
233
|
+
// and re-running it yields a self-consistent stamp. The committed blob is fixed
|
|
234
|
+
// by the commit id, so changing it requires a new commit -- which changes
|
|
235
|
+
// `git_head` and is therefore visible to the reviewer.
|
|
236
|
+
/** sha256 of every distinct blob this path has ever had in any ref-reachable commit. */
|
|
237
|
+
export async function gitObjectType(commitish: string): Promise<string | null> {
|
|
238
|
+
try {
|
|
239
|
+
const out = new TextDecoder().decode(await git(["cat-file", "-t", commitish])).trim();
|
|
240
|
+
return out || null;
|
|
241
|
+
} catch {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
export async function committedBlobSha256(commit: string, filePath: string): Promise<string | null> {
|
|
246
|
+
const result = Bun.spawn(["git", "cat-file", "blob", `${commit}:${filePath}`], {
|
|
247
|
+
cwd: REPOSITORY_ROOT,
|
|
248
|
+
stdout: "pipe",
|
|
249
|
+
stderr: "pipe",
|
|
250
|
+
});
|
|
251
|
+
const bytes = new Uint8Array(await new Response(result.stdout).arrayBuffer());
|
|
252
|
+
if ((await result.exited) !== 0) return null;
|
|
253
|
+
return hash(bytes);
|
|
254
|
+
}
|
|
255
|
+
export type CaptureProvenance = {
|
|
256
|
+
git_head: string;
|
|
257
|
+
oracle_commit: string;
|
|
258
|
+
git_diff_scope: readonly string[];
|
|
259
|
+
git_diff_binary_sha256: string;
|
|
260
|
+
source_sha256: Record<string, string>;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// Single source of truth: the verifier imports this so capture and verify can
|
|
264
|
+
// never drift into computing the field two different ways.
|
|
265
|
+
export async function captureProvenance(): Promise<CaptureProvenance> {
|
|
266
|
+
const gitHead = new TextDecoder().decode(await git(["rev-parse", "HEAD"])).trim();
|
|
267
|
+
const sourceSha256 = Object.fromEntries(
|
|
268
|
+
await Promise.all(
|
|
269
|
+
PROVENANCE_SOURCES.map(async source => [
|
|
270
|
+
source,
|
|
271
|
+
hash(new Uint8Array(await Bun.file(resolveRepositoryPath(source)).arrayBuffer())),
|
|
272
|
+
]),
|
|
273
|
+
),
|
|
274
|
+
);
|
|
275
|
+
return {
|
|
276
|
+
git_head: gitHead,
|
|
277
|
+
oracle_commit: process.env.GJC_STICKY_VIEWPORT_ORACLE_COMMIT?.trim() ?? gitHead,
|
|
278
|
+
git_diff_scope: PROVENANCE_DIFF_SCOPE,
|
|
279
|
+
git_diff_binary_sha256: hash(await git(["diff", "--binary", "HEAD", "--", ...PROVENANCE_DIFF_SCOPE])),
|
|
280
|
+
source_sha256: sourceSha256,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
172
283
|
function out(args: string[]): string {
|
|
173
284
|
if (args.length !== 2 || args[0] !== "--out" || !args[1]) throw new Error(`Usage: ${COMMAND}`);
|
|
174
285
|
return args[1];
|
|
175
286
|
}
|
|
176
|
-
async function capture(entry: StickyViewportShowcaseEntry, root: string) {
|
|
287
|
+
async function capture(entry: StickyViewportShowcaseEntry, root: string, sourceProvenance: CaptureProvenance) {
|
|
177
288
|
const rendered = await renderStickyViewportShowcase(entry);
|
|
178
289
|
if (!rendered.state.composer_visible)
|
|
179
290
|
throw new Error(`${entry.key}: focused composer was not visible in production frame`);
|
|
180
|
-
if (
|
|
181
|
-
|
|
291
|
+
if (
|
|
292
|
+
(entry.stateId === "manual-new-output" && rendered.state.notice !== true) ||
|
|
293
|
+
(entry.stateId !== "manual-new-output" && rendered.state.notice !== false)
|
|
294
|
+
)
|
|
295
|
+
throw new Error(`${entry.key}: renderer-owned output notice precondition failed`);
|
|
182
296
|
if (
|
|
183
297
|
JSON.stringify(rendered.cjkPhraseBoundaries) !==
|
|
184
298
|
JSON.stringify(entry.stateId === "narrow-cjk" ? CJK_PHRASE_BOUNDARIES : [])
|
|
@@ -210,6 +324,7 @@ async function capture(entry: StickyViewportShowcaseEntry, root: string) {
|
|
|
210
324
|
fixed_clock: true,
|
|
211
325
|
author_identity: "capture-sticky-viewport-showcase",
|
|
212
326
|
executor_identity: "capture-sticky-viewport-showcase",
|
|
327
|
+
...sourceProvenance,
|
|
213
328
|
},
|
|
214
329
|
cjk_phrase_boundaries: rendered.cjkPhraseBoundaries,
|
|
215
330
|
});
|
|
@@ -241,8 +356,9 @@ async function capture(entry: StickyViewportShowcaseEntry, root: string) {
|
|
|
241
356
|
async function main() {
|
|
242
357
|
const root = path.resolve(out(process.argv.slice(2)));
|
|
243
358
|
await fs.mkdir(root, { recursive: true });
|
|
359
|
+
const sourceProvenance = await captureProvenance();
|
|
244
360
|
const entries = [];
|
|
245
|
-
for (const entry of STICKY_VIEWPORT_SHOWCASE_ENTRIES) entries.push(await capture(entry, root));
|
|
361
|
+
for (const entry of STICKY_VIEWPORT_SHOWCASE_ENTRIES) entries.push(await capture(entry, root, sourceProvenance));
|
|
246
362
|
const manifest = json({
|
|
247
363
|
schema_version: 2,
|
|
248
364
|
fixture_revision: REVISION,
|
|
@@ -258,6 +374,7 @@ async function main() {
|
|
|
258
374
|
fixed_clock: true,
|
|
259
375
|
author_identity: "capture-sticky-viewport-showcase",
|
|
260
376
|
executor_identity: "capture-sticky-viewport-showcase",
|
|
377
|
+
...sourceProvenance,
|
|
261
378
|
},
|
|
262
379
|
review_input_file: "review-input.json",
|
|
263
380
|
entries,
|
|
@@ -281,6 +398,15 @@ async function main() {
|
|
|
281
398
|
acceptance_version: ACCEPTANCE_VERSION,
|
|
282
399
|
design_version: DESIGN_VERSION,
|
|
283
400
|
host_matrix: HOST_MATRIX,
|
|
401
|
+
provenance: {
|
|
402
|
+
capture_mode: "production-tui-virtual-terminal",
|
|
403
|
+
live_pty: false,
|
|
404
|
+
network: false,
|
|
405
|
+
fixed_clock: true,
|
|
406
|
+
author_identity: "capture-sticky-viewport-showcase",
|
|
407
|
+
executor_identity: "capture-sticky-viewport-showcase",
|
|
408
|
+
...sourceProvenance,
|
|
409
|
+
},
|
|
284
410
|
narrow_cjk: {
|
|
285
411
|
entry_key: "narrow-cjk/48x10/unicode-color",
|
|
286
412
|
phrase_boundaries: ["의미 있는 문장 경계", "意味のある文の境界", "保留语义短语边界"],
|