@abelxiaoxing/cadence 1.8.4 → 2.0.0
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/README.md +324 -117
- package/THIRD_PARTY_NOTICES.md +15 -0
- package/agents/design-explorer.md +14 -18
- package/agents/diagnosis-worker.md +14 -14
- package/agents/implementation-worker.md +16 -17
- package/config/workflow-task.example.json +7 -0
- package/docs/remote-access.md +60 -0
- package/docs/reuse-and-distribution.md +44 -0
- package/docs/service-management.md +108 -0
- package/licenses/bundled-web.txt +6245 -0
- package/licenses/pi-web-ui-MIT.txt +21 -0
- package/licenses/pi-web-ui-reuse.md +22 -0
- package/package.json +94 -21
- package/src/index.ts +21 -1802
- package/src/native-build.ts +6 -0
- package/src/native-client.ts +103 -0
- package/src/native-export.ts +58 -0
- package/src/native-history.ts +359 -0
- package/src/operator-cli.mjs +453 -1937
- package/src/plan-proposal.ts +87 -0
- package/src/sdk-worker.mjs +549 -0
- package/src/service/contracts/active.ts +82 -0
- package/src/service/contracts/budget.ts +148 -0
- package/src/service/contracts/build.ts +67 -0
- package/src/service/contracts/capture.ts +48 -0
- package/src/service/contracts/core.ts +33 -0
- package/src/service/contracts/current.ts +261 -0
- package/src/service/contracts/domain.ts +68 -0
- package/src/service/contracts/history.ts +2245 -0
- package/src/service/contracts/models.ts +139 -0
- package/src/service/coordination.ts +862 -0
- package/src/service/private-files.ts +204 -0
- package/src/service-cli.mjs +5592 -0
- package/src/service-client.ts +747 -0
- package/src/service-contract.ts +245 -0
- package/src/service-host.mjs +22382 -0
- package/src/service-http-client.ts +425 -0
- package/src/service-wire.ts +372 -0
- package/src/task-shell.ts +1045 -0
- package/src/task-store.ts +479 -0
- package/src/task-types.ts +184 -0
- package/src/verification-diagnostics.ts +29 -72
- package/src/worker-capture.mjs +1197 -0
- package/src/worker-public.mjs +1753 -0
- package/src/worker-redaction.mjs +608 -0
- package/src/worker-tools.mjs +202 -0
- package/web/dist/assets/KaTeX_AMS-Regular.ttf +0 -0
- package/web/dist/assets/KaTeX_AMS-Regular.woff +0 -0
- package/web/dist/assets/KaTeX_AMS-Regular.woff2 +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold.woff +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular.woff +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Bold.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-Bold.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Bold.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic.woff +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Italic.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-Italic.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Italic.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Regular.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-Regular.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Regular.woff2 +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic.woff +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/web/dist/assets/KaTeX_Math-Italic.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-Italic.woff +0 -0
- package/web/dist/assets/KaTeX_Math-Italic.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/web/dist/assets/KaTeX_Script-Regular.ttf +0 -0
- package/web/dist/assets/KaTeX_Script-Regular.woff +0 -0
- package/web/dist/assets/KaTeX_Script-Regular.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular.ttf +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular.woff +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular.ttf +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular.woff +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular.ttf +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular.woff +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular.ttf +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular.woff +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular.woff2 +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular.ttf +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular.woff +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/web/dist/assets/cadence.css +2 -0
- package/web/dist/assets/cadence.js +7 -0
- package/web/dist/assets/markdown.js +296 -0
- package/web/dist/assets/react.js +9 -0
- package/web/dist/assets/rolldown-runtime.js +1 -0
- package/web/dist/assets/timeline-client.js +41 -0
- package/web/dist/assets/vis-timeline.css +1274 -0
- package/web/dist/assets/vis-timeline.js +32 -0
- package/web/dist/index.html +18 -0
- package/web/dist/manifest.json +505 -0
- package/config/plan-draft.example.json +0 -125
- package/config/plan-draft.multiple-tasks.example.json +0 -375
- package/config/plan-draft.quick.example.json +0 -78
- package/prompts/abel-design.md +0 -382
- package/prompts/abel-diagnose.md +0 -71
- package/prompts/abel-implement.md +0 -284
- package/prompts/abel-init.md +0 -52
- package/src/activation.ts +0 -44
- package/src/activity-contracts.ts +0 -82
- package/src/agent-registry.ts +0 -53
- package/src/apply-transaction.ts +0 -1437
- package/src/artifact-store.ts +0 -213
- package/src/build-windows-job.mjs +0 -95
- package/src/candidate-artifact.ts +0 -143
- package/src/candidate-context.ts +0 -289
- package/src/candidate-patch.ts +0 -271
- package/src/candidate-workspace.ts +0 -80
- package/src/canonical.ts +0 -16
- package/src/change-contract-schema.ts +0 -191
- package/src/change-contract.ts +0 -324
- package/src/change-verification.ts +0 -1617
- package/src/contracts.ts +0 -2466
- package/src/control-contracts.ts +0 -382
- package/src/delivery-compiler.ts +0 -1805
- package/src/delivery-revision.ts +0 -42
- package/src/design-control.ts +0 -1299
- package/src/design-diagnostics.ts +0 -181
- package/src/design-journal.ts +0 -1773
- package/src/directory-sync.ts +0 -36
- package/src/durable-contracts.ts +0 -227
- package/src/durable-workflow.ts +0 -822
- package/src/evidence-draft.ts +0 -122
- package/src/execution-profile.ts +0 -64
- package/src/execution-retention.ts +0 -77
- package/src/file-snapshot.ts +0 -163
- package/src/implement-continuation.ts +0 -559
- package/src/implement-graph.ts +0 -690
- package/src/implement-plan.ts +0 -72
- package/src/install-config.d.mts +0 -6
- package/src/isolation-backend.ts +0 -353
- package/src/model-source.ts +0 -22
- package/src/openspec-cli.ts +0 -494
- package/src/operator-cli-entry.mjs +0 -24
- package/src/operator-tools.ts +0 -309
- package/src/package-candidate-process.ts +0 -206
- package/src/package-candidate.ts +0 -24
- package/src/package-delivery.ts +0 -486
- package/src/package-state.ts +0 -320
- package/src/package-verification.ts +0 -635
- package/src/package-workflow.ts +0 -305
- package/src/packet-runtime.ts +0 -459
- package/src/phase-execution.ts +0 -2163
- package/src/pi-adapter.ts +0 -19
- package/src/plan-draft-summary.ts +0 -527
- package/src/plan-draft.ts +0 -502
- package/src/remove-path.ts +0 -32
- package/src/run-state.ts +0 -420
- package/src/run-store.ts +0 -1179
- package/src/safe-path.ts +0 -77
- package/src/scoped-grep-worker.mjs +0 -23
- package/src/scoped-tools.ts +0 -775
- package/src/single-task-draft.ts +0 -142
- package/src/sqlite-schema.ts +0 -171
- package/src/state-root.ts +0 -215
- package/src/storage-schema.ts +0 -360
- package/src/subagent-activity.ts +0 -1417
- package/src/subagent-process.ts +0 -476
- package/src/task-ledger.ts +0 -1338
- package/src/transport-budget.ts +0 -50
- package/src/verification-capability.ts +0 -1191
- package/src/verification-environment-io.ts +0 -389
- package/src/verification-environment.ts +0 -162
- package/src/verification-identity.ts +0 -77
- package/src/verification-scan.ts +0 -64
- package/src/windows-job-backend.ts +0 -419
- package/src/windows-job.c +0 -149
- package/src/workflow-engine.ts +0 -28
- package/src/workflow-policy.ts +0 -1670
- package/src/workflow-recovery-policy.ts +0 -97
- package/src/workflow-scheduling.ts +0 -105
- package/src/workflow-state-machine.ts +0 -4341
- package/src/workflow-status.ts +0 -576
- package/src/workspace-io-entry.mjs +0 -76
- package/src/workspace-io-worker.mjs +0 -1312
- package/src/workspace-io.ts +0 -89
- package/src/workspace-store.ts +0 -634
package/src/artifact-store.ts
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
chmodSync,
|
|
4
|
-
closeSync,
|
|
5
|
-
constants,
|
|
6
|
-
copyFileSync,
|
|
7
|
-
fsyncSync,
|
|
8
|
-
lstatSync,
|
|
9
|
-
mkdirSync,
|
|
10
|
-
openSync,
|
|
11
|
-
readFileSync,
|
|
12
|
-
renameSync,
|
|
13
|
-
unlinkSync,
|
|
14
|
-
writeFileSync,
|
|
15
|
-
} from "node:fs";
|
|
16
|
-
import path from "node:path";
|
|
17
|
-
import { syncDirectory } from "./directory-sync.ts";
|
|
18
|
-
|
|
19
|
-
const SHA256 = /^[a-f0-9]{64}$/u;
|
|
20
|
-
|
|
21
|
-
export interface ArtifactIdentity {
|
|
22
|
-
hash: string;
|
|
23
|
-
bytes: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function digest(bytes: Uint8Array): string {
|
|
27
|
-
return createHash("sha256").update(bytes).digest("hex");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function requireHash(hash: string): void {
|
|
31
|
-
if (!SHA256.test(hash)) throw new Error("artifact-hash-invalid");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function ensureDirectory(directory: string): void {
|
|
35
|
-
const stat = lstatSync(directory, { throwIfNoEntry: false });
|
|
36
|
-
if (stat) {
|
|
37
|
-
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
38
|
-
throw new Error("artifact-store-path-unsafe");
|
|
39
|
-
}
|
|
40
|
-
chmodSync(directory, 0o700);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
let cursor = path.dirname(directory);
|
|
44
|
-
while (cursor !== path.dirname(cursor)) {
|
|
45
|
-
const ancestor = lstatSync(cursor, { throwIfNoEntry: false });
|
|
46
|
-
if (ancestor) {
|
|
47
|
-
if (ancestor.isSymbolicLink() || !ancestor.isDirectory()) {
|
|
48
|
-
throw new Error("artifact-store-path-unsafe");
|
|
49
|
-
}
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
cursor = path.dirname(cursor);
|
|
53
|
-
}
|
|
54
|
-
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
55
|
-
const created = lstatSync(directory);
|
|
56
|
-
if (created.isSymbolicLink() || !created.isDirectory()) {
|
|
57
|
-
throw new Error("artifact-store-path-unsafe");
|
|
58
|
-
}
|
|
59
|
-
chmodSync(directory, 0o700);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function writeAtomic(target: string, bytes: Uint8Array): void {
|
|
63
|
-
const directory = path.dirname(target);
|
|
64
|
-
ensureDirectory(directory);
|
|
65
|
-
const temporary = path.join(
|
|
66
|
-
directory,
|
|
67
|
-
`.${path.basename(target)}.${process.pid}.${randomUUID()}.tmp`,
|
|
68
|
-
);
|
|
69
|
-
const descriptor = openSync(
|
|
70
|
-
temporary,
|
|
71
|
-
constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY,
|
|
72
|
-
0o600,
|
|
73
|
-
);
|
|
74
|
-
try {
|
|
75
|
-
writeFileSync(descriptor, bytes);
|
|
76
|
-
fsyncSync(descriptor);
|
|
77
|
-
} finally {
|
|
78
|
-
closeSync(descriptor);
|
|
79
|
-
}
|
|
80
|
-
try {
|
|
81
|
-
renameSync(temporary, target);
|
|
82
|
-
chmodSync(target, 0o600);
|
|
83
|
-
syncDirectory(directory);
|
|
84
|
-
} catch (error) {
|
|
85
|
-
try {
|
|
86
|
-
unlinkSync(temporary);
|
|
87
|
-
} catch {
|
|
88
|
-
// The rename may already have consumed the temporary file.
|
|
89
|
-
}
|
|
90
|
-
throw error;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** Durable content-addressed bytes used by workspace revisions and sealed results. */
|
|
95
|
-
export class ArtifactStore {
|
|
96
|
-
readonly root: string;
|
|
97
|
-
readonly #blobs: string;
|
|
98
|
-
readonly #references: string;
|
|
99
|
-
|
|
100
|
-
constructor(root: string) {
|
|
101
|
-
if (!path.isAbsolute(root)) throw new Error("artifact-store-root-invalid");
|
|
102
|
-
this.root = path.resolve(root);
|
|
103
|
-
this.#blobs = path.join(this.root, "blobs");
|
|
104
|
-
this.#references = path.join(this.root, "references");
|
|
105
|
-
ensureDirectory(this.root);
|
|
106
|
-
ensureDirectory(this.#blobs);
|
|
107
|
-
ensureDirectory(this.#references);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
#blobPath(hash: string): string {
|
|
111
|
-
requireHash(hash);
|
|
112
|
-
return path.join(this.#blobs, hash.slice(0, 2), hash);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
#referencePath(hash: string): string {
|
|
116
|
-
requireHash(hash);
|
|
117
|
-
return path.join(this.#references, hash.slice(0, 2), `${hash}.ref`);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
put(input: Uint8Array): ArtifactIdentity {
|
|
121
|
-
if (!(input instanceof Uint8Array))
|
|
122
|
-
throw new Error("artifact-bytes-invalid");
|
|
123
|
-
const bytes = Buffer.from(input);
|
|
124
|
-
const hash = digest(bytes);
|
|
125
|
-
const target = this.#blobPath(hash);
|
|
126
|
-
const existing = lstatSync(target, { throwIfNoEntry: false });
|
|
127
|
-
if (existing) {
|
|
128
|
-
if (existing.isSymbolicLink() || !existing.isFile()) {
|
|
129
|
-
throw new Error("artifact-store-path-unsafe");
|
|
130
|
-
}
|
|
131
|
-
const current = readFileSync(target);
|
|
132
|
-
if (current.length !== bytes.length || digest(current) !== hash) {
|
|
133
|
-
throw new Error("artifact-integrity-invalid");
|
|
134
|
-
}
|
|
135
|
-
} else {
|
|
136
|
-
writeAtomic(target, bytes);
|
|
137
|
-
const stored = readFileSync(target);
|
|
138
|
-
if (stored.length !== bytes.length || digest(stored) !== hash) {
|
|
139
|
-
throw new Error("artifact-integrity-invalid");
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return Object.freeze({ hash, bytes: bytes.length });
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
read(hash: string): Uint8Array {
|
|
146
|
-
const target = this.#blobPath(hash);
|
|
147
|
-
const stat = lstatSync(target, { throwIfNoEntry: false });
|
|
148
|
-
if (!stat?.isFile() || stat.isSymbolicLink()) {
|
|
149
|
-
throw new Error("artifact-unavailable");
|
|
150
|
-
}
|
|
151
|
-
const bytes = readFileSync(target);
|
|
152
|
-
if (digest(bytes) !== hash) throw new Error("artifact-integrity-invalid");
|
|
153
|
-
return Buffer.from(bytes);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/** Clone when supported; always use a distinct inode and verify the copied bytes. */
|
|
157
|
-
copyVerified(hash: string, destination: string): number {
|
|
158
|
-
const source = this.#blobPath(hash);
|
|
159
|
-
const stat = lstatSync(source, { throwIfNoEntry: false });
|
|
160
|
-
if (!stat?.isFile() || stat.isSymbolicLink())
|
|
161
|
-
throw new Error("artifact-unavailable");
|
|
162
|
-
copyFileSync(
|
|
163
|
-
source,
|
|
164
|
-
destination,
|
|
165
|
-
constants.COPYFILE_EXCL | constants.COPYFILE_FICLONE,
|
|
166
|
-
);
|
|
167
|
-
const bytes = readFileSync(destination);
|
|
168
|
-
if (digest(bytes) !== hash) throw new Error("artifact-integrity-invalid");
|
|
169
|
-
return bytes.byteLength;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
referenceCount(hash: string): number {
|
|
173
|
-
requireHash(hash);
|
|
174
|
-
const referencePath = this.#referencePath(hash);
|
|
175
|
-
const stat = lstatSync(referencePath, { throwIfNoEntry: false });
|
|
176
|
-
if (!stat) return 0;
|
|
177
|
-
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
178
|
-
throw new Error("artifact-reference-invalid");
|
|
179
|
-
}
|
|
180
|
-
const raw = readFileSync(referencePath, "utf8");
|
|
181
|
-
if (!/^(?:0|[1-9][0-9]*)\n$/u.test(raw)) {
|
|
182
|
-
throw new Error("artifact-reference-invalid");
|
|
183
|
-
}
|
|
184
|
-
const count = Number(raw.trim());
|
|
185
|
-
if (!Number.isSafeInteger(count))
|
|
186
|
-
throw new Error("artifact-reference-invalid");
|
|
187
|
-
return count;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
#setReferenceCount(hash: string, count: number): number {
|
|
191
|
-
if (!Number.isSafeInteger(count) || count < 0) {
|
|
192
|
-
throw new Error("artifact-reference-invalid");
|
|
193
|
-
}
|
|
194
|
-
writeAtomic(this.#referencePath(hash), Buffer.from(`${count}\n`));
|
|
195
|
-
return count;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
retain(hash: string): number {
|
|
199
|
-
this.read(hash);
|
|
200
|
-
const current = this.referenceCount(hash);
|
|
201
|
-
if (current === Number.MAX_SAFE_INTEGER) {
|
|
202
|
-
throw new Error("artifact-reference-overflow");
|
|
203
|
-
}
|
|
204
|
-
return this.#setReferenceCount(hash, current + 1);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
release(hash: string): number {
|
|
208
|
-
this.read(hash);
|
|
209
|
-
const current = this.referenceCount(hash);
|
|
210
|
-
if (current === 0) throw new Error("artifact-reference-underflow");
|
|
211
|
-
return this.#setReferenceCount(hash, current - 1);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
// Explicit operator/release build only. Never invoked on import, install or verification.
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { createHash } from "node:crypto";
|
|
4
|
-
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
|
-
|
|
8
|
-
function main() {
|
|
9
|
-
const args = process.argv.slice(2);
|
|
10
|
-
if (
|
|
11
|
-
process.platform !== "win32" ||
|
|
12
|
-
process.arch !== "x64" ||
|
|
13
|
-
args.length !== 2 ||
|
|
14
|
-
args[0] !== "--output"
|
|
15
|
-
)
|
|
16
|
-
throw new Error(
|
|
17
|
-
"Windows x64 required; usage: node build-windows-job.mjs --output <directory>",
|
|
18
|
-
);
|
|
19
|
-
const output = path.resolve(args[1]);
|
|
20
|
-
const compiler = path.join(
|
|
21
|
-
process.env.VCToolsInstallDir ?? "",
|
|
22
|
-
"bin/Hostx64/x64/cl.exe",
|
|
23
|
-
);
|
|
24
|
-
if (!path.isAbsolute(compiler))
|
|
25
|
-
throw new Error(
|
|
26
|
-
"Select the installed MSVC x64 developer environment first",
|
|
27
|
-
);
|
|
28
|
-
const sdkVersion = process.env.WindowsSDKVersion?.replace(/[\\/]+$/u, "");
|
|
29
|
-
if (!sdkVersion || !/^10\.0\.\d+\.0$/u.test(sdkVersion))
|
|
30
|
-
throw new Error("Windows 10 SDK required");
|
|
31
|
-
const version = spawnSync(compiler, [], {
|
|
32
|
-
shell: false,
|
|
33
|
-
encoding: "utf8",
|
|
34
|
-
timeout: 10000,
|
|
35
|
-
maxBuffer: 16384,
|
|
36
|
-
});
|
|
37
|
-
const compilerVersion =
|
|
38
|
-
`${version.stdout ?? ""}${version.stderr ?? ""}`.match(
|
|
39
|
-
/19\.(?:3\d|4\d)\.\d+/u,
|
|
40
|
-
)?.[0];
|
|
41
|
-
if (!compilerVersion) throw new Error("MSVC 19.3x/19.4x required");
|
|
42
|
-
mkdirSync(output, { recursive: true });
|
|
43
|
-
const source = fileURLToPath(new URL("./windows-job.c", import.meta.url));
|
|
44
|
-
const helper = path.join(output, "windows-job.exe");
|
|
45
|
-
rmSync(`${helper}.json`, { force: true });
|
|
46
|
-
rmSync(helper, { force: true });
|
|
47
|
-
const result = spawnSync(
|
|
48
|
-
compiler,
|
|
49
|
-
[
|
|
50
|
-
"/nologo",
|
|
51
|
-
"/W4",
|
|
52
|
-
"/WX",
|
|
53
|
-
"/O2",
|
|
54
|
-
"/MT",
|
|
55
|
-
"/utf-8",
|
|
56
|
-
"/DUNICODE",
|
|
57
|
-
"/D_UNICODE",
|
|
58
|
-
source,
|
|
59
|
-
`/Fe:${helper}`,
|
|
60
|
-
`/Fo:${path.join(output, "windows-job.obj")}`,
|
|
61
|
-
],
|
|
62
|
-
{
|
|
63
|
-
shell: false,
|
|
64
|
-
cwd: output,
|
|
65
|
-
encoding: "utf8",
|
|
66
|
-
timeout: 60000,
|
|
67
|
-
maxBuffer: 65536,
|
|
68
|
-
},
|
|
69
|
-
);
|
|
70
|
-
writeFileSync(
|
|
71
|
-
path.join(output, "build.log"),
|
|
72
|
-
`${result.stdout ?? ""}${result.stderr ?? ""}`,
|
|
73
|
-
);
|
|
74
|
-
if (result.error || result.status !== 0)
|
|
75
|
-
throw new Error("Native build failed; inspect build.log");
|
|
76
|
-
const hash = (file) =>
|
|
77
|
-
createHash("sha256").update(readFileSync(file)).digest("hex");
|
|
78
|
-
writeFileSync(
|
|
79
|
-
`${helper}.json`,
|
|
80
|
-
`${JSON.stringify({ version: 2, arch: "x64", sourceSha256: hash(source), helperSha256: hash(helper), compilerSha256: hash(compiler), compilerVersion, sdkVersion }, null, 2)}\n`,
|
|
81
|
-
{ flag: "wx" },
|
|
82
|
-
);
|
|
83
|
-
console.log(`Built ${helper}`);
|
|
84
|
-
}
|
|
85
|
-
if (
|
|
86
|
-
process.argv[1] &&
|
|
87
|
-
path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)
|
|
88
|
-
) {
|
|
89
|
-
try {
|
|
90
|
-
main();
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.error(error.message);
|
|
93
|
-
process.exitCode = 1;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { diffWritePaths } from "./contracts.ts";
|
|
3
|
-
import {
|
|
4
|
-
type BeginCandidateInput,
|
|
5
|
-
TASK_LEDGER_LIMITS,
|
|
6
|
-
type TaskLedger,
|
|
7
|
-
} from "./task-ledger.ts";
|
|
8
|
-
import type { DurableCandidateProposal } from "./workflow-policy.ts";
|
|
9
|
-
|
|
10
|
-
type ArtifactProposal = Extract<
|
|
11
|
-
DurableCandidateProposal,
|
|
12
|
-
{ kind: "candidate" | "sealed-candidate" }
|
|
13
|
-
>;
|
|
14
|
-
interface CandidateArtifactInput {
|
|
15
|
-
ledger: TaskLedger;
|
|
16
|
-
identity: BeginCandidateInput;
|
|
17
|
-
proposal: ArtifactProposal;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const sha256 = (bytes: Uint8Array) =>
|
|
21
|
-
createHash("sha256").update(bytes).digest("hex");
|
|
22
|
-
|
|
23
|
-
/** Inspect the same sealed bytes for normal phases and repairs. Callers own recovery policy. */
|
|
24
|
-
export function inspectCandidateArtifact({
|
|
25
|
-
ledger,
|
|
26
|
-
identity,
|
|
27
|
-
proposal,
|
|
28
|
-
approvedPaths,
|
|
29
|
-
}: CandidateArtifactInput & { approvedPaths: readonly string[] }):
|
|
30
|
-
| { ok: true; bytes: Buffer; paths: string[] }
|
|
31
|
-
| {
|
|
32
|
-
ok: false;
|
|
33
|
-
code: "candidate-diff-invalid" | "write-set-mismatch";
|
|
34
|
-
stage: string;
|
|
35
|
-
} {
|
|
36
|
-
const invalid = (stage: string) => ({
|
|
37
|
-
ok: false as const,
|
|
38
|
-
code: "candidate-diff-invalid" as const,
|
|
39
|
-
stage,
|
|
40
|
-
});
|
|
41
|
-
ledger.beginCandidate(identity);
|
|
42
|
-
let bytes: Buffer;
|
|
43
|
-
if (proposal.kind === "sealed-candidate") {
|
|
44
|
-
if (
|
|
45
|
-
proposal.candidateId !== identity.candidateId ||
|
|
46
|
-
!/^[a-f0-9]{64}$/u.test(proposal.artifactHash) ||
|
|
47
|
-
!Number.isSafeInteger(proposal.bytes) ||
|
|
48
|
-
proposal.bytes < 1 ||
|
|
49
|
-
!Array.isArray(proposal.paths)
|
|
50
|
-
)
|
|
51
|
-
return invalid("candidate-seal");
|
|
52
|
-
bytes = Buffer.from(ledger.readSealedCandidate(identity.candidateId));
|
|
53
|
-
if (
|
|
54
|
-
bytes.length !== proposal.bytes ||
|
|
55
|
-
sha256(bytes) !== proposal.artifactHash
|
|
56
|
-
) {
|
|
57
|
-
throw new Error("candidate-seal-integrity-invalid");
|
|
58
|
-
}
|
|
59
|
-
} else {
|
|
60
|
-
if (
|
|
61
|
-
!(proposal.bytes instanceof Uint8Array) ||
|
|
62
|
-
proposal.bytes.length === 0
|
|
63
|
-
) {
|
|
64
|
-
return invalid("candidate-submit");
|
|
65
|
-
}
|
|
66
|
-
bytes = Buffer.from(proposal.bytes);
|
|
67
|
-
}
|
|
68
|
-
let paths: string[];
|
|
69
|
-
try {
|
|
70
|
-
paths = diffWritePaths(
|
|
71
|
-
new TextDecoder("utf-8", { fatal: true }).decode(bytes),
|
|
72
|
-
).paths;
|
|
73
|
-
} catch {
|
|
74
|
-
return invalid("candidate-diff");
|
|
75
|
-
}
|
|
76
|
-
if (paths.some((relative) => !approvedPaths.includes(relative))) {
|
|
77
|
-
return {
|
|
78
|
-
ok: false,
|
|
79
|
-
code: "write-set-mismatch",
|
|
80
|
-
stage: "candidate-boundary",
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
if (
|
|
84
|
-
proposal.kind === "sealed-candidate" &&
|
|
85
|
-
JSON.stringify([...proposal.paths].sort()) !==
|
|
86
|
-
JSON.stringify([...paths].sort())
|
|
87
|
-
) {
|
|
88
|
-
return invalid("candidate-seal");
|
|
89
|
-
}
|
|
90
|
-
return { ok: true, bytes, paths };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** Seal after isolated patch/dependency checks, before any phase verification. */
|
|
94
|
-
export function sealCandidateArtifact({
|
|
95
|
-
ledger,
|
|
96
|
-
identity,
|
|
97
|
-
proposal,
|
|
98
|
-
bytes,
|
|
99
|
-
}: CandidateArtifactInput & { bytes: Buffer }):
|
|
100
|
-
| { ok: true; artifactHash: string }
|
|
101
|
-
| { ok: false; kind: "paused" | "retryable"; code: string; stage: string } {
|
|
102
|
-
if (proposal.kind === "sealed-candidate")
|
|
103
|
-
return { ok: true, artifactHash: proposal.artifactHash };
|
|
104
|
-
let sequence = 0;
|
|
105
|
-
for (
|
|
106
|
-
let offset = 0;
|
|
107
|
-
offset < bytes.length;
|
|
108
|
-
offset += TASK_LEDGER_LIMITS.maxSegmentBytes
|
|
109
|
-
) {
|
|
110
|
-
const segment = bytes.subarray(
|
|
111
|
-
offset,
|
|
112
|
-
Math.min(offset + TASK_LEDGER_LIMITS.maxSegmentBytes, bytes.length),
|
|
113
|
-
);
|
|
114
|
-
const accepted = ledger.appendCandidateSegment({
|
|
115
|
-
...identity,
|
|
116
|
-
sequence,
|
|
117
|
-
bytes: segment,
|
|
118
|
-
segmentHash: sha256(segment),
|
|
119
|
-
});
|
|
120
|
-
if (!accepted.ok)
|
|
121
|
-
return {
|
|
122
|
-
ok: false,
|
|
123
|
-
kind: "paused",
|
|
124
|
-
code: accepted.code,
|
|
125
|
-
stage: "candidate-segment",
|
|
126
|
-
};
|
|
127
|
-
sequence++;
|
|
128
|
-
}
|
|
129
|
-
const sealed = ledger.sealCandidate({
|
|
130
|
-
...identity,
|
|
131
|
-
segmentCount: sequence,
|
|
132
|
-
totalBytes: bytes.length,
|
|
133
|
-
candidateHash: sha256(bytes),
|
|
134
|
-
});
|
|
135
|
-
return sealed.ok
|
|
136
|
-
? { ok: true, artifactHash: sealed.artifactHash }
|
|
137
|
-
: {
|
|
138
|
-
ok: false,
|
|
139
|
-
kind: "retryable",
|
|
140
|
-
code: sealed.code,
|
|
141
|
-
stage: "candidate-seal",
|
|
142
|
-
};
|
|
143
|
-
}
|