@abelxiaoxing/cadence 2.0.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,37 +4,11 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
4
 
5
5
  // src/service/host.ts
6
6
  import { lstatSync as lstatSync10, opendirSync as opendirSync3 } from "node:fs";
7
- import { join as join16 } from "node:path";
7
+ import { join as join17 } from "node:path";
8
8
 
9
- // src/history/files.ts
10
- import { createHash as createHash5, randomBytes, randomUUID as randomUUID3 } from "node:crypto";
11
- import {
12
- closeSync as closeSync4,
13
- constants as constants4,
14
- fstatSync as fstatSync4,
15
- fsyncSync as fsyncSync3,
16
- lstatSync as lstatSync4,
17
- opendirSync,
18
- openSync as openSync4,
19
- statfsSync
20
- } from "node:fs";
21
- import { open } from "node:fs/promises";
22
- import { dirname as dirname4, join as join3 } from "node:path";
23
-
24
- // src/service/private-files.ts
25
- import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
26
- import {
27
- closeSync as closeSync2,
28
- constants as constants2,
29
- fstatSync as fstatSync2,
30
- fsyncSync as fsyncSync2,
31
- lstatSync as lstatSync2,
32
- openSync as openSync2,
33
- renameSync as renameSync2,
34
- unlinkSync as unlinkSync2,
35
- writeFileSync as writeFileSync2
36
- } from "node:fs";
37
- import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
9
+ // src/agent-registry.ts
10
+ import { createHash as createHash2 } from "node:crypto";
11
+ import { fileURLToPath } from "node:url";
38
12
 
39
13
  // src/task-store.ts
40
14
  import { spawnSync } from "node:child_process";
@@ -170,11 +144,8 @@ function safeDirectory(path, create = false, inspectExisting) {
170
144
  at = join(at, part);
171
145
  let existing;
172
146
  try {
173
- const st = lstatSync(at);
174
- if (!st.isDirectory())
175
- throw new Error("Unsafe directory");
176
147
  const checked = lstatSync(at);
177
- if (checked.isSymbolicLink() || inspectExisting && !checked.isDirectory())
148
+ if (!checked.isDirectory() || checked.isSymbolicLink())
178
149
  throw new Error("Unsafe directory");
179
150
  existing = checked;
180
151
  } catch (error) {
@@ -188,7 +159,8 @@ function safeDirectory(path, create = false, inspectExisting) {
188
159
  if (!object(mkdirError) || mkdirError.code !== "EEXIST")
189
160
  throw mkdirError;
190
161
  }
191
- if (!lstatSync(at).isDirectory() || lstatSync(at).isSymbolicLink())
162
+ const created = lstatSync(at);
163
+ if (!created.isDirectory() || created.isSymbolicLink())
192
164
  throw new Error("Unsafe directory");
193
165
  }
194
166
  if (existing)
@@ -196,13 +168,29 @@ function safeDirectory(path, create = false, inspectExisting) {
196
168
  }
197
169
  return true;
198
170
  }
199
- function readBounded(path, max) {
171
+ var transientWindows = new Set(["EPERM", "EACCES", "EBUSY"]);
172
+ function retryWindowsFileOperation(operation, recheck) {
173
+ if (process.platform !== "win32")
174
+ return operation();
175
+ const deadline = performance.now() + 2000;
176
+ for (let delay = 2;; delay = Math.min(delay * 2, 50)) {
177
+ try {
178
+ return operation();
179
+ } catch (error) {
180
+ if (!object(error) || !transientWindows.has(String(error.code)) || performance.now() >= deadline)
181
+ throw error;
182
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, delay);
183
+ recheck?.();
184
+ }
185
+ }
186
+ }
187
+ function readBounded(path, max, packaged = false) {
200
188
  if (!safeDirectory(dirname(path)))
201
189
  return;
202
190
  let fd;
203
191
  try {
204
192
  const st = lstatSync(path);
205
- if (!st.isFile() || st.isSymbolicLink() || st.nlink !== 1 || st.size > max)
193
+ if (!st.isFile() || st.isSymbolicLink() || !packaged && st.nlink !== 1 || st.size > max)
206
194
  throw new Error("Unsafe or oversized file");
207
195
  fd = openSync(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
208
196
  } catch (error) {
@@ -212,7 +200,7 @@ function readBounded(path, max) {
212
200
  }
213
201
  try {
214
202
  const st = fstatSync(fd);
215
- if (!st.isFile() || st.nlink !== 1 || st.size > max)
203
+ if (!st.isFile() || !packaged && st.nlink !== 1 || st.size > max)
216
204
  throw new Error("Unsafe or oversized file");
217
205
  const buffer = Buffer.alloc(max + 1);
218
206
  let size = 0;
@@ -293,7 +281,13 @@ function canonicalAmbientRoot(path) {
293
281
  return join(canonicalAmbientRoot(parent), full.slice(parent.length));
294
282
  }
295
283
  }
296
-
284
+ function privateRootFor(canonicalRoot, stateHome) {
285
+ return join(canonicalAmbientRoot(stateHome), "cadence-assistant-v1", createHash("sha256").update(canonicalRoot).digest("hex"));
286
+ }
287
+ function contains(root, path) {
288
+ const within = relative(root, resolve(path));
289
+ return !within || !within.startsWith(`..${sep}`) && within !== ".." && !isAbsolute(within);
290
+ }
297
291
  class TaskStore {
298
292
  root;
299
293
  tasks;
@@ -301,9 +295,8 @@ class TaskStore {
301
295
  constructor(root, stateHome = defaultStateHome()) {
302
296
  this.root = realpathSync(root);
303
297
  this.tasks = join(this.root, ".cadence", "assistant", "tasks");
304
- this.privateRoot = join(canonicalAmbientRoot(stateHome), "cadence-assistant-v1", createHash("sha256").update(this.root).digest("hex"));
305
- const within = relative(this.root, resolve(this.privateRoot));
306
- if (!within || !within.startsWith(`..${sep}`) && within !== ".." && !isAbsolute(within))
298
+ this.privateRoot = privateRootFor(this.root, stateHome);
299
+ if (contains(this.root, this.privateRoot))
307
300
  throw new Error("Private state home must be outside the working copy");
308
301
  }
309
302
  get lockPath() {
@@ -355,7 +348,7 @@ class TaskStore {
355
348
  };
356
349
  let fd;
357
350
  try {
358
- fd = openSync(this.lockPath, "wx", 384);
351
+ fd = retryWindowsFileOperation(() => openSync(this.lockPath, "wx", 384));
359
352
  } catch {
360
353
  throw new Error("Checkout busy or unresolved lock; inspect and explicitly recover only a dead owner");
361
354
  }
@@ -375,7 +368,7 @@ class TaskStore {
375
368
  if (lock.pid !== process.pid || lock.host !== hostname())
376
369
  throw new Error("Only the owning process may release a lock");
377
370
  this.assertOwner(lock);
378
- unlinkSync(this.lockPath);
371
+ retryWindowsFileOperation(() => unlinkSync(this.lockPath), () => this.assertOwner(lock));
379
372
  }
380
373
  recover(expected, acknowledgeEscapedProcesses) {
381
374
  if (!acknowledgeEscapedProcesses || expected.host !== hostname())
@@ -455,7 +448,12 @@ class TaskStore {
455
448
  const latest = readBounded(join(dir, "task.json"), MAX_RECORD_BYTES);
456
449
  if ((latest ? contentIdentity(latest) : undefined) !== expectedIdentity)
457
450
  throw new Error("Task content changed; replacement preserved without overwrite");
458
- renameSync(temporary, join(dir, "task.json"));
451
+ retryWindowsFileOperation(() => renameSync(temporary, join(dir, "task.json")), () => {
452
+ this.assertOwner(lock);
453
+ const now = readBounded(join(dir, "task.json"), MAX_RECORD_BYTES);
454
+ if ((now ? contentIdentity(now) : undefined) !== expectedIdentity)
455
+ throw new Error("Task content changed; replacement preserved without overwrite");
456
+ });
459
457
  return next;
460
458
  } finally {
461
459
  if (!held)
@@ -495,6 +493,61 @@ class TaskStore {
495
493
  }
496
494
  var TASK_CONFIG_SCHEMA = "cadence-assistant-checks/1";
497
495
 
496
+ // src/agent-registry.ts
497
+ var AGENT_FILES = [
498
+ "design-explorer.md",
499
+ "implementation-worker.md",
500
+ "diagnosis-worker.md"
501
+ ];
502
+ function loadAgentDefinitions() {
503
+ return AGENT_FILES.map((fileName) => {
504
+ const path = fileURLToPath(new URL(`../agents/${fileName}`, import.meta.url));
505
+ const data = readBounded(path, 32768, true);
506
+ if (!data)
507
+ throw new Error("Missing package Agent");
508
+ return {
509
+ role: fileName.replace(/\.md$/, ""),
510
+ fileName,
511
+ path,
512
+ sha256: createHash2("sha256").update(data).digest("hex"),
513
+ bytes: data.length,
514
+ content: data.toString("utf8")
515
+ };
516
+ });
517
+ }
518
+
519
+ // src/history/files.ts
520
+ import { createHash as createHash6, randomBytes, randomUUID as randomUUID3 } from "node:crypto";
521
+ import {
522
+ closeSync as closeSync4,
523
+ constants as constants4,
524
+ fstatSync as fstatSync4,
525
+ fsyncSync as fsyncSync3,
526
+ lstatSync as lstatSync4,
527
+ opendirSync,
528
+ openSync as openSync4,
529
+ statfsSync
530
+ } from "node:fs";
531
+ import { open } from "node:fs/promises";
532
+ import { dirname as dirname4, join as join3 } from "node:path";
533
+
534
+ // src/service/private-files.ts
535
+ import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
536
+ import {
537
+ closeSync as closeSync2,
538
+ constants as constants2,
539
+ fstatSync as fstatSync2,
540
+ fsyncSync as fsyncSync2,
541
+ lstatSync as lstatSync2,
542
+ mkdirSync as mkdirSync2,
543
+ openSync as openSync2,
544
+ readSync as readSync2,
545
+ renameSync as renameSync2,
546
+ unlinkSync as unlinkSync2,
547
+ writeFileSync as writeFileSync2
548
+ } from "node:fs";
549
+ import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
550
+
498
551
  // src/worker-public.mjs
499
552
  var SERVICE_PROTOCOL = 1;
500
553
  var WORKER_PROTOCOL = 2;
@@ -2079,7 +2132,7 @@ function refused() {
2079
2132
  throw new ContractError("corrupt-selected");
2080
2133
  }
2081
2134
  function hash(bytes) {
2082
- return createHash2("sha256").update(bytes).digest("hex");
2135
+ return createHash3("sha256").update(bytes).digest("hex");
2083
2136
  }
2084
2137
  function privateMode(st) {
2085
2138
  if (process.platform !== "win32" && ((st.mode & 63) !== 0 || process.getuid && st.uid !== process.getuid()))
@@ -2091,38 +2144,108 @@ function same(a, b) {
2091
2144
  function missing(error) {
2092
2145
  return error instanceof Error && "code" in error && error.code === "ENOENT";
2093
2146
  }
2147
+ var job = 0;
2148
+ var advancing = false;
2149
+ function currentJob() {
2150
+ if (!advancing) {
2151
+ advancing = true;
2152
+ queueMicrotask(() => {
2153
+ job++;
2154
+ advancing = false;
2155
+ });
2156
+ }
2157
+ return job;
2158
+ }
2159
+
2160
+ class DirectoryWalks {
2161
+ job = currentJob();
2162
+ walked = new Map;
2163
+ open() {
2164
+ if (this.job === job)
2165
+ return true;
2166
+ this.walked.clear();
2167
+ return false;
2168
+ }
2169
+ remember(path, st) {
2170
+ if (this.open())
2171
+ this.walked.set(path, { dev: st.dev, ino: st.ino });
2172
+ }
2173
+ reuse(path) {
2174
+ const walked = this.open() ? this.walked.get(path) : undefined;
2175
+ if (!walked)
2176
+ return false;
2177
+ let st;
2178
+ try {
2179
+ st = lstatSync2(path);
2180
+ } catch (error) {
2181
+ if (!missing(error))
2182
+ throw error;
2183
+ this.walked.delete(path);
2184
+ return false;
2185
+ }
2186
+ if (!st.isDirectory() || st.isSymbolicLink() || st.dev !== walked.dev || st.ino !== walked.ino) {
2187
+ this.walked.delete(path);
2188
+ return false;
2189
+ }
2190
+ privateMode(st);
2191
+ return true;
2192
+ }
2193
+ }
2094
2194
 
2095
2195
  class PrivateFiles {
2096
2196
  namespace;
2097
2197
  constructor(namespace) {
2098
2198
  this.namespace = namespace;
2099
2199
  }
2100
- directory(path, create = false) {
2200
+ directory(path, create = false, walks) {
2101
2201
  const tail = relative2(this.namespace, path);
2102
2202
  if (isAbsolute2(tail) || tail === ".." || tail.startsWith(`..${sep2}`))
2103
2203
  refused();
2104
2204
  if (!create) {
2205
+ const full = resolve2(path);
2206
+ if (walks?.reuse(full))
2207
+ return true;
2105
2208
  const namespace = resolve2(this.namespace);
2106
- let inside = false;
2107
- return safeDirectory(path, false, (at2, st) => {
2209
+ let inside = false, last;
2210
+ const found = safeDirectory(path, false, (at2, st) => {
2108
2211
  if (at2 === namespace)
2109
2212
  inside = true;
2110
2213
  if (inside)
2111
2214
  privateMode(st);
2215
+ last = st;
2112
2216
  });
2217
+ if (found && last)
2218
+ walks?.remember(full, last);
2219
+ return found;
2113
2220
  }
2221
+ if (!safeDirectory(this.namespace, true))
2222
+ return false;
2223
+ privateMode(lstatSync2(this.namespace));
2114
2224
  let at = this.namespace;
2115
- for (const part of ["", ...tail.split(sep2).filter(Boolean)]) {
2116
- if (part)
2117
- at = join2(at, part);
2118
- if (!safeDirectory(at, create))
2119
- return false;
2120
- privateMode(lstatSync2(at));
2225
+ for (const part of tail.split(sep2).filter(Boolean)) {
2226
+ at = join2(at, part);
2227
+ let st;
2228
+ try {
2229
+ st = lstatSync2(at);
2230
+ } catch (error) {
2231
+ if (!missing(error))
2232
+ throw error;
2233
+ try {
2234
+ mkdirSync2(at, { mode: 448 });
2235
+ } catch (mkdirError) {
2236
+ if (!(mkdirError instanceof Error && ("code" in mkdirError) && mkdirError.code === "EEXIST"))
2237
+ throw mkdirError;
2238
+ }
2239
+ st = lstatSync2(at);
2240
+ }
2241
+ if (!st.isDirectory() || st.isSymbolicLink())
2242
+ throw new Error("Unsafe directory");
2243
+ privateMode(st);
2121
2244
  }
2122
2245
  return true;
2123
2246
  }
2124
- read(path, maximum = METADATA_BYTES) {
2125
- if (!this.directory(dirname2(path)))
2247
+ read(path, maximum = METADATA_BYTES, walks) {
2248
+ if (!this.directory(dirname2(path), false, walks))
2126
2249
  return;
2127
2250
  let before;
2128
2251
  try {
@@ -2140,16 +2263,24 @@ class PrivateFiles {
2140
2263
  const opened = fstatSync2(fd);
2141
2264
  if (!same(before, opened))
2142
2265
  refused();
2143
- const bytes = readBounded(path, opened.size);
2144
- if (!bytes || bytes.length !== opened.size || !same(opened, fstatSync2(fd)) || !same(opened, lstatSync2(path)))
2266
+ const buffer = Buffer.alloc(opened.size + 1);
2267
+ let size = 0;
2268
+ while (size < buffer.length) {
2269
+ const n = readSync2(fd, buffer, size, buffer.length - size, null);
2270
+ if (!n)
2271
+ break;
2272
+ size += n;
2273
+ }
2274
+ const bytes = buffer.subarray(0, size);
2275
+ if (size !== opened.size || !same(opened, fstatSync2(fd)) || !same(opened, lstatSync2(path)))
2145
2276
  refused();
2146
2277
  return { bytes, identity: hash(bytes), stamp: stamp(opened) };
2147
2278
  } finally {
2148
2279
  closeSync2(fd);
2149
2280
  }
2150
2281
  }
2151
- assert(path, expected, maximum = METADATA_BYTES) {
2152
- const current = this.read(path, maximum);
2282
+ assert(path, expected, maximum = METADATA_BYTES, walks) {
2283
+ const current = this.read(path, maximum, walks);
2153
2284
  if (current?.identity !== expected?.identity || current?.stamp !== expected?.stamp)
2154
2285
  throw new ContractError("conflict");
2155
2286
  }
@@ -2157,7 +2288,7 @@ class PrivateFiles {
2157
2288
  if (Buffer.byteLength(bytes) > maximum)
2158
2289
  throw new ContractError("oversize");
2159
2290
  this.directory(dirname2(path), true);
2160
- const fd = openSync2(path, "wx", 384);
2291
+ const fd = retryWindowsFileOperation(() => openSync2(path, "wx", 384));
2161
2292
  try {
2162
2293
  writeFileSync2(fd, bytes);
2163
2294
  fsyncSync2(fd);
@@ -2175,7 +2306,7 @@ class PrivateFiles {
2175
2306
  const temporary = join2(dirname2(path), `pending-${randomUUID2()}.json`);
2176
2307
  this.create(temporary, bytes, maximum);
2177
2308
  this.assert(path, expected, maximum);
2178
- renameSync2(temporary, path);
2309
+ retryWindowsFileOperation(() => renameSync2(temporary, path), () => this.assert(path, expected, maximum));
2179
2310
  this.syncDirectory(dirname2(path));
2180
2311
  const result = this.read(path, maximum);
2181
2312
  if (!result || result.identity !== hash(bytes))
@@ -2184,7 +2315,7 @@ class PrivateFiles {
2184
2315
  }
2185
2316
  remove(path, expected, maximum = METADATA_BYTES) {
2186
2317
  this.assert(path, expected, maximum);
2187
- unlinkSync2(path);
2318
+ retryWindowsFileOperation(() => unlinkSync2(path), () => this.assert(path, expected, maximum));
2188
2319
  this.syncDirectory(dirname2(path));
2189
2320
  }
2190
2321
  syncDirectory(path) {
@@ -3915,22 +4046,22 @@ function decodeRunAdmission(value) {
3915
4046
  }
3916
4047
 
3917
4048
  // src/history/read-io.ts
3918
- import { createHash as createHash3 } from "node:crypto";
4049
+ import { createHash as createHash4 } from "node:crypto";
3919
4050
  import {
3920
4051
  closeSync as closeSync3,
3921
4052
  constants as constants3,
3922
4053
  fstatSync as fstatSync3,
3923
4054
  lstatSync as lstatSync3,
3924
4055
  openSync as openSync3,
3925
- readSync as readSync2
4056
+ readSync as readSync3
3926
4057
  } from "node:fs";
3927
4058
  import { dirname as dirname3 } from "node:path";
3928
4059
  function bad() {
3929
4060
  throw new ContractError("corrupt-selected");
3930
4061
  }
3931
4062
  var stamp2 = (s) => [s.dev, s.ino, s.size, s.mode, s.uid, s.nlink, s.ctimeMs, s.mtimeMs].join(":");
3932
- function selected(files, path, read) {
3933
- if (!files.files.directory(dirname3(path)))
4063
+ function selected(files, path, read, walks) {
4064
+ if (!files.files.directory(dirname3(path), false, walks))
3934
4065
  bad();
3935
4066
  const before = lstatSync3(path);
3936
4067
  if (!before.isFile() || before.nlink !== 1 || process.platform !== "win32" && (before.mode & 63 || process.getuid && before.uid !== process.getuid()))
@@ -3967,7 +4098,7 @@ function reproveAppend(files, path, expected, length, sha256, budget) {
3967
4098
  if (b.slice(0, 2).join(":") !== a.slice(0, 2).join(":") || b.slice(3, 6).join(":") !== a.slice(3, 6).join(":") || Number(b[2]) <= Number(a[2]))
3968
4099
  bad();
3969
4100
  const bytes = readRange(files, path, 0, length, budget);
3970
- if (createHash3("sha256").update(bytes).digest("hex") !== sha256)
4101
+ if (createHash4("sha256").update(bytes).digest("hex") !== sha256)
3971
4102
  bad();
3972
4103
  assertIncarnation(files, path, current.stamp);
3973
4104
  return current.stamp;
@@ -3989,17 +4120,17 @@ function readRange(files, path, offset, length, budget) {
3989
4120
  let n = 0;
3990
4121
  while (n < length) {
3991
4122
  budget.reserve(0);
3992
- const got = readSync2(fd, out, n, length - n, offset + n);
4123
+ const got = readSync3(fd, out, n, length - n, offset + n);
3993
4124
  if (!got)
3994
4125
  bad();
3995
4126
  n += got;
3996
4127
  }
3997
4128
  return out;
3998
- });
4129
+ }, budget.walks);
3999
4130
  }
4000
4131
 
4001
4132
  // src/history/types.ts
4002
- import { createHash as createHash4 } from "node:crypto";
4133
+ import { createHash as createHash5 } from "node:crypto";
4003
4134
  var RECORD_BYTES = LIMITS.controlBytes + 64 * 1024;
4004
4135
  var LEGACY_FORMAT = "cadence-history-store/2";
4005
4136
  var FORMAT = "cadence-history-store/3";
@@ -4365,7 +4496,7 @@ function batchArtifacts(rows) {
4365
4496
  }
4366
4497
  var decodedLines = new Map;
4367
4498
  var decodedBytes = 0;
4368
- var lineKey = (text2) => createHash4("sha256").update(text2).digest("hex");
4499
+ var lineKey = (text2) => createHash5("sha256").update(text2).digest("hex");
4369
4500
  function remember(text2, value) {
4370
4501
  const key = lineKey(text2);
4371
4502
  if (decodedLines.has(key))
@@ -4428,13 +4559,45 @@ function decodeJournalText(line) {
4428
4559
 
4429
4560
  // src/history/files.ts
4430
4561
  class HistoryReadBudget {
4562
+ clock;
4431
4563
  started = performance.now();
4432
4564
  bytes = 0;
4565
+ walks = new DirectoryWalks;
4566
+ constructor(clock = true) {
4567
+ this.clock = clock;
4568
+ }
4569
+ static authority() {
4570
+ return new HistoryReadBudget(false);
4571
+ }
4433
4572
  reserve(bytes) {
4434
- if (!Number.isSafeInteger(bytes) || bytes < 0 || this.bytes + bytes > LIMITS.searchBytes || performance.now() - this.started >= LIMITS.searchMs)
4573
+ if (!Number.isSafeInteger(bytes) || bytes < 0 || this.bytes + bytes > LIMITS.searchBytes || this.elapsed)
4435
4574
  throw new ContractError("receipt-inconclusive");
4436
4575
  this.bytes += bytes;
4437
4576
  }
4577
+ get elapsed() {
4578
+ return this.clock && performance.now() - this.started >= LIMITS.searchMs;
4579
+ }
4580
+ }
4581
+
4582
+ class StalledQuantum extends ContractError {
4583
+ constructor() {
4584
+ super("receipt-inconclusive");
4585
+ }
4586
+ }
4587
+ function noProgress(budget) {
4588
+ throw budget.elapsed ? new StalledQuantum : new ContractError("receipt-inconclusive");
4589
+ }
4590
+ var STALL_RETRIES = 2;
4591
+ async function retryStalled(read) {
4592
+ for (let retry = 0;; retry++) {
4593
+ try {
4594
+ return await read();
4595
+ } catch (error) {
4596
+ if (!(error instanceof StalledQuantum) || retry >= STALL_RETRIES)
4597
+ throw error;
4598
+ await new Promise((resolve3) => setImmediate(resolve3));
4599
+ }
4600
+ }
4438
4601
  }
4439
4602
  function corrupt() {
4440
4603
  throw new ContractError("corrupt-selected");
@@ -4596,12 +4759,12 @@ class HistoryFiles {
4596
4759
  try {
4597
4760
  size = lstatSync4(path).size;
4598
4761
  } catch {
4599
- return this.files.read(path, 0);
4762
+ return this.files.read(path, 0, budget.walks);
4600
4763
  }
4601
4764
  if (size > maximum)
4602
4765
  corrupt();
4603
4766
  budget.reserve(size);
4604
- return this.files.read(path, size);
4767
+ return this.files.read(path, size, budget.walks);
4605
4768
  }
4606
4769
  readCommand(commandId, budget) {
4607
4770
  decodeId(commandId);
@@ -4754,7 +4917,7 @@ class HistoryFiles {
4754
4917
  state.bytes = file.bytes.length;
4755
4918
  state.identity = file.identity;
4756
4919
  state.records = 0;
4757
- let at = 0, pending = [], pendingBytes = 0, checksum = createHash5("sha256");
4920
+ let at = 0, pending = [], pendingBytes = 0, checksum = createHash6("sha256");
4758
4921
  while (at < file.bytes.length) {
4759
4922
  budget?.reserve(0);
4760
4923
  const end = file.bytes.indexOf(10, at);
@@ -4822,7 +4985,7 @@ class HistoryFiles {
4822
4985
  };
4823
4986
  pending = [];
4824
4987
  pendingBytes = 0;
4825
- checksum = createHash5("sha256");
4988
+ checksum = createHash6("sha256");
4826
4989
  }
4827
4990
  if (pending.length)
4828
4991
  state.tail = true;
@@ -5014,7 +5177,7 @@ class HistoryFiles {
5014
5177
  lease.assert();
5015
5178
  this.assertWritable();
5016
5179
  const after = this.files.read(path, LIMITS.segmentBytes);
5017
- if (!after || after.identity !== createHash5("sha256").update(before.bytes).update(body).update(trailer).digest("hex"))
5180
+ if (!after || after.identity !== createHash6("sha256").update(before.bytes).update(body).update(trailer).digest("hex"))
5018
5181
  corrupt();
5019
5182
  return {
5020
5183
  committedSeq: marker.last,
@@ -5283,7 +5446,7 @@ class HistoryLive {
5283
5446
  }
5284
5447
 
5285
5448
  // src/history/navigation.ts
5286
- import { createHash as createHash6 } from "node:crypto";
5449
+ import { createHash as createHash7 } from "node:crypto";
5287
5450
  import { lstatSync as lstatSync6 } from "node:fs";
5288
5451
  import { dirname as dirname5, join as join5 } from "node:path";
5289
5452
 
@@ -5465,7 +5628,7 @@ class IndexTree {
5465
5628
 
5466
5629
  // src/history/run-state.ts
5467
5630
  var uncertainSettlement = (completion) => completion.native.closure === "unconfirmed" || completion.recording.status === "pending" && completion.recording.selected !== null || completion.recording.status === "uncertain";
5468
- function readRunState(files, runId, snapshotSeq, budget = new HistoryReadBudget) {
5631
+ function readRunState(files, runId, snapshotSeq, budget = HistoryReadBudget.authority()) {
5469
5632
  const state = new RunState(runId);
5470
5633
  if (snapshotSeq === "0")
5471
5634
  return state;
@@ -5543,6 +5706,27 @@ class TaskPublicationLineage {
5543
5706
  };
5544
5707
  }
5545
5708
  }
5709
+ get operationId() {
5710
+ return this.operation?.operationId ?? null;
5711
+ }
5712
+ progress() {
5713
+ return {
5714
+ operationId: this.operation?.operationId ?? null,
5715
+ state: structuredClone(this.state),
5716
+ endpoint: this.endpoint && { ...this.endpoint },
5717
+ graphIdentity: this.graphIdentity
5718
+ };
5719
+ }
5720
+ static resumed(operation, progress) {
5721
+ if ((operation?.operationId ?? null) !== progress.operationId)
5722
+ throw new ContractError("invalid");
5723
+ const lineage = new TaskPublicationLineage;
5724
+ lineage.operation = operation;
5725
+ lineage.state = structuredClone(progress.state);
5726
+ lineage.endpoint = progress.endpoint && { ...progress.endpoint };
5727
+ lineage.graphIdentity = progress.graphIdentity;
5728
+ return lineage;
5729
+ }
5546
5730
  current() {
5547
5731
  requireFact(this.operation && this.state.status === "published" && this.endpoint?.identity);
5548
5732
  return {
@@ -5596,6 +5780,21 @@ class OperationState {
5596
5780
  }, fact, seq);
5597
5781
  }
5598
5782
  }
5783
+ progress() {
5784
+ return {
5785
+ reviewed: this.reviewed,
5786
+ publication: structuredClone(this.publication)
5787
+ };
5788
+ }
5789
+ static resumed(operationId, command, progress) {
5790
+ if (command.intent.operationId !== operationId)
5791
+ throw new ContractError("invalid");
5792
+ const state = new OperationState(operationId);
5793
+ state.command = command;
5794
+ state.reviewed = progress.reviewed;
5795
+ state.publication = structuredClone(progress.publication);
5796
+ return state;
5797
+ }
5599
5798
  publicationExpected() {
5600
5799
  const identity = this.command?.intent.identity;
5601
5800
  requireFact(identity?.kind === "action" && (!this.publication.intent || this.publication.status === "published"));
@@ -5621,7 +5820,7 @@ class OperationState {
5621
5820
  }
5622
5821
  function readOperationState(files, operationId) {
5623
5822
  const state = new OperationState(operationId);
5624
- for (const batch of files.scan(emptyScan(), false, new HistoryReadBudget))
5823
+ for (const batch of files.scan(emptyScan(), false, HistoryReadBudget.authority()))
5625
5824
  for (const row of batch.rows)
5626
5825
  state.apply(row, batch.marker.last);
5627
5826
  return state;
@@ -6247,7 +6446,7 @@ class HistoryNavigation {
6247
6446
  return structuredClone(source.value);
6248
6447
  }
6249
6448
  try {
6250
- if (!this.files.files.directory(dirname5(path)))
6449
+ if (!this.files.files.directory(dirname5(path), false, budget.walks))
6251
6450
  return source ? structuredClone(source.value) : undefined;
6252
6451
  const size = lstatSync6(path).size;
6253
6452
  if (size > RECORD_BYTES)
@@ -6474,7 +6673,7 @@ class HistoryNavigation {
6474
6673
  continue;
6475
6674
  }
6476
6675
  let pending = Buffer.alloc(0), at = offset, bodyBytes = 0;
6477
- const checksum = createHash6("sha256"), rows = [];
6676
+ const checksum = createHash7("sha256"), rows = [];
6478
6677
  while (at < size) {
6479
6678
  const chunk = this.block(path, at, size, budget);
6480
6679
  at += chunk.length;
@@ -6758,16 +6957,41 @@ class HistoryNavigation {
6758
6957
  throw new ContractError("receipt-inconclusive");
6759
6958
  let head = expected;
6760
6959
  while (head) {
6761
- const value = this.index(roster ? "roster-links" : "entity-links", `${id}/${head.seq}`, budget);
6762
- if (!value)
6763
- throw new ContractError("receipt-inconclusive");
6764
- const o = closed(value, ["pointer", "previous", "previousHash", "hash"]), p = pointer(o.pointer);
6765
- const previous = o.previous === null ? null : decodeSequence(o.previous), previousHash = o.previousHash === null ? null : typeof o.previousHash === "string" ? o.previousHash : undefined;
6766
- if (previousHash === undefined || previous === null !== (previousHash === null) || p.seq !== head.seq || o.hash !== head.hash || chainHash(p.seq, previous, previousHash) !== head.hash || previous !== null && BigInt(previous) >= BigInt(p.seq))
6767
- throw new ContractError("receipt-inconclusive");
6768
- yield this.batch(p, budget);
6769
- head = previous !== null && previousHash !== null ? { seq: previous, hash: previousHash } : null;
6960
+ const link = this.link(roster ? "roster-links" : "entity-links", id, head, budget);
6961
+ yield this.batch(link.pointer, budget);
6962
+ head = link.previous;
6963
+ }
6964
+ }
6965
+ link(group, id, head, budget) {
6966
+ const value = this.index(group, `${id}/${head.seq}`, budget);
6967
+ if (!value)
6968
+ throw new ContractError("receipt-inconclusive");
6969
+ const o = closed(value, ["pointer", "previous", "previousHash", "hash"]), p = pointer(o.pointer);
6970
+ const previous = o.previous === null ? null : decodeSequence(o.previous), previousHash = o.previousHash === null ? null : typeof o.previousHash === "string" ? o.previousHash : undefined;
6971
+ if (previousHash === undefined || previous === null !== (previousHash === null) || p.seq !== head.seq || o.hash !== head.hash || chainHash(p.seq, previous, previousHash) !== head.hash || previous !== null && BigInt(previous) >= BigInt(p.seq))
6972
+ throw new ContractError("receipt-inconclusive");
6973
+ return {
6974
+ pointer: p,
6975
+ previous: previous !== null && previousHash !== null ? { seq: previous, hash: previousHash } : null
6976
+ };
6977
+ }
6978
+ taskSuffix(taskId, snapshot, budget, accept) {
6979
+ decodeId(taskId);
6980
+ try {
6981
+ let head = this.anchoredHead(taskId, snapshot, budget) ?? null;
6982
+ const newer = [];
6983
+ while (head) {
6984
+ const base = accept(head);
6985
+ if (base !== undefined)
6986
+ return { base, batches: newer.reverse() };
6987
+ const link = this.link("entity-links", taskId, head, budget);
6988
+ newer.push(this.batch(link.pointer, budget));
6989
+ head = link.previous;
6990
+ }
6991
+ } catch {
6992
+ budget.reserve(0);
6770
6993
  }
6994
+ return;
6771
6995
  }
6772
6996
  runBatches(id, snapshot, budget) {
6773
6997
  const expected = this.anchoredHead(id, snapshot, budget);
@@ -6952,19 +7176,77 @@ function navigationKeys(row) {
6952
7176
  }
6953
7177
 
6954
7178
  // src/history/projection.ts
6955
- import { createHash as createHash12 } from "node:crypto";
7179
+ import { createHash as createHash13 } from "node:crypto";
7180
+
7181
+ // src/history/task-folds.ts
7182
+ var TASKS = 1024;
7183
+ var STATES = 8;
7184
+
7185
+ class TaskFoldMemory {
7186
+ tasks = new Map;
7187
+ has(taskId) {
7188
+ return this.tasks.has(taskId);
7189
+ }
7190
+ remember(taskId, anchor, state) {
7191
+ let states = this.tasks.get(taskId);
7192
+ if (!states) {
7193
+ if (this.tasks.size >= TASKS)
7194
+ this.tasks.delete(this.tasks.keys().next().value ?? "");
7195
+ states = new Map;
7196
+ this.tasks.set(taskId, states);
7197
+ }
7198
+ states.delete(anchor.seq);
7199
+ states.set(anchor.seq, {
7200
+ hash: anchor.hash,
7201
+ state: structuredClone(state)
7202
+ });
7203
+ if (states.size > STATES)
7204
+ states.delete(states.keys().next().value ?? "");
7205
+ }
7206
+ recall(taskId, anchor) {
7207
+ const entry = this.tasks.get(taskId)?.get(anchor.seq);
7208
+ return entry?.hash === anchor.hash ? structuredClone(entry.state) : undefined;
7209
+ }
7210
+ }
7211
+ var memories = new Map;
7212
+ function taskFoldMemory(files) {
7213
+ const key = `${files.directory}\x00${files.format.storeId}`;
7214
+ let memory = memories.get(key);
7215
+ if (!memory) {
7216
+ memory = new TaskFoldMemory;
7217
+ memories.set(key, memory);
7218
+ }
7219
+ return memory;
7220
+ }
7221
+ function resumeTaskFold(files, navigation, taskId, snapshot, budget, resume) {
7222
+ const memory = taskFoldMemory(files);
7223
+ const suffix = memory.has(taskId) ? navigation.taskSuffix(taskId, snapshot, budget, (head) => {
7224
+ const state = memory.recall(taskId, head);
7225
+ if (!state)
7226
+ return;
7227
+ try {
7228
+ return resume(state);
7229
+ } catch {
7230
+ budget.reserve(0);
7231
+ return;
7232
+ }
7233
+ }) : undefined;
7234
+ return suffix ?? {
7235
+ base: undefined,
7236
+ batches: navigation.entityBatches(taskId, snapshot, budget) ?? navigation.scanSnapshot(snapshot, budget)
7237
+ };
7238
+ }
6956
7239
 
6957
7240
  // src/history/checks.ts
6958
- function currentChecks(files, taskId, configured, current, snapshotSeq) {
6959
- const budget = new HistoryReadBudget, navigation = new HistoryNavigation(files);
6960
- const snapshot = snapshotSeq ?? navigation.latest(budget);
6961
- navigation.snapshot(snapshot, budget);
6962
- const starts = new Map;
6963
- const results = new Map;
6964
- const incomplete = new Map;
6965
- const batches = navigation.entityBatches(taskId, snapshot, budget) ?? navigation.scanSnapshot(snapshot, budget);
6966
- for (const b of batches)
6967
- for (const row of b.rows) {
7241
+ class CheckFold {
7242
+ starts;
7243
+ settled;
7244
+ constructor(state) {
7245
+ this.starts = new Map(state?.starts);
7246
+ this.settled = new Map(state?.settled);
7247
+ }
7248
+ apply(batch, taskId) {
7249
+ for (const row of batch.rows) {
6968
7250
  const v = row.value;
6969
7251
  if (v.kind !== "owner" || v.link.taskId !== taskId)
6970
7252
  continue;
@@ -6973,44 +7255,83 @@ function currentChecks(files, taskId, configured, current, snapshotSeq) {
6973
7255
  continue;
6974
7256
  const f = e.value.fact;
6975
7257
  if (f.kind === "check-start")
6976
- starts.set(f.checkId, {
7258
+ this.starts.set(f.checkId, {
6977
7259
  selection: f.selection,
6978
7260
  epoch: v.link.epoch,
6979
7261
  cwdId: f.cwdId,
6980
7262
  checkEnvGeneration: f.checkEnvGeneration
6981
7263
  });
6982
7264
  if (f.kind === "check-settled") {
6983
- const s = starts.get(f.checkId);
7265
+ const s = this.starts.get(f.checkId);
6984
7266
  if (!s)
6985
7267
  throw new ContractError("corrupt-selected");
6986
- if (s.selection.kind === "manual" || configured.selections.some((c) => canonicalJson(c) === canonicalJson(s.selection))) {
6987
- const fresh = current.status === "available" && current.version.epoch === s.epoch && current.version.cwdId === s.cwdId && current.version.checkEnvGeneration === s.checkEnvGeneration && current.version.observation.identity === f.after.identity && current.version.observation.complete === f.after.complete && current.version.checkoutGeneration === f.after.checkoutGeneration;
6988
- incomplete.set(canonicalJson(s.selection), f.output === null || f.coverage.observed !== "complete" || f.coverage.source !== "complete" || f.coverage.omissions.length > 0);
6989
- results.set(canonicalJson(s.selection), {
6990
- selection: s.selection,
6991
- status: f.status === "passed" && !fresh ? "stale" : f.status,
6992
- checkId: f.checkId
6993
- });
6994
- }
6995
- starts.delete(f.checkId);
7268
+ this.settled.set(canonicalJson(s.selection), {
7269
+ ...s,
7270
+ checkId: f.checkId,
7271
+ status: f.status,
7272
+ after: {
7273
+ identity: f.after.identity,
7274
+ complete: f.after.complete,
7275
+ checkoutGeneration: f.after.checkoutGeneration
7276
+ },
7277
+ incomplete: f.output === null || f.coverage.observed !== "complete" || f.coverage.source !== "complete" || f.coverage.omissions.length > 0
7278
+ });
7279
+ this.starts.delete(f.checkId);
6996
7280
  }
6997
- if (starts.size > LIMITS.childReservations || results.size > 32)
7281
+ if (this.starts.size > LIMITS.childReservations)
6998
7282
  throw new ContractError("receipt-inconclusive");
6999
7283
  }
7000
7284
  }
7001
- return {
7002
- checks: decodeCheckObligations({
7003
- taskId,
7004
- revision: configured.revision,
7005
- definitions: configured.selections.map((selection) => results.get(canonicalJson(selection)) ?? {
7006
- selection,
7007
- status: "not-run",
7008
- checkId: null
7009
- })
7010
- }),
7011
- recorded: [...results.values()],
7012
- recordingIncomplete: [...incomplete.values()].some(Boolean)
7013
- };
7285
+ }
7286
+ state() {
7287
+ return {
7288
+ starts: [...this.starts],
7289
+ settled: [...this.settled]
7290
+ };
7291
+ }
7292
+ evaluate(taskId, configured, current) {
7293
+ const results = new Map;
7294
+ const incomplete = new Map;
7295
+ for (const [key, s] of this.settled) {
7296
+ if (s.selection.kind !== "manual" && !configured.selections.some((c) => canonicalJson(c) === key))
7297
+ continue;
7298
+ const fresh = current.status === "available" && current.version.epoch === s.epoch && current.version.cwdId === s.cwdId && current.version.checkEnvGeneration === s.checkEnvGeneration && current.version.observation.identity === s.after.identity && current.version.observation.complete === s.after.complete && current.version.checkoutGeneration === s.after.checkoutGeneration;
7299
+ incomplete.set(key, s.incomplete);
7300
+ results.set(key, {
7301
+ selection: s.selection,
7302
+ status: s.status === "passed" && !fresh ? "stale" : s.status,
7303
+ checkId: s.checkId
7304
+ });
7305
+ }
7306
+ if (results.size > 32)
7307
+ throw new ContractError("receipt-inconclusive");
7308
+ return {
7309
+ checks: decodeCheckObligations({
7310
+ taskId,
7311
+ revision: configured.revision,
7312
+ definitions: configured.selections.map((selection) => results.get(canonicalJson(selection)) ?? {
7313
+ selection,
7314
+ status: "not-run",
7315
+ checkId: null
7316
+ })
7317
+ }),
7318
+ recorded: [...results.values()],
7319
+ recordingIncomplete: [...incomplete.values()].some(Boolean)
7320
+ };
7321
+ }
7322
+ }
7323
+ function checkFold(files, taskId, snapshot, budget, navigation = new HistoryNavigation(files)) {
7324
+ navigation.snapshot(snapshot, budget);
7325
+ const { base, batches } = resumeTaskFold(files, navigation, taskId, snapshot, budget, (state) => state.checks);
7326
+ const fold = new CheckFold(base);
7327
+ for (const b of batches)
7328
+ fold.apply(b, taskId);
7329
+ return fold;
7330
+ }
7331
+ function currentChecks(files, taskId, configured, current, snapshotSeq) {
7332
+ const budget = HistoryReadBudget.authority(), navigation = new HistoryNavigation(files);
7333
+ const snapshot = snapshotSeq ?? navigation.latest(budget);
7334
+ return checkFold(files, taskId, snapshot, budget, navigation).evaluate(taskId, configured, current);
7014
7335
  }
7015
7336
 
7016
7337
  // src/history/entity-state.ts
@@ -7198,17 +7519,17 @@ function materializeEntity(s, sources) {
7198
7519
  }
7199
7520
 
7200
7521
  // src/history/export.ts
7201
- import { createHash as createHash10, randomUUID as randomUUID4 } from "node:crypto";
7522
+ import { createHash as createHash11, randomUUID as randomUUID4 } from "node:crypto";
7202
7523
  import { readFileSync } from "node:fs";
7203
7524
 
7204
7525
  // src/history/search.ts
7205
- import { createHash as createHash9 } from "node:crypto";
7526
+ import { createHash as createHash10 } from "node:crypto";
7206
7527
 
7207
7528
  // src/history/read-proof.ts
7208
7529
  import {
7209
7530
  createCipheriv,
7210
7531
  createDecipheriv,
7211
- createHash as createHash7,
7532
+ createHash as createHash8,
7212
7533
  randomBytes as randomBytes2
7213
7534
  } from "node:crypto";
7214
7535
  var PREFIX = "rp1.";
@@ -7260,7 +7581,7 @@ class HistoryReadProof {
7260
7581
  root: this.files.format.rootIdentity,
7261
7582
  format: material.formatStamp,
7262
7583
  key: material.keyStamp,
7263
- request: createHash7("sha256").update(canonicalJson(readIdentity(request))).digest("hex")
7584
+ request: createHash8("sha256").update(canonicalJson(readIdentity(request))).digest("hex")
7264
7585
  }));
7265
7586
  }
7266
7587
  seal(context, plaintext, budget) {
@@ -8032,11 +8353,11 @@ function decodeRetainedProgress(value) {
8032
8353
  }
8033
8354
 
8034
8355
  // src/history/retained-traversal.ts
8035
- import { createHash as createHash8 } from "node:crypto";
8356
+ import { createHash as createHash9 } from "node:crypto";
8036
8357
  function bad5() {
8037
8358
  throw new ContractError("corrupt-selected");
8038
8359
  }
8039
- var fingerprint = (v) => createHash8("sha256").update(canonicalJson(v)).digest("hex");
8360
+ var fingerprint = (v) => createHash9("sha256").update(canonicalJson(v)).digest("hex");
8040
8361
  var ready = (v) => {
8041
8362
  const s = v.state;
8042
8363
  if (s.phase !== "ready")
@@ -8392,11 +8713,11 @@ var digits = (id) => {
8392
8713
  return s.slice(0, 12) + s.slice(13, 16) + s.slice(17);
8393
8714
  };
8394
8715
  var publicTextRef = (id, label, text2, field, batch, row, slot) => ({
8395
- recordId: uuid(address(batch.pointer).toString(16).padStart(14, "0") + createHash9("sha256").update(`${id}/${label}`).digest("hex").slice(0, 16)),
8716
+ recordId: uuid(address(batch.pointer).toString(16).padStart(14, "0") + createHash10("sha256").update(`${id}/${label}`).digest("hex").slice(0, 16)),
8396
8717
  version: batch.rows.indexOf(row) * EVENT_SLOTS + slot + 1,
8397
8718
  field,
8398
8719
  bytes: Buffer.byteLength(text2),
8399
- sha256: createHash9("sha256").update(text2).digest("hex")
8720
+ sha256: createHash10("sha256").update(text2).digest("hex")
8400
8721
  });
8401
8722
  var initial = () => ({
8402
8723
  pos: { segment: 1, offset: 0 },
@@ -8412,7 +8733,7 @@ function scanCursor(base, p) {
8412
8733
  const snapshot = p.snapshot.toString(16).padStart(14, "0");
8413
8734
  if (snapshot.length !== 14)
8414
8735
  throw new ContractError("capacity");
8415
- const binding = createHash9("sha256").update(canonicalJson({
8736
+ const binding = createHash10("sha256").update(canonicalJson({
8416
8737
  ...readIdentity(base),
8417
8738
  recordId: null,
8418
8739
  recordVersion: version,
@@ -8753,7 +9074,7 @@ class RetainedScan {
8753
9074
  graph: {
8754
9075
  recordId: v.intent.operationId,
8755
9076
  revision: graph.revision,
8756
- sha256: createHash9("sha256").update(canonicalJson(graph)).digest("hex")
9077
+ sha256: createHash10("sha256").update(canonicalJson(graph)).digest("hex")
8757
9078
  }
8758
9079
  },
8759
9080
  graph
@@ -8941,6 +9262,9 @@ class RetainedScan {
8941
9262
  }
8942
9263
  }
8943
9264
  async function searchHistory(reader, value, limit = LIMITS.pageEntries) {
9265
+ return retryStalled(() => searchQuantum(reader, value, limit));
9266
+ }
9267
+ async function searchQuantum(reader, value, limit = LIMITS.pageEntries) {
8944
9268
  const cursor = decodeCursor(value);
8945
9269
  if (!cursor.query || !Number.isInteger(limit) || limit < 1 || limit > LIMITS.maxPageEntries)
8946
9270
  throw new ContractError("invalid");
@@ -9034,7 +9358,7 @@ async function searchHistory(reader, value, limit = LIMITS.pageEntries) {
9034
9358
  if (!(error instanceof ContractError) || error.code !== "receipt-inconclusive")
9035
9359
  throw error;
9036
9360
  if (!hits.length && before === coordinate())
9037
- throw error;
9361
+ noProgress(originalBudget);
9038
9362
  done = false;
9039
9363
  }
9040
9364
  scan.traversal?.assertCurrent();
@@ -9049,7 +9373,7 @@ async function searchHistory(reader, value, limit = LIMITS.pageEntries) {
9049
9373
  // src/history/export.ts
9050
9374
  var exporterIdentity;
9051
9375
  function buildIdentity() {
9052
- exporterIdentity ??= createHash10("sha256").update(readFileSync(new URL(import.meta.url))).digest("hex");
9376
+ exporterIdentity ??= createHash11("sha256").update(readFileSync(new URL(import.meta.url))).digest("hex");
9053
9377
  return exporterIdentity;
9054
9378
  }
9055
9379
  function aborted(signal) {
@@ -9109,7 +9433,7 @@ Coverage: ${canonicalJson(event.coverage)}
9109
9433
  }
9110
9434
  }
9111
9435
  async function* exportHistory(projection, input, signal) {
9112
- const request = decodeExportRequest(input), exportId = randomUUID4(), digest = createHash10("sha256");
9436
+ const request = decodeExportRequest(input), exportId = randomUUID4(), digest = createHash11("sha256");
9113
9437
  let ordinal = 0, encodedBytes = 0, coverage = { ...COMPLETE, omissions: [] };
9114
9438
  const frame = (event) => {
9115
9439
  aborted(signal);
@@ -9138,7 +9462,7 @@ async function* exportHistory(projection, input, signal) {
9138
9462
  snapshot: 0
9139
9463
  };
9140
9464
  const scan = new RetainedScan(projection.reader, request, new HistoryReadBudget, true);
9141
- for (;; ) {
9465
+ for (let stalls2 = 0;; ) {
9142
9466
  aborted(signal);
9143
9467
  const before = canonicalJson({ point, state: scan.checkpoint() });
9144
9468
  scan.renew(new HistoryReadBudget);
@@ -9146,8 +9470,13 @@ async function* exportHistory(projection, input, signal) {
9146
9470
  scan.prepare(point);
9147
9471
  break;
9148
9472
  } catch (error) {
9149
- if (!(error instanceof ContractError) || error.code !== "receipt-inconclusive" || before === canonicalJson({ point, state: scan.checkpoint() }))
9473
+ if (!(error instanceof ContractError) || error.code !== "receipt-inconclusive")
9150
9474
  throw error;
9475
+ if (before === canonicalJson({ point, state: scan.checkpoint() })) {
9476
+ if (!scan.budget.elapsed || ++stalls2 > STALL_RETRIES)
9477
+ throw error;
9478
+ } else
9479
+ stalls2 = 0;
9151
9480
  await yieldTurn();
9152
9481
  }
9153
9482
  }
@@ -9173,7 +9502,7 @@ async function* exportHistory(projection, input, signal) {
9173
9502
  const { detail, owner } = item, original = open2.get(detail.content.recordId);
9174
9503
  if (detail.content.bytes ? !original || original.bytes !== detail.content.bytes || original.content !== canonicalJson(detail.content) : original !== undefined)
9175
9504
  throw new ContractError("corrupt-selected");
9176
- if ((original?.hash ?? createHash10("sha256")).digest("hex") !== detail.content.sha256)
9505
+ if ((original?.hash ?? createHash11("sha256")).digest("hex") !== detail.content.sha256)
9177
9506
  throw new ContractError("corrupt-selected");
9178
9507
  open2.delete(detail.content.recordId);
9179
9508
  const events = [];
@@ -9204,7 +9533,7 @@ async function* exportHistory(projection, input, signal) {
9204
9533
  coverage = combineCoverage(coverage, item.coverage);
9205
9534
  const length = Buffer.byteLength(item.text);
9206
9535
  if (item.inline) {
9207
- if (item.start !== 0 || length !== item.content.bytes || createHash10("sha256").update(item.text).digest("hex") !== item.content.sha256)
9536
+ if (item.start !== 0 || length !== item.content.bytes || createHash11("sha256").update(item.text).digest("hex") !== item.content.sha256)
9208
9537
  throw new ContractError("corrupt-selected");
9209
9538
  } else {
9210
9539
  let original = open2.get(item.content.recordId);
@@ -9214,7 +9543,7 @@ async function* exportHistory(projection, input, signal) {
9214
9543
  original = {
9215
9544
  bytes: 0,
9216
9545
  content: canonicalJson(item.content),
9217
- hash: createHash10("sha256")
9546
+ hash: createHash11("sha256")
9218
9547
  };
9219
9548
  open2.set(item.content.recordId, original);
9220
9549
  }
@@ -9234,7 +9563,7 @@ async function* exportHistory(projection, input, signal) {
9234
9563
  }
9235
9564
  ];
9236
9565
  };
9237
- let finished = false;
9566
+ let finished = false, stalls = 0;
9238
9567
  while (!finished) {
9239
9568
  aborted(signal);
9240
9569
  const before = canonicalJson({ point, state: scan.checkpoint() });
@@ -9293,8 +9622,13 @@ async function* exportHistory(projection, input, signal) {
9293
9622
  if (finished)
9294
9623
  scan.finish();
9295
9624
  } catch (error) {
9296
- if (!(error instanceof ContractError) || error.code !== "receipt-inconclusive" || before === canonicalJson({ point, state: scan.checkpoint() }))
9625
+ if (!(error instanceof ContractError) || error.code !== "receipt-inconclusive")
9297
9626
  throw error;
9627
+ if (before === canonicalJson({ point, state: scan.checkpoint() })) {
9628
+ if (!scan.budget.elapsed || ++stalls > STALL_RETRIES)
9629
+ throw error;
9630
+ } else
9631
+ stalls = 0;
9298
9632
  finished = false;
9299
9633
  }
9300
9634
  coverage = combineCoverage(coverage, scan.coverage);
@@ -9324,7 +9658,7 @@ async function* exportHistory(projection, input, signal) {
9324
9658
  }
9325
9659
 
9326
9660
  // src/history/list-progress.ts
9327
- import { createHash as createHash11 } from "node:crypto";
9661
+ import { createHash as createHash12 } from "node:crypto";
9328
9662
 
9329
9663
  // src/history/detail-progress.ts
9330
9664
  function bad7() {
@@ -9365,6 +9699,9 @@ function detailPreparation(cursor, completion) {
9365
9699
  });
9366
9700
  }
9367
9701
  async function readRetainedDetail(reader, input) {
9702
+ return retryStalled(() => detailQuantum(reader, input));
9703
+ }
9704
+ async function detailQuantum(reader, input) {
9368
9705
  const cursor = decodeCursor(input);
9369
9706
  if (cursor.storeId !== reader.storeId || !cursor.recordId)
9370
9707
  bad7();
@@ -9466,8 +9803,10 @@ async function readRetainedDetail(reader, input) {
9466
9803
  p.event = 0;
9467
9804
  }
9468
9805
  } catch (error) {
9469
- if (!(error instanceof ContractError) || error.code !== "receipt-inconclusive" || coordinate() === before)
9806
+ if (!(error instanceof ContractError) || error.code !== "receipt-inconclusive")
9470
9807
  throw error;
9808
+ if (coordinate() === before)
9809
+ noProgress(original);
9471
9810
  return decodeDetailReadResult({
9472
9811
  kind: "progress",
9473
9812
  cursor,
@@ -9793,7 +10132,7 @@ function fits(link, scope) {
9793
10132
  return scope.kind === "workspace" || (scope.kind === "task" ? link.taskId === scope.id : scope.kind === "run" ? link.runId === scope.id : link.childRunId === scope.id);
9794
10133
  }
9795
10134
  function nextAfter(request, n) {
9796
- const h = createHash11("sha256").update(canonicalJson({ ...readIdentity(request), after: null, ordinal: n })).digest("hex");
10135
+ const h = createHash12("sha256").update(canonicalJson({ ...readIdentity(request), after: null, ordinal: n })).digest("hex");
9797
10136
  return {
9798
10137
  recordId: `${h.slice(0, 8)}-${h.slice(8, 12)}-4${h.slice(13, 16)}-8${h.slice(17, 20)}-${h.slice(20, 32)}`,
9799
10138
  version: 1,
@@ -9900,10 +10239,10 @@ function advanceTarget(p, t, snapshot, budget, sources) {
9900
10239
  }
9901
10240
  }
9902
10241
  async function readRetainedList(p, request) {
9903
- return read(p, request, false);
10242
+ return retryStalled(() => read(p, request, false));
9904
10243
  }
9905
10244
  async function readRetainedEntity(p, request) {
9906
- return read(p, request, true);
10245
+ return retryStalled(() => read(p, request, true));
9907
10246
  }
9908
10247
  async function read(p, request, entity) {
9909
10248
  const budget = new HistoryReadBudget, proof = new HistoryReadProof(p.reader.files), completion = proof.prepareCompletion(budget);
@@ -9932,7 +10271,7 @@ async function read(p, request, entity) {
9932
10271
  };
9933
10272
  const progress = () => {
9934
10273
  if (coordinate() === before)
9935
- throw new ContractError("receipt-inconclusive");
10274
+ noProgress(budget);
9936
10275
  const next = seal(request);
9937
10276
  return entity ? decodeEntityReadResult({
9938
10277
  kind: "progress",
@@ -10177,7 +10516,7 @@ async function read(p, request, entity) {
10177
10516
  const tasks = [...p.environment.legacyTasks(budget)].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
10178
10517
  if (tasks.length > 1000)
10179
10518
  throw new ContractError("capacity");
10180
- const sum = createHash11("sha256");
10519
+ const sum = createHash12("sha256");
10181
10520
  for (const task2 of tasks) {
10182
10521
  budget.reserve(0);
10183
10522
  sum.update(JSON.stringify({
@@ -10190,7 +10529,7 @@ async function read(p, request, entity) {
10190
10529
  if (s.legacy > tasks.length)
10191
10530
  bad9();
10192
10531
  if (!s.legacyIdentity && request.after?.version === Number.MAX_SAFE_INTEGER) {
10193
- const h = createHash11("sha256").update(canonicalJson({
10532
+ const h = createHash12("sha256").update(canonicalJson({
10194
10533
  ...readIdentity(request),
10195
10534
  after: null,
10196
10535
  legacy: s.legacy === 0 ? "begin" : identity,
@@ -10470,7 +10809,7 @@ class HistoryProjection {
10470
10809
  };
10471
10810
  cursor(request, pos, row, item) {
10472
10811
  const offset = pos.offset * (LIMITS.segmentRecords + 1) * ROW_SLOTS + row * ROW_SLOTS + item;
10473
- const digest = createHash12("sha256").update(canonicalJson({
10812
+ const digest = createHash13("sha256").update(canonicalJson({
10474
10813
  ...readIdentity(request),
10475
10814
  after: null,
10476
10815
  position: { ...pos, row, item }
@@ -10661,7 +11000,7 @@ class HistoryProjection {
10661
11000
  if (legacyPhase)
10662
11001
  this.navigation.snapshot(snapshot, budget);
10663
11002
  const cursor = (offset2, identity2) => {
10664
- const digest2 = createHash12("sha256").update(canonicalJson({ ...request, after: null, legacy: identity2, offset: offset2 })).digest("hex");
11003
+ const digest2 = createHash13("sha256").update(canonicalJson({ ...request, after: null, legacy: identity2, offset: offset2 })).digest("hex");
10665
11004
  return {
10666
11005
  recordId: `${digest2.slice(0, 8)}-${digest2.slice(8, 12)}-4${digest2.slice(13, 16)}-8${digest2.slice(17, 20)}-${digest2.slice(20, 32)}`,
10667
11006
  version: legacyVersion,
@@ -10688,7 +11027,7 @@ class HistoryProjection {
10688
11027
  }
10689
11028
  if (legacy.length > 1000)
10690
11029
  throw new ContractError("capacity");
10691
- const items = [...legacy].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0), digest = createHash12("sha256");
11030
+ const items = [...legacy].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0), digest = createHash13("sha256");
10692
11031
  for (const item of items) {
10693
11032
  budget.reserve(0);
10694
11033
  if (Buffer.byteLength(item.goal) > 8192)
@@ -10878,7 +11217,7 @@ class HistoryProjection {
10878
11217
  }
10879
11218
 
10880
11219
  // src/history/reader.ts
10881
- import { createHash as createHash13 } from "node:crypto";
11220
+ import { createHash as createHash14 } from "node:crypto";
10882
11221
  import { existsSync } from "node:fs";
10883
11222
  import { join as join6 } from "node:path";
10884
11223
 
@@ -11010,6 +11349,9 @@ function graphPreparation(request, completion) {
11010
11349
  });
11011
11350
  }
11012
11351
  async function readRetainedGraph(reader, request) {
11352
+ return retryStalled(() => graphQuantum(reader, request));
11353
+ }
11354
+ async function graphQuantum(reader, request) {
11013
11355
  if (request.storeId !== reader.storeId)
11014
11356
  throw new ContractError("corrupt-selected");
11015
11357
  const budget = new HistoryReadBudget, proof = new HistoryReadProof(reader.files), completion = proof.prepareCompletion(budget);
@@ -11069,8 +11411,10 @@ async function readRetainedGraph(reader, request) {
11069
11411
  point.event = 0;
11070
11412
  }
11071
11413
  } catch (error) {
11072
- if (!(error instanceof ContractError) || error.code !== "receipt-inconclusive" || coordinate() === before)
11414
+ if (!(error instanceof ContractError) || error.code !== "receipt-inconclusive")
11073
11415
  throw error;
11416
+ if (coordinate() === before)
11417
+ noProgress(budget);
11074
11418
  traversal.assertCurrent();
11075
11419
  const next = {
11076
11420
  ...readIdentity(request),
@@ -11089,6 +11433,95 @@ async function readRetainedGraph(reader, request) {
11089
11433
  }
11090
11434
 
11091
11435
  // src/history/reader.ts
11436
+ class PlanFold {
11437
+ lineage;
11438
+ operation = null;
11439
+ graphIdentity = "";
11440
+ savePlanAt = null;
11441
+ lineageAt = null;
11442
+ constructor(lineage) {
11443
+ this.lineage = lineage;
11444
+ }
11445
+ apply(batch, taskId) {
11446
+ batch.rows.forEach((row, index) => {
11447
+ const value = row.value;
11448
+ if (value.kind === "admission" && value.intent.identity.kind === "action" && value.intent.identity.action.kind === "save-plan" && value.intent.identity.action.taskId === taskId) {
11449
+ if (value.intent.runId !== null)
11450
+ throw new ContractError("corrupt-selected");
11451
+ this.operation = new OperationState(value.intent.operationId);
11452
+ this.graphIdentity = hash(canonicalJson(value.intent.identity.action.graph));
11453
+ this.savePlanAt = { pointer: batch.pointer, row: index };
11454
+ }
11455
+ this.operation?.apply(row, batch.pointer.seq);
11456
+ if (!this.lineage)
11457
+ return;
11458
+ this.lineage.apply(row, batch.pointer.seq, taskId, this.graphIdentity);
11459
+ if (value.kind === "admission" && this.lineage.operationId === value.intent.operationId)
11460
+ this.lineageAt = { pointer: batch.pointer, row: index };
11461
+ });
11462
+ }
11463
+ state() {
11464
+ if (!this.lineage)
11465
+ throw new ContractError("invalid");
11466
+ return {
11467
+ savePlan: this.operation && this.savePlanAt ? { at: this.savePlanAt, ...this.operation.progress() } : null,
11468
+ graphIdentity: this.graphIdentity,
11469
+ lineage: { at: this.lineageAt, progress: this.lineage.progress() }
11470
+ };
11471
+ }
11472
+ static resumed(state, withLineage, read2) {
11473
+ let lineage = null;
11474
+ if (withLineage) {
11475
+ const row = state.lineage.at && read2(state.lineage.at).value;
11476
+ if (row && row.kind !== "admission")
11477
+ throw new ContractError("invalid");
11478
+ lineage = TaskPublicationLineage.resumed(row ? row.intent : null, state.lineage.progress);
11479
+ }
11480
+ const fold = new PlanFold(lineage);
11481
+ fold.lineageAt = state.lineage.at;
11482
+ fold.graphIdentity = state.graphIdentity;
11483
+ if (!state.savePlan) {
11484
+ if (state.graphIdentity !== "")
11485
+ throw new ContractError("invalid");
11486
+ return fold;
11487
+ }
11488
+ const v = read2(state.savePlan.at).value;
11489
+ if (v.kind !== "admission" || v.intent.identity.kind !== "action" || v.intent.identity.action.kind !== "save-plan" || hash(canonicalJson(v.intent.identity.action.graph)) !== state.graphIdentity)
11490
+ throw new ContractError("invalid");
11491
+ fold.operation = OperationState.resumed(v.intent.operationId, { intent: v.intent, record: v.record }, state.savePlan);
11492
+ fold.savePlanAt = state.savePlan.at;
11493
+ return fold;
11494
+ }
11495
+ }
11496
+ function planFold(files, taskId, snapshot, budget, navigation, withLineage) {
11497
+ navigation.snapshot(snapshot, budget);
11498
+ const read2 = (at) => {
11499
+ if (BigInt(at.pointer.seq) > BigInt(snapshot))
11500
+ throw new ContractError("invalid");
11501
+ const row = navigation.batch(at.pointer, budget).rows[at.row];
11502
+ if (!row)
11503
+ throw new ContractError("invalid");
11504
+ return row;
11505
+ };
11506
+ const { base, batches } = resumeTaskFold(files, navigation, taskId, snapshot, budget, (state) => PlanFold.resumed(state.plan, withLineage, read2));
11507
+ const fold = base ?? new PlanFold(withLineage ? new TaskPublicationLineage : null);
11508
+ for (const batch of batches)
11509
+ fold.apply(batch, taskId);
11510
+ return fold;
11511
+ }
11512
+ function latestTaskRun(files, taskId, snapshot, budget, navigation = new HistoryNavigation(files)) {
11513
+ navigation.snapshot(snapshot, budget);
11514
+ const { base, batches } = resumeTaskFold(files, navigation, taskId, snapshot, budget, (state) => state.run);
11515
+ let latest = base ?? null;
11516
+ for (const batch of batches)
11517
+ for (const row of batch.rows) {
11518
+ const v = row.value;
11519
+ if (v.kind === "admission" && v.intent.identity.kind === "action" && v.intent.identity.expected.task?.id === taskId && (v.intent.identity.action.kind === "start" || v.intent.identity.action.kind === "generate-plan"))
11520
+ latest = v.intent.runId;
11521
+ }
11522
+ return latest;
11523
+ }
11524
+
11092
11525
  class HistoryReader {
11093
11526
  files;
11094
11527
  cached;
@@ -11104,7 +11537,7 @@ class HistoryReader {
11104
11537
  admission(runId, snapshotSeq) {
11105
11538
  decodeId(runId);
11106
11539
  decodeSequence(snapshotSeq);
11107
- const budget = new HistoryReadBudget;
11540
+ const budget = HistoryReadBudget.authority();
11108
11541
  this.navigation.snapshot(snapshotSeq, budget);
11109
11542
  const batches = this.navigation.entityBatches(runId, snapshotSeq, budget);
11110
11543
  const state = batches ? new RunState(runId) : readRunState(this.files, runId, snapshotSeq, budget);
@@ -11119,26 +11552,9 @@ class HistoryReader {
11119
11552
  publishedPlan(taskId, snapshotSeq, current2) {
11120
11553
  decodeId(taskId);
11121
11554
  decodeSequence(snapshotSeq);
11122
- const budget = new HistoryReadBudget;
11123
- this.navigation.snapshot(snapshotSeq, budget);
11124
- const batches = this.navigation.entityBatches(taskId, snapshotSeq, budget) ?? this.navigation.scanSnapshot(snapshotSeq, budget);
11125
- let operation = null;
11126
- const lineage = new TaskPublicationLineage;
11127
- let graphIdentity = "";
11128
- for (const batch of batches) {
11129
- for (const row of batch.rows) {
11130
- const value = row.value;
11131
- if (value.kind === "admission" && value.intent.identity.kind === "action" && value.intent.identity.action.kind === "save-plan" && value.intent.identity.action.taskId === taskId) {
11132
- if (value.intent.runId !== null)
11133
- throw new ContractError("corrupt-selected");
11134
- operation = new OperationState(value.intent.operationId);
11135
- graphIdentity = hash(canonicalJson(value.intent.identity.action.graph));
11136
- }
11137
- operation?.apply(row, batch.pointer.seq);
11138
- if (current2)
11139
- lineage.apply(row, batch.pointer.seq, taskId, graphIdentity);
11140
- }
11141
- }
11555
+ const budget = HistoryReadBudget.authority();
11556
+ const fold = planFold(this.files, taskId, snapshotSeq, budget, this.navigation, !!current2);
11557
+ const { operation, lineage } = fold;
11142
11558
  if (!operation)
11143
11559
  return null;
11144
11560
  const command = operation.command;
@@ -11149,7 +11565,7 @@ class HistoryReader {
11149
11565
  throw new ContractError("conflict");
11150
11566
  const { graph, plan } = command.intent.identity.action;
11151
11567
  const ref = graph.plan;
11152
- const detail = this.selected({
11568
+ const { detail, bytes: text2 } = this.planText({
11153
11569
  storeId: this.storeId,
11154
11570
  scope: { kind: "task", id: taskId },
11155
11571
  snapshotSeq,
@@ -11161,13 +11577,10 @@ class HistoryReader {
11161
11577
  }, budget);
11162
11578
  if (canonicalJson(detail.content) !== canonicalJson(ref) || detail.origin.kind !== "owner" || detail.origin.id !== operation.operationId || detail.owner.taskId !== taskId || detail.owner.runId !== null || detail.owner.childRunId !== null || detail.owner.entity.kind !== "task" || detail.owner.entity.id !== taskId || detail.owner.entity.version !== graph.planRevision || ref.bytes > 32768)
11163
11579
  throw new ContractError("corrupt-selected");
11164
- const chunks = [];
11165
- for (const part of this.parts(detail, snapshotSeq, budget))
11166
- chunks.push(part.bytes);
11167
- if (Buffer.concat(chunks).toString("utf8") !== plan)
11580
+ if (text2.toString("utf8") !== plan)
11168
11581
  throw new ContractError("corrupt-selected");
11169
- const publication = current2 ? lineage.current() : operation.publicationExpected();
11170
- if (!publication.identity)
11582
+ const publication = current2 ? lineage?.current() : operation.publicationExpected();
11583
+ if (!publication?.identity)
11171
11584
  throw new ContractError("corrupt-selected");
11172
11585
  if (current2 && (current2.identity !== publication.identity || current2.revision !== publication.revision || current2.plan !== plan))
11173
11586
  throw new ContractError("stale");
@@ -11186,19 +11599,11 @@ class HistoryReader {
11186
11599
  committedSeq: receipt.receipt.committedSeq
11187
11600
  };
11188
11601
  }
11189
- reviewRun(taskId, runId, snapshotSeq, budget = new HistoryReadBudget) {
11602
+ reviewRun(taskId, runId, snapshotSeq, budget = HistoryReadBudget.authority()) {
11190
11603
  decodeId(taskId);
11191
11604
  decodeId(runId);
11192
11605
  decodeSequence(snapshotSeq);
11193
- this.navigation.snapshot(snapshotSeq, budget);
11194
- const batches = () => this.navigation.entityBatches(taskId, snapshotSeq, budget) ?? this.navigation.scanSnapshot(snapshotSeq, budget);
11195
- let latest = null;
11196
- for (const batch of batches())
11197
- for (const row of batch.rows) {
11198
- const v = row.value;
11199
- if (v.kind === "admission" && v.intent.identity.kind === "action" && v.intent.identity.expected.task?.id === taskId && (v.intent.identity.action.kind === "start" || v.intent.identity.action.kind === "generate-plan"))
11200
- latest = v.intent.runId;
11201
- }
11606
+ const latest = latestTaskRun(this.files, taskId, snapshotSeq, budget, this.navigation);
11202
11607
  if (latest !== runId)
11203
11608
  throw new ContractError("stale");
11204
11609
  const state = new RunState(runId);
@@ -11212,7 +11617,7 @@ class HistoryReader {
11212
11617
  return state;
11213
11618
  }
11214
11619
  reviewSelection(taskId, runId, snapshotSeq) {
11215
- const budget = new HistoryReadBudget;
11620
+ const budget = HistoryReadBudget.authority();
11216
11621
  const run = this.reviewRun(taskId, runId, snapshotSeq, budget);
11217
11622
  if (!run.admission)
11218
11623
  throw new ContractError("corrupt-selected");
@@ -11220,7 +11625,7 @@ class HistoryReader {
11220
11625
  if (!graph)
11221
11626
  return { run, graph, readablePlan: "" };
11222
11627
  const ref = graph.plan;
11223
- const detail = this.selected({
11628
+ const { detail, bytes } = this.planText({
11224
11629
  storeId: this.storeId,
11225
11630
  scope: { kind: "task", id: taskId },
11226
11631
  snapshotSeq,
@@ -11232,7 +11637,6 @@ class HistoryReader {
11232
11637
  }, budget);
11233
11638
  if (ref.bytes > 32768 || canonicalJson(detail.content) !== canonicalJson(ref) || detail.owner.taskId !== taskId || detail.owner.runId !== null || detail.owner.childRunId !== null || detail.owner.entity.kind !== "task" || detail.owner.entity.id !== taskId || detail.owner.entity.version !== graph.planRevision)
11234
11639
  throw new ContractError("corrupt-selected");
11235
- const bytes = Buffer.concat([...this.parts(detail, snapshotSeq, budget)].map((p) => p.bytes));
11236
11640
  return { run, graph, readablePlan: bytes.toString("utf8") };
11237
11641
  }
11238
11642
  async graph(value) {
@@ -11437,6 +11841,52 @@ class HistoryReader {
11437
11841
  throw new ContractError("invalid");
11438
11842
  return this.cached.detail;
11439
11843
  }
11844
+ planText(cursor, budget) {
11845
+ const indexed = this.indexedText(cursor, budget);
11846
+ if (indexed)
11847
+ return indexed;
11848
+ const detail = this.selected(cursor, budget);
11849
+ return {
11850
+ detail,
11851
+ bytes: Buffer.concat([...this.parts(detail, cursor.snapshotSeq, budget)].map((p) => p.bytes))
11852
+ };
11853
+ }
11854
+ indexedText(cursor, budget) {
11855
+ const nav = this.navigation, id = cursor.recordId;
11856
+ if (!id)
11857
+ return;
11858
+ try {
11859
+ this.files.assertReadFormat(budget);
11860
+ nav.snapshot(cursor.snapshotSeq, budget);
11861
+ const detail = nav.content(id, cursor.snapshotSeq, budget);
11862
+ if (!detail || detail.content.version !== cursor.recordVersion || detail.content.field !== cursor.field)
11863
+ return;
11864
+ const pieces = [];
11865
+ let end = 0;
11866
+ if (detail.content.bytes) {
11867
+ const count2 = nav.partCount(id, budget);
11868
+ for (let part = 0;part < count2; part++) {
11869
+ const chunks = nav.part(id, part, cursor.snapshotSeq, budget);
11870
+ if (!chunks?.length)
11871
+ return;
11872
+ const bytes = this.files.readArtifact(chunks[0].artifact, budget);
11873
+ for (const c of chunks) {
11874
+ if (c.offset !== end || c.start + c.length > bytes.length)
11875
+ return;
11876
+ pieces.push(bytes.subarray(c.start, c.start + c.length));
11877
+ end += c.length;
11878
+ }
11879
+ }
11880
+ }
11881
+ const text2 = Buffer.concat(pieces);
11882
+ if (end !== detail.content.bytes || createHash14("sha256").update(text2).digest("hex") !== detail.content.sha256)
11883
+ return;
11884
+ return { detail, bytes: text2 };
11885
+ } catch {
11886
+ budget.reserve(0);
11887
+ return;
11888
+ }
11889
+ }
11440
11890
  *parts(detail, snapshotSeq, budget, range2) {
11441
11891
  if (budget)
11442
11892
  this.files.assertReadFormat(budget);
@@ -11464,7 +11914,7 @@ class HistoryReader {
11464
11914
  if (!current2 || current2.length < expected.bytes || hash(current2.subarray(0, expected.bytes)) !== expected.identity)
11465
11915
  throw new ContractError("corrupt-selected");
11466
11916
  }
11467
- const checksum = createHash13("sha256");
11917
+ const checksum = createHash14("sha256");
11468
11918
  let bytes = 0;
11469
11919
  let cached;
11470
11920
  for (const e of locator.chunks) {
@@ -11738,7 +12188,7 @@ class HistoryReader {
11738
12188
  }
11739
12189
 
11740
12190
  // src/history/writer.ts
11741
- import { createHash as createHash15, randomUUID as randomUUID6 } from "node:crypto";
12191
+ import { createHash as createHash16, randomUUID as randomUUID6 } from "node:crypto";
11742
12192
  import { join as join8 } from "node:path";
11743
12193
 
11744
12194
  // src/worker-redaction.mjs
@@ -12100,11 +12550,11 @@ class DetailSanitizer {
12100
12550
  }
12101
12551
 
12102
12552
  // src/history/plans.ts
12103
- import { createHash as createHash14, randomUUID as randomUUID5 } from "node:crypto";
12553
+ import { createHash as createHash15, randomUUID as randomUUID5 } from "node:crypto";
12104
12554
  function assertPlanContent(plan, reference, secrets) {
12105
12555
  text(plan, 32768);
12106
12556
  const ref = decodeContentRef(reference);
12107
- if (ref.field !== "plan" || ref.bytes !== Buffer.byteLength(plan) || ref.sha256 !== createHash14("sha256").update(plan).digest("hex") || sanitizeText(plan, secrets) !== plan)
12557
+ if (ref.field !== "plan" || ref.bytes !== Buffer.byteLength(plan) || ref.sha256 !== createHash15("sha256").update(plan).digest("hex") || sanitizeText(plan, secrets) !== plan)
12108
12558
  throw new ContractError("invalid");
12109
12559
  }
12110
12560
  function proposePlanContent(plan, version, secrets) {
@@ -12114,7 +12564,7 @@ function proposePlanContent(plan, version, secrets) {
12114
12564
  version,
12115
12565
  field: "plan",
12116
12566
  bytes: Buffer.byteLength(plan),
12117
- sha256: createHash14("sha256").update(plan).digest("hex")
12567
+ sha256: createHash15("sha256").update(plan).digest("hex")
12118
12568
  });
12119
12569
  assertPlanContent(plan, reference, secrets);
12120
12570
  return reference;
@@ -12833,9 +13283,9 @@ class HistoryWriter {
12833
13283
  const continuation = jobs.every((j) => j.safety || j.continuation);
12834
13284
  try {
12835
13285
  this.assertWritable(safety, continuation);
12836
- for (const job of jobs) {
13286
+ for (const job2 of jobs) {
12837
13287
  const seq2 = String(BigInt(this.state.committedSeq) + BigInt(rows.length) + 1n);
12838
- const value = await job.build(seq2);
13288
+ const value = await job2.build(seq2);
12839
13289
  if (value) {
12840
13290
  const row = {
12841
13291
  kind: "record",
@@ -12844,7 +13294,7 @@ class HistoryWriter {
12844
13294
  value
12845
13295
  };
12846
13296
  rows.push(row);
12847
- ownRows.set(job, row);
13297
+ ownRows.set(job2, row);
12848
13298
  }
12849
13299
  }
12850
13300
  if (rows.length) {
@@ -12900,8 +13350,8 @@ class HistoryWriter {
12900
13350
  this.assertReviews(rows);
12901
13351
  }, preparedIndex?.root, (encodedBatch) => {
12902
13352
  let markerBytes = encodedBatch.trailerBytes, index = 0;
12903
- for (const [job, row] of ownRows) {
12904
- this.charge(encodedBatch.rowBytes[index++] + markerBytes, this.rowRunId(row.value), job.control);
13353
+ for (const [job2, row] of ownRows) {
13354
+ this.charge(encodedBatch.rowBytes[index++] + markerBytes, this.rowRunId(row.value), job2.control);
12905
13355
  markerBytes = 0;
12906
13356
  }
12907
13357
  }, () => this.assertReviews(rows));
@@ -12916,6 +13366,7 @@ class HistoryWriter {
12916
13366
  seq: this.state.committedSeq
12917
13367
  }, rows, (bytes) => this.charge(bytes, null, true), preparedIndex);
12918
13368
  } catch {}
13369
+ this.rememberTaskFolds(rows, preparedIndex);
12919
13370
  }
12920
13371
  const batch = {
12921
13372
  committedSeq: this.state.committedSeq,
@@ -13040,14 +13491,14 @@ class HistoryWriter {
13040
13491
  this.fence();
13041
13492
  result = failure(true);
13042
13493
  }
13043
- for (const job of jobs) {
13494
+ for (const job2 of jobs) {
13044
13495
  if (result.status !== "committed") {
13045
- job.resolve(result);
13496
+ job2.resolve(result);
13046
13497
  continue;
13047
13498
  }
13048
- const v = ownRows.get(job)?.value;
13499
+ const v = ownRows.get(job2)?.value;
13049
13500
  const ends = v?.kind === "capture" || v?.kind === "owner" ? v.events.flatMap((e) => e.kind === "end" ? [e.detail] : []) : [];
13050
- job.resolve({
13501
+ job2.resolve({
13051
13502
  status: "committed",
13052
13503
  batch: {
13053
13504
  ...result.batch,
@@ -13093,7 +13544,7 @@ class HistoryWriter {
13093
13544
  reservedIdentity(commandId) {
13094
13545
  decodeId(commandId);
13095
13546
  try {
13096
- const bytes = this.files.readCommand(commandId, new HistoryReadBudget);
13547
+ const bytes = this.files.readCommand(commandId, HistoryReadBudget.authority());
13097
13548
  return bytes ? decodeAdmissionIntent(json(bytes, RECORD_BYTES)).identity : null;
13098
13549
  } catch {
13099
13550
  return null;
@@ -13111,7 +13562,7 @@ class HistoryWriter {
13111
13562
  async lookupCommitted(commandId) {
13112
13563
  decodeId(commandId);
13113
13564
  try {
13114
- const budget = new HistoryReadBudget;
13565
+ const budget = HistoryReadBudget.authority();
13115
13566
  const intent = this.files.readCommand(commandId, budget);
13116
13567
  const directoryExists = this.files.files.directory(join8(this.files.directory, "commands", commandId));
13117
13568
  const wanted = intent ? decodeAdmissionIntent(json(intent, RECORD_BYTES)) : null;
@@ -13381,6 +13832,29 @@ class HistoryWriter {
13381
13832
  return this.ownerValue(input, null, selected2.plan);
13382
13833
  }, lease.budget.retainedBytes + lease.budget.outputBytes, true, () => begun ? lease.settled() : lease.release());
13383
13834
  }
13835
+ rememberTaskFolds(rows, prepared) {
13836
+ if (!prepared)
13837
+ return;
13838
+ const tasks = new Set;
13839
+ for (const { value: v } of rows)
13840
+ if (v.kind === "owner" && v.events.some((e) => e.kind === "owner" && e.value.kind === "fact" && e.value.fact.kind === "publication-settled"))
13841
+ tasks.add(v.link.taskId);
13842
+ for (const taskId of tasks) {
13843
+ const head = prepared.heads.get(taskId);
13844
+ if (!head || head.seq !== this.state.committedSeq)
13845
+ continue;
13846
+ try {
13847
+ const checks = checkFold(this.files, taskId, head.seq, HistoryReadBudget.authority()).state();
13848
+ const run = latestTaskRun(this.files, taskId, head.seq, HistoryReadBudget.authority());
13849
+ const plan = planFold(this.files, taskId, head.seq, HistoryReadBudget.authority(), new HistoryNavigation(this.files), true).state();
13850
+ taskFoldMemory(this.files).remember(taskId, head, {
13851
+ checks,
13852
+ run,
13853
+ plan
13854
+ });
13855
+ } catch {}
13856
+ }
13857
+ }
13384
13858
  async publishTask(request) {
13385
13859
  request = structuredClone(request);
13386
13860
  decodeId(request.operationId);
@@ -13572,7 +14046,7 @@ class HistoryWriter {
13572
14046
  }
13573
14047
  }
13574
14048
  retainedRun(runId) {
13575
- const budget = new HistoryReadBudget;
14049
+ const budget = HistoryReadBudget.authority();
13576
14050
  const snapshot = this.state.committedSeq;
13577
14051
  this.navigation.snapshot(snapshot, budget);
13578
14052
  const batches = this.navigation.runBatches(runId, snapshot, budget);
@@ -13585,7 +14059,7 @@ class HistoryWriter {
13585
14059
  return state;
13586
14060
  }
13587
14061
  prior(matches) {
13588
- for (const batch of this.files.scan(emptyScan(), false, new HistoryReadBudget)) {
14062
+ for (const batch of this.files.scan(emptyScan(), false, HistoryReadBudget.authority())) {
13589
14063
  if (batch.rows.some((row) => matches(row.value)))
13590
14064
  return true;
13591
14065
  }
@@ -13757,7 +14231,7 @@ class HistoryWriter {
13757
14231
  recordId: randomUUID6(),
13758
14232
  version: 1,
13759
14233
  bytes: 0,
13760
- hash: createHash15("sha256"),
14234
+ hash: createHash16("sha256"),
13761
14235
  parts: 0,
13762
14236
  ended: null,
13763
14237
  committedSeq: null
@@ -13949,7 +14423,7 @@ class HistoryWriter {
13949
14423
  assertReview(input, fact) {
13950
14424
  let accepted2 = null;
13951
14425
  let changes = null;
13952
- for (const batch of this.files.scan(emptyScan(), false, new HistoryReadBudget))
14426
+ for (const batch of this.files.scan(emptyScan(), false, HistoryReadBudget.authority()))
13953
14427
  for (const row of batch.rows) {
13954
14428
  const v = row.value;
13955
14429
  if (v.kind === "admission" && v.intent.operationId === input.link.operationId)
@@ -14106,7 +14580,7 @@ function readOperationStateForPublication(files, operationId) {
14106
14580
  let publication = null;
14107
14581
  const state = new OperationState(operationId);
14108
14582
  const facts = [];
14109
- for (const batch of files.scan(emptyScan(), false, new HistoryReadBudget))
14583
+ for (const batch of files.scan(emptyScan(), false, HistoryReadBudget.authority()))
14110
14584
  for (const row of batch.rows) {
14111
14585
  const v = row.value;
14112
14586
  if (v.kind === "recovery" && intent)
@@ -14133,10 +14607,10 @@ function readOperationStateForPublication(files, operationId) {
14133
14607
  }
14134
14608
 
14135
14609
  // src/service-assets.ts
14136
- import { createHash as createHash16 } from "node:crypto";
14610
+ import { createHash as createHash17 } from "node:crypto";
14137
14611
  import { lstatSync as lstatSync7, readdirSync as readdirSync2 } from "node:fs";
14138
14612
  import { join as join9 } from "node:path";
14139
- import { fileURLToPath } from "node:url";
14613
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
14140
14614
  var ASSET_MEMBER_BYTES = 16 * 1024 * 1024;
14141
14615
  var ASSET_TOTAL_BYTES = 64 * 1024 * 1024;
14142
14616
  var fixed = new Set([
@@ -14209,7 +14683,7 @@ function decodeAssetManifest(input) {
14209
14683
  if ([...fixed].some((name) => !names.has(name)) || assets.filter((a) => font.test(a.name)).length !== 60 || assets.some((a) => new Set(a.references).size !== a.references.length || a.references.some((r) => !names.has(r))))
14210
14684
  throw new Error("asset-closure-refused");
14211
14685
  const sourceHash = hash2(o.sourceHash), contractHash = hash2(o.contractHash), buildId = hash2(o.buildId);
14212
- if (buildId !== createHash16("sha256").update(JSON.stringify({ sourceHash, contractHash })).digest("hex"))
14686
+ if (buildId !== createHash17("sha256").update(JSON.stringify({ sourceHash, contractHash })).digest("hex"))
14213
14687
  throw new Error("asset-identity-refused");
14214
14688
  return { schema: o.schema, sourceHash, contractHash, buildId, assets };
14215
14689
  }
@@ -14224,7 +14698,7 @@ function incarnation2(st) {
14224
14698
  st.ctimeMs
14225
14699
  ].join(":");
14226
14700
  }
14227
- function loadWebAssets(directory = fileURLToPath(new URL("../web/dist/", import.meta.url))) {
14701
+ function loadWebAssets(directory = fileURLToPath2(new URL("../web/dist/", import.meta.url))) {
14228
14702
  if (!safeDirectory(directory) || !safeDirectory(join9(directory, "assets")))
14229
14703
  throw new Error("assets-unavailable");
14230
14704
  const observed = new Map;
@@ -14232,7 +14706,7 @@ function loadWebAssets(directory = fileURLToPath(new URL("../web/dist/", import.
14232
14706
  observed.set(path, incarnation2(lstatSync7(path)));
14233
14707
  const read2 = (path, limit) => {
14234
14708
  const before = incarnation2(lstatSync7(path));
14235
- const body = readBounded(path, limit);
14709
+ const body = readBounded(path, limit, true);
14236
14710
  if (!body || before !== incarnation2(lstatSync7(path)))
14237
14711
  throw new Error("asset-read-changed");
14238
14712
  observed.set(path, before);
@@ -14248,7 +14722,7 @@ function loadWebAssets(directory = fileURLToPath(new URL("../web/dist/", import.
14248
14722
  throw new Error("asset-members-refused");
14249
14723
  const assets = manifest.assets.map((a) => {
14250
14724
  const body = read2(join9(directory, a.name), a.bytes);
14251
- if (!body || body.length !== a.bytes || createHash16("sha256").update(body).digest("hex") !== a.sha256)
14725
+ if (!body || body.length !== a.bytes || createHash17("sha256").update(body).digest("hex") !== a.sha256)
14252
14726
  throw new Error("asset-body-refused");
14253
14727
  return {
14254
14728
  path: a.name === "index.html" ? "/app" : `/${a.name}`,
@@ -14261,13 +14735,13 @@ function loadWebAssets(directory = fileURLToPath(new URL("../web/dist/", import.
14261
14735
  return {
14262
14736
  manifest,
14263
14737
  assets,
14264
- identity: createHash16("sha256").update(bytes).digest("hex")
14738
+ identity: createHash17("sha256").update(bytes).digest("hex")
14265
14739
  };
14266
14740
  }
14267
14741
 
14268
14742
  // src/service/auth.ts
14269
14743
  import {
14270
- createHash as createHash17,
14744
+ createHash as createHash18,
14271
14745
  randomBytes as randomBytes3,
14272
14746
  randomUUID as randomUUID7,
14273
14747
  timingSafeEqual
@@ -14331,8 +14805,8 @@ function token(value) {
14331
14805
  return result;
14332
14806
  }
14333
14807
  function sameSecret(candidate, expected) {
14334
- const a = createHash17("sha256").update(candidate).digest();
14335
- const b = createHash17("sha256").update(expected).digest();
14808
+ const a = createHash18("sha256").update(candidate).digest();
14809
+ const b = createHash18("sha256").update(expected).digest();
14336
14810
  return timingSafeEqual(a, b);
14337
14811
  }
14338
14812
  function buildTokenCookie(name, encodedValue, maxAge, secure) {
@@ -14652,7 +15126,10 @@ function safeChildEnv() {
14652
15126
  "TMPDIR",
14653
15127
  "LANG",
14654
15128
  "LC_ALL",
14655
- "PATHEXT"
15129
+ "PATHEXT",
15130
+ "ProgramFiles",
15131
+ "ProgramFiles(x86)",
15132
+ "ProgramW6432"
14656
15133
  ])
14657
15134
  if (process.env[key2] !== undefined)
14658
15135
  env[key2] = process.env[key2];
@@ -15014,8 +15491,8 @@ class ServiceCoordination {
15014
15491
  }
15015
15492
  };
15016
15493
  }
15017
- assertNamespace() {
15018
- if (!this.files.directory(this.directory))
15494
+ assertNamespace(walks) {
15495
+ if (!this.files.directory(this.directory, false, walks))
15019
15496
  refused();
15020
15497
  names(this.directory, [
15021
15498
  "format.json",
@@ -15028,14 +15505,15 @@ class ServiceCoordination {
15028
15505
  "host-config.json",
15029
15506
  "history-v2"
15030
15507
  ]);
15031
- this.files.directory(join11(this.directory, "history-v2"));
15508
+ this.files.directory(join11(this.directory, "history-v2"), false, walks);
15032
15509
  }
15033
15510
  selected() {
15034
- if (!this.files.directory(this.directory))
15511
+ const walks = new DirectoryWalks;
15512
+ if (!this.files.directory(this.directory, false, walks))
15035
15513
  return;
15036
- this.assertNamespace();
15037
- const manifest = this.files.read(this.path("format.json"));
15038
- const config = this.files.read(this.path("config.json"));
15514
+ this.assertNamespace(walks);
15515
+ const manifest = this.files.read(this.path("format.json"), undefined, walks);
15516
+ const config = this.files.read(this.path("config.json"), undefined, walks);
15039
15517
  if (!manifest || !config)
15040
15518
  refused();
15041
15519
  const f = closed(json(manifest), [
@@ -15049,13 +15527,13 @@ class ServiceCoordination {
15049
15527
  literal(f.stateHome, this.stateHome);
15050
15528
  literal(f.configIdentity, config.identity);
15051
15529
  const c = decodeOwnerConfig(json(config));
15052
- const hostConfig = this.files.read(this.path("host-config.json"));
15530
+ const hostConfig = this.files.read(this.path("host-config.json"), undefined, walks);
15053
15531
  if (hostConfig && hostConfig.identity !== c.policyIdentity)
15054
15532
  refused();
15055
- const registration = this.files.read(this.path("registration.json"));
15056
- const owner = this.files.read(this.path("owner.lock"));
15057
- const capability = this.files.read(this.path("local-capability.json"));
15058
- const checkout = this.files.read(this.store.lockPath, 8192);
15533
+ const registration = this.files.read(this.path("registration.json"), undefined, walks);
15534
+ const owner = this.files.read(this.path("owner.lock"), undefined, walks);
15535
+ const capability = this.files.read(this.path("local-capability.json"), undefined, walks);
15536
+ const checkout = this.files.read(this.store.lockPath, 8192, walks);
15059
15537
  const value = registration ? decodeRegistration(json(registration)) : undefined;
15060
15538
  if (value && (value.root !== this.store.root || value.stateHome !== this.stateHome || value.configIdentity !== config.identity || !endpointMatches(c.endpoint, value.endpoint)))
15061
15539
  refused();
@@ -15402,8 +15880,8 @@ class OwnerLease {
15402
15880
  assert() {
15403
15881
  if (this.released || this.selected.value.pid !== process.pid || this.selected.value.host !== hostname2())
15404
15882
  throw new ContractError("conflict");
15405
- const c = this.coordination;
15406
- c.assertNamespace();
15883
+ const c = this.coordination, walks = new DirectoryWalks;
15884
+ c.assertNamespace(walks);
15407
15885
  for (const [name, snapshot] of [
15408
15886
  ["config.json", this.selected.config],
15409
15887
  ["host-config.json", this.selected.hostConfig],
@@ -15412,8 +15890,8 @@ class OwnerLease {
15412
15890
  ["owner.lock", this.selected.owner],
15413
15891
  ["local-capability.json", this.selected.capability]
15414
15892
  ])
15415
- c.files.assert(c.path(name), snapshot);
15416
- c.files.assert(c.store.lockPath, this.selected.checkout, 8192);
15893
+ c.files.assert(c.path(name), snapshot, undefined, walks);
15894
+ c.files.assert(c.store.lockPath, this.selected.checkout, 8192, walks);
15417
15895
  c.store.assertOwner(this.checkout);
15418
15896
  }
15419
15897
  phase(phase) {
@@ -15448,7 +15926,7 @@ class OwnerLease {
15448
15926
  }
15449
15927
 
15450
15928
  // src/service/http.ts
15451
- import { createHash as createHash18, randomUUID as randomUUID9 } from "node:crypto";
15929
+ import { createHash as createHash19, randomUUID as randomUUID9 } from "node:crypto";
15452
15930
  import {
15453
15931
  createServer
15454
15932
  } from "node:http";
@@ -15732,7 +16210,7 @@ class ServiceHttpServer {
15732
16210
  this.assets.set(asset.path, {
15733
16211
  ...asset,
15734
16212
  bytes: Uint8Array.from(asset.bytes),
15735
- etag: `"${createHash18("sha256").update(asset.bytes).digest("hex")}"`
16213
+ etag: `"${createHash19("sha256").update(asset.bytes).digest("hex")}"`
15736
16214
  });
15737
16215
  }
15738
16216
  this.server = createServer({
@@ -16241,7 +16719,7 @@ Content-Length: 0\r
16241
16719
  res.setHeader("Content-Type", operation === "download" && request.format === "markdown" ? "text/markdown; charset=utf-8" : "application/x-ndjson; charset=utf-8");
16242
16720
  res.setHeader("Content-Disposition", `attachment; filename="cadence-export.${operation === "download" && request.format === "markdown" ? "md" : "ndjson"}"`);
16243
16721
  let trailer;
16244
- const digest = createHash18("sha256");
16722
+ const digest = createHash19("sha256");
16245
16723
  const write = async (frame) => {
16246
16724
  const data = Buffer.from(operation === "download" ? encodeExportFrame(frame, request.format) : `${canonicalJson(frame)}
16247
16725
  `);
@@ -16552,9 +17030,6 @@ class OwnerModelChoice {
16552
17030
  }
16553
17031
  }
16554
17032
 
16555
- // src/service/model-context.ts
16556
- import { randomUUID as randomUUID11 } from "node:crypto";
16557
-
16558
17033
  // src/service/model-config.ts
16559
17034
  import { lstatSync as lstatSync8, realpathSync as realpathSync4 } from "node:fs";
16560
17035
  import { dirname as dirname9, isAbsolute as isAbsolute6, join as join12, resolve as resolve3 } from "node:path";
@@ -16723,7 +17198,8 @@ function compat(value) {
16723
17198
  "forceAdaptiveThinking",
16724
17199
  "allowEmptySignature",
16725
17200
  "supportsStrictTools",
16726
- "supportsToolReferences"
17201
+ "supportsToolReferences",
17202
+ "supportsMidConvoSystemMessages"
16727
17203
  ];
16728
17204
  const enums = {
16729
17205
  maxTokensField: ["max_completion_tokens", "max_tokens"],
@@ -16921,6 +17397,11 @@ function modelJson(snapshot) {
16921
17397
  return parseWireJson(normalized, CONFIG_BYTES);
16922
17398
  }
16923
17399
  function readPiSnapshot(source) {
17400
+ const { auth, credentials } = readPiAuth(source);
17401
+ const { models, providers } = readPiModels(source);
17402
+ return { auth, models, credentials, providers };
17403
+ }
17404
+ function readPiAuth(source) {
16924
17405
  const auth = source.files.read(source.authPath, CONFIG_BYTES);
16925
17406
  if (!auth)
16926
17407
  refuse2();
@@ -16944,6 +17425,9 @@ function readPiSnapshot(source) {
16944
17425
  refuse2();
16945
17426
  credentials[provider] = credential;
16946
17427
  }
17428
+ return { auth, credentials };
17429
+ }
17430
+ function readPiModels(source) {
16947
17431
  const models = source.files.read(source.modelsPath, CONFIG_BYTES);
16948
17432
  const providers = Object.create(null);
16949
17433
  if (models) {
@@ -16987,7 +17471,7 @@ function readPiSnapshot(source) {
16987
17471
  providers[id] = provider;
16988
17472
  }
16989
17473
  }
16990
- return { auth, models, credentials, providers };
17474
+ return { models, providers };
16991
17475
  }
16992
17476
  function sourceIdentity(snapshot, provider) {
16993
17477
  const credential = snapshot.credentials[provider];
@@ -17074,6 +17558,7 @@ function clonePrivate(value) {
17074
17558
  }
17075
17559
 
17076
17560
  // src/service/model-context.ts
17561
+ import { randomUUID as randomUUID11 } from "node:crypto";
17077
17562
  function committed(result) {
17078
17563
  if (result.status !== "committed")
17079
17564
  throw new ContractError("recording-exhausted");
@@ -18117,6 +18602,28 @@ function decodeHostInput(value) {
18117
18602
  environmentToken
18118
18603
  };
18119
18604
  }
18605
+ class StartupRefusal extends ContractError {
18606
+ stage;
18607
+ quarantined;
18608
+ constructor(code, stage, quarantined = false) {
18609
+ super(code);
18610
+ this.stage = stage;
18611
+ this.quarantined = quarantined;
18612
+ }
18613
+ }
18614
+ function startupReport(error) {
18615
+ if (error instanceof StartupRefusal)
18616
+ return {
18617
+ status: error.quarantined ? "quarantined" : "refused",
18618
+ error: error.code,
18619
+ stage: error.stage
18620
+ };
18621
+ return {
18622
+ status: "refused",
18623
+ error: error instanceof ContractError ? error.code : "unavailable",
18624
+ stage: "service"
18625
+ };
18626
+ }
18120
18627
 
18121
18628
  // src/service/task-actions.ts
18122
18629
  import { randomUUID as randomUUID15 } from "node:crypto";
@@ -18124,13 +18631,13 @@ import { realpathSync as realpathSync5 } from "node:fs";
18124
18631
 
18125
18632
  // src/task-diff.ts
18126
18633
  import { spawnSync as spawnSync2 } from "node:child_process";
18127
- import { createHash as createHash19 } from "node:crypto";
18634
+ import { createHash as createHash20 } from "node:crypto";
18128
18635
  import { lstatSync as lstatSync9, readdirSync as readdirSync3, readlinkSync } from "node:fs";
18129
18636
  import { join as join14, relative as relative5 } from "node:path";
18130
18637
  var admin = (path) => path === ".cadence/assistant/tasks" || path.startsWith(".cadence/assistant/tasks/");
18131
18638
  function captureChanges(root) {
18132
18639
  const deadline = Date.now() + 3000;
18133
- const hash3 = createHash19("sha256");
18640
+ const hash3 = createHash20("sha256");
18134
18641
  const parts = [];
18135
18642
  let complete = true;
18136
18643
  const limits = [];
@@ -18187,7 +18694,7 @@ function captureChanges(root) {
18187
18694
  fileBytes += data2.length;
18188
18695
  add(name, data2);
18189
18696
  const binary = data2.includes(0);
18190
- parts.push(`${name} (${binary ? "binary" : "text"}, ${data2.length} bytes, sha256 ${createHash19("sha256").update(data2).digest("hex")})`);
18697
+ parts.push(`${name} (${binary ? "binary" : "text"}, ${data2.length} bytes, sha256 ${createHash20("sha256").update(data2).digest("hex")})`);
18191
18698
  } catch {
18192
18699
  complete = false;
18193
18700
  limits.push(`Unreadable/changing: ${name}`);
@@ -18867,33 +19374,6 @@ class ActionAdmission {
18867
19374
  // src/service/graph.ts
18868
19375
  import { createHash as createHash21 } from "node:crypto";
18869
19376
  import { join as join15 } from "node:path";
18870
-
18871
- // src/agent-registry.ts
18872
- import { createHash as createHash20 } from "node:crypto";
18873
- import { fileURLToPath as fileURLToPath2 } from "node:url";
18874
- var AGENT_FILES = [
18875
- "design-explorer.md",
18876
- "implementation-worker.md",
18877
- "diagnosis-worker.md"
18878
- ];
18879
- function loadAgentDefinitions() {
18880
- return AGENT_FILES.map((fileName) => {
18881
- const path = fileURLToPath2(new URL(`../agents/${fileName}`, import.meta.url));
18882
- const data2 = readBounded(path, 32768);
18883
- if (!data2)
18884
- throw new Error("Missing package Agent");
18885
- return {
18886
- role: fileName.replace(/\.md$/, ""),
18887
- fileName,
18888
- path,
18889
- sha256: createHash20("sha256").update(data2).digest("hex"),
18890
- bytes: data2.length,
18891
- content: data2.toString("utf8")
18892
- };
18893
- });
18894
- }
18895
-
18896
- // src/service/graph.ts
18897
19377
  var hash3 = (text2) => createHash21("sha256").update(text2).digest("hex");
18898
19378
 
18899
19379
  class GraphContext {
@@ -19040,6 +19520,7 @@ import { randomUUID as randomUUID14 } from "node:crypto";
19040
19520
 
19041
19521
  // src/subagent-process.ts
19042
19522
  import { spawn } from "node:child_process";
19523
+ import { join as join16 } from "node:path";
19043
19524
  import { StringDecoder } from "node:string_decoder";
19044
19525
  import { fileURLToPath as fileURLToPath3 } from "node:url";
19045
19526
  // src/worker-capture.mjs
@@ -19622,6 +20103,15 @@ class WorkerRecording {
19622
20103
  }
19623
20104
 
19624
20105
  // src/subagent-process.ts
20106
+ function terminateWindowsTree(pid, fallback) {
20107
+ const root = process.env.SystemRoot;
20108
+ const taskkill = spawn(root ? join16(root, "System32", "taskkill.exe") : "taskkill.exe", ["/F", "/T", "/PID", String(pid)], { stdio: "ignore", windowsHide: true });
20109
+ taskkill.once("error", fallback);
20110
+ taskkill.once("close", (code) => {
20111
+ if (code !== 0)
20112
+ fallback();
20113
+ });
20114
+ }
19625
20115
  function runProcess(spec) {
19626
20116
  const started = Date.now();
19627
20117
  const early = (outcome, text2) => ({
@@ -19739,6 +20229,8 @@ function runProcess(spec) {
19739
20229
  return;
19740
20230
  if (process.platform !== "win32" && child.pid)
19741
20231
  process.kill(-child.pid, signal);
20232
+ else if (child.pid && child.exitCode === null && child.signalCode === null)
20233
+ terminateWindowsTree(child.pid, () => child.kill(signal));
19742
20234
  else
19743
20235
  child.kill(signal);
19744
20236
  } catch {}
@@ -20706,8 +21198,8 @@ class TaskScheduler {
20706
21198
  this.pumping = false;
20707
21199
  }
20708
21200
  }
20709
- current(e, n) {
20710
- return !this.closed && !e.reason && !n.abort.signal.aborted && this.options.owner.state === "idle" && this.owned() && e.input.current() && e.input.sources.current() && canonicalJson(e.input.observe(false).observation) === canonicalJson(e.expectedObservation);
21201
+ current(e, n, changes = false) {
21202
+ return !this.closed && !e.reason && !n.abort.signal.aborted && this.options.owner.state === "idle" && this.owned() && e.input.current() && e.input.sources.current() && (!changes || canonicalJson(e.input.observe(false).observation) === canonicalJson(e.expectedObservation));
20711
21203
  }
20712
21204
  async execute(e, n) {
20713
21205
  if (!n.assignment || !n.result || e.input.kind === "check")
@@ -20734,7 +21226,7 @@ class TaskScheduler {
20734
21226
  reservationId: n.childRunId,
20735
21227
  lane,
20736
21228
  state: "held",
20737
- checkoutGeneration: e.input.observe(false).observation.checkoutGeneration
21229
+ checkoutGeneration: e.input.generation()
20738
21230
  });
20739
21231
  held = true;
20740
21232
  if (!this.current(e, n)) {
@@ -20744,7 +21236,7 @@ class TaskScheduler {
20744
21236
  const observed = e.input.observe(false), before = observed.observation;
20745
21237
  const baseline = await this.changes(e, "before", observed);
20746
21238
  e.baseline ??= baseline;
20747
- if (!this.current(e, n)) {
21239
+ if (!this.current(e, n) || canonicalJson(before) !== canonicalJson(e.expectedObservation)) {
20748
21240
  await this.close(e, e.reason ?? "stale-dependency");
20749
21241
  return;
20750
21242
  }
@@ -20790,7 +21282,7 @@ class TaskScheduler {
20790
21282
  });
20791
21283
  originalAuth = auth.settled;
20792
21284
  const prepared = await auth.result;
20793
- if (prepared.status !== "prepared" || !this.current(e, n)) {
21285
+ if (prepared.status !== "prepared" || !this.current(e, n, true)) {
20794
21286
  await this.close(e, e.reason ?? "failed");
20795
21287
  await this.fact(e, {
20796
21288
  kind: "assignment-state",
@@ -20860,7 +21352,7 @@ class TaskScheduler {
20860
21352
  reservationId: n.childRunId,
20861
21353
  lane,
20862
21354
  state: "released",
20863
- checkoutGeneration: e.input.observe(false).observation.checkoutGeneration
21355
+ checkoutGeneration: e.input.generation()
20864
21356
  });
20865
21357
  this.holders.delete(n.childRunId);
20866
21358
  n.state = "done";
@@ -20908,7 +21400,7 @@ class TaskScheduler {
20908
21400
  if (this.current(e, n) && input.definitionCurrent()) {
20909
21401
  const output = recording;
20910
21402
  const original = Promise.resolve().then(async () => {
20911
- if (!this.current(e, n) || !input.definitionCurrent())
21403
+ if (!this.current(e, n, true) || !input.definitionCurrent())
20912
21404
  return native;
20913
21405
  await runCheck(input.check, input.cwd, n.abort.signal, {
20914
21406
  environment: input.environment,
@@ -20940,7 +21432,7 @@ class TaskScheduler {
20940
21432
  }
20941
21433
  };
20942
21434
  const observed = input.observe(false).observation;
20943
- const after = held ? input.observe(true).observation : observed;
21435
+ const after = held ? { ...observed, checkoutGeneration: input.advance() } : observed;
20944
21436
  const ownAdvance = held && observed.checkoutGeneration === before.checkoutGeneration ? {
20945
21437
  operationId: e.link.operationId,
20946
21438
  reservationId: checkId,
@@ -21107,6 +21599,14 @@ class TaskScheduler {
21107
21599
 
21108
21600
  // src/service/task-actions.ts
21109
21601
  var actionOwners = new WeakSet;
21602
+ function snapshotReads() {
21603
+ const kept = new Map;
21604
+ return (key2, read2) => {
21605
+ if (!kept.has(key2))
21606
+ kept.set(key2, read2());
21607
+ return kept.get(key2);
21608
+ };
21609
+ }
21110
21610
 
21111
21611
  class TaskActions {
21112
21612
  options;
@@ -21586,14 +22086,16 @@ class TaskActions {
21586
22086
  assertCurrent();
21587
22087
  return checks;
21588
22088
  }
21589
- obligations(version, snapshot) {
22089
+ obligations(version, snapshot, reads) {
21590
22090
  if (!version.task)
21591
22091
  throw new ContractError("stale");
21592
- return this.obligationsFor(version.task.id, version.task.kind, { status: "available", version }, snapshot);
22092
+ return this.obligationsFor(version.task.id, version.task.kind, { status: "available", version }, snapshot, reads);
21593
22093
  }
21594
- obligationsFor(taskId, kind, context, snapshot) {
22094
+ obligationsFor(taskId, kind, context, snapshot, reads) {
21595
22095
  const configured = this.checks(taskId);
21596
- const state = currentChecks(this.options.host.reader.files, taskId, kind === "code" ? configured : { revision: configured.revision, selections: [] }, context, snapshot);
22096
+ const selections = kind === "code" ? configured : { revision: configured.revision, selections: [] };
22097
+ const fold = () => currentChecks(this.options.host.reader.files, taskId, selections, context, snapshot);
22098
+ const state = reads ? reads(`checks:${canonicalJson({ taskId, selections, context, snapshot })}`, fold) : fold();
21597
22099
  if (canonicalJson(configured) !== canonicalJson(this.checks(taskId)))
21598
22100
  throw new ContractError("stale");
21599
22101
  if (context.status !== "available")
@@ -21805,6 +22307,8 @@ class TaskActions {
21805
22307
  return false;
21806
22308
  }
21807
22309
  },
22310
+ generation: () => this.generation,
22311
+ advance: () => ++this.generation,
21808
22312
  observe: (advance) => {
21809
22313
  if (advance)
21810
22314
  this.generation++;
@@ -21831,13 +22335,14 @@ class TaskActions {
21831
22335
  });
21832
22336
  accepted2.activate(work);
21833
22337
  }
21834
- reviewObservation(runId, version, snapshot = this.options.host.writer.committedSeq) {
22338
+ reviewObservation(runId, version, snapshot = this.options.host.writer.committedSeq, reads) {
21835
22339
  if (!version.task)
21836
22340
  throw new ContractError("stale");
21837
22341
  const h = this.options.host, taskId = version.task.id;
21838
- const selection = h.reader.reviewSelection(taskId, runId, snapshot);
22342
+ const select = () => h.reader.reviewSelection(taskId, runId, snapshot);
22343
+ const selection = reads ? reads(`selection:${taskId}:${runId}:${snapshot}`, select) : select();
21839
22344
  const { run } = selection;
21840
- const state = this.obligations(version, snapshot);
22345
+ const state = this.obligations(version, snapshot, reads);
21841
22346
  const current2 = {
21842
22347
  ...state,
21843
22348
  checks: state.checks,
@@ -21869,6 +22374,7 @@ class TaskActions {
21869
22374
  const currentGraph = graph?.graph ?? (this.options.choice ? this.defaultGraph(selected2.record, selected2.identity, expected.model) : null);
21870
22375
  if ((currentGraph ? hash(canonicalJson(currentGraph)) : null) !== task.graphIdentity || (currentGraph?.revision ?? null) !== task.graphRevision)
21871
22376
  throw new ContractError("stale");
22377
+ const reads = snapshotReads();
21872
22378
  const validate = (published) => {
21873
22379
  this.assertChoice(expected);
21874
22380
  held.assertHeld();
@@ -21878,14 +22384,14 @@ class TaskActions {
21878
22384
  const changes2 = captureChanges(h.coordination.store.root);
21879
22385
  if (changes2.fingerprint !== expected.observation.identity || changes2.complete !== expected.observation.complete)
21880
22386
  throw new ContractError("stale");
21881
- const proven = h.reader.publishedPlan(task.id, snapshot, {
22387
+ const proven = reads(`plan:${task.id}:${snapshot}`, () => h.reader.publishedPlan(task.id, snapshot, {
21882
22388
  revision: selected2.record.revision,
21883
22389
  identity: selected2.identity,
21884
22390
  plan: selected2.record.plan
21885
- });
22391
+ }));
21886
22392
  if ((proven?.reference.sha256 ?? (currentGraph ? hash(canonicalJson(currentGraph)) : null)) !== task.graphIdentity)
21887
22393
  throw new ContractError("stale");
21888
- const current3 = this.reviewObservation(action.runId, expected, snapshot);
22394
+ const current3 = this.reviewObservation(action.runId, expected, snapshot, reads);
21889
22395
  if (current3.checks.revision !== action.checksRevision || current3.issues.length && !action.acceptIssues)
21890
22396
  throw new ContractError("stale");
21891
22397
  return current3;
@@ -22077,7 +22583,7 @@ function legacy(store, budget, reader) {
22077
22583
  decodeId(entry.name);
22078
22584
  if (created.has(entry.name))
22079
22585
  continue;
22080
- const path = join16(store.tasks, entry.name, "task.json");
22586
+ const path = join17(store.tasks, entry.name, "task.json");
22081
22587
  const size = lstatSync10(path).size;
22082
22588
  if (size > 128 * 1024)
22083
22589
  throw new ContractError("corrupt-selected");
@@ -22092,12 +22598,23 @@ function legacy(store, budget, reader) {
22092
22598
  }
22093
22599
  return records;
22094
22600
  }
22601
+ function refuseAt(stage, step) {
22602
+ try {
22603
+ return step();
22604
+ } catch (error2) {
22605
+ throw new StartupRefusal(error2 instanceof ContractError ? error2.code : "unavailable", stage);
22606
+ }
22607
+ }
22095
22608
  async function createServiceHost(value, sourceBuild) {
22096
22609
  const embedded = "e7e5248f8273a373827ac70d2d8be1d5aaea1e329379e59e4947fc10f82be818";
22097
22610
  if (embedded && sourceBuild)
22098
22611
  throw new ContractError("unsupported-context");
22099
22612
  const contractHash = decodeHash(embedded ?? sourceBuild?.contractHash);
22100
- const web = loadWebAssets(sourceBuild?.webDirectory);
22613
+ const web = refuseAt("package", () => {
22614
+ if (!sourceBuild?.deferActions)
22615
+ loadAgentDefinitions();
22616
+ return loadWebAssets(sourceBuild?.webDirectory);
22617
+ });
22101
22618
  const build2 = {
22102
22619
  contractHash,
22103
22620
  assets: {
@@ -22124,12 +22641,17 @@ async function createServiceHost(value, sourceBuild) {
22124
22641
  throw new ContractError("corrupt-selected");
22125
22642
  history.assertWritable();
22126
22643
  }
22644
+ const home = launch.HOME ?? launch.USERPROFILE ?? input.config.agentDir;
22645
+ const pi = refuseAt("pi-agent-directory", () => piSource(input.config.agentDir, home, input.config.cwd, launch));
22646
+ refuseAt("pi-auth", () => readPiAuth(pi));
22647
+ refuseAt("pi-models", () => readPiModels(pi));
22127
22648
  const http = new ServiceHttpServer({
22128
22649
  policy: input.config.http,
22129
22650
  assets: web.assets
22130
22651
  });
22131
22652
  const endpoint2 = await http.listen();
22132
22653
  let owner;
22654
+ let stage = "service";
22133
22655
  try {
22134
22656
  const resolved = {
22135
22657
  ...input.config,
@@ -22179,7 +22701,7 @@ async function createServiceHost(value, sourceBuild) {
22179
22701
  owner,
22180
22702
  accounting: writer.auth,
22181
22703
  network,
22182
- home: launch.HOME ?? launch.USERPROFILE ?? input.config.agentDir,
22704
+ home,
22183
22705
  agentDir: input.config.agentDir,
22184
22706
  cwd: input.config.cwd,
22185
22707
  environment: launch
@@ -22320,9 +22842,11 @@ async function createServiceHost(value, sourceBuild) {
22320
22842
  owner.quarantine();
22321
22843
  throw new ContractError("quarantine");
22322
22844
  }
22845
+ stage = "pi-runtime";
22323
22846
  const loading = models.load();
22324
22847
  owner.trackAuth(loading);
22325
22848
  await loading;
22849
+ stage = "service";
22326
22850
  lease.assert();
22327
22851
  if (owner.state !== "idle")
22328
22852
  throw new ContractError("quarantine");
@@ -22353,7 +22877,7 @@ async function createServiceHost(value, sourceBuild) {
22353
22877
  } catch {}
22354
22878
  } else
22355
22879
  await http.close();
22356
- throw new ContractError(error2 instanceof ContractError ? error2.code : "unavailable");
22880
+ throw new StartupRefusal(error2 instanceof ContractError ? error2.code : "unavailable", stage, !!owner);
22357
22881
  }
22358
22882
  }
22359
22883
 
@@ -22375,7 +22899,9 @@ try {
22375
22899
  const host = await createServiceHost(input);
22376
22900
  process.stdout.write(`${JSON.stringify({ status: "ready", epoch: host.owner.lease.registration.epoch })}
22377
22901
  `);
22378
- } catch {
22902
+ } catch (error2) {
22903
+ process.stdout.write(`${JSON.stringify(startupReport(error2))}
22904
+ `);
22379
22905
  process.stderr.write(`{"error":"service-host-refused"}
22380
22906
  `);
22381
22907
  process.exitCode = 1;