@brainervirus/workit-codex 8.13.0 → 8.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6622,13 +6622,13 @@ var require_dist = __commonJS(function(exports, module) {
6622
6622
 
6623
6623
  // packages/workit-codex/scripts/launch-mcp.ts
6624
6624
  import { existsSync as existsSync10, realpathSync as realpathSync7, statSync as statSync3 } from "node:fs";
6625
- import path22 from "node:path";
6625
+ import path24 from "node:path";
6626
6626
  import { fileURLToPath as fileURLToPath3 } from "node:url";
6627
6627
 
6628
6628
  // packages/workit-core/src/core.ts
6629
6629
  import { spawnSync as spawnSync14 } from "node:child_process";
6630
6630
  import { existsSync as existsSync7, realpathSync as realpathSync5 } from "node:fs";
6631
- import path19 from "node:path";
6631
+ import path21 from "node:path";
6632
6632
 
6633
6633
  // packages/workit-core/src/core/task-contract.ts
6634
6634
  import { createHash, randomUUID } from "node:crypto";
@@ -15456,9 +15456,9 @@ function parseAdvertisedOperation(family, input, host) {
15456
15456
  });
15457
15457
  }
15458
15458
  // packages/workit-core/src/core/task-store.ts
15459
- import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
15460
- import * as fs7 from "node:fs";
15461
- import path6 from "node:path";
15459
+ import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
15460
+ import * as fs8 from "node:fs";
15461
+ import path8 from "node:path";
15462
15462
 
15463
15463
  // node_modules/@openclaw/fs-safe/dist/errors.js
15464
15464
  var OPERATIONAL_CODES = new Set([
@@ -16061,8 +16061,14 @@ function acquireFileLockSync(targetPath, options) {
16061
16061
  }
16062
16062
  }
16063
16063
  }
16064
+ // packages/workit-core/src/host-session.ts
16065
+ import { createHash as createHash3, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
16066
+ import fs5 from "node:fs";
16067
+ import path5 from "node:path";
16068
+
16064
16069
  // packages/workit-core/src/core/logger.ts
16065
16070
  import os from "node:os";
16071
+ import path3 from "node:path";
16066
16072
  var REDACTED = "[REDACTED]";
16067
16073
  var SECRET_VALUE = /\b(?:Bearer|Basic|Digest|Token)\s+\S+/gi;
16068
16074
  var KEY_EQ_VALUE = /\b([A-Za-z0-9_-]*(?:token|secret|password|passwd|apikey|api[_-]?key|authorization|credential|bearer)[A-Za-z0-9_-]*)([:=]\s*).+/gi;
@@ -16105,6 +16111,22 @@ var SENSITIVE_WORDS = new Set([
16105
16111
  ]);
16106
16112
  var STACK_WORDS = new Set(["stack", "stacktrace", "trace"]);
16107
16113
  var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
16114
+ var resolveStateDir = () => {
16115
+ const override = process.env.WORKFLOW_TOOLKIT_STATE;
16116
+ if (override)
16117
+ return override;
16118
+ const home = os.homedir();
16119
+ if (process.env.XDG_STATE_HOME)
16120
+ return path3.join(process.env.XDG_STATE_HOME, "workit");
16121
+ switch (os.platform()) {
16122
+ case "darwin":
16123
+ return path3.join(home, "Library", "Application Support", "workit");
16124
+ case "win32":
16125
+ return path3.join(process.env.LOCALAPPDATA ?? path3.join(home, "AppData", "Local"), "workit");
16126
+ default:
16127
+ return path3.join(process.env.HOME ?? home, ".local", "state", "workit");
16128
+ }
16129
+ };
16108
16130
  var homePattern = new RegExp(`${escapeRegExp(os.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
16109
16131
  var applyPatterns = (value) => {
16110
16132
  let out = value;
@@ -16122,7 +16144,7 @@ var redactSecrets = (value) => applyPatterns(value);
16122
16144
  import { spawnSync } from "node:child_process";
16123
16145
  import { createHash as createHash2 } from "node:crypto";
16124
16146
  import fs4 from "node:fs";
16125
- import path3 from "node:path";
16147
+ import path4 from "node:path";
16126
16148
  var NOT_A_REPO = /not a git repository \(or any (of the parent directories|parent up to)/u;
16127
16149
  var gitRun = (cwd, args) => {
16128
16150
  const run = spawnSync("git", args, {
@@ -16164,14 +16186,14 @@ var DISCOVERY_ENV = [
16164
16186
  ];
16165
16187
  var isGitDir = (dir) => {
16166
16188
  try {
16167
- return fs4.statSync(path3.join(dir, "HEAD")).isFile() && fs4.statSync(path3.join(dir, "objects")).isDirectory() && fs4.statSync(path3.join(dir, "refs")).isDirectory();
16189
+ return fs4.statSync(path4.join(dir, "HEAD")).isFile() && fs4.statSync(path4.join(dir, "objects")).isDirectory() && fs4.statSync(path4.join(dir, "refs")).isDirectory();
16168
16190
  } catch {
16169
16191
  return false;
16170
16192
  }
16171
16193
  };
16172
16194
  var reftableRefs = (common) => {
16173
16195
  try {
16174
- return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs4.readFileSync(path3.join(common, "config"), "utf8"));
16196
+ return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs4.readFileSync(path4.join(common, "config"), "utf8"));
16175
16197
  } catch {
16176
16198
  return false;
16177
16199
  }
@@ -16191,7 +16213,7 @@ function fastGit(root) {
16191
16213
  if (device !== null && stat.dev !== device)
16192
16214
  return { kind: "none" };
16193
16215
  device = stat.dev;
16194
- const dotGit = path3.join(dir, ".git");
16216
+ const dotGit = path4.join(dir, ".git");
16195
16217
  let entry = null;
16196
16218
  try {
16197
16219
  entry = fs4.statSync(dotGit);
@@ -16212,19 +16234,19 @@ function fastGit(root) {
16212
16234
  const match = /^gitdir: (.+)$/mu.exec(text);
16213
16235
  if (!match)
16214
16236
  return null;
16215
- gitDir = path3.resolve(dir, match[1].trim());
16237
+ gitDir = path4.resolve(dir, match[1].trim());
16216
16238
  } else
16217
16239
  return null;
16218
- if (!fs4.existsSync(path3.join(gitDir, "HEAD")))
16240
+ if (!fs4.existsSync(path4.join(gitDir, "HEAD")))
16219
16241
  return null;
16220
16242
  } else if (isGitDir(dir))
16221
16243
  gitDir = dir;
16222
16244
  if (gitDir) {
16223
16245
  let common = gitDir;
16224
16246
  try {
16225
- common = path3.resolve(gitDir, fs4.readFileSync(path3.join(gitDir, "commondir"), "utf8").trim());
16247
+ common = path4.resolve(gitDir, fs4.readFileSync(path4.join(gitDir, "commondir"), "utf8").trim());
16226
16248
  } catch {}
16227
- if (!fs4.existsSync(path3.join(common, "objects")))
16249
+ if (!fs4.existsSync(path4.join(common, "objects")))
16228
16250
  return null;
16229
16251
  return {
16230
16252
  kind: "repo",
@@ -16234,26 +16256,26 @@ function fastGit(root) {
16234
16256
  reftable: reftableRefs(common)
16235
16257
  };
16236
16258
  }
16237
- const parent = path3.dirname(dir);
16259
+ const parent = path4.dirname(dir);
16238
16260
  if (parent === dir)
16239
16261
  return { kind: "none" };
16240
16262
  dir = parent;
16241
16263
  }
16242
16264
  }
16243
16265
  function resolveStore(root) {
16244
- root = path3.resolve(root);
16266
+ root = path4.resolve(root);
16245
16267
  let directory = false;
16246
16268
  try {
16247
16269
  directory = fs4.statSync(root).isDirectory();
16248
16270
  } catch {}
16249
16271
  if (!directory)
16250
- return { dir: path3.join(root, ".workit"), shared: false, top: null };
16272
+ return { dir: path4.join(root, ".workit"), shared: false, top: null };
16251
16273
  const fast = fastGit(root);
16252
16274
  if (fast?.kind === "none")
16253
- return { dir: path3.join(root, ".workit"), shared: false, top: null };
16275
+ return { dir: path4.join(root, ".workit"), shared: false, top: null };
16254
16276
  if (fast?.kind === "repo")
16255
16277
  return {
16256
- dir: path3.join(fast.common, "workit"),
16278
+ dir: path4.join(fast.common, "workit"),
16257
16279
  shared: true,
16258
16280
  top: fast.top,
16259
16281
  git: { gitDir: fast.gitDir, top: fast.top, reftable: fast.reftable }
@@ -16263,20 +16285,20 @@ function resolveStore(root) {
16263
16285
  if (run.ok && common) {
16264
16286
  const top = gitRun(root, ["rev-parse", "--path-format=absolute", "--show-toplevel"]);
16265
16287
  return {
16266
- dir: path3.join(real(path3.resolve(root, common)), "workit"),
16288
+ dir: path4.join(real(path4.resolve(root, common)), "workit"),
16267
16289
  shared: true,
16268
16290
  top: top.ok && top.stdout.trim() ? real(top.stdout.trim()) : null
16269
16291
  };
16270
16292
  }
16271
16293
  if (run.missing || !run.ok && NOT_A_REPO.test(run.stderr))
16272
- return { dir: path3.join(root, ".workit"), shared: false, top: null };
16294
+ return { dir: path4.join(root, ".workit"), shared: false, top: null };
16273
16295
  return new Error(`cannot locate the workit store: git rev-parse failed (${run.stderr.trim().split(`
16274
16296
  `)[0] || "no output"}); fix the repository (git status should work here)`);
16275
16297
  }
16276
16298
  var rebasingBranch = (gitDir) => {
16277
16299
  for (const state of ["rebase-merge", "rebase-apply"]) {
16278
16300
  try {
16279
- const ref = fs4.readFileSync(path3.join(gitDir, state, "head-name"), "utf8").trim();
16301
+ const ref = fs4.readFileSync(path4.join(gitDir, state, "head-name"), "utf8").trim();
16280
16302
  const match = /^refs\/heads\/(.+)$/u.exec(ref);
16281
16303
  if (match)
16282
16304
  return match[1];
@@ -16291,7 +16313,7 @@ function resolveTaskKey(root, location) {
16291
16313
  if (location.git && !location.git.reftable) {
16292
16314
  let head = "";
16293
16315
  try {
16294
- head = fs4.readFileSync(path3.join(location.git.gitDir, "HEAD"), "utf8").trim();
16316
+ head = fs4.readFileSync(path4.join(location.git.gitDir, "HEAD"), "utf8").trim();
16295
16317
  } catch {}
16296
16318
  const ref = /^ref: refs\/heads\/(.+)$/u.exec(head);
16297
16319
  if (ref && ref[1] !== ".invalid")
@@ -16322,7 +16344,7 @@ function resolveTaskKey(root, location) {
16322
16344
  return { key: `detached-${shortHash(real(worktree))}`, kind: "detached", branch: null };
16323
16345
  }
16324
16346
  function checkoutRootOf(root, location) {
16325
- const resolved = path3.resolve(root);
16347
+ const resolved = path4.resolve(root);
16326
16348
  let canonical = resolved;
16327
16349
  try {
16328
16350
  canonical = fs4.realpathSync(resolved);
@@ -16353,13 +16375,13 @@ function branchRenames(location) {
16353
16375
  }
16354
16376
  for (const entry of entries)
16355
16377
  if (entry.isDirectory())
16356
- walk(path3.join(dir, entry.name));
16378
+ walk(path4.join(dir, entry.name));
16357
16379
  else
16358
- files.push(path3.join(dir, entry.name));
16380
+ files.push(path4.join(dir, entry.name));
16359
16381
  };
16360
- walk(path3.join(path3.dirname(location.dir), "logs", "refs", "heads"));
16382
+ walk(path4.join(path4.dirname(location.dir), "logs", "refs", "heads"));
16361
16383
  if (location.git)
16362
- files.push(path3.join(location.git.gitDir, "logs", "HEAD"));
16384
+ files.push(path4.join(location.git.gitDir, "logs", "HEAD"));
16363
16385
  const seen = new Set;
16364
16386
  const renames = [];
16365
16387
  for (const file of files) {
@@ -16394,7 +16416,7 @@ var checkoutSlug = (root) => {
16394
16416
  let canonical = real(root);
16395
16417
  if (process.platform === "win32")
16396
16418
  canonical = canonical.toLowerCase();
16397
- const base = path3.basename(canonical).replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 40) || "root";
16419
+ const base = path4.basename(canonical).replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 40) || "root";
16398
16420
  return `${base}-${shortHash(canonical)}`;
16399
16421
  };
16400
16422
 
@@ -16426,30 +16448,113 @@ function hostSessionFromEnv(env) {
16426
16448
  }
16427
16449
  return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
16428
16450
  }
16451
+ var hash = (value) => createHash3("sha256").update(value).digest("hex").slice(0, 32);
16452
+ var userIssuedRoot = () => path5.join(resolveStateDir(), "issued");
16453
+ var userTokenRoot = () => path5.join(resolveStateDir(), "issued-tokens");
16454
+ function migrateRepoIssued(cwd) {
16455
+ if (cwd === undefined)
16456
+ return;
16457
+ let old;
16458
+ try {
16459
+ const location = resolveStore(cwd);
16460
+ if (location instanceof Error)
16461
+ return;
16462
+ old = path5.join(location.dir, "hooks", "issued");
16463
+ if (!fs5.existsSync(old))
16464
+ return;
16465
+ } catch {
16466
+ return;
16467
+ }
16468
+ for (const lead of safeList(old)) {
16469
+ try {
16470
+ const from = path5.join(old, lead);
16471
+ if (!fs5.statSync(from).isDirectory())
16472
+ continue;
16473
+ const to = path5.join(userIssuedRoot(), lead);
16474
+ fs5.mkdirSync(to, { recursive: true, mode: 448 });
16475
+ for (const id of fs5.readdirSync(from)) {
16476
+ try {
16477
+ fs5.copyFileSync(path5.join(from, id), path5.join(to, id), fs5.constants.COPYFILE_EXCL);
16478
+ } catch (error) {
16479
+ if (error.code !== "EEXIST")
16480
+ throw error;
16481
+ }
16482
+ fs5.rmSync(path5.join(from, id), { force: true });
16483
+ }
16484
+ removeIfEmpty(from);
16485
+ } catch {}
16486
+ }
16487
+ removeIfEmpty(old);
16488
+ }
16489
+ var safeList = (dir) => {
16490
+ try {
16491
+ return fs5.readdirSync(dir);
16492
+ } catch {
16493
+ return [];
16494
+ }
16495
+ };
16496
+ var removeIfEmpty = (dir) => {
16497
+ try {
16498
+ fs5.rmdirSync(dir);
16499
+ } catch {}
16500
+ };
16501
+ var issuedRecord = (cwd, claimed) => {
16502
+ const cut = claimed.lastIndexOf(":");
16503
+ if (cut <= 0)
16504
+ return null;
16505
+ migrateRepoIssued(cwd);
16506
+ try {
16507
+ return fs5.readFileSync(path5.join(userIssuedRoot(), hash(claimed.slice(0, cut)), hash(claimed)), "utf8");
16508
+ } catch {
16509
+ return null;
16510
+ }
16511
+ };
16512
+ var TOKEN_HASH = /^([0-9a-f]{64})$/mu;
16513
+ var issuedToken = (claimed) => {
16514
+ const cut = claimed.lastIndexOf(":");
16515
+ if (cut <= 0)
16516
+ return { stored: null, leadBound: false };
16517
+ const dir = path5.join(userTokenRoot(), hash(claimed.slice(0, cut)));
16518
+ try {
16519
+ const text = fs5.readFileSync(path5.join(dir, hash(claimed)), "utf8");
16520
+ return { stored: TOKEN_HASH.exec(text)?.[1] ?? null, leadBound: true };
16521
+ } catch {
16522
+ return { stored: null, leadBound: safeList(dir).length > 0 };
16523
+ }
16524
+ };
16525
+ function issuedBinding(cwd, claimed) {
16526
+ const record = issuedRecord(cwd, claimed);
16527
+ const { stored, leadBound } = issuedToken(claimed);
16528
+ if (stored)
16529
+ return "token";
16530
+ if (record === null)
16531
+ return null;
16532
+ return leadBound ? "token" : "legacy";
16533
+ }
16429
16534
  var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
16430
16535
 
16431
16536
  // packages/workit-core/src/core/package-root.ts
16432
16537
  import { existsSync } from "node:fs";
16433
- import path4 from "node:path";
16538
+ import path6 from "node:path";
16434
16539
  import { fileURLToPath } from "node:url";
16435
16540
  var packageRoot = () => {
16436
- let dir = path4.dirname(fileURLToPath(import.meta.url));
16541
+ let dir = path6.dirname(fileURLToPath(import.meta.url));
16437
16542
  while (true) {
16438
- const parent = path4.dirname(dir);
16439
- if (existsSync(path4.join(dir, "package.json")) || parent === dir)
16543
+ const parent = path6.dirname(dir);
16544
+ if (existsSync(path6.join(dir, "package.json")) || parent === dir)
16440
16545
  return dir;
16441
16546
  dir = parent;
16442
16547
  }
16443
16548
  };
16444
16549
  var assetRoot = () => {
16445
16550
  const root = packageRoot();
16446
- const assets = path4.join(root, "assets");
16551
+ const assets = path6.join(root, "assets");
16447
16552
  return existsSync(assets) ? assets : root;
16448
16553
  };
16449
16554
 
16450
16555
  // packages/workit-core/src/core/store-lock.ts
16451
16556
  import { spawnSync as spawnSync2 } from "node:child_process";
16452
- import fs5 from "node:fs";
16557
+ import fs6 from "node:fs";
16453
16558
  import { hostname } from "node:os";
16454
16559
  var metadataLockSchema = object({
16455
16560
  pid: number2().int().nonnegative().safe(),
@@ -16461,8 +16566,10 @@ var metadataLockSchema = object({
16461
16566
  var FOREIGN_LOCK_TTL_MS = 10 * 60000;
16462
16567
  var UNREADABLE_LOCK_TTL_MS = 30000;
16463
16568
  var RECLAIM_GUARD_TTL_MS = 30000;
16464
- var defaultLockTimeoutMs = 250;
16569
+ var IN_PROCESS_LOCK_TIMEOUT_MS = 250;
16570
+ var defaultLockTimeoutMs = IN_PROCESS_LOCK_TIMEOUT_MS;
16465
16571
  var defaultLockTimeout = () => defaultLockTimeoutMs;
16572
+ var hostAwareLockTimeout = (cliMs) => defaultLockTimeoutMs > IN_PROCESS_LOCK_TIMEOUT_MS ? cliMs : IN_PROCESS_LOCK_TIMEOUT_MS;
16466
16573
  var parseMetadataLock = (raw) => {
16467
16574
  let value;
16468
16575
  try {
@@ -16491,7 +16598,7 @@ var parseProcStatStart = (stat) => {
16491
16598
  var processStartOf = (pid) => {
16492
16599
  if (process.platform === "linux") {
16493
16600
  try {
16494
- return parseProcStatStart(fs5.readFileSync(`/proc/${pid}/stat`, "utf8"));
16601
+ return parseProcStatStart(fs6.readFileSync(`/proc/${pid}/stat`, "utf8"));
16495
16602
  } catch {
16496
16603
  return null;
16497
16604
  }
@@ -16512,7 +16619,7 @@ var processStartOf = (pid) => {
16512
16619
  };
16513
16620
  var readTrimmed = (file) => {
16514
16621
  try {
16515
- return fs5.readFileSync(file, "utf8").trim() || null;
16622
+ return fs6.readFileSync(file, "utf8").trim() || null;
16516
16623
  } catch {
16517
16624
  return null;
16518
16625
  }
@@ -16523,7 +16630,7 @@ var localLockHost = () => {
16523
16630
  return cachedLockHost;
16524
16631
  let pidns = null;
16525
16632
  try {
16526
- pidns = /\[(\d+)\]/.exec(fs5.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
16633
+ pidns = /\[(\d+)\]/.exec(fs6.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
16527
16634
  } catch {}
16528
16635
  const boot = readTrimmed("/proc/sys/kernel/random/boot_id");
16529
16636
  cachedLockHost = pidns || boot ? `${hostname()}#${pidns ?? "?"}:${boot ?? "?"}` : hostname();
@@ -16569,7 +16676,7 @@ var classifyLockOwner = (payload, ageMs, localHost = localLockHost(), options =
16569
16676
  };
16570
16677
  var ageOf = (file, nowMs) => {
16571
16678
  try {
16572
- return nowMs - fs5.lstatSync(file).mtimeMs;
16679
+ return nowMs - fs6.lstatSync(file).mtimeMs;
16573
16680
  } catch {
16574
16681
  return null;
16575
16682
  }
@@ -16580,7 +16687,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
16580
16687
  if (age === null || age <= RECLAIM_GUARD_TTL_MS)
16581
16688
  return false;
16582
16689
  try {
16583
- fs5.rmdirSync(guard);
16690
+ fs6.rmdirSync(guard);
16584
16691
  return true;
16585
16692
  } catch {
16586
16693
  return false;
@@ -16589,8 +16696,8 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
16589
16696
 
16590
16697
  // packages/workit-core/src/store/event-log.ts
16591
16698
  import { randomUUID as randomUUID2 } from "node:crypto";
16592
- import fs6 from "node:fs";
16593
- import path5 from "node:path";
16699
+ import fs7 from "node:fs";
16700
+ import path7 from "node:path";
16594
16701
  var EVENT_VERSION = 1;
16595
16702
 
16596
16703
  class LogDamage extends Error {
@@ -16619,7 +16726,7 @@ var parseEvent = (line, file, offset) => {
16619
16726
  function readLog(file, from = 0, expectSeq = null) {
16620
16727
  let fd;
16621
16728
  try {
16622
- fd = fs6.openSync(file, "r");
16729
+ fd = fs7.openSync(file, "r");
16623
16730
  } catch (error) {
16624
16731
  if (error.code === "ENOENT")
16625
16732
  return null;
@@ -16628,13 +16735,13 @@ function readLog(file, from = 0, expectSeq = null) {
16628
16735
  let bytes;
16629
16736
  let size;
16630
16737
  try {
16631
- size = fs6.fstatSync(fd).size;
16738
+ size = fs7.fstatSync(fd).size;
16632
16739
  if (from > size)
16633
16740
  throw new LogDamage(`${file}: shorter than its snapshot`);
16634
16741
  bytes = Buffer.alloc(size - from);
16635
16742
  let read = 0;
16636
16743
  while (read < bytes.length) {
16637
- const got = fs6.readSync(fd, bytes, read, bytes.length - read, from + read);
16744
+ const got = fs7.readSync(fd, bytes, read, bytes.length - read, from + read);
16638
16745
  if (got === 0)
16639
16746
  break;
16640
16747
  read += got;
@@ -16642,7 +16749,7 @@ function readLog(file, from = 0, expectSeq = null) {
16642
16749
  bytes = bytes.subarray(0, read);
16643
16750
  size = from + read;
16644
16751
  } finally {
16645
- fs6.closeSync(fd);
16752
+ fs7.closeSync(fd);
16646
16753
  }
16647
16754
  const events = [];
16648
16755
  let start = 0;
@@ -16667,11 +16774,11 @@ function readLog(file, from = 0, expectSeq = null) {
16667
16774
  }
16668
16775
  var fsyncDirectory = (dir) => {
16669
16776
  try {
16670
- const fd = fs6.openSync(dir, "r");
16777
+ const fd = fs7.openSync(dir, "r");
16671
16778
  try {
16672
- fs6.fsyncSync(fd);
16779
+ fs7.fsyncSync(fd);
16673
16780
  } finally {
16674
- fs6.closeSync(fd);
16781
+ fs7.closeSync(fd);
16675
16782
  }
16676
16783
  } catch (error) {
16677
16784
  if (process.platform !== "win32")
@@ -16681,46 +16788,46 @@ var fsyncDirectory = (dir) => {
16681
16788
  function appendEvent(file, event, validEnd) {
16682
16789
  const line = Buffer.from(`${JSON.stringify(event)}
16683
16790
  `, "utf8");
16684
- const created = !fs6.existsSync(file);
16685
- if (!created && fs6.statSync(file).size !== validEnd) {
16686
- const cut = fs6.openSync(file, "r+");
16791
+ const created = !fs7.existsSync(file);
16792
+ if (!created && fs7.statSync(file).size !== validEnd) {
16793
+ const cut = fs7.openSync(file, "r+");
16687
16794
  try {
16688
- fs6.ftruncateSync(cut, validEnd);
16689
- fs6.fsyncSync(cut);
16795
+ fs7.ftruncateSync(cut, validEnd);
16796
+ fs7.fsyncSync(cut);
16690
16797
  } finally {
16691
- fs6.closeSync(cut);
16798
+ fs7.closeSync(cut);
16692
16799
  }
16693
16800
  }
16694
- const fd = fs6.openSync(file, "a", 384);
16801
+ const fd = fs7.openSync(file, "a", 384);
16695
16802
  try {
16696
16803
  let written = 0;
16697
16804
  while (written < line.length)
16698
- written += fs6.writeSync(fd, line, written, line.length - written);
16699
- fs6.fsyncSync(fd);
16805
+ written += fs7.writeSync(fd, line, written, line.length - written);
16806
+ fs7.fsyncSync(fd);
16700
16807
  } finally {
16701
- fs6.closeSync(fd);
16808
+ fs7.closeSync(fd);
16702
16809
  }
16703
16810
  if (created)
16704
- fsyncDirectory(path5.dirname(file));
16811
+ fsyncDirectory(path7.dirname(file));
16705
16812
  return validEnd;
16706
16813
  }
16707
16814
  function replaceFile(file, bytes, durable) {
16708
16815
  const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
16709
16816
  try {
16710
- const fd = fs6.openSync(temporary, "wx", 384);
16817
+ const fd = fs7.openSync(temporary, "wx", 384);
16711
16818
  try {
16712
- fs6.writeSync(fd, bytes);
16819
+ fs7.writeSync(fd, bytes);
16713
16820
  if (durable)
16714
- fs6.fsyncSync(fd);
16821
+ fs7.fsyncSync(fd);
16715
16822
  } finally {
16716
- fs6.closeSync(fd);
16823
+ fs7.closeSync(fd);
16717
16824
  }
16718
16825
  renameWithRetry(temporary, file);
16719
16826
  if (durable)
16720
- fsyncDirectory(path5.dirname(file));
16827
+ fsyncDirectory(path7.dirname(file));
16721
16828
  } catch (error) {
16722
16829
  try {
16723
- fs6.unlinkSync(temporary);
16830
+ fs7.unlinkSync(temporary);
16724
16831
  } catch {}
16725
16832
  throw error;
16726
16833
  }
@@ -16745,7 +16852,7 @@ var retryTransient = (run) => {
16745
16852
  }
16746
16853
  }
16747
16854
  };
16748
- var renameWithRetry = (from, to) => retryTransient(() => fs6.renameSync(from, to));
16855
+ var renameWithRetry = (from, to) => retryTransient(() => fs7.renameSync(from, to));
16749
16856
 
16750
16857
  // packages/workit-core/src/store/patch.ts
16751
16858
  var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -16858,7 +16965,7 @@ var isPatch = (value) => Array.isArray(value) && value.every((op) => {
16858
16965
  });
16859
16966
 
16860
16967
  // packages/workit-core/src/store/reduce.ts
16861
- import { createHash as createHash3 } from "node:crypto";
16968
+ import { createHash as createHash4 } from "node:crypto";
16862
16969
  var OPENING_TYPES = new Set([
16863
16970
  "task.opened",
16864
16971
  "task.imported",
@@ -16887,7 +16994,7 @@ var isObject4 = (value) => typeof value === "object" && value !== null && !Array
16887
16994
  var isKey = (value) => isObject4(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string");
16888
16995
  var BLOB_REF = "$blob";
16889
16996
  var blobRef = (value) => isObject4(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null;
16890
- var blobDigest = (value) => createHash3("sha256").update(JSON.stringify(value)).digest("hex");
16997
+ var blobDigest = (value) => createHash4("sha256").update(JSON.stringify(value)).digest("hex");
16891
16998
  var toBlob = (value, blobs) => {
16892
16999
  if (!isObject4(value))
16893
17000
  return value;
@@ -17042,7 +17149,7 @@ var indexEntry = (task, key, legacy, file) => {
17042
17149
  };
17043
17150
  var fileSignature = (file) => {
17044
17151
  try {
17045
- const stat = fs7.statSync(file, { bigint: true });
17152
+ const stat = fs8.statSync(file, { bigint: true });
17046
17153
  return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
17047
17154
  } catch {
17048
17155
  return null;
@@ -17060,7 +17167,7 @@ var cachedRuntimeVersion = null;
17060
17167
  var runtimeVersion = () => {
17061
17168
  if (cachedRuntimeVersion === null) {
17062
17169
  try {
17063
- const pkg = JSON.parse(fs7.readFileSync(path6.join(packageRoot(), "package.json"), "utf8"));
17170
+ const pkg = JSON.parse(fs8.readFileSync(path8.join(packageRoot(), "package.json"), "utf8"));
17064
17171
  cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
17065
17172
  } catch {
17066
17173
  cachedRuntimeVersion = "0.0.0";
@@ -17086,14 +17193,14 @@ var isNewerVersion = (candidate, current) => {
17086
17193
  var validId = (value) => /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(value);
17087
17194
  var readText = (file) => {
17088
17195
  try {
17089
- return fs7.readFileSync(file, "utf8");
17196
+ return fs8.readFileSync(file, "utf8");
17090
17197
  } catch {
17091
17198
  return "";
17092
17199
  }
17093
17200
  };
17094
17201
  var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
17095
17202
  var branchStart = (location, branch, aliases) => {
17096
- const first = readText(path6.join(path6.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
17203
+ const first = readText(path8.join(path8.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
17097
17204
  `, 1)[0];
17098
17205
  const created = REFLOG_LINE.exec(first);
17099
17206
  const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
@@ -17103,7 +17210,7 @@ var branchStart = (location, branch, aliases) => {
17103
17210
  return start;
17104
17211
  if (!location.git)
17105
17212
  return null;
17106
- for (const line of readText(path6.join(location.git.gitDir, "logs", "HEAD")).split(`
17213
+ for (const line of readText(path8.join(location.git.gitDir, "logs", "HEAD")).split(`
17107
17214
  `)) {
17108
17215
  const entry = REFLOG_LINE.exec(line);
17109
17216
  const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
@@ -17113,23 +17220,23 @@ var branchStart = (location, branch, aliases) => {
17113
17220
  }
17114
17221
  return null;
17115
17222
  };
17116
- var refExists = (common, ref) => fs7.existsSync(path6.join(common, ref)) || readText(path6.join(common, "packed-refs")).includes(` ${ref}
17223
+ var refExists = (common, ref) => fs8.existsSync(path8.join(common, ref)) || readText(path8.join(common, "packed-refs")).includes(` ${ref}
17117
17224
  `);
17118
17225
  var origins = new Map;
17119
17226
  var sameDirectoryIdentity = (left, right) => {
17120
- if (!path6.isAbsolute(left) || !path6.isAbsolute(right))
17227
+ if (!path8.isAbsolute(left) || !path8.isAbsolute(right))
17121
17228
  return false;
17122
- const normalizedLeft = path6.resolve(left);
17123
- const normalizedRight = path6.resolve(right);
17229
+ const normalizedLeft = path8.resolve(left);
17230
+ const normalizedRight = path8.resolve(right);
17124
17231
  try {
17125
- const a = fs7.statSync(normalizedLeft, { bigint: true });
17126
- const b = fs7.statSync(normalizedRight, { bigint: true });
17232
+ const a = fs8.statSync(normalizedLeft, { bigint: true });
17233
+ const b = fs8.statSync(normalizedRight, { bigint: true });
17127
17234
  if (!a.isDirectory() || !b.isDirectory())
17128
17235
  return false;
17129
17236
  if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
17130
17237
  return true;
17131
- const canonicalLeft = fs7.realpathSync(normalizedLeft);
17132
- const canonicalRight = fs7.realpathSync(normalizedRight);
17238
+ const canonicalLeft = fs8.realpathSync(normalizedLeft);
17239
+ const canonicalRight = fs8.realpathSync(normalizedRight);
17133
17240
  if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
17134
17241
  return true;
17135
17242
  return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
@@ -17166,8 +17273,8 @@ class TaskStore {
17166
17273
  migrationChecked = false;
17167
17274
  compactDue = new Set;
17168
17275
  constructor(root, options = {}) {
17169
- const resolved = path6.resolve(root);
17170
- this.origin = fs7.existsSync(resolved) ? fs7.realpathSync(resolved) : resolved;
17276
+ const resolved = path8.resolve(root);
17277
+ this.origin = fs8.existsSync(resolved) ? fs8.realpathSync(resolved) : resolved;
17171
17278
  this.located = resolveStore(this.origin);
17172
17279
  this.root = checkoutRootOf(this.origin, this.located);
17173
17280
  this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
@@ -17175,7 +17282,7 @@ class TaskStore {
17175
17282
  this.migrateOnRead = options.migrateOnRead;
17176
17283
  }
17177
17284
  location() {
17178
- if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs7.existsSync(path6.join(this.root, ".git"))) {
17285
+ if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs8.existsSync(path8.join(this.root, ".git"))) {
17179
17286
  this.located = undefined;
17180
17287
  this.migrationChecked = false;
17181
17288
  }
@@ -17239,7 +17346,7 @@ class TaskStore {
17239
17346
  const tasksDir = this.paths().tasks;
17240
17347
  let names;
17241
17348
  try {
17242
- names = fs7.existsSync(tasksDir) ? fs7.readdirSync(tasksDir).filter((name) => validId(name)) : [];
17349
+ names = fs8.existsSync(tasksDir) ? fs8.readdirSync(tasksDir).filter((name) => validId(name)) : [];
17243
17350
  } catch (error) {
17244
17351
  return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
17245
17352
  path: tasksDir
@@ -17280,7 +17387,7 @@ class TaskStore {
17280
17387
  const file = this.paths().workspace;
17281
17388
  let bytes;
17282
17389
  try {
17283
- bytes = retryTransient(() => fs7.readFileSync(file, "utf8"));
17390
+ bytes = retryTransient(() => fs8.readFileSync(file, "utf8"));
17284
17391
  } catch (error) {
17285
17392
  if (error.code === "ENOENT")
17286
17393
  return success(null, null, null);
@@ -17331,7 +17438,7 @@ class TaskStore {
17331
17438
  const moved = this.bindLocked(again.data.id, key, input.now);
17332
17439
  return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
17333
17440
  }
17334
- const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path6.basename(this.root) || this.root;
17441
+ const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path8.basename(this.root) || this.root;
17335
17442
  const intent = {
17336
17443
  objective: input.objective?.trim() || `Work on ${label}`,
17337
17444
  scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
@@ -17391,14 +17498,14 @@ class TaskStore {
17391
17498
  const branch = key.ok ? key.data.branch : null;
17392
17499
  if (!branch || !location.ok)
17393
17500
  return success(null, null, null);
17394
- const common = path6.dirname(location.data.dir);
17395
- const heads = path6.join(common, "logs", "refs", "heads");
17396
- const headLog = location.data.git ? path6.join(location.data.git.gitDir, "logs", "HEAD") : "";
17501
+ const common = path8.dirname(location.data.dir);
17502
+ const heads = path8.join(common, "logs", "refs", "heads");
17503
+ const headLog = location.data.git ? path8.join(location.data.git.gitDir, "logs", "HEAD") : "";
17397
17504
  const signatures = [
17398
- path6.join(heads, branch),
17505
+ path8.join(heads, branch),
17399
17506
  headLog,
17400
17507
  heads,
17401
- path6.join(common, "packed-refs")
17508
+ path8.join(common, "packed-refs")
17402
17509
  ].map((file) => fileSignature(file) ?? "-");
17403
17510
  const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
17404
17511
  let resolved = origins.get(slot);
@@ -17410,7 +17517,7 @@ class TaskStore {
17410
17517
  aliases.push(rename.from);
17411
17518
  const start = branchStart(location.data, branch, aliases);
17412
17519
  const slash = start?.indexOf("/") ?? -1;
17413
- const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path6.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
17520
+ const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path8.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
17414
17521
  const name = start && (remote ? start.slice(slash + 1) : start);
17415
17522
  resolved = {
17416
17523
  signature: signatures.join("|"),
@@ -17648,13 +17755,13 @@ class TaskStore {
17648
17755
  if (!ready.ok)
17649
17756
  return ready;
17650
17757
  const dirs = this.paths();
17651
- const recovery = path6.join(this.root, ".workit", "recovery");
17652
- if (fs7.existsSync(recovery)) {
17758
+ const recovery = path8.join(this.root, ".workit", "recovery");
17759
+ if (fs8.existsSync(recovery)) {
17653
17760
  let files = 0;
17654
17761
  let bytes = 0;
17655
17762
  try {
17656
- for (const name of fs7.readdirSync(recovery)) {
17657
- const stat = fs7.lstatSync(path6.join(recovery, name));
17763
+ for (const name of fs8.readdirSync(recovery)) {
17764
+ const stat = fs8.lstatSync(path8.join(recovery, name));
17658
17765
  if (!stat.isFile())
17659
17766
  continue;
17660
17767
  files += 1;
@@ -17663,17 +17770,17 @@ class TaskStore {
17663
17770
  } catch {}
17664
17771
  const remove = options.pruneRecovery === true && !dryRun;
17665
17772
  if (remove)
17666
- fs7.rmSync(recovery, { recursive: true, force: true });
17773
+ fs8.rmSync(recovery, { recursive: true, force: true });
17667
17774
  report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
17668
17775
  }
17669
- if (!fs7.existsSync(dirs.tasks))
17776
+ if (!fs8.existsSync(dirs.tasks))
17670
17777
  return success(null, null, report);
17671
- const names = fs7.readdirSync(dirs.tasks).filter((name) => validId(name));
17778
+ const names = fs8.readdirSync(dirs.tasks).filter((name) => validId(name));
17672
17779
  for (const name of names) {
17673
17780
  const file = this.eventsPath(name);
17674
17781
  let size = 0;
17675
17782
  try {
17676
- size = fs7.statSync(file).size;
17783
+ size = fs8.statSync(file).size;
17677
17784
  } catch {
17678
17785
  continue;
17679
17786
  }
@@ -17701,16 +17808,16 @@ class TaskStore {
17701
17808
  const references = new Set;
17702
17809
  for (const name of names)
17703
17810
  try {
17704
- for (const match of fs7.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
17811
+ for (const match of fs8.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
17705
17812
  references.add(match[1]);
17706
17813
  } catch {}
17707
- if (fs7.existsSync(dirs.blobs))
17708
- for (const name of fs7.readdirSync(dirs.blobs)) {
17814
+ if (fs8.existsSync(dirs.blobs))
17815
+ for (const name of fs8.readdirSync(dirs.blobs)) {
17709
17816
  const digest = name.replace(/\.json$/, "");
17710
- const file = path6.join(dirs.blobs, name);
17817
+ const file = path8.join(dirs.blobs, name);
17711
17818
  let stat;
17712
17819
  try {
17713
- stat = fs7.lstatSync(file);
17820
+ stat = fs8.lstatSync(file);
17714
17821
  } catch {
17715
17822
  continue;
17716
17823
  }
@@ -17721,11 +17828,11 @@ class TaskStore {
17721
17828
  report.blobs.removed += 1;
17722
17829
  report.blobs.removedBytes += stat.size;
17723
17830
  if (!dryRun)
17724
- fs7.rmSync(file, { force: true });
17831
+ fs8.rmSync(file, { force: true });
17725
17832
  }
17726
17833
  return success(null, null, null);
17727
17834
  };
17728
- const swept = dryRun ? sweep() : this.withLock(path6.join(dirs.dir, "gc.lock"), sweep);
17835
+ const swept = dryRun ? sweep() : this.withLock(path8.join(dirs.dir, "gc.lock"), sweep);
17729
17836
  if (!swept.ok)
17730
17837
  return swept;
17731
17838
  const temporaryDirs = [
@@ -17733,17 +17840,17 @@ class TaskStore {
17733
17840
  dirs.tasks,
17734
17841
  dirs.blobs,
17735
17842
  dirs.checkout,
17736
- ...names.map((name) => path6.join(dirs.tasks, name))
17843
+ ...names.map((name) => path8.join(dirs.tasks, name))
17737
17844
  ];
17738
17845
  for (const directory of temporaryDirs) {
17739
- if (!fs7.existsSync(directory))
17846
+ if (!fs8.existsSync(directory))
17740
17847
  continue;
17741
- for (const name of fs7.readdirSync(directory)) {
17848
+ for (const name of fs8.readdirSync(directory)) {
17742
17849
  if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
17743
17850
  continue;
17744
- const file = path6.join(directory, name);
17851
+ const file = path8.join(directory, name);
17745
17852
  try {
17746
- const stat = fs7.lstatSync(file);
17853
+ const stat = fs8.lstatSync(file);
17747
17854
  if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
17748
17855
  continue;
17749
17856
  } catch {
@@ -17751,37 +17858,37 @@ class TaskStore {
17751
17858
  }
17752
17859
  report.temporary.removed += 1;
17753
17860
  if (!dryRun)
17754
- fs7.rmSync(file, { force: true });
17861
+ fs8.rmSync(file, { force: true });
17755
17862
  }
17756
17863
  }
17757
17864
  return success(null, null, report);
17758
17865
  }
17759
17866
  paths() {
17760
17867
  const location = this.location();
17761
- const dir = location.ok ? location.data.dir : path6.join(this.root, ".workit");
17762
- const checkout = path6.join(dir, "checkouts", checkoutSlug(this.root));
17868
+ const dir = location.ok ? location.data.dir : path8.join(this.root, ".workit");
17869
+ const checkout = path8.join(dir, "checkouts", checkoutSlug(this.root));
17763
17870
  return {
17764
17871
  dir,
17765
17872
  shared: location.ok ? location.data.shared : false,
17766
- marker: path6.join(dir, "store.json"),
17873
+ marker: path8.join(dir, "store.json"),
17767
17874
  checkout,
17768
- workspace: path6.join(checkout, "workspace.json"),
17769
- checkoutLock: path6.join(checkout, "metadata.lock"),
17770
- tasks: path6.join(dir, "tasks"),
17771
- index: path6.join(dir, "task-index.json"),
17772
- blobs: path6.join(dir, "blobs", "candidates"),
17773
- legacy: path6.join(dir, "legacy", checkoutSlug(this.root), "v2"),
17774
- v2: path6.join(this.root, ".workit")
17875
+ workspace: path8.join(checkout, "workspace.json"),
17876
+ checkoutLock: path8.join(checkout, "metadata.lock"),
17877
+ tasks: path8.join(dir, "tasks"),
17878
+ index: path8.join(dir, "task-index.json"),
17879
+ blobs: path8.join(dir, "blobs", "candidates"),
17880
+ legacy: path8.join(dir, "legacy", checkoutSlug(this.root), "v2"),
17881
+ v2: path8.join(this.root, ".workit")
17775
17882
  };
17776
17883
  }
17777
17884
  eventsPath(taskId) {
17778
- return path6.join(this.paths().tasks, taskId, "events.jsonl");
17885
+ return path8.join(this.paths().tasks, taskId, "events.jsonl");
17779
17886
  }
17780
17887
  snapshotPath(taskId) {
17781
- return path6.join(this.paths().tasks, taskId, "snapshot.json");
17888
+ return path8.join(this.paths().tasks, taskId, "snapshot.json");
17782
17889
  }
17783
17890
  taskLockPath(taskId) {
17784
- return path6.join(this.paths().tasks, taskId, "lock");
17891
+ return path8.join(this.paths().tasks, taskId, "lock");
17785
17892
  }
17786
17893
  ready(write = false) {
17787
17894
  const location = this.location();
@@ -17791,7 +17898,7 @@ class TaskStore {
17791
17898
  return success(null, null, null);
17792
17899
  const dirs = this.paths();
17793
17900
  try {
17794
- const marker = JSON.parse(fs7.readFileSync(dirs.marker, "utf8"));
17901
+ const marker = JSON.parse(fs8.readFileSync(dirs.marker, "utf8"));
17795
17902
  if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
17796
17903
  return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
17797
17904
  } catch {}
@@ -17820,21 +17927,21 @@ class TaskStore {
17820
17927
  return {
17821
17928
  read: (digest) => {
17822
17929
  try {
17823
- return JSON.parse(fs7.readFileSync(path6.join(dir, `${digest}.json`), "utf8"));
17930
+ return JSON.parse(fs8.readFileSync(path8.join(dir, `${digest}.json`), "utf8"));
17824
17931
  } catch (error) {
17825
17932
  throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
17826
17933
  }
17827
17934
  },
17828
17935
  write: (digest, value) => {
17829
- const file = path6.join(dir, `${digest}.json`);
17830
- if (fs7.existsSync(file)) {
17936
+ const file = path8.join(dir, `${digest}.json`);
17937
+ if (fs8.existsSync(file)) {
17831
17938
  const stamp = new Date;
17832
17939
  try {
17833
- fs7.utimesSync(file, stamp, stamp);
17940
+ fs8.utimesSync(file, stamp, stamp);
17834
17941
  return;
17835
17942
  } catch {}
17836
17943
  }
17837
- fs7.mkdirSync(dir, { recursive: true });
17944
+ fs8.mkdirSync(dir, { recursive: true });
17838
17945
  replaceFile(file, JSON.stringify(value), true);
17839
17946
  }
17840
17947
  };
@@ -17916,7 +18023,7 @@ class TaskStore {
17916
18023
  }
17917
18024
  readSnapshot(taskId) {
17918
18025
  try {
17919
- const value = JSON.parse(fs7.readFileSync(this.snapshotPath(taskId), "utf8"));
18026
+ const value = JSON.parse(fs8.readFileSync(this.snapshotPath(taskId), "utf8"));
17920
18027
  if (!isObject5(value) || value.v !== 1 || value.task !== taskId || typeof value.seq !== "number" || typeof value.lastId !== "string" || typeof value.lastStart !== "number" || typeof value.end !== "number" || !isObject5(value.record))
17921
18028
  return null;
17922
18029
  return value;
@@ -18018,8 +18125,8 @@ class TaskStore {
18018
18125
  }
18019
18126
  }
18020
18127
  openTask(record, type, key, legacy = null) {
18021
- const dir = path6.join(this.paths().tasks, record.id);
18022
- fs7.mkdirSync(dir, { recursive: true });
18128
+ const dir = path8.join(this.paths().tasks, record.id);
18129
+ fs8.mkdirSync(dir, { recursive: true });
18023
18130
  const blobs = this.blobStore();
18024
18131
  const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
18025
18132
  const event = this.event(record.id, 1, type, {
@@ -18071,11 +18178,11 @@ class TaskStore {
18071
18178
  } catch {}
18072
18179
  if (!latest || latest.events[0]?.id !== last.id)
18073
18180
  return failure2("busy", "the task log changed during compaction; retry", { taskId });
18074
- const appended = fs7.readFileSync(file).subarray(log.end, latest.end);
18181
+ const appended = fs8.readFileSync(file).subarray(log.end, latest.end);
18075
18182
  const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
18076
18183
  replaceFile(file, bytes.toString("utf8"), true);
18077
18184
  try {
18078
- fs7.rmSync(this.snapshotPath(taskId), { force: true });
18185
+ fs8.rmSync(this.snapshotPath(taskId), { force: true });
18079
18186
  } catch {}
18080
18187
  const reloaded = this.load(taskId);
18081
18188
  if (reloaded.ok && reloaded.data)
@@ -18088,7 +18195,7 @@ class TaskStore {
18088
18195
  }
18089
18196
  countEvents(file) {
18090
18197
  try {
18091
- const bytes = fs7.readFileSync(file);
18198
+ const bytes = fs8.readFileSync(file);
18092
18199
  let count = 0;
18093
18200
  for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
18094
18201
  count += 1;
@@ -18110,8 +18217,8 @@ class TaskStore {
18110
18217
  return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
18111
18218
  }
18112
18219
  withKeyLock(key, operation) {
18113
- const digest = createHash4("sha256").update(key).digest("hex").slice(0, 32);
18114
- return this.withLock(path6.join(this.paths().dir, "keys", `${digest}.lock`), operation);
18220
+ const digest = createHash5("sha256").update(key).digest("hex").slice(0, 32);
18221
+ return this.withLock(path8.join(this.paths().dir, "keys", `${digest}.lock`), operation);
18115
18222
  }
18116
18223
  bindLocked(taskId, key, timestamp) {
18117
18224
  const current = this.readWorkspace();
@@ -18252,7 +18359,7 @@ class TaskStore {
18252
18359
  writeWorkspace(record) {
18253
18360
  const file = this.paths().workspace;
18254
18361
  try {
18255
- fs7.mkdirSync(path6.dirname(file), { recursive: true });
18362
+ fs8.mkdirSync(path8.dirname(file), { recursive: true });
18256
18363
  replaceFile(file, `${canonicalJson(record)}
18257
18364
  `, true);
18258
18365
  return success(null, null, null);
@@ -18262,7 +18369,7 @@ class TaskStore {
18262
18369
  }
18263
18370
  readIndex() {
18264
18371
  try {
18265
- const value = JSON.parse(fs7.readFileSync(this.paths().index, "utf8"));
18372
+ const value = JSON.parse(fs8.readFileSync(this.paths().index, "utf8"));
18266
18373
  if (!isObject5(value) || value.version !== INDEX_VERSION || !isObject5(value.tasks))
18267
18374
  return {};
18268
18375
  const tasks = {};
@@ -18276,7 +18383,7 @@ class TaskStore {
18276
18383
  }
18277
18384
  writeIndex(entries) {
18278
18385
  try {
18279
- fs7.mkdirSync(this.paths().tasks, { recursive: true });
18386
+ fs8.mkdirSync(this.paths().tasks, { recursive: true });
18280
18387
  replaceFile(this.paths().index, JSON.stringify({
18281
18388
  version: INDEX_VERSION,
18282
18389
  tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
@@ -18330,23 +18437,23 @@ class TaskStore {
18330
18437
  return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
18331
18438
  }
18332
18439
  v2Dirs() {
18333
- return [...new Set([this.root, this.origin])].map((dir) => path6.join(dir, ".workit"));
18440
+ return [...new Set([this.root, this.origin])].map((dir) => path8.join(dir, ".workit"));
18334
18441
  }
18335
18442
  pendingMigrations() {
18336
18443
  return this.v2Dirs().filter((dir) => {
18337
- const raw = this.readV2Workspace(path6.join(dir, "workspace.json"));
18444
+ const raw = this.readV2Workspace(path8.join(dir, "workspace.json"));
18338
18445
  return raw !== null && raw !== TOMBSTONE;
18339
18446
  });
18340
18447
  }
18341
18448
  migrateV2(v2) {
18342
18449
  const dirs = this.paths();
18343
- const v2Workspace = path6.join(v2, "workspace.json");
18344
- const v2Tasks = path6.join(v2, "tasks");
18345
- const legacy = path6.join(dirs.dir, "legacy", checkoutSlug(path6.dirname(v2)), "v2");
18450
+ const v2Workspace = path8.join(v2, "workspace.json");
18451
+ const v2Tasks = path8.join(v2, "tasks");
18452
+ const legacy = path8.join(dirs.dir, "legacy", checkoutSlug(path8.dirname(v2)), "v2");
18346
18453
  const raw = this.readV2Workspace(v2Workspace);
18347
18454
  if (raw === null || raw === TOMBSTONE)
18348
18455
  return success(null, null, null);
18349
- return this.withLock(dirs.checkoutLock, () => this.withLock(path6.join(v2, "metadata.lock"), () => {
18456
+ return this.withLock(dirs.checkoutLock, () => this.withLock(path8.join(v2, "metadata.lock"), () => {
18350
18457
  const workspace = this.readV2Workspace(v2Workspace);
18351
18458
  if (workspace === null || workspace === TOMBSTONE)
18352
18459
  return success(null, null, null);
@@ -18355,7 +18462,7 @@ class TaskStore {
18355
18462
  return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
18356
18463
  let files = [];
18357
18464
  try {
18358
- files = fs7.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path6.join(v2Tasks, name)));
18465
+ files = fs8.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path8.join(v2Tasks, name)));
18359
18466
  } catch {}
18360
18467
  const current = this.readWorkspace();
18361
18468
  if (!current.ok)
@@ -18373,22 +18480,22 @@ class TaskStore {
18373
18480
  let skipped = 0;
18374
18481
  const done = new Map;
18375
18482
  try {
18376
- fs7.mkdirSync(path6.join(legacy, "tasks"), { recursive: true });
18483
+ fs8.mkdirSync(path8.join(legacy, "tasks"), { recursive: true });
18377
18484
  for (const name of ["workspace.json", "index.json"])
18378
- if (fs7.existsSync(path6.join(v2, name)))
18379
- fs7.copyFileSync(path6.join(v2, name), path6.join(legacy, name));
18485
+ if (fs8.existsSync(path8.join(v2, name)))
18486
+ fs8.copyFileSync(path8.join(v2, name), path8.join(legacy, name));
18380
18487
  for (const name of files) {
18381
18488
  const id = name.slice(0, -5);
18382
- const file = path6.join(v2Tasks, name);
18383
- const bytes = fs7.readFileSync(file, "utf8");
18489
+ const file = path8.join(v2Tasks, name);
18490
+ const bytes = fs8.readFileSync(file, "utf8");
18384
18491
  const digest = sha256(bytes);
18385
- fs7.writeFileSync(path6.join(legacy, "tasks", name), bytes);
18492
+ fs8.writeFileSync(path8.join(legacy, "tasks", name), bytes);
18386
18493
  const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
18387
18494
  if (!parsed.ok || parsed.data.id !== id)
18388
18495
  return failure2("recovery_required", `cannot migrate 2.x task ${id}: ${parsed.ok ? "file name and record ID differ" : parsed.error}; move ${file} aside to continue`, { path: file });
18389
18496
  const record = { ...parsed.data, workspaceId: target.id };
18390
- const origin = { path: path6.join(legacy, "tasks", name), digest };
18391
- if (!fs7.existsSync(this.eventsPath(id))) {
18497
+ const origin = { path: path8.join(legacy, "tasks", name), digest };
18498
+ if (!fs8.existsSync(this.eventsPath(id))) {
18392
18499
  this.openTask(record, "migrated.from_v2", null, origin);
18393
18500
  migrated += 1;
18394
18501
  } else {
@@ -18423,8 +18530,8 @@ class TaskStore {
18423
18530
  try {
18424
18531
  let complete = true;
18425
18532
  for (const [name, digest] of done) {
18426
- const file = path6.join(v2Tasks, name);
18427
- if (sha256(fs7.readFileSync(file, "utf8")) !== digest) {
18533
+ const file = path8.join(v2Tasks, name);
18534
+ if (sha256(fs8.readFileSync(file, "utf8")) !== digest) {
18428
18535
  complete = false;
18429
18536
  continue;
18430
18537
  }
@@ -18434,7 +18541,7 @@ class TaskStore {
18434
18541
  return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
18435
18542
  path: v2
18436
18543
  });
18437
- fs7.rmSync(path6.join(v2, "index.json"), { force: true });
18544
+ fs8.rmSync(path8.join(v2, "index.json"), { force: true });
18438
18545
  this.writeTombstone(v2, target.id);
18439
18546
  } catch (error) {
18440
18547
  return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
@@ -18454,45 +18561,45 @@ class TaskStore {
18454
18561
  }
18455
18562
  adoptLocalStore() {
18456
18563
  const dirs = this.paths();
18457
- const marker = path6.join(dirs.v2, "store.json");
18458
- if (!dirs.shared || !fs7.existsSync(marker))
18564
+ const marker = path8.join(dirs.v2, "store.json");
18565
+ if (!dirs.shared || !fs8.existsSync(marker))
18459
18566
  return success(null, null, null);
18460
18567
  return this.withLock(dirs.checkoutLock, () => {
18461
- if (!fs7.existsSync(marker))
18568
+ if (!fs8.existsSync(marker))
18462
18569
  return success(null, null, null);
18463
18570
  let tasks = 0;
18464
18571
  try {
18465
18572
  const merge = (from, to) => {
18466
- if (!fs7.existsSync(to)) {
18467
- fs7.mkdirSync(path6.dirname(to), { recursive: true });
18573
+ if (!fs8.existsSync(to)) {
18574
+ fs8.mkdirSync(path8.dirname(to), { recursive: true });
18468
18575
  try {
18469
- fs7.renameSync(from, to);
18576
+ fs8.renameSync(from, to);
18470
18577
  } catch {
18471
- fs7.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
18472
- fs7.rmSync(from, { recursive: true, force: true });
18578
+ fs8.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
18579
+ fs8.rmSync(from, { recursive: true, force: true });
18473
18580
  }
18474
18581
  return;
18475
18582
  }
18476
- if (fs7.lstatSync(from).isDirectory() && fs7.lstatSync(to).isDirectory())
18477
- for (const name of fs7.readdirSync(from))
18478
- merge(path6.join(from, name), path6.join(to, name));
18583
+ if (fs8.lstatSync(from).isDirectory() && fs8.lstatSync(to).isDirectory())
18584
+ for (const name of fs8.readdirSync(from))
18585
+ merge(path8.join(from, name), path8.join(to, name));
18479
18586
  };
18480
18587
  for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
18481
- const from = path6.join(dirs.v2, sub);
18482
- if (!fs7.existsSync(from))
18588
+ const from = path8.join(dirs.v2, sub);
18589
+ if (!fs8.existsSync(from))
18483
18590
  continue;
18484
18591
  if (sub === "tasks") {
18485
- for (const name of fs7.readdirSync(from))
18486
- if (validId(name) && !fs7.existsSync(path6.join(dirs.dir, sub, name)))
18592
+ for (const name of fs8.readdirSync(from))
18593
+ if (validId(name) && !fs8.existsSync(path8.join(dirs.dir, sub, name)))
18487
18594
  tasks += 1;
18488
18595
  }
18489
- merge(from, path6.join(dirs.dir, sub));
18596
+ merge(from, path8.join(dirs.dir, sub));
18490
18597
  }
18491
- const ledger = path6.join(dirs.v2, "ledger");
18492
- if (fs7.existsSync(ledger) && !fs7.existsSync(path6.join(dirs.dir, "ledger")))
18493
- merge(ledger, path6.join(dirs.dir, "ledger"));
18494
- fs7.rmSync(path6.join(dirs.v2, "task-index.json"), { force: true });
18495
- fs7.renameSync(marker, path6.join(dirs.v2, "store.moved.json"));
18598
+ const ledger = path8.join(dirs.v2, "ledger");
18599
+ if (fs8.existsSync(ledger) && !fs8.existsSync(path8.join(dirs.dir, "ledger")))
18600
+ merge(ledger, path8.join(dirs.dir, "ledger"));
18601
+ fs8.rmSync(path8.join(dirs.v2, "task-index.json"), { force: true });
18602
+ fs8.renameSync(marker, path8.join(dirs.v2, "store.moved.json"));
18496
18603
  } catch (error) {
18497
18604
  return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
18498
18605
  path: dirs.v2
@@ -18512,7 +18619,7 @@ class TaskStore {
18512
18619
  readV2Workspace(file) {
18513
18620
  let bytes;
18514
18621
  try {
18515
- bytes = fs7.readFileSync(file, "utf8");
18622
+ bytes = fs8.readFileSync(file, "utf8");
18516
18623
  } catch {
18517
18624
  return null;
18518
18625
  }
@@ -18530,7 +18637,7 @@ class TaskStore {
18530
18637
  schemaVersion: SCHEMA_VERSION,
18531
18638
  id: workspaceId ?? newId(),
18532
18639
  revision: newRevision(),
18533
- root: path6.dirname(v2),
18640
+ root: path8.dirname(v2),
18534
18641
  runtime: { createdWith: version, updatedWith: version },
18535
18642
  writer: null,
18536
18643
  store: {
@@ -18541,12 +18648,12 @@ class TaskStore {
18541
18648
  },
18542
18649
  critical: ["store"]
18543
18650
  };
18544
- fs7.mkdirSync(v2, { recursive: true });
18545
- const ignore = path6.join(v2, ".gitignore");
18546
- if (!fs7.existsSync(ignore))
18547
- fs7.writeFileSync(ignore, `*
18651
+ fs8.mkdirSync(v2, { recursive: true });
18652
+ const ignore = path8.join(v2, ".gitignore");
18653
+ if (!fs8.existsSync(ignore))
18654
+ fs8.writeFileSync(ignore, `*
18548
18655
  `);
18549
- replaceFile(path6.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
18656
+ replaceFile(path8.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
18550
18657
  `, true);
18551
18658
  }
18552
18659
  stubFor(taskId) {
@@ -18562,7 +18669,7 @@ class TaskStore {
18562
18669
  }
18563
18670
  isStub(file) {
18564
18671
  try {
18565
- const value = JSON.parse(fs7.readFileSync(file, "utf8"));
18672
+ const value = JSON.parse(fs8.readFileSync(file, "utf8"));
18566
18673
  return isObject5(value) && isObject5(value.store) && value.store.format === "workit-store";
18567
18674
  } catch {
18568
18675
  return false;
@@ -18570,32 +18677,32 @@ class TaskStore {
18570
18677
  }
18571
18678
  writeTombstoneIfMissing() {
18572
18679
  try {
18573
- const v2 = path6.join(this.root, ".workit");
18574
- if (fs7.existsSync(path6.join(v2, "workspace.json")))
18680
+ const v2 = path8.join(this.root, ".workit");
18681
+ if (fs8.existsSync(path8.join(v2, "workspace.json")))
18575
18682
  return;
18576
18683
  let id = null;
18577
18684
  try {
18578
- id = JSON.parse(fs7.readFileSync(this.paths().workspace, "utf8")).id ?? null;
18685
+ id = JSON.parse(fs8.readFileSync(this.paths().workspace, "utf8")).id ?? null;
18579
18686
  } catch {}
18580
18687
  this.writeTombstone(v2, id);
18581
18688
  } catch {}
18582
18689
  }
18583
18690
  initializeStorage() {
18584
18691
  const dirs = this.paths();
18585
- retryTransient(() => fs7.mkdirSync(dirs.checkout, { recursive: true }));
18586
- retryTransient(() => fs7.mkdirSync(dirs.tasks, { recursive: true }));
18587
- if (!fs7.existsSync(dirs.marker))
18692
+ retryTransient(() => fs8.mkdirSync(dirs.checkout, { recursive: true }));
18693
+ retryTransient(() => fs8.mkdirSync(dirs.tasks, { recursive: true }));
18694
+ if (!fs8.existsSync(dirs.marker))
18588
18695
  replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
18589
18696
  `, false);
18590
18697
  if (!dirs.shared) {
18591
- const ignore = path6.join(dirs.dir, ".gitignore");
18698
+ const ignore = path8.join(dirs.dir, ".gitignore");
18592
18699
  let current = null;
18593
18700
  try {
18594
- current = fs7.readFileSync(ignore, "utf8");
18701
+ current = fs8.readFileSync(ignore, "utf8");
18595
18702
  } catch {}
18596
18703
  if (current !== `*
18597
18704
  `)
18598
- retryTransient(() => fs7.writeFileSync(ignore, `*
18705
+ retryTransient(() => fs8.writeFileSync(ignore, `*
18599
18706
  `));
18600
18707
  }
18601
18708
  this.writeTombstoneIfMissing();
@@ -18611,7 +18718,7 @@ class TaskStore {
18611
18718
  shouldReclaim: ({ payload, nowMs }) => {
18612
18719
  let ageMs = null;
18613
18720
  try {
18614
- ageMs = nowMs - fs7.lstatSync(lockPath).mtimeMs;
18721
+ ageMs = nowMs - fs8.lstatSync(lockPath).mtimeMs;
18615
18722
  } catch {}
18616
18723
  return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
18617
18724
  },
@@ -18648,7 +18755,7 @@ class TaskStore {
18648
18755
  withLock(lockPath, operation) {
18649
18756
  try {
18650
18757
  this.initializeStorage();
18651
- fs7.mkdirSync(path6.dirname(lockPath), { recursive: true });
18758
+ fs8.mkdirSync(path8.dirname(lockPath), { recursive: true });
18652
18759
  } catch (error) {
18653
18760
  return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
18654
18761
  path: this.paths().dir
@@ -18688,18 +18795,18 @@ class TaskStore {
18688
18795
  lockDirWritable(lockPath) {
18689
18796
  const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
18690
18797
  try {
18691
- fs7.closeSync(fs7.openSync(probe, "wx", 384));
18798
+ fs8.closeSync(fs8.openSync(probe, "wx", 384));
18692
18799
  } catch {
18693
18800
  return false;
18694
18801
  }
18695
18802
  try {
18696
- fs7.rmSync(probe, { force: true });
18803
+ fs8.rmSync(probe, { force: true });
18697
18804
  } catch {}
18698
18805
  return true;
18699
18806
  }
18700
18807
  lockHolderPresent(lockPath) {
18701
18808
  try {
18702
- fs7.lstatSync(lockPath);
18809
+ fs8.lstatSync(lockPath);
18703
18810
  return true;
18704
18811
  } catch (error) {
18705
18812
  return error?.code !== "ENOENT";
@@ -18711,12 +18818,12 @@ class TaskStore {
18711
18818
  if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
18712
18819
  return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
18713
18820
  path: lockPath,
18714
- guidance: `Check permissions and the read-only attribute on ${path6.dirname(lockPath)}.`
18821
+ guidance: `Check permissions and the read-only attribute on ${path8.dirname(lockPath)}.`
18715
18822
  });
18716
18823
  if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
18717
18824
  let lock = null;
18718
18825
  try {
18719
- lock = parseMetadataLockOrNull(fs7.readFileSync(lockPath, "utf8"));
18826
+ lock = parseMetadataLockOrNull(fs8.readFileSync(lockPath, "utf8"));
18720
18827
  } catch {}
18721
18828
  return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
18722
18829
  outcome: "not_started",
@@ -18734,15 +18841,15 @@ var isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state);
18734
18841
  var workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state);
18735
18842
 
18736
18843
  // packages/workit-core/src/core/task-evaluation.ts
18737
- import { createHash as createHash9 } from "node:crypto";
18738
- import * as fs12 from "node:fs";
18844
+ import { createHash as createHash10 } from "node:crypto";
18845
+ import * as fs13 from "node:fs";
18739
18846
  import { spawnSync as spawnSync10 } from "node:child_process";
18740
- import path14 from "node:path";
18847
+ import path16 from "node:path";
18741
18848
 
18742
18849
  // packages/workit-core/src/check-config.ts
18743
18850
  import { spawnSync as spawnSync3 } from "node:child_process";
18744
- import fs8 from "node:fs";
18745
- import path7 from "node:path";
18851
+ import fs9 from "node:fs";
18852
+ import path9 from "node:path";
18746
18853
  var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
18747
18854
  var CHECKS_FILE = "workit.checks.json";
18748
18855
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -18795,10 +18902,10 @@ var git = (cwd, args) => {
18795
18902
  return value || null;
18796
18903
  };
18797
18904
  function checkRoot(cwd) {
18798
- return path7.resolve(git(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
18905
+ return path9.resolve(git(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
18799
18906
  }
18800
18907
  var packageManager = (root) => {
18801
- const has = (file) => fs8.existsSync(path7.join(root, file));
18908
+ const has = (file) => fs9.existsSync(path9.join(root, file));
18802
18909
  if (has("bun.lock") || has("bun.lockb"))
18803
18910
  return "bun";
18804
18911
  if (has("pnpm-lock.yaml"))
@@ -18818,7 +18925,7 @@ var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
18818
18925
  function detectedChecks(root) {
18819
18926
  const read = (file) => {
18820
18927
  try {
18821
- return fs8.readFileSync(path7.join(root, file), "utf8");
18928
+ return fs9.readFileSync(path9.join(root, file), "utf8");
18822
18929
  } catch {
18823
18930
  return null;
18824
18931
  }
@@ -18857,7 +18964,7 @@ function detectedChecks(root) {
18857
18964
  var GATES = ["testing", "verification"];
18858
18965
  function loadCheckConfig(cwd) {
18859
18966
  const root = checkRoot(cwd);
18860
- const file = path7.join(root, CHECKS_FILE);
18967
+ const file = path9.join(root, CHECKS_FILE);
18861
18968
  const none = (error = null) => ({
18862
18969
  source: error ? CHECKS_FILE : "none",
18863
18970
  root,
@@ -18867,7 +18974,7 @@ function loadCheckConfig(cwd) {
18867
18974
  });
18868
18975
  let text = null;
18869
18976
  try {
18870
- text = fs8.readFileSync(file, "utf8");
18977
+ text = fs9.readFileSync(file, "utf8");
18871
18978
  } catch (error) {
18872
18979
  if (error.code !== "ENOENT")
18873
18980
  return none(`cannot read ${CHECKS_FILE}: ${error.message}`);
@@ -18930,10 +19037,10 @@ function workitAvailable(env = process.env) {
18930
19037
  return workitOnPath;
18931
19038
  const windows = process.platform === "win32";
18932
19039
  const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
18933
- const dirs = (env.PATH ?? env.Path ?? "").split(path7.delimiter).filter(Boolean);
19040
+ const dirs = (env.PATH ?? env.Path ?? "").split(path9.delimiter).filter(Boolean);
18934
19041
  workitOnPath = dirs.some((dir) => exts.some((ext) => {
18935
19042
  try {
18936
- return fs8.statSync(path7.join(dir, `workit${ext}`)).isFile();
19043
+ return fs9.statSync(path9.join(dir, `workit${ext}`)).isFile();
18937
19044
  } catch {
18938
19045
  return false;
18939
19046
  }
@@ -18946,10 +19053,10 @@ function checkCommand(args, version, onPath = workitAvailable()) {
18946
19053
 
18947
19054
  // packages/workit-core/src/git/rev.ts
18948
19055
  import { spawnSync as spawnSync4 } from "node:child_process";
18949
- import { createHash as createHash5 } from "node:crypto";
18950
- import fs9 from "node:fs";
19056
+ import { createHash as createHash6 } from "node:crypto";
19057
+ import fs10 from "node:fs";
18951
19058
  import os2 from "node:os";
18952
- import path8 from "node:path";
19059
+ import path10 from "node:path";
18953
19060
  var MAX_BUFFER = 256 * 1024 * 1024;
18954
19061
  var GIT_TIMEOUTS = { local: 20000, worktree: 120000, network: 15000 };
18955
19062
  var git2 = (cwd, args, options = {}) => {
@@ -18984,10 +19091,10 @@ function headSha(cwd) {
18984
19091
  var emptyTree = (cwd) => line(git2(cwd, ["mktree"], { input: "" }));
18985
19092
  var MAX_UNTRACKED_BYTES = 5 * 1024 * 1024;
18986
19093
  var seedIndex = (from, to) => {
18987
- fs9.copyFileSync(from, to);
18988
- const { atimeNs, mtimeNs } = fs9.statSync(from, { bigint: true });
19094
+ fs10.copyFileSync(from, to);
19095
+ const { atimeNs, mtimeNs } = fs10.statSync(from, { bigint: true });
18989
19096
  const seconds = (ns) => (Number(ns / 1000n) - 1) / 1e6;
18990
- fs9.utimesSync(to, seconds(atimeNs), seconds(mtimeNs));
19097
+ fs10.utimesSync(to, seconds(atimeNs), seconds(mtimeNs));
18991
19098
  };
18992
19099
  function worktreeTree(cwd, options = {}) {
18993
19100
  const top = line(git2(cwd, ["rev-parse", "--show-toplevel"]));
@@ -18996,10 +19103,10 @@ function worktreeTree(cwd, options = {}) {
18996
19103
  return null;
18997
19104
  const cap = options.maxUntrackedBytes ?? MAX_UNTRACKED_BYTES;
18998
19105
  const timeoutMs = options.timeoutMs ?? GIT_TIMEOUTS.worktree;
18999
- const scratch = fs9.mkdtempSync(path8.join(os2.tmpdir(), "workit-tree-"));
19106
+ const scratch = fs10.mkdtempSync(path10.join(os2.tmpdir(), "workit-tree-"));
19000
19107
  try {
19001
- const tempIndex = path8.join(scratch, "index");
19002
- if (fs9.existsSync(indexPath))
19108
+ const tempIndex = path10.join(scratch, "index");
19109
+ if (fs10.existsSync(indexPath))
19003
19110
  seedIndex(indexPath, tempIndex);
19004
19111
  const env = { ...process.env, GIT_INDEX_FILE: tempIndex };
19005
19112
  const untracked = git2(top, ["ls-files", "--others", "--exclude-standard", "-z"], {
@@ -19011,7 +19118,7 @@ function worktreeTree(cwd, options = {}) {
19011
19118
  const skipped = [];
19012
19119
  for (const file of untracked.stdout.split("\x00").filter(Boolean)) {
19013
19120
  try {
19014
- const stat = fs9.statSync(path8.join(top, file));
19121
+ const stat = fs10.statSync(path10.join(top, file));
19015
19122
  if (stat.isFile() && stat.size > cap)
19016
19123
  skipped.push({ path: file, size: stat.size, mtimeMs: Math.trunc(stat.mtimeMs) });
19017
19124
  } catch {}
@@ -19028,10 +19135,10 @@ function worktreeTree(cwd, options = {}) {
19028
19135
  if (!tree)
19029
19136
  return null;
19030
19137
  const base = line(git2(top, ["rev-parse", "--verify", "-q", "HEAD^{tree}"])) ?? emptyTree(top);
19031
- const key = skipped.length ? `sha256:${createHash5("sha256").update(JSON.stringify({ tree, skipped })).digest("hex")}` : tree;
19138
+ const key = skipped.length ? `sha256:${createHash6("sha256").update(JSON.stringify({ tree, skipped })).digest("hex")}` : tree;
19032
19139
  return { tree, key, dirty: tree !== base || skipped.length > 0, skipped };
19033
19140
  } finally {
19034
- fs9.rmSync(scratch, { recursive: true, force: true });
19141
+ fs10.rmSync(scratch, { recursive: true, force: true });
19035
19142
  }
19036
19143
  }
19037
19144
  function worktreeSignal(cwd, options = {}) {
@@ -19051,16 +19158,16 @@ function worktreeSignal(cwd, options = {}) {
19051
19158
  });
19052
19159
  if (!status.ok)
19053
19160
  return null;
19054
- const hash = createHash5("sha256");
19161
+ const hash = createHash6("sha256");
19055
19162
  hash.update(`${headSha(top) ?? "unborn"}\x00`);
19056
19163
  for (const entry of status.stdout.split("\x00")) {
19057
19164
  if (entry.length < 4)
19058
19165
  continue;
19059
19166
  const file = entry.slice(3);
19060
- const absolute = path8.join(top, file);
19167
+ const absolute = path10.join(top, file);
19061
19168
  let stat = "-";
19062
19169
  try {
19063
- const info = fs9.lstatSync(absolute, { bigint: true });
19170
+ const info = fs10.lstatSync(absolute, { bigint: true });
19064
19171
  stat = `${info.mode.toString(8)}:${info.size}:${info.mtimeNs}`;
19065
19172
  if (info.isDirectory())
19066
19173
  stat += `:${headSha(absolute) ?? "-"}`;
@@ -19127,17 +19234,17 @@ function pushRemoteName(cwd, branch) {
19127
19234
 
19128
19235
  // packages/workit-core/src/core/policy/derive.ts
19129
19236
  import { existsSync as existsSync4 } from "node:fs";
19130
- import path13 from "node:path";
19237
+ import path15 from "node:path";
19131
19238
 
19132
19239
  // packages/workit-core/src/ledger.ts
19133
19240
  import { spawnSync as spawnSync9 } from "node:child_process";
19134
- import { createHash as createHash8, randomBytes as randomBytes2 } from "node:crypto";
19135
- import fs11 from "node:fs";
19136
- import path12 from "node:path";
19241
+ import { createHash as createHash9, randomBytes as randomBytes3 } from "node:crypto";
19242
+ import fs12 from "node:fs";
19243
+ import path14 from "node:path";
19137
19244
 
19138
19245
  // packages/workit-core/src/core/vcs-config.ts
19139
- import fs10 from "node:fs";
19140
- import path11 from "node:path";
19246
+ import fs11 from "node:fs";
19247
+ import path13 from "node:path";
19141
19248
  import { spawnSync as spawnSync8 } from "node:child_process";
19142
19249
 
19143
19250
  // packages/workit-core/src/core/config.ts
@@ -19151,7 +19258,7 @@ import {
19151
19258
  writeFileSync as writeFileSync2
19152
19259
  } from "node:fs";
19153
19260
  import os3 from "node:os";
19154
- import path9 from "node:path";
19261
+ import path11 from "node:path";
19155
19262
 
19156
19263
  // packages/workit-core/src/core/boundary.ts
19157
19264
  import { statSync as statSync2 } from "node:fs";
@@ -19210,7 +19317,7 @@ var mergePreset = (preset, input = {}, current = {
19210
19317
  protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
19211
19318
  };
19212
19319
  };
19213
- var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path9.join(process.env.XDG_CONFIG_HOME || path9.join(os3.homedir(), ".config"), "workit");
19320
+ var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path11.join(process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config"), "workit");
19214
19321
  var migratedDir = null;
19215
19322
  var migrationFailed = false;
19216
19323
  var ensureConfigDir = (dir = resolveConfigDir()) => {
@@ -19220,7 +19327,7 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
19220
19327
  migratedDir = dir;
19221
19328
  return dir;
19222
19329
  }
19223
- const legacy = path9.join(process.env.XDG_CONFIG_HOME || path9.join(os3.homedir(), ".config"), "workflow-toolkit");
19330
+ const legacy = path11.join(process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config"), "workflow-toolkit");
19224
19331
  if (!existsSync3(legacy)) {
19225
19332
  migratedDir = dir;
19226
19333
  return dir;
@@ -19233,8 +19340,8 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
19233
19340
  mkdirSync2(dir, { recursive: true });
19234
19341
  diagnosticLogger?.info(EVENT.migration, { from: legacy, to: dir });
19235
19342
  for (const entry of readdirSync2(legacy, { withFileTypes: true })) {
19236
- const src = path9.join(legacy, entry.name);
19237
- const dest = path9.join(dir, entry.name);
19343
+ const src = path11.join(legacy, entry.name);
19344
+ const dest = path11.join(dir, entry.name);
19238
19345
  if (existsSync3(dest))
19239
19346
  continue;
19240
19347
  try {
@@ -19306,7 +19413,7 @@ var parseConfigResult = (raw, file) => {
19306
19413
  return { status: "valid", path: file, config };
19307
19414
  };
19308
19415
  var readConfigTyped = (dir) => {
19309
- const file = path9.join(dir ?? configDir(), "config.json");
19416
+ const file = path11.join(dir ?? configDir(), "config.json");
19310
19417
  return parseConfigResult(readSafe(file), file);
19311
19418
  };
19312
19419
  var readConfig = () => {
@@ -19315,7 +19422,7 @@ var readConfig = () => {
19315
19422
  throw new Error(result.error);
19316
19423
  return result.config ?? DEFAULTS;
19317
19424
  };
19318
- var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path9.join(configDir(), "vcs.json");
19425
+ var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path11.join(configDir(), "vcs.json");
19319
19426
  var branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i");
19320
19427
  var resolveBranchPolicy = (config, workspace, repoPreset) => {
19321
19428
  const wp = workspace?.branchPolicy ?? {};
@@ -19347,9 +19454,9 @@ var COMMIT_PRESETS = [
19347
19454
 
19348
19455
  // packages/workit-core/src/core/workspaces.ts
19349
19456
  import { spawnSync as spawnSync6 } from "node:child_process";
19350
- import { createHash as createHash6 } from "node:crypto";
19457
+ import { createHash as createHash7 } from "node:crypto";
19351
19458
  import { readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
19352
- import path10 from "node:path";
19459
+ import path12 from "node:path";
19353
19460
 
19354
19461
  // packages/workit-core/src/core/branch-policy.ts
19355
19462
  import { spawnSync as spawnSync5 } from "node:child_process";
@@ -19474,7 +19581,7 @@ var releaseTrackSchema = object({
19474
19581
  context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
19475
19582
  }
19476
19583
  }
19477
- if (track.versionSource?.kind === "package-json" && (path10.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
19584
+ if (track.versionSource?.kind === "package-json" && (path12.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
19478
19585
  context.addIssue({
19479
19586
  code: "custom",
19480
19587
  path: ["versionSource", "path"],
@@ -19495,6 +19602,8 @@ var workspaceConfigSchema = object({
19495
19602
  defaultEndpoint: unknown().optional(),
19496
19603
  verification: _enum(["self", "independent"]).optional(),
19497
19604
  trailers: boolean2().optional(),
19605
+ liveSessionGuard: boolean2().optional(),
19606
+ fanout: object({ tierModels: unknown().optional() }).passthrough().optional(),
19498
19607
  autonomy: object(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
19499
19608
  kind,
19500
19609
  union([boolean2(), literal("verified")]).optional()
@@ -19535,7 +19644,7 @@ var workspacesFileSchema = object({ workspaces: array(workspaceConfigSchema).opt
19535
19644
  names.add(workspace.name);
19536
19645
  }
19537
19646
  });
19538
- var workspacesRevision = (contents) => createHash6("sha256").update(contents ?? "<missing>").digest("hex");
19647
+ var workspacesRevision = (contents) => createHash7("sha256").update(contents ?? "<missing>").digest("hex");
19539
19648
  var validateWorkspacesDocument = (parsed, file) => {
19540
19649
  if (!isConfigObject(parsed)) {
19541
19650
  return { status: "malformed", path: file, entries: [], error: `${file} is not a JSON object` };
@@ -19573,7 +19682,7 @@ var validateWorkspacesDocument = (parsed, file) => {
19573
19682
  };
19574
19683
  };
19575
19684
  var readWorkspacesResult = (dir = configDir()) => {
19576
- const file = path10.join(dir, "workspaces.json");
19685
+ const file = path12.join(dir, "workspaces.json");
19577
19686
  let raw;
19578
19687
  try {
19579
19688
  raw = readFileSync3(file, "utf8");
@@ -19684,9 +19793,9 @@ var mainCheckoutOf = (cwd) => {
19684
19793
  let main = null;
19685
19794
  const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
19686
19795
  const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
19687
- if (gitDir && common && path10.resolve(gitDir) !== path10.resolve(common)) {
19796
+ if (gitDir && common && path12.resolve(gitDir) !== path12.resolve(common)) {
19688
19797
  const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
19689
- main = listed?.trim() || (path10.basename(common) === ".git" ? path10.dirname(common) : common);
19798
+ main = listed?.trim() || (path12.basename(common) === ".git" ? path12.dirname(common) : common);
19690
19799
  }
19691
19800
  mainCheckouts.set(cwd, main);
19692
19801
  return main;
@@ -19777,7 +19886,7 @@ var runtimeWorkspaceIndexSchema = object({
19777
19886
  workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
19778
19887
  }).passthrough();
19779
19888
  var matchRuntimeWorkspace = (cwd, dir = configDir()) => {
19780
- const file = path10.join(dir, "workspaces.json");
19889
+ const file = path12.join(dir, "workspaces.json");
19781
19890
  let raw;
19782
19891
  try {
19783
19892
  raw = readFileSync3(file, "utf8");
@@ -19812,6 +19921,17 @@ var resolveRuntimeReleaseTracks = (cwd) => {
19812
19921
  const matched = matchRuntimeWorkspace(cwd);
19813
19922
  return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
19814
19923
  };
19924
+ var TIER_KEYS = new Set(["mundane", "standard", "hard"]);
19925
+ var TIER_HOSTS = new Set([
19926
+ "claude_code",
19927
+ "opencode",
19928
+ "codex",
19929
+ "codex_cli",
19930
+ "codex_desktop",
19931
+ "cursor",
19932
+ "pi",
19933
+ "default"
19934
+ ]);
19815
19935
  var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
19816
19936
  const matched = matchRuntimeWorkspace(cwd);
19817
19937
  if (!matched)
@@ -19852,7 +19972,7 @@ function workspaceDefaultTarget(cwd, globalDefault) {
19852
19972
  }
19853
19973
 
19854
19974
  // packages/workit-core/src/core/release-tracks.ts
19855
- import { createHash as createHash7 } from "node:crypto";
19975
+ import { createHash as createHash8 } from "node:crypto";
19856
19976
  import { spawnSync as spawnSync7 } from "node:child_process";
19857
19977
  var KNOWN_FIELDS = new Set([
19858
19978
  "strategy",
@@ -20222,7 +20342,7 @@ function resolveTrackFor(cwd, options) {
20222
20342
  ]) ?? "",
20223
20343
  git3(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
20224
20344
  ] : [];
20225
- key = createHash7("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
20345
+ key = createHash8("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
20226
20346
  const hit = memo2.get(key);
20227
20347
  if (hit)
20228
20348
  return hit;
@@ -20237,7 +20357,7 @@ function resolveTrackFor(cwd, options) {
20237
20357
  }
20238
20358
 
20239
20359
  // packages/workit-core/src/core/vcs-config.ts
20240
- var workspacesPath = () => path11.join(configDir(), "workspaces.json");
20360
+ var workspacesPath = () => path13.join(configDir(), "workspaces.json");
20241
20361
  var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
20242
20362
  var remoteProvider = (cwd) => {
20243
20363
  const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
@@ -20327,7 +20447,7 @@ var readVcsConfig = () => {
20327
20447
  const file = vcsConfigPath();
20328
20448
  let raw;
20329
20449
  try {
20330
- raw = fs10.readFileSync(file, "utf8");
20450
+ raw = fs11.readFileSync(file, "utf8");
20331
20451
  } catch {
20332
20452
  return { status: "missing", path: file, config: {} };
20333
20453
  }
@@ -20412,7 +20532,7 @@ function vcsConfig(mode, cwd, options = {}) {
20412
20532
  const prov = cfg[provider] ?? {};
20413
20533
  const out = {
20414
20534
  ok: true,
20415
- configPath: path11.resolve(cfgPath),
20535
+ configPath: path13.resolve(cfgPath),
20416
20536
  provider,
20417
20537
  defaultTargetBranch: workspaceDefault,
20418
20538
  pr: cfg.pr ?? {},
@@ -20623,7 +20743,7 @@ function diffHash(cwd, base, head) {
20623
20743
  ], GIT_TIMEOUTS.worktree);
20624
20744
  if (!diff.ok || !diff.stdout)
20625
20745
  return null;
20626
- const hash = createHash8("sha256");
20746
+ const hash = createHash9("sha256");
20627
20747
  for (const line of diff.stdout.split(`
20628
20748
  `)) {
20629
20749
  if (line.startsWith("index "))
@@ -20635,16 +20755,16 @@ function diffHash(cwd, base, head) {
20635
20755
  return `sha256:${hash.digest("hex")}`;
20636
20756
  }
20637
20757
  function storeRoot(cwd) {
20638
- const location = resolveStore(path12.resolve(cwd));
20758
+ const location = resolveStore(path14.resolve(cwd));
20639
20759
  if (location instanceof Error)
20640
20760
  return err("unavailable", location.message.replace(/; fix the repository.*$/u, ""), "fix the repository (git status should work here) or run from a non-git directory");
20641
20761
  return { ok: true, value: { root: location.dir, shared: location.shared } };
20642
20762
  }
20643
20763
  function ledgerPath(cwd) {
20644
20764
  const root = storeRoot(cwd);
20645
- return root.ok ? { ok: true, value: path12.join(root.value.root, "ledger", "ledger.jsonl") } : root;
20765
+ return root.ok ? { ok: true, value: path14.join(root.value.root, "ledger", "ledger.jsonl") } : root;
20646
20766
  }
20647
- var newId2 = () => `${Date.now().toString(36)}-${randomBytes2(6).toString("hex")}`;
20767
+ var newId2 = () => `${Date.now().toString(36)}-${randomBytes3(6).toString("hex")}`;
20648
20768
  var NETWORK_FS_TYPES = new Set([
20649
20769
  26985,
20650
20770
  20859,
@@ -20662,7 +20782,7 @@ var onNetworkFs = (dir) => {
20662
20782
  if (process.platform !== "linux")
20663
20783
  return false;
20664
20784
  try {
20665
- return isNetworkFsType(fs11.statfsSync(dir).type);
20785
+ return isNetworkFsType(fs12.statfsSync(dir).type);
20666
20786
  } catch {
20667
20787
  return false;
20668
20788
  }
@@ -20672,15 +20792,15 @@ var LOCK_STALE_MS = 30000;
20672
20792
  var LOCK_OWNER = "owner";
20673
20793
  var lockToken = (lock) => {
20674
20794
  try {
20675
- return fs11.readFileSync(path12.join(lock, LOCK_OWNER), "utf8");
20795
+ return fs12.readFileSync(path14.join(lock, LOCK_OWNER), "utf8");
20676
20796
  } catch {
20677
20797
  return null;
20678
20798
  }
20679
20799
  };
20680
20800
  var lockAgeMs = (lock) => {
20681
- for (const target of [path12.join(lock, LOCK_OWNER), lock]) {
20801
+ for (const target of [path14.join(lock, LOCK_OWNER), lock]) {
20682
20802
  try {
20683
- return Date.now() - fs11.statSync(target).mtimeMs;
20803
+ return Date.now() - fs12.statSync(target).mtimeMs;
20684
20804
  } catch {}
20685
20805
  }
20686
20806
  return null;
@@ -20688,55 +20808,55 @@ var lockAgeMs = (lock) => {
20688
20808
  var ledgerLock = {
20689
20809
  acquire(lock) {
20690
20810
  try {
20691
- fs11.mkdirSync(lock);
20811
+ fs12.mkdirSync(lock);
20692
20812
  } catch (error) {
20693
20813
  if (error.code === "EEXIST")
20694
20814
  return null;
20695
20815
  throw error;
20696
20816
  }
20697
- const token = `${process.pid}-${randomBytes2(8).toString("hex")}`;
20698
- fs11.writeFileSync(path12.join(lock, LOCK_OWNER), token);
20817
+ const token = `${process.pid}-${randomBytes3(8).toString("hex")}`;
20818
+ fs12.writeFileSync(path14.join(lock, LOCK_OWNER), token);
20699
20819
  return token;
20700
20820
  },
20701
20821
  release(lock, token) {
20702
20822
  if (lockToken(lock) !== token)
20703
20823
  return false;
20704
- const tomb = `${lock}.release-${randomBytes2(6).toString("hex")}`;
20824
+ const tomb = `${lock}.release-${randomBytes3(6).toString("hex")}`;
20705
20825
  try {
20706
- fs11.renameSync(lock, tomb);
20826
+ fs12.renameSync(lock, tomb);
20707
20827
  } catch {
20708
20828
  return false;
20709
20829
  }
20710
20830
  if (lockToken(tomb) !== token) {
20711
20831
  try {
20712
- fs11.renameSync(tomb, lock);
20832
+ fs12.renameSync(tomb, lock);
20713
20833
  } catch {}
20714
20834
  return false;
20715
20835
  }
20716
- fs11.rmSync(tomb, { recursive: true, force: true });
20836
+ fs12.rmSync(tomb, { recursive: true, force: true });
20717
20837
  return true;
20718
20838
  },
20719
20839
  token: lockToken,
20720
20840
  reap(lock, observed) {
20721
- const tomb = `${lock}.reap-${randomBytes2(6).toString("hex")}`;
20841
+ const tomb = `${lock}.reap-${randomBytes3(6).toString("hex")}`;
20722
20842
  try {
20723
- fs11.renameSync(lock, tomb);
20843
+ fs12.renameSync(lock, tomb);
20724
20844
  } catch {
20725
20845
  return false;
20726
20846
  }
20727
20847
  if (lockToken(tomb) === observed) {
20728
- fs11.rmSync(tomb, { recursive: true, force: true });
20848
+ fs12.rmSync(tomb, { recursive: true, force: true });
20729
20849
  return true;
20730
20850
  }
20731
20851
  try {
20732
- fs11.renameSync(tomb, lock);
20852
+ fs12.renameSync(tomb, lock);
20733
20853
  } catch {
20734
- fs11.rmSync(tomb, { recursive: true, force: true });
20854
+ fs12.rmSync(tomb, { recursive: true, force: true });
20735
20855
  }
20736
20856
  return false;
20737
20857
  }
20738
20858
  };
20739
- function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
20859
+ function withLedgerLock(file, fn, waitMs = hostAwareLockTimeout(LOCK_WAIT_MS)) {
20740
20860
  const lock = `${file}.lock`;
20741
20861
  const deadline = Date.now() + waitMs;
20742
20862
  let token = null;
@@ -20758,14 +20878,14 @@ function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
20758
20878
  ledgerLock.release(lock, token);
20759
20879
  }
20760
20880
  }
20761
- var sha2562 = (text) => createHash8("sha256").update(text).digest("hex");
20881
+ var sha2562 = (text) => createHash9("sha256").update(text).digest("hex");
20762
20882
  var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
20763
20883
  ${body}`);
20764
20884
  var TAIL_BYTES = 64 * 1024;
20765
20885
  var lastLine = (fd, size) => {
20766
20886
  for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
20767
20887
  const buffer = Buffer.alloc(span);
20768
- fs11.readSync(fd, buffer, 0, span, size - span);
20888
+ fs12.readSync(fd, buffer, 0, span, size - span);
20769
20889
  const end = buffer.lastIndexOf(10);
20770
20890
  if (end < 0) {
20771
20891
  if (span === size)
@@ -20794,15 +20914,23 @@ var lastLine = (fd, size) => {
20794
20914
  }
20795
20915
  return null;
20796
20916
  };
20917
+ var tighten = (fd) => {
20918
+ try {
20919
+ if ((fs12.fstatSync(fd).mode & 63) !== 0)
20920
+ fs12.fchmodSync(fd, 384);
20921
+ } catch {}
20922
+ };
20797
20923
  function appendLine(file, build, options) {
20798
20924
  const write = () => {
20799
- const fd = fs11.openSync(file, "a+");
20925
+ const fd = fs12.openSync(file, "a+", 384);
20800
20926
  try {
20801
- const size = fs11.fstatSync(fd).size;
20927
+ if (process.platform !== "win32")
20928
+ tighten(fd);
20929
+ const size = fs12.fstatSync(fd).size;
20802
20930
  let fence = "";
20803
20931
  if (size > 0) {
20804
20932
  const last = Buffer.alloc(1);
20805
- fs11.readSync(fd, last, 0, 1, size - 1);
20933
+ fs12.readSync(fd, last, 0, 1, size - 1);
20806
20934
  if (last[0] !== 10)
20807
20935
  fence = `
20808
20936
  `;
@@ -20811,17 +20939,17 @@ function appendLine(file, build, options) {
20811
20939
  if (!line.ok)
20812
20940
  return line;
20813
20941
  const bytes = Buffer.from(fence + line.value);
20814
- const written = fs11.writeSync(fd, bytes);
20942
+ const written = fs12.writeSync(fd, bytes);
20815
20943
  if (written !== bytes.length)
20816
20944
  return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
20817
20945
  return { ok: true, value: undefined };
20818
20946
  } finally {
20819
- fs11.closeSync(fd);
20947
+ fs12.closeSync(fd);
20820
20948
  }
20821
20949
  };
20822
20950
  try {
20823
- fs11.mkdirSync(path12.dirname(file), { recursive: true });
20824
- if (!options.forceLock && !onNetworkFs(path12.dirname(file)))
20951
+ fs12.mkdirSync(path14.dirname(file), { recursive: true });
20952
+ if (!options.forceLock && !onNetworkFs(path14.dirname(file)))
20825
20953
  return write();
20826
20954
  const locked = withLedgerLock(file, write);
20827
20955
  return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
@@ -20889,8 +21017,10 @@ function readLedger(cwd, options = {}) {
20889
21017
  if (!file.ok)
20890
21018
  return file;
20891
21019
  let text = "";
21020
+ let stat = null;
20892
21021
  try {
20893
- text = fs11.readFileSync(file.value, "utf8");
21022
+ stat = fs12.statSync(file.value);
21023
+ text = fs12.readFileSync(file.value, "utf8");
20894
21024
  } catch (error) {
20895
21025
  if (error.code === "ENOENT")
20896
21026
  return {
@@ -20909,6 +21039,7 @@ function readLedger(cwd, options = {}) {
20909
21039
  const integrity = { chained: 0, legacy: 0, unverified: [] };
20910
21040
  const earlier = new Set([null]);
20911
21041
  let chainStarted = false;
21042
+ const ids = new Set;
20912
21043
  for (const raw of text.split(`
20913
21044
  `)) {
20914
21045
  const trimmed = raw.trim();
@@ -20942,6 +21073,10 @@ function readLedger(cwd, options = {}) {
20942
21073
  reason = "unsigned";
20943
21074
  else
20944
21075
  rowIntegrity = "legacy";
21076
+ if (options.integrity && !reason && ids.has(parsed.id))
21077
+ reason = "duplicate_id";
21078
+ if (options.integrity)
21079
+ ids.add(parsed.id);
20945
21080
  if (reason)
20946
21081
  rowIntegrity = "unverified";
20947
21082
  const pr = typeof parsed.pr === "number" && Number.isInteger(parsed.pr) ? parsed.pr : undefined;
@@ -20965,7 +21100,8 @@ function readLedger(cwd, options = {}) {
20965
21100
  seq: rows.length + 1,
20966
21101
  superseded: false,
20967
21102
  supersedeIgnored: false,
20968
- ...rowIntegrity ? { integrity: rowIntegrity } : {}
21103
+ ...rowIntegrity ? { integrity: rowIntegrity } : {},
21104
+ ...reason ? { integrityReason: reason } : {}
20969
21105
  };
20970
21106
  rows.push(row);
20971
21107
  if (!options.integrity)
@@ -20993,18 +21129,48 @@ function readLedger(cwd, options = {}) {
20993
21129
  const byId = new Map;
20994
21130
  for (const row of rows) {
20995
21131
  const target = row.supersedes ? byId.get(row.supersedes) : undefined;
20996
- if (target && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
21132
+ if (target && row.integrity !== "unverified" && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
20997
21133
  target.superseded = true;
20998
21134
  else if (row.supersedes)
20999
21135
  row.supersedeIgnored = true;
21000
21136
  if (!byId.has(row.id))
21001
21137
  byId.set(row.id, row);
21002
21138
  }
21139
+ if (options.integrity && stat && Buffer.byteLength(text) === stat.size)
21140
+ tamperCache.set(file.value, {
21141
+ size: stat.size,
21142
+ stamp: fileStamp(stat),
21143
+ breaks: integrity.unverified.filter((row) => TAMPER_REASONS.has(row.reason))
21144
+ });
21003
21145
  return {
21004
21146
  ok: true,
21005
21147
  value: { path: file.value, rows, skipped, integrity: options.integrity ? integrity : null }
21006
21148
  };
21007
21149
  }
21150
+ var TAMPER_REASONS = new Set(["hash_mismatch", "broken_link"]);
21151
+ var tamperCache = new Map;
21152
+ var fileStamp = (stat) => `${stat.ino}:${stat.mtimeMs}:${stat.ctimeMs}`;
21153
+ function ledgerTampering(cwd) {
21154
+ const file = ledgerPath(cwd);
21155
+ if (!file.ok)
21156
+ return [];
21157
+ try {
21158
+ const stat = fs12.statSync(file.value);
21159
+ const cached = tamperCache.get(file.value);
21160
+ if (cached && cached.size === stat.size && cached.stamp === fileStamp(stat))
21161
+ return cached.breaks;
21162
+ } catch {
21163
+ return [];
21164
+ }
21165
+ const read = readLedger(cwd, { integrity: true });
21166
+ return read.ok ? (read.value.integrity?.unverified ?? []).filter((row) => TAMPER_REASONS.has(row.reason)) : [];
21167
+ }
21168
+ function tamperedUnblock(cwd) {
21169
+ const file = ledgerPath(cwd);
21170
+ const where = file.ok ? file.value : "the ledger file";
21171
+ return `workit ledger verify-integrity # lists the edited or missing rows; if the edit is understood, move ${where} aside (mv ${where} ${where}.tampered-<date>) and record the verdicts again`;
21172
+ }
21173
+ var tamperedWarning = (cwd, breaks) => `the ledger was edited, or a row was removed or moved (${breaks.slice(0, 3).map((row) => `${row.reason} at row ${row.seq}`).join(", ")}${breaks.length > 3 ? ", …" : ""}): no verdict is accepted until it is repaired. ${tamperedUnblock(cwd)}`;
21008
21174
  function verdictBasis(verdict, current) {
21009
21175
  if (verdict.head && verdict.head === current.head)
21010
21176
  return "fresh";
@@ -21012,7 +21178,7 @@ function verdictBasis(verdict, current) {
21012
21178
  return "carried";
21013
21179
  return "stale";
21014
21180
  }
21015
- var isLiveVerdict = (row) => row.type === "verdict" && typeof row.result === "string" && !row.superseded;
21181
+ var isLiveVerdict = (row, retired) => row.type === "verdict" && typeof row.result === "string" && !retired.has(row.id);
21016
21182
  function trailerSessions(cwd, base, head) {
21017
21183
  if (!base || !head || !safeRef(base) || !safeRef(head))
21018
21184
  return [];
@@ -21093,6 +21259,56 @@ var authoredBy = (authors, session) => {
21093
21259
  return true;
21094
21260
  return false;
21095
21261
  };
21262
+ var TRUST_REASONS = new Set([
21263
+ "unsigned",
21264
+ "hash_mismatch",
21265
+ "broken_link",
21266
+ "duplicate_id",
21267
+ "unissued_session",
21268
+ "unbound_session"
21269
+ ]);
21270
+ var SHELL_VOUCHED_HOSTS = new Set([
21271
+ "cli",
21272
+ "opencode",
21273
+ "pi",
21274
+ "codex_cli",
21275
+ "codex_desktop"
21276
+ ]);
21277
+ function sessionTrust(cwd, row) {
21278
+ const session = row.actor.session;
21279
+ if (!session || row.self === true)
21280
+ return null;
21281
+ const source = typeof row.sessionSource === "string" ? row.sessionSource : "env";
21282
+ const host = row.actor.host;
21283
+ const issuedOnly = source === "flag" ? host !== "cli" : source === "env" && session.includes(":") && !SHELL_VOUCHED_HOSTS.has(host);
21284
+ if (!issuedOnly)
21285
+ return null;
21286
+ const binding = issuedBinding(cwd, session);
21287
+ if (binding === null)
21288
+ return "unissued_session";
21289
+ return binding === "token" && row.sessionBound !== true ? "unbound_session" : null;
21290
+ }
21291
+ function trustReasons(cwd, row) {
21292
+ if (row.integrity === "unverified")
21293
+ return [row.integrityReason ?? "unsigned"];
21294
+ if (row.integrity !== "verified")
21295
+ return ["unsigned"];
21296
+ const session = sessionTrust(cwd, row);
21297
+ return session ? [session] : [];
21298
+ }
21299
+ function withIntegrity(cwd, rows) {
21300
+ if (rows.every((row) => row.integrity !== undefined))
21301
+ return rows;
21302
+ const read = readLedger(cwd, { integrity: true });
21303
+ const bySeq = new Map(read.ok ? read.value.rows.map((row) => [row.seq, row]) : []);
21304
+ return rows.map((row) => {
21305
+ if (row.integrity !== undefined)
21306
+ return row;
21307
+ const fresh = bySeq.get(row.seq);
21308
+ return fresh && fresh.id === row.id && fresh.at === row.at ? fresh : row;
21309
+ });
21310
+ }
21311
+ var untrusted = (reasons) => reasons.some((reason) => TRUST_REASONS.has(reason));
21096
21312
  var independenceReasons = (row, authors) => {
21097
21313
  const reasons = [];
21098
21314
  if (!row.actor.session)
@@ -21103,15 +21319,17 @@ var independenceReasons = (row, authors) => {
21103
21319
  reasons.push("self");
21104
21320
  return reasons;
21105
21321
  };
21106
- function effectiveOf(rows, authors, sameCode, isCurrent) {
21322
+ function effectiveOf(rows, reasonsOf, sameCode, isCurrent) {
21107
21323
  let effective = null;
21108
21324
  for (const row of rows) {
21109
21325
  if (!effective) {
21110
21326
  effective = row;
21111
21327
  continue;
21112
21328
  }
21113
- const rowIndependent = independenceReasons(row, authors).length === 0;
21114
- const effIndependent = independenceReasons(effective, authors).length === 0;
21329
+ if (untrusted(reasonsOf(row)) && !untrusted(reasonsOf(effective)))
21330
+ continue;
21331
+ const rowIndependent = reasonsOf(row).length === 0;
21332
+ const effIndependent = reasonsOf(effective).length === 0;
21115
21333
  if (effIndependent && !rowIndependent && isCurrent(effective))
21116
21334
  continue;
21117
21335
  if (effIndependent && FAILING.has(String(effective.result)) && row.actor.session === effective.actor.session && sameCode(effective, row))
@@ -21125,7 +21343,7 @@ function restackCarries(rows, branch, from, to) {
21125
21343
  return false;
21126
21344
  const edges = new Map;
21127
21345
  for (const row of rows)
21128
- if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
21346
+ if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.integrity === "verified" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
21129
21347
  edges.set(row.fromHead, [...edges.get(row.fromHead) ?? [], row.head]);
21130
21348
  const seen = new Set([from]);
21131
21349
  const queue = [from];
@@ -21141,7 +21359,8 @@ function restackCarries(rows, branch, from, to) {
21141
21359
  }
21142
21360
  return false;
21143
21361
  }
21144
- function checkVerdicts(cwd, branch, rows) {
21362
+ function checkVerdicts(cwd, branch, ledgerRows) {
21363
+ const rows = withIntegrity(cwd, ledgerRows);
21145
21364
  const head = branchHead(cwd, branch);
21146
21365
  const fallbackBase = defaultBase(cwd);
21147
21366
  const scope = branchScope(cwd, branch);
@@ -21171,21 +21390,47 @@ function checkVerdicts(cwd, branch, rows) {
21171
21390
  return verdictBasis(failed, { head: row.head, ...keys }) !== "stale" || restackCarries(rows, branch, failed.head, row.head);
21172
21391
  };
21173
21392
  const authors = authorSessions(cwd, rows, branch, { base: fallbackBase, head }, scope);
21393
+ const failureAuthorCache = new Map;
21394
+ const failureAuthors = (row) => {
21395
+ let set = failureAuthorCache.get(row.seq);
21396
+ if (!set) {
21397
+ set = authorSessions(cwd, rows.filter((other) => other.integrity === "verified" && other.seq < row.seq), branch, { base: null, head: null }, scope);
21398
+ failureAuthorCache.set(row.seq, set);
21399
+ }
21400
+ return set;
21401
+ };
21402
+ const reasonCache = new Map;
21403
+ const reasonsOf = (row) => {
21404
+ let reasons = reasonCache.get(row);
21405
+ if (!reasons) {
21406
+ const failing = FAILING.has(String(row.result));
21407
+ reasons = [
21408
+ ...trustReasons(cwd, row),
21409
+ ...independenceReasons(row, failing ? failureAuthors(row) : authors)
21410
+ ];
21411
+ reasonCache.set(row, reasons);
21412
+ }
21413
+ return reasons;
21414
+ };
21415
+ const retired = new Set;
21416
+ for (const row of rows)
21417
+ if (row.type === "verdict" && row.supersedes && !row.supersedeIgnored && trustReasons(cwd, row).length === 0)
21418
+ retired.add(row.supersedes);
21174
21419
  const byKind = new Map;
21175
21420
  for (const row of rows)
21176
- if (isLiveVerdict(row) && scope(row)) {
21421
+ if (isLiveVerdict(row, retired) && scope(row)) {
21177
21422
  const kind = typeof row.kind === "string" ? row.kind : "review";
21178
21423
  byKind.set(kind, [...byKind.get(kind) ?? [], row]);
21179
21424
  }
21180
21425
  const verdicts = [];
21181
21426
  const warnings = [];
21182
21427
  for (const [kind, list] of byKind) {
21183
- const row = effectiveOf(list, authors, sameCode, (candidate) => basisOf(candidate) !== "stale");
21428
+ const row = effectiveOf(list, reasonsOf, sameCode, (candidate) => basisOf(candidate) !== "stale");
21184
21429
  if (!row)
21185
21430
  continue;
21186
21431
  const basis = basisOf(row);
21187
21432
  const current = basis !== "stale";
21188
- const independence = independenceReasons(row, authors);
21433
+ const independence = reasonsOf(row);
21189
21434
  const reasons = [
21190
21435
  ...current ? [] : ["stale"],
21191
21436
  ...PASSING.has(String(row.result)) ? [] : ["not_passing"],
@@ -21202,23 +21447,31 @@ function checkVerdicts(cwd, branch, rows) {
21202
21447
  });
21203
21448
  if (reasons.length === 0) {
21204
21449
  for (const later of list)
21205
- if (later.seq > row.seq && independenceReasons(later, authors).length > 0 && FAILING.has(String(later.result)) && basisOf(later) !== "stale")
21450
+ if (later.seq > row.seq && reasonsOf(later).length > 0 && !untrusted(reasonsOf(later)) && FAILING.has(String(later.result)) && basisOf(later) !== "stale")
21206
21451
  warnings.push(`the author's own (self) ${String(later.result)} ${kind} verdict ${later.id} by ${later.actor.session ?? "no session"} on the current code is newer than the accepted pass ${row.id}: read it before merging`);
21207
21452
  }
21208
21453
  }
21209
21454
  for (const row of rows)
21210
21455
  if (row.integrity === "unverified" && scope(row))
21211
21456
  warnings.push(`ledger row ${row.id} (${row.type}) on ${row.branch ?? branch} is unverified: the workit CLI did not write it or it changed afterwards (workit ledger verify-integrity)`);
21457
+ const tampered = ledgerTampering(cwd);
21458
+ if (tampered.length) {
21459
+ warnings.push(tamperedWarning(cwd, tampered));
21460
+ for (const entry of verdicts) {
21461
+ entry.accepted = false;
21462
+ entry.reasons = [...entry.reasons, "ledger_tampered"];
21463
+ }
21464
+ }
21212
21465
  verdicts.sort((a, b) => a.verdict.seq - b.verdict.seq);
21213
21466
  const newestCurrent = verdicts.findLast((entry) => entry.current) ?? verdicts.at(-1) ?? null;
21214
21467
  const failing = verdicts.find((entry) => entry.current && entry.independent && FAILING.has(String(entry.verdict.result)));
21215
21468
  const newestAccepted = verdicts.findLast((entry) => entry.accepted && STRONG_RESULTS.has(String(entry.verdict.result))) ?? null;
21216
- const accepted = newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
21469
+ const accepted = tampered.length ? { accepted: false, verdict: null, reasons: ["ledger_tampered"] } : newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
21217
21470
  accepted: false,
21218
21471
  verdict: failing?.verdict ?? null,
21219
21472
  reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
21220
21473
  };
21221
- const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && STRONG_RESULTS.has(String(entry.verdict.result)));
21474
+ const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && !untrusted(entry.reasons) && STRONG_RESULTS.has(String(entry.verdict.result)));
21222
21475
  return {
21223
21476
  branch,
21224
21477
  head,
@@ -21381,7 +21634,7 @@ var productDecision = (task, ledger) => {
21381
21634
  };
21382
21635
  };
21383
21636
  var planRecorded = (task, root) => {
21384
- const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path13.resolve(root, ref.path)));
21637
+ const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path15.resolve(root, ref.path)));
21385
21638
  if (cited)
21386
21639
  return {
21387
21640
  met: true,
@@ -21429,15 +21682,15 @@ function derivedRuleStatus(task, requirement, root, ledger) {
21429
21682
  }
21430
21683
 
21431
21684
  // packages/workit-core/src/core/task-evaluation.ts
21432
- var digestBytes = (value) => createHash9("sha256").update(value).digest("hex");
21433
- var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path14.sep}`);
21434
- var relative = (root, candidate) => path14.relative(root, candidate).split(path14.sep).join("/") || ".";
21685
+ var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
21686
+ var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
21687
+ var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
21435
21688
  var canonicalPath = (value) => {
21436
21689
  if (typeof value !== "string" || !value)
21437
21690
  return null;
21438
21691
  if (value.includes("\\") || value.split("/").includes(".."))
21439
21692
  return null;
21440
- const normalized = path14.posix.normalize(value);
21693
+ const normalized = path16.posix.normalize(value);
21441
21694
  if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
21442
21695
  return null;
21443
21696
  return normalized === "." ? "." : normalized.replace(/\/$/, "");
@@ -21485,21 +21738,21 @@ var gitPaths = (root) => {
21485
21738
  git: !/not a git repository/i.test(stderr)
21486
21739
  };
21487
21740
  }
21488
- const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path14.sep).join("/")) : [];
21741
+ const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
21489
21742
  const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
21490
21743
  if (stagedDeleted.status !== 0) {
21491
21744
  const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
21492
21745
  if (!/not a git repository/i.test(stderr))
21493
21746
  return { paths, uncertain: true, git: true };
21494
21747
  } else if (stagedDeleted.stdout) {
21495
- paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path14.sep).join("/")));
21748
+ paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
21496
21749
  }
21497
21750
  return { paths: [...new Set(paths)], uncertain: false, git: true };
21498
21751
  };
21499
21752
  var walk = (root, directory, output) => {
21500
21753
  let names;
21501
21754
  try {
21502
- names = fs12.readdirSync(directory);
21755
+ names = fs13.readdirSync(directory);
21503
21756
  } catch {
21504
21757
  return true;
21505
21758
  }
@@ -21507,10 +21760,10 @@ var walk = (root, directory, output) => {
21507
21760
  for (const name of names) {
21508
21761
  if (name === ".git" || name === ".workit")
21509
21762
  continue;
21510
- const target = path14.join(directory, name);
21763
+ const target = path16.join(directory, name);
21511
21764
  let stat;
21512
21765
  try {
21513
- stat = fs12.lstatSync(target);
21766
+ stat = fs13.lstatSync(target);
21514
21767
  } catch {
21515
21768
  uncertain = true;
21516
21769
  continue;
@@ -21525,14 +21778,14 @@ var walk = (root, directory, output) => {
21525
21778
  var scopeRoots = (root, scope) => {
21526
21779
  const roots = [];
21527
21780
  for (const item of scope.paths.length ? scope.paths : ["."]) {
21528
- const target = path14.resolve(root, item);
21781
+ const target = path16.resolve(root, item);
21529
21782
  if (!inside(root, target))
21530
21783
  return failure2("invalid_input", `candidate scope escapes checkout: ${item} — keep one task per repository and coordinate a separate linked task in the other checkout`, { fields: [{ path: "scope.paths", reason: `${item} is outside the checkout` }] });
21531
21784
  let ancestor = target;
21532
- while (!fs12.existsSync(ancestor) && ancestor !== root)
21533
- ancestor = path14.dirname(ancestor);
21785
+ while (!fs13.existsSync(ancestor) && ancestor !== root)
21786
+ ancestor = path16.dirname(ancestor);
21534
21787
  try {
21535
- if (!inside(root, fs12.realpathSync(ancestor)))
21788
+ if (!inside(root, fs13.realpathSync(ancestor)))
21536
21789
  return failure2("invalid_input", `candidate scope escapes checkout through a symlink: ${item} — keep one task per repository and coordinate a separate linked task in the other checkout`, { fields: [{ path: "scope.paths", reason: `${item} resolves outside the checkout` }] });
21537
21790
  } catch {
21538
21791
  return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
@@ -21544,7 +21797,7 @@ var scopeRoots = (root, scope) => {
21544
21797
  function captureCandidate(root, scope, environment = []) {
21545
21798
  let checkout;
21546
21799
  try {
21547
- checkout = fs12.realpathSync(root);
21800
+ checkout = fs13.realpathSync(root);
21548
21801
  } catch {
21549
21802
  return failure2("invalid_input", "candidate root does not exist");
21550
21803
  }
@@ -21562,11 +21815,11 @@ function captureCandidate(root, scope, environment = []) {
21562
21815
  if (item === ".git" || item === ".workit")
21563
21816
  continue;
21564
21817
  names.add(item);
21565
- if (!fs12.existsSync(target))
21818
+ if (!fs13.existsSync(target))
21566
21819
  continue;
21567
21820
  let stat;
21568
21821
  try {
21569
- stat = fs12.lstatSync(target);
21822
+ stat = fs13.lstatSync(target);
21570
21823
  } catch {
21571
21824
  uncertain = true;
21572
21825
  continue;
@@ -21582,17 +21835,17 @@ function captureCandidate(root, scope, environment = []) {
21582
21835
  for (const item of [...names].toSorted()) {
21583
21836
  if (!scopeMatches(item, normalizedScope))
21584
21837
  continue;
21585
- const target = path14.join(checkout, item);
21838
+ const target = path16.join(checkout, item);
21586
21839
  try {
21587
- const stat = fs12.lstatSync(target);
21840
+ const stat = fs13.lstatSync(target);
21588
21841
  if (stat.isSymbolicLink()) {
21589
- const link = fs12.readlinkSync(target);
21842
+ const link = fs13.readlinkSync(target);
21590
21843
  files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
21591
21844
  } else if (stat.isFile()) {
21592
21845
  files.push({
21593
21846
  path: item,
21594
21847
  kind: "file",
21595
- digest: digestBytes(fs12.readFileSync(target)),
21848
+ digest: digestBytes(fs13.readFileSync(target)),
21596
21849
  executable: (stat.mode & 73) !== 0
21597
21850
  });
21598
21851
  } else if (!stat.isDirectory()) {
@@ -21757,7 +22010,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
21757
22010
  var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
21758
22011
  let root;
21759
22012
  try {
21760
- root = fs12.realpathSync(checkoutRoot);
22013
+ root = fs13.realpathSync(checkoutRoot);
21761
22014
  } catch {
21762
22015
  return failure2("permission_denied", "checkout root is unavailable");
21763
22016
  }
@@ -21766,23 +22019,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
21766
22019
  continue;
21767
22020
  if (!reference.digest)
21768
22021
  return failure2("invalid_input", "document references require a byte digest");
21769
- const target = path14.resolve(root, reference.path);
21770
- if (target !== root && !target.startsWith(`${root}${path14.sep}`))
22022
+ const target = path16.resolve(root, reference.path);
22023
+ if (target !== root && !target.startsWith(`${root}${path16.sep}`))
21771
22024
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
21772
22025
  fields: [
21773
22026
  { path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
21774
22027
  ]
21775
22028
  });
21776
22029
  try {
21777
- const below = path14.relative(root, target);
22030
+ const below = path16.relative(root, target);
21778
22031
  let current = root;
21779
- for (const segment of below.split(path14.sep)) {
22032
+ for (const segment of below.split(path16.sep)) {
21780
22033
  if (!segment)
21781
22034
  continue;
21782
- current = path14.join(current, segment);
21783
- const stat = fs12.lstatSync(current);
21784
- const real = fs12.realpathSync(current);
21785
- if (real !== root && !real.startsWith(`${root}${path14.sep}`))
22035
+ current = path16.join(current, segment);
22036
+ const stat = fs13.lstatSync(current);
22037
+ const real = fs13.realpathSync(current);
22038
+ if (real !== root && !real.startsWith(`${root}${path16.sep}`))
21786
22039
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
21787
22040
  fields: [
21788
22041
  {
@@ -21798,7 +22051,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
21798
22051
  if (current !== target && !stat.isDirectory())
21799
22052
  return failure2("invalid_input", "document reference ancestor is not a directory");
21800
22053
  }
21801
- if (digestBytes(fs12.readFileSync(target)) !== reference.digest)
22054
+ if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
21802
22055
  return failure2("permission_denied", "decision document bytes have changed");
21803
22056
  } catch {
21804
22057
  return failure2("invalid_input", "decision document is unavailable");
@@ -22656,7 +22909,7 @@ var judgeInputSummary = (raw) => {
22656
22909
 
22657
22910
  // packages/workit-core/src/autonomy.ts
22658
22911
  import os4 from "node:os";
22659
- import path15 from "node:path";
22912
+ import path17 from "node:path";
22660
22913
  var accountHome = () => {
22661
22914
  try {
22662
22915
  return os4.userInfo().homedir;
@@ -22665,10 +22918,10 @@ var accountHome = () => {
22665
22918
  }
22666
22919
  };
22667
22920
  var grantsHome = { resolve: accountHome };
22668
- var grantsDir = () => path15.join(grantsHome.resolve(), ".config", "workit");
22921
+ var grantsDir = () => path17.join(grantsHome.resolve(), ".config", "workit");
22669
22922
  var grantsOverride = () => {
22670
- const configured = path15.resolve(resolveConfigDir());
22671
- return configured === path15.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path15.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
22923
+ const configured = path17.resolve(resolveConfigDir());
22924
+ return configured === path17.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path17.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
22672
22925
  };
22673
22926
  var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
22674
22927
  var DEFAULT_GRANTS = Object.freeze({
@@ -24440,7 +24693,7 @@ class WorkitCore {
24440
24693
  // packages/workit-core/src/core/repo-context.ts
24441
24694
  import { spawnSync as spawnSync11 } from "node:child_process";
24442
24695
  import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
24443
- import path16 from "node:path";
24696
+ import path18 from "node:path";
24444
24697
  var isSafeContextRange = (value) => value.length <= 4096 && (() => {
24445
24698
  try {
24446
24699
  gitRevisionParts(value);
@@ -24574,7 +24827,7 @@ var findPrTemplate = (cwd) => {
24574
24827
  ]) {
24575
24828
  const parts = rel.split("/");
24576
24829
  const base = parts[parts.length - 1];
24577
- const dir = parts.length > 1 ? path16.join(cwd, ...parts.slice(0, -1)) : cwd;
24830
+ const dir = parts.length > 1 ? path18.join(cwd, ...parts.slice(0, -1)) : cwd;
24578
24831
  const actual = probeCaseInsensitive(dir, base);
24579
24832
  if (actual)
24580
24833
  return [...parts.slice(0, -1), actual].join("/");
@@ -24605,7 +24858,7 @@ var diffStatForRange = (cwd, range) => {
24605
24858
  return runGit(cwd, ["diff", "--stat", "--"]).stdout;
24606
24859
  };
24607
24860
  var packageScripts = (cwd, keys) => {
24608
- const pkgPath = path16.join(cwd, "package.json");
24861
+ const pkgPath = path18.join(cwd, "package.json");
24609
24862
  if (!existsSync6(pkgPath))
24610
24863
  return [];
24611
24864
  try {
@@ -24631,9 +24884,9 @@ var documentationFiles = (cwd) => {
24631
24884
  if (entry.isDirectory()) {
24632
24885
  if (excluded.has(entry.name))
24633
24886
  continue;
24634
- walk(path16.join(dir, entry.name), depth + 1);
24887
+ walk(path18.join(dir, entry.name), depth + 1);
24635
24888
  } else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
24636
- matches.push("./" + path16.relative(cwd, path16.join(dir, entry.name)).replaceAll("\\", "/"));
24889
+ matches.push("./" + path18.relative(cwd, path18.join(dir, entry.name)).replaceAll("\\", "/"));
24637
24890
  }
24638
24891
  }
24639
24892
  };
@@ -24649,7 +24902,7 @@ var readTrimmed2 = (file, maxLines) => {
24649
24902
  `);
24650
24903
  };
24651
24904
  function prReadyContext(root, range) {
24652
- const cwd = path16.resolve(repoRoot(root));
24905
+ const cwd = path18.resolve(repoRoot(root));
24653
24906
  if (range !== undefined && !isResolvableContextRange(cwd, range))
24654
24907
  return invalidRange(cwd);
24655
24908
  let stdout = "";
@@ -24707,7 +24960,7 @@ ${status.stderr}` : "");
24707
24960
  stdout += `template_path: ${template}
24708
24961
 
24709
24962
  `;
24710
- stdout += readTrimmed2(path16.join(cwd, template), 220);
24963
+ stdout += readTrimmed2(path18.join(cwd, template), 220);
24711
24964
  } else {
24712
24965
  stdout += `template_path: none
24713
24966
 
@@ -24717,7 +24970,7 @@ ${status.stderr}` : "");
24717
24970
  stdout += `
24718
24971
  `;
24719
24972
  stdout += printSection("Recent Validation Signals");
24720
- if (existsSync6(path16.join(cwd, "package.json"))) {
24973
+ if (existsSync6(path18.join(cwd, "package.json"))) {
24721
24974
  stdout += `package.json detected. Common scripts:
24722
24975
  `;
24723
24976
  const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
@@ -24726,7 +24979,7 @@ ${status.stderr}` : "");
24726
24979
  `) + `
24727
24980
  `;
24728
24981
  }
24729
- if (existsSync6(path16.join(cwd, "Cargo.toml")) || existsSync6(path16.join(cwd, "src-tauri/Cargo.toml"))) {
24982
+ if (existsSync6(path18.join(cwd, "Cargo.toml")) || existsSync6(path18.join(cwd, "src-tauri/Cargo.toml"))) {
24730
24983
  stdout += `Rust project detected.
24731
24984
  `;
24732
24985
  }
@@ -24759,7 +25012,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
24759
25012
  - Apply with the host-native editor, preserving the repository changelog conventions.
24760
25013
  - If Unreleased already has duplicate category headings, normalize_only first.`;
24761
25014
  function changelogContext(root, range) {
24762
- const cwd = path16.resolve(repoRoot(root));
25015
+ const cwd = path18.resolve(repoRoot(root));
24763
25016
  if (range !== undefined && !isResolvableContextRange(cwd, range))
24764
25017
  return invalidRange(cwd);
24765
25018
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -24777,7 +25030,7 @@ function changelogContext(root, range) {
24777
25030
  stdout += CHANGELOG_RULES + `
24778
25031
  `;
24779
25032
  stdout += printSection("Existing CHANGELOG.md");
24780
- const changelogPath = path16.join(cwd, "CHANGELOG.md");
25033
+ const changelogPath = path18.join(cwd, "CHANGELOG.md");
24781
25034
  if (existsSync6(changelogPath)) {
24782
25035
  stdout += readTrimmed2(changelogPath, 260) + `
24783
25036
  `;
@@ -24797,7 +25050,7 @@ function changelogContext(root, range) {
24797
25050
  return { stdout, stderr: "", exitCode: 0, cwd };
24798
25051
  }
24799
25052
  function docsRefreshContext(root, range) {
24800
- const cwd = path16.resolve(repoRoot(root));
25053
+ const cwd = path18.resolve(repoRoot(root));
24801
25054
  if (range !== undefined && !isResolvableContextRange(cwd, range))
24802
25055
  return invalidRange(cwd);
24803
25056
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -24819,7 +25072,7 @@ function docsRefreshContext(root, range) {
24819
25072
  `) + `
24820
25073
  `;
24821
25074
  stdout += printSection("README Preview");
24822
- const readme = path16.join(cwd, "README.md");
25075
+ const readme = path18.join(cwd, "README.md");
24823
25076
  if (existsSync6(readme)) {
24824
25077
  stdout += readTrimmed2(readme, 220) + `
24825
25078
  `;
@@ -24828,7 +25081,7 @@ function docsRefreshContext(root, range) {
24828
25081
  `;
24829
25082
  }
24830
25083
  stdout += printSection("Package Scripts");
24831
- const pkgPath = path16.join(cwd, "package.json");
25084
+ const pkgPath = path18.join(cwd, "package.json");
24832
25085
  if (existsSync6(pkgPath)) {
24833
25086
  try {
24834
25087
  const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
@@ -24842,7 +25095,7 @@ function docsRefreshContext(root, range) {
24842
25095
  return { stdout, stderr: "", exitCode: 0, cwd };
24843
25096
  }
24844
25097
  function releaseNotesContext(root, rangeOrTag) {
24845
- const cwd = path16.resolve(repoRoot(root));
25098
+ const cwd = path18.resolve(repoRoot(root));
24846
25099
  if (!rangeOrTag) {
24847
25100
  return { stdout: "", stderr: `ERROR: release tag or range required
24848
25101
  `, exitCode: 1, cwd };
@@ -24880,7 +25133,7 @@ function releaseNotesContext(root, rangeOrTag) {
24880
25133
  `;
24881
25134
  stdout += printSection("Existing Release Files");
24882
25135
  for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
24883
- if (existsSync6(path16.join(cwd, rel)))
25136
+ if (existsSync6(path18.join(cwd, rel)))
24884
25137
  stdout += rel + `
24885
25138
  `;
24886
25139
  }
@@ -24911,8 +25164,8 @@ function releaseNotesContext(root, rangeOrTag) {
24911
25164
  import { spawnSync as spawnSync13 } from "node:child_process";
24912
25165
 
24913
25166
  // packages/workit-core/src/core/pr-create.ts
24914
- import fs13 from "node:fs";
24915
- import path17 from "node:path";
25167
+ import fs14 from "node:fs";
25168
+ import path19 from "node:path";
24916
25169
  import { spawnSync as spawnSync12 } from "node:child_process";
24917
25170
  // packages/workit-core/src/forge/pr-body.ts
24918
25171
  function parseGhIssue(value) {
@@ -24923,13 +25176,13 @@ function parseGhIssue(value) {
24923
25176
  // packages/workit-core/src/core/pr-create.ts
24924
25177
  function whichOnPath(tool) {
24925
25178
  const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
24926
- for (const dir of (process.env.PATH ?? "").split(path17.delimiter)) {
25179
+ for (const dir of (process.env.PATH ?? "").split(path19.delimiter)) {
24927
25180
  if (!dir)
24928
25181
  continue;
24929
25182
  for (const name of names) {
24930
- const candidate = path17.join(dir, name);
25183
+ const candidate = path19.join(dir, name);
24931
25184
  try {
24932
- fs13.accessSync(candidate, fs13.constants.X_OK);
25185
+ fs14.accessSync(candidate, fs14.constants.X_OK);
24933
25186
  return candidate;
24934
25187
  } catch {}
24935
25188
  }
@@ -25047,8 +25300,8 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
25047
25300
  };
25048
25301
 
25049
25302
  // packages/workit-core/src/core/youtrack.ts
25050
- import fs14 from "node:fs";
25051
- import path18 from "node:path";
25303
+ import fs15 from "node:fs";
25304
+ import path20 from "node:path";
25052
25305
 
25053
25306
  // packages/workit-core/src/core/templates.ts
25054
25307
  var repoRoot2 = assetRoot();
@@ -25061,22 +25314,22 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
25061
25314
  // packages/workit-core/src/core/youtrack.ts
25062
25315
  var ISSUE_RE = /^[A-Z]+-\d+$/;
25063
25316
  var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
25064
- var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path18.join(configDir(), "youtrack.json");
25065
- var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path18.join(resolveConfigDir(), "youtrack.json");
25317
+ var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(configDir(), "youtrack.json");
25318
+ var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(resolveConfigDir(), "youtrack.json");
25066
25319
  var youTrackTokenModeOk = (p) => {
25067
25320
  if (process.platform === "win32")
25068
25321
  return true;
25069
- const mode = fs14.statSync(p).mode & 511;
25322
+ const mode = fs15.statSync(p).mode & 511;
25070
25323
  return mode === 384;
25071
25324
  };
25072
25325
  function readYouTrackConfig(required) {
25073
25326
  const cfgPath = youTrackConfigPath();
25074
- if (!fs14.existsSync(cfgPath)) {
25327
+ if (!fs15.existsSync(cfgPath)) {
25075
25328
  return required ? { error: "ERROR: missing youtrack.json", path: cfgPath } : { config: {}, path: cfgPath };
25076
25329
  }
25077
25330
  let parsed;
25078
25331
  try {
25079
- parsed = JSON.parse(fs14.readFileSync(cfgPath, "utf8"));
25332
+ parsed = JSON.parse(fs15.readFileSync(cfgPath, "utf8"));
25080
25333
  } catch {
25081
25334
  return { error: `${cfgPath} is not valid JSON`, path: cfgPath };
25082
25335
  }
@@ -25087,11 +25340,11 @@ function readYouTrackConfig(required) {
25087
25340
  }
25088
25341
  var readYouTrackContextConfig = () => {
25089
25342
  const cfgPath = youTrackReadOnlyConfigPath();
25090
- if (!fs14.existsSync(cfgPath))
25343
+ if (!fs15.existsSync(cfgPath))
25091
25344
  return { data: {} };
25092
25345
  let parsed;
25093
25346
  try {
25094
- parsed = JSON.parse(fs14.readFileSync(cfgPath, "utf8"));
25347
+ parsed = JSON.parse(fs15.readFileSync(cfgPath, "utf8"));
25095
25348
  } catch {
25096
25349
  return { error: "YouTrack configuration is unavailable" };
25097
25350
  }
@@ -25130,12 +25383,12 @@ var youTrackToken = () => {
25130
25383
  if ("error" in loaded)
25131
25384
  return loaded;
25132
25385
  const tokenFile = String(loaded.config.tokenFile ?? "");
25133
- const tokenPath = tokenFile ? path18.isAbsolute(tokenFile) ? path18.resolve(tokenFile) : path18.resolve(process.cwd(), tokenFile) : "";
25134
- if (!tokenPath || !fs14.existsSync(tokenPath))
25386
+ const tokenPath = tokenFile ? path20.isAbsolute(tokenFile) ? path20.resolve(tokenFile) : path20.resolve(process.cwd(), tokenFile) : "";
25387
+ if (!tokenPath || !fs15.existsSync(tokenPath))
25135
25388
  return { error: "missing youtrack.token" };
25136
25389
  if (!youTrackTokenModeOk(tokenPath))
25137
25390
  return { error: "youtrack.token mode must be 0600" };
25138
- const token = fs14.readFileSync(tokenPath, "utf8").trim();
25391
+ const token = fs15.readFileSync(tokenPath, "utf8").trim();
25139
25392
  if (!token)
25140
25393
  return { error: "empty token file" };
25141
25394
  if (token === TOKEN_PLACEHOLDER || token.startsWith(TOKEN_PLACEHOLDER)) {
@@ -25200,9 +25453,9 @@ function resolveYouTrackFromPaths(spec_path, plan_path, workspace_root) {
25200
25453
  } catch {
25201
25454
  continue;
25202
25455
  }
25203
- if (!fs14.existsSync(full))
25456
+ if (!fs15.existsSync(full))
25204
25457
  continue;
25205
- const text = fs14.readFileSync(full, "utf8");
25458
+ const text = fs15.readFileSync(full, "utf8");
25206
25459
  const m = text.match(/^\*\*YouTrack:\*\*\s*`?([A-Z]+-\d+)`?/m);
25207
25460
  if (m)
25208
25461
  return m[1];
@@ -25472,15 +25725,15 @@ function resolveGitRevision(root, value) {
25472
25725
  }
25473
25726
  function resolveInside(root, candidate) {
25474
25727
  const base = realpathSync5(root);
25475
- const target = path19.resolve(base, candidate);
25476
- if (target !== base && !target.startsWith(base + path19.sep)) {
25728
+ const target = path21.resolve(base, candidate);
25729
+ if (target !== base && !target.startsWith(base + path21.sep)) {
25477
25730
  throw new Error("path must stay inside repository root");
25478
25731
  }
25479
25732
  let ancestor = target;
25480
25733
  while (!existsSync7(ancestor))
25481
- ancestor = path19.dirname(ancestor);
25734
+ ancestor = path21.dirname(ancestor);
25482
25735
  const canonicalAncestor = realpathSync5(ancestor);
25483
- if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path19.sep)) {
25736
+ if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path21.sep)) {
25484
25737
  throw new Error("path must stay inside repository root");
25485
25738
  }
25486
25739
  return target;
@@ -25512,7 +25765,7 @@ var SUPPORT_MATRIX = {
25512
25765
 
25513
25766
  // packages/workit-mcp/src/server.ts
25514
25767
  import { existsSync as existsSync8, readFileSync as readFileSync6, realpathSync as realpathSync6 } from "node:fs";
25515
- import path20 from "node:path";
25768
+ import path22 from "node:path";
25516
25769
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
25517
25770
  function isZ4Schema(s) {
25518
25771
  const schema = s;
@@ -27926,13 +28179,13 @@ var rootVariants = (workspaceRoot) => {
27926
28179
  if (!workspaceRoot)
27927
28180
  return [];
27928
28181
  const roots = new Set;
27929
- for (const candidate of [workspaceRoot, path20.resolve(workspaceRoot)]) {
27930
- if (path20.isAbsolute(candidate) && candidate !== path20.parse(candidate).root)
28182
+ for (const candidate of [workspaceRoot, path22.resolve(workspaceRoot)]) {
28183
+ if (path22.isAbsolute(candidate) && candidate !== path22.parse(candidate).root)
27931
28184
  roots.add(candidate);
27932
28185
  }
27933
28186
  try {
27934
28187
  const canonical = realpathSync6(workspaceRoot);
27935
- if (canonical !== path20.parse(canonical).root)
28188
+ if (canonical !== path22.parse(canonical).root)
27936
28189
  roots.add(canonical);
27937
28190
  } catch {}
27938
28191
  return [...roots].toSorted((left, right) => right.length - left.length);
@@ -28014,11 +28267,11 @@ var thrownResult = (tool, error, workspaceRoot) => {
28014
28267
  };
28015
28268
  function createMcpServer(host, contextProvider) {
28016
28269
  assertMcpHost(host);
28017
- const here = path20.dirname(fileURLToPath2(import.meta.url));
28270
+ const here = path22.dirname(fileURLToPath2(import.meta.url));
28018
28271
  const sourceMarker = markSourcesLoaded([
28019
- path20.join(here, "server.ts"),
28020
- path20.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
28021
- path20.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
28272
+ path22.join(here, "server.ts"),
28273
+ path22.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
28274
+ path22.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
28022
28275
  ].filter((file) => existsSync8(file)));
28023
28276
  let staleWarned = false;
28024
28277
  const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
@@ -28211,10 +28464,44 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
28211
28464
  var signals = new Map;
28212
28465
  var cache = new Map;
28213
28466
  var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
28467
+ // packages/workit-core/src/core/live-session.ts
28468
+ import { spawnSync as spawnSync15 } from "node:child_process";
28469
+ var LIVE_SESSION_TTL_MS = 15 * 60000;
28470
+ var liveProbe = {
28471
+ platform: process.platform,
28472
+ run: (args) => spawnSync15("ps", args, { encoding: "utf8", timeout: 2000 }).stdout ?? "",
28473
+ start: (pid) => processStartOf(pid)
28474
+ };
28475
+ var PIDS = new Map;
28476
+
28214
28477
  // packages/workit-core/src/hooks/write-gate.ts
28215
28478
  var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
28216
28479
  var PREFIXES2 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "xargs"]);
28217
28480
  var cache2 = new Map;
28481
+ var MUTATING_GIT = new Set([
28482
+ "add",
28483
+ "am",
28484
+ "apply",
28485
+ "checkout",
28486
+ "cherry-pick",
28487
+ "clean",
28488
+ "commit",
28489
+ "merge",
28490
+ "mv",
28491
+ "pull",
28492
+ "rebase",
28493
+ "reset",
28494
+ "restore",
28495
+ "revert",
28496
+ "rm",
28497
+ "stash",
28498
+ "switch"
28499
+ ]);
28500
+ var DRY_N = new Set(["add", "clean", "rm", "mv"]);
28501
+ var MUTATING_WORKIT_GIT = new Set(["commit", "branch"]);
28502
+ var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
28503
+ var PUSHD2 = new Set(["pushd", "push-location"]);
28504
+ var POPD2 = new Set(["popd", "pop-location"]);
28218
28505
  // packages/workit-core/src/core/skill-manifests.ts
28219
28506
  if (false) {}
28220
28507
 
@@ -28401,14 +28688,14 @@ import {
28401
28688
  writeFileSync as writeFileSync3
28402
28689
  } from "node:fs";
28403
28690
  import os5 from "node:os";
28404
- import path21 from "node:path";
28691
+ import path23 from "node:path";
28405
28692
  var CODEX_AGENT_MARKER = "# Generated by Workit";
28406
28693
  var codexHomeOfInstall = (pluginRoot) => {
28407
- const parts = path21.resolve(pluginRoot).split(path21.sep);
28694
+ const parts = path23.resolve(pluginRoot).split(path23.sep);
28408
28695
  const cache = parts.length - 4;
28409
- return cache >= 2 && parts[cache] === "cache" && parts[cache - 1] === "plugins" ? parts.slice(0, cache - 1).join(path21.sep) || path21.sep : null;
28696
+ return cache >= 2 && parts[cache] === "cache" && parts[cache - 1] === "plugins" ? parts.slice(0, cache - 1).join(path23.sep) || path23.sep : null;
28410
28697
  };
28411
- var codexHomeFor = (pluginRoot, env) => codexHomeOfInstall(pluginRoot) ?? (env.CODEX_HOME || path21.join(env.HOME || os5.homedir(), ".codex"));
28698
+ var codexHomeFor = (pluginRoot, env) => codexHomeOfInstall(pluginRoot) ?? (env.CODEX_HOME || path23.join(env.HOME || os5.homedir(), ".codex"));
28412
28699
  var MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
28413
28700
  var agentMarkerVersion = (text) => MARKER_VERSION.exec(text)?.[1] ?? null;
28414
28701
  var stampCodexAgent = (content, version) => version && content.startsWith(CODEX_AGENT_MARKER) && !agentMarkerVersion(content) ? `${CODEX_AGENT_MARKER} ${version}${content.slice(CODEX_AGENT_MARKER.length)}` : content;
@@ -28422,7 +28709,7 @@ var versionAtLeast = (version, min) => {
28422
28709
  };
28423
28710
  var pluginVersion = (pluginRoot) => {
28424
28711
  try {
28425
- const version = JSON.parse(readFileSync7(path21.join(pluginRoot, "package.json"), "utf8")).version;
28712
+ const version = JSON.parse(readFileSync7(path23.join(pluginRoot, "package.json"), "utf8")).version;
28426
28713
  return typeof version === "string" && /^\d+\.\d+\.\d+/.test(version) ? version.match(/^\d+\.\d+\.\d+/)[0] : null;
28427
28714
  } catch {
28428
28715
  return null;
@@ -28436,15 +28723,15 @@ var lstatOrNull = (file) => {
28436
28723
  }
28437
28724
  };
28438
28725
  var installCodexAgents = (pluginRoot, codexHome) => {
28439
- const source = path21.join(pluginRoot, "agents");
28726
+ const source = path23.join(pluginRoot, "agents");
28440
28727
  if (!existsSync9(source))
28441
28728
  return [];
28442
28729
  const version = pluginVersion(pluginRoot);
28443
- const target = path21.join(codexHome, "agents");
28730
+ const target = path23.join(codexHome, "agents");
28444
28731
  const results = [];
28445
28732
  for (const file of readdirSync5(source).filter((name) => name.endsWith(".toml")).toSorted()) {
28446
- const content = stampCodexAgent(readFileSync7(path21.join(source, file), "utf8"), version);
28447
- const dest = path21.join(target, file);
28733
+ const content = stampCodexAgent(readFileSync7(path23.join(source, file), "utf8"), version);
28734
+ const dest = path23.join(target, file);
28448
28735
  const stat = lstatOrNull(dest);
28449
28736
  if (stat?.isSymbolicLink()) {
28450
28737
  results.push({ file: dest, action: "skipped-symlink" });
@@ -28480,7 +28767,7 @@ var installCodexAgents = (pluginRoot, codexHome) => {
28480
28767
  results.push({ file: dest, action: "kept-newer-version" });
28481
28768
  continue;
28482
28769
  }
28483
- const temp = path21.join(target, `.${file}.${process.pid}.${Date.now()}.tmp`);
28770
+ const temp = path23.join(target, `.${file}.${process.pid}.${Date.now()}.tmp`);
28484
28771
  writeFileSync3(temp, content, { flag: "wx" });
28485
28772
  try {
28486
28773
  renameSync2(temp, dest);
@@ -28502,8 +28789,8 @@ var codexQualification = (host) => host === "codex_cli" ? { surface: host, cli:
28502
28789
  var resolveCodexWorkspaceRoot = (pluginRoot, env) => {
28503
28790
  const explicit = env.WORKFLOW_WORKSPACE_ROOT;
28504
28791
  const inherited = env.PWD;
28505
- const candidate = explicit ?? (inherited && path22.resolve(inherited) !== path22.resolve(pluginRoot) ? inherited : undefined);
28506
- if (!candidate || !path22.isAbsolute(candidate) || !existsSync10(candidate))
28792
+ const candidate = explicit ?? (inherited && path24.resolve(inherited) !== path24.resolve(pluginRoot) ? inherited : undefined);
28793
+ if (!candidate || !path24.isAbsolute(candidate) || !existsSync10(candidate))
28507
28794
  return null;
28508
28795
  try {
28509
28796
  if (!statSync3(candidate).isDirectory())
@@ -28542,7 +28829,7 @@ var codexContextProvider = (host = detectCodexSurface(process.env), root) => ({
28542
28829
  };
28543
28830
  }
28544
28831
  });
28545
- var pluginRoot = () => path22.resolve(path22.dirname(fileURLToPath3(import.meta.url)), "..");
28832
+ var pluginRoot = () => path24.resolve(path24.dirname(fileURLToPath3(import.meta.url)), "..");
28546
28833
  var syncCodexAgents = (root) => {
28547
28834
  const codexHome = codexHomeOfInstall(root);
28548
28835
  if (!codexHome)