@brainervirus/workit-mcp 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.
Files changed (2) hide show
  1. package/dist/index.js +643 -390
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -6620,11 +6620,11 @@ var require_dist = __commonJS(function(exports, module) {
6620
6620
 
6621
6621
  // packages/workit-mcp/src/index.ts
6622
6622
  import { fileURLToPath as fileURLToPath3 } from "node:url";
6623
- import path21 from "node:path";
6623
+ import path23 from "node:path";
6624
6624
 
6625
6625
  // packages/workit-mcp/src/server.ts
6626
6626
  import { existsSync as existsSync8, readFileSync as readFileSync6, realpathSync as realpathSync6 } from "node:fs";
6627
- import path20 from "node:path";
6627
+ import path22 from "node:path";
6628
6628
 
6629
6629
  // node_modules/zod/v4/core/util.js
6630
6630
  function getEnumValues(entries) {
@@ -16576,7 +16576,7 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
16576
16576
  // packages/workit-core/src/core.ts
16577
16577
  import { spawnSync as spawnSync14 } from "node:child_process";
16578
16578
  import { existsSync as existsSync7, realpathSync as realpathSync5 } from "node:fs";
16579
- import path19 from "node:path";
16579
+ import path21 from "node:path";
16580
16580
 
16581
16581
  // packages/workit-core/src/core/task-contract.ts
16582
16582
  import { createHash, randomUUID } from "node:crypto";
@@ -17831,9 +17831,9 @@ function parseAdvertisedOperation(family, input, host) {
17831
17831
  });
17832
17832
  }
17833
17833
  // packages/workit-core/src/core/task-store.ts
17834
- import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
17835
- import * as fs7 from "node:fs";
17836
- import path6 from "node:path";
17834
+ import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
17835
+ import * as fs8 from "node:fs";
17836
+ import path8 from "node:path";
17837
17837
 
17838
17838
  // node_modules/@openclaw/fs-safe/dist/errors.js
17839
17839
  var OPERATIONAL_CODES = new Set([
@@ -18436,8 +18436,14 @@ function acquireFileLockSync(targetPath, options) {
18436
18436
  }
18437
18437
  }
18438
18438
  }
18439
+ // packages/workit-core/src/host-session.ts
18440
+ import { createHash as createHash3, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
18441
+ import fs5 from "node:fs";
18442
+ import path5 from "node:path";
18443
+
18439
18444
  // packages/workit-core/src/core/logger.ts
18440
18445
  import os from "node:os";
18446
+ import path3 from "node:path";
18441
18447
  var REDACTED = "[REDACTED]";
18442
18448
  var SECRET_VALUE = /\b(?:Bearer|Basic|Digest|Token)\s+\S+/gi;
18443
18449
  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;
@@ -18480,6 +18486,22 @@ var SENSITIVE_WORDS = new Set([
18480
18486
  ]);
18481
18487
  var STACK_WORDS = new Set(["stack", "stacktrace", "trace"]);
18482
18488
  var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18489
+ var resolveStateDir = () => {
18490
+ const override = process.env.WORKFLOW_TOOLKIT_STATE;
18491
+ if (override)
18492
+ return override;
18493
+ const home = os.homedir();
18494
+ if (process.env.XDG_STATE_HOME)
18495
+ return path3.join(process.env.XDG_STATE_HOME, "workit");
18496
+ switch (os.platform()) {
18497
+ case "darwin":
18498
+ return path3.join(home, "Library", "Application Support", "workit");
18499
+ case "win32":
18500
+ return path3.join(process.env.LOCALAPPDATA ?? path3.join(home, "AppData", "Local"), "workit");
18501
+ default:
18502
+ return path3.join(process.env.HOME ?? home, ".local", "state", "workit");
18503
+ }
18504
+ };
18483
18505
  var homePattern = new RegExp(`${escapeRegExp(os.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
18484
18506
  var applyPatterns = (value) => {
18485
18507
  let out = value;
@@ -18497,7 +18519,7 @@ var redactSecrets = (value) => applyPatterns(value);
18497
18519
  import { spawnSync } from "node:child_process";
18498
18520
  import { createHash as createHash2 } from "node:crypto";
18499
18521
  import fs4 from "node:fs";
18500
- import path3 from "node:path";
18522
+ import path4 from "node:path";
18501
18523
  var NOT_A_REPO = /not a git repository \(or any (of the parent directories|parent up to)/u;
18502
18524
  var gitRun = (cwd, args) => {
18503
18525
  const run = spawnSync("git", args, {
@@ -18539,14 +18561,14 @@ var DISCOVERY_ENV = [
18539
18561
  ];
18540
18562
  var isGitDir = (dir) => {
18541
18563
  try {
18542
- return fs4.statSync(path3.join(dir, "HEAD")).isFile() && fs4.statSync(path3.join(dir, "objects")).isDirectory() && fs4.statSync(path3.join(dir, "refs")).isDirectory();
18564
+ return fs4.statSync(path4.join(dir, "HEAD")).isFile() && fs4.statSync(path4.join(dir, "objects")).isDirectory() && fs4.statSync(path4.join(dir, "refs")).isDirectory();
18543
18565
  } catch {
18544
18566
  return false;
18545
18567
  }
18546
18568
  };
18547
18569
  var reftableRefs = (common) => {
18548
18570
  try {
18549
- return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs4.readFileSync(path3.join(common, "config"), "utf8"));
18571
+ return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs4.readFileSync(path4.join(common, "config"), "utf8"));
18550
18572
  } catch {
18551
18573
  return false;
18552
18574
  }
@@ -18566,7 +18588,7 @@ function fastGit(root) {
18566
18588
  if (device !== null && stat.dev !== device)
18567
18589
  return { kind: "none" };
18568
18590
  device = stat.dev;
18569
- const dotGit = path3.join(dir, ".git");
18591
+ const dotGit = path4.join(dir, ".git");
18570
18592
  let entry = null;
18571
18593
  try {
18572
18594
  entry = fs4.statSync(dotGit);
@@ -18587,19 +18609,19 @@ function fastGit(root) {
18587
18609
  const match = /^gitdir: (.+)$/mu.exec(text);
18588
18610
  if (!match)
18589
18611
  return null;
18590
- gitDir = path3.resolve(dir, match[1].trim());
18612
+ gitDir = path4.resolve(dir, match[1].trim());
18591
18613
  } else
18592
18614
  return null;
18593
- if (!fs4.existsSync(path3.join(gitDir, "HEAD")))
18615
+ if (!fs4.existsSync(path4.join(gitDir, "HEAD")))
18594
18616
  return null;
18595
18617
  } else if (isGitDir(dir))
18596
18618
  gitDir = dir;
18597
18619
  if (gitDir) {
18598
18620
  let common = gitDir;
18599
18621
  try {
18600
- common = path3.resolve(gitDir, fs4.readFileSync(path3.join(gitDir, "commondir"), "utf8").trim());
18622
+ common = path4.resolve(gitDir, fs4.readFileSync(path4.join(gitDir, "commondir"), "utf8").trim());
18601
18623
  } catch {}
18602
- if (!fs4.existsSync(path3.join(common, "objects")))
18624
+ if (!fs4.existsSync(path4.join(common, "objects")))
18603
18625
  return null;
18604
18626
  return {
18605
18627
  kind: "repo",
@@ -18609,26 +18631,26 @@ function fastGit(root) {
18609
18631
  reftable: reftableRefs(common)
18610
18632
  };
18611
18633
  }
18612
- const parent = path3.dirname(dir);
18634
+ const parent = path4.dirname(dir);
18613
18635
  if (parent === dir)
18614
18636
  return { kind: "none" };
18615
18637
  dir = parent;
18616
18638
  }
18617
18639
  }
18618
18640
  function resolveStore(root) {
18619
- root = path3.resolve(root);
18641
+ root = path4.resolve(root);
18620
18642
  let directory = false;
18621
18643
  try {
18622
18644
  directory = fs4.statSync(root).isDirectory();
18623
18645
  } catch {}
18624
18646
  if (!directory)
18625
- return { dir: path3.join(root, ".workit"), shared: false, top: null };
18647
+ return { dir: path4.join(root, ".workit"), shared: false, top: null };
18626
18648
  const fast = fastGit(root);
18627
18649
  if (fast?.kind === "none")
18628
- return { dir: path3.join(root, ".workit"), shared: false, top: null };
18650
+ return { dir: path4.join(root, ".workit"), shared: false, top: null };
18629
18651
  if (fast?.kind === "repo")
18630
18652
  return {
18631
- dir: path3.join(fast.common, "workit"),
18653
+ dir: path4.join(fast.common, "workit"),
18632
18654
  shared: true,
18633
18655
  top: fast.top,
18634
18656
  git: { gitDir: fast.gitDir, top: fast.top, reftable: fast.reftable }
@@ -18638,20 +18660,20 @@ function resolveStore(root) {
18638
18660
  if (run.ok && common) {
18639
18661
  const top = gitRun(root, ["rev-parse", "--path-format=absolute", "--show-toplevel"]);
18640
18662
  return {
18641
- dir: path3.join(real(path3.resolve(root, common)), "workit"),
18663
+ dir: path4.join(real(path4.resolve(root, common)), "workit"),
18642
18664
  shared: true,
18643
18665
  top: top.ok && top.stdout.trim() ? real(top.stdout.trim()) : null
18644
18666
  };
18645
18667
  }
18646
18668
  if (run.missing || !run.ok && NOT_A_REPO.test(run.stderr))
18647
- return { dir: path3.join(root, ".workit"), shared: false, top: null };
18669
+ return { dir: path4.join(root, ".workit"), shared: false, top: null };
18648
18670
  return new Error(`cannot locate the workit store: git rev-parse failed (${run.stderr.trim().split(`
18649
18671
  `)[0] || "no output"}); fix the repository (git status should work here)`);
18650
18672
  }
18651
18673
  var rebasingBranch = (gitDir) => {
18652
18674
  for (const state of ["rebase-merge", "rebase-apply"]) {
18653
18675
  try {
18654
- const ref = fs4.readFileSync(path3.join(gitDir, state, "head-name"), "utf8").trim();
18676
+ const ref = fs4.readFileSync(path4.join(gitDir, state, "head-name"), "utf8").trim();
18655
18677
  const match = /^refs\/heads\/(.+)$/u.exec(ref);
18656
18678
  if (match)
18657
18679
  return match[1];
@@ -18666,7 +18688,7 @@ function resolveTaskKey(root, location) {
18666
18688
  if (location.git && !location.git.reftable) {
18667
18689
  let head = "";
18668
18690
  try {
18669
- head = fs4.readFileSync(path3.join(location.git.gitDir, "HEAD"), "utf8").trim();
18691
+ head = fs4.readFileSync(path4.join(location.git.gitDir, "HEAD"), "utf8").trim();
18670
18692
  } catch {}
18671
18693
  const ref = /^ref: refs\/heads\/(.+)$/u.exec(head);
18672
18694
  if (ref && ref[1] !== ".invalid")
@@ -18697,7 +18719,7 @@ function resolveTaskKey(root, location) {
18697
18719
  return { key: `detached-${shortHash(real(worktree))}`, kind: "detached", branch: null };
18698
18720
  }
18699
18721
  function checkoutRootOf(root, location) {
18700
- const resolved = path3.resolve(root);
18722
+ const resolved = path4.resolve(root);
18701
18723
  let canonical = resolved;
18702
18724
  try {
18703
18725
  canonical = fs4.realpathSync(resolved);
@@ -18728,13 +18750,13 @@ function branchRenames(location) {
18728
18750
  }
18729
18751
  for (const entry of entries)
18730
18752
  if (entry.isDirectory())
18731
- walk(path3.join(dir, entry.name));
18753
+ walk(path4.join(dir, entry.name));
18732
18754
  else
18733
- files.push(path3.join(dir, entry.name));
18755
+ files.push(path4.join(dir, entry.name));
18734
18756
  };
18735
- walk(path3.join(path3.dirname(location.dir), "logs", "refs", "heads"));
18757
+ walk(path4.join(path4.dirname(location.dir), "logs", "refs", "heads"));
18736
18758
  if (location.git)
18737
- files.push(path3.join(location.git.gitDir, "logs", "HEAD"));
18759
+ files.push(path4.join(location.git.gitDir, "logs", "HEAD"));
18738
18760
  const seen = new Set;
18739
18761
  const renames = [];
18740
18762
  for (const file of files) {
@@ -18769,7 +18791,7 @@ var checkoutSlug = (root) => {
18769
18791
  let canonical = real(root);
18770
18792
  if (process.platform === "win32")
18771
18793
  canonical = canonical.toLowerCase();
18772
- const base = path3.basename(canonical).replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 40) || "root";
18794
+ const base = path4.basename(canonical).replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 40) || "root";
18773
18795
  return `${base}-${shortHash(canonical)}`;
18774
18796
  };
18775
18797
 
@@ -18801,30 +18823,113 @@ function hostSessionFromEnv(env) {
18801
18823
  }
18802
18824
  return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
18803
18825
  }
18826
+ var hash = (value) => createHash3("sha256").update(value).digest("hex").slice(0, 32);
18827
+ var userIssuedRoot = () => path5.join(resolveStateDir(), "issued");
18828
+ var userTokenRoot = () => path5.join(resolveStateDir(), "issued-tokens");
18829
+ function migrateRepoIssued(cwd) {
18830
+ if (cwd === undefined)
18831
+ return;
18832
+ let old;
18833
+ try {
18834
+ const location = resolveStore(cwd);
18835
+ if (location instanceof Error)
18836
+ return;
18837
+ old = path5.join(location.dir, "hooks", "issued");
18838
+ if (!fs5.existsSync(old))
18839
+ return;
18840
+ } catch {
18841
+ return;
18842
+ }
18843
+ for (const lead of safeList(old)) {
18844
+ try {
18845
+ const from = path5.join(old, lead);
18846
+ if (!fs5.statSync(from).isDirectory())
18847
+ continue;
18848
+ const to = path5.join(userIssuedRoot(), lead);
18849
+ fs5.mkdirSync(to, { recursive: true, mode: 448 });
18850
+ for (const id of fs5.readdirSync(from)) {
18851
+ try {
18852
+ fs5.copyFileSync(path5.join(from, id), path5.join(to, id), fs5.constants.COPYFILE_EXCL);
18853
+ } catch (error) {
18854
+ if (error.code !== "EEXIST")
18855
+ throw error;
18856
+ }
18857
+ fs5.rmSync(path5.join(from, id), { force: true });
18858
+ }
18859
+ removeIfEmpty(from);
18860
+ } catch {}
18861
+ }
18862
+ removeIfEmpty(old);
18863
+ }
18864
+ var safeList = (dir) => {
18865
+ try {
18866
+ return fs5.readdirSync(dir);
18867
+ } catch {
18868
+ return [];
18869
+ }
18870
+ };
18871
+ var removeIfEmpty = (dir) => {
18872
+ try {
18873
+ fs5.rmdirSync(dir);
18874
+ } catch {}
18875
+ };
18876
+ var issuedRecord = (cwd, claimed) => {
18877
+ const cut = claimed.lastIndexOf(":");
18878
+ if (cut <= 0)
18879
+ return null;
18880
+ migrateRepoIssued(cwd);
18881
+ try {
18882
+ return fs5.readFileSync(path5.join(userIssuedRoot(), hash(claimed.slice(0, cut)), hash(claimed)), "utf8");
18883
+ } catch {
18884
+ return null;
18885
+ }
18886
+ };
18887
+ var TOKEN_HASH = /^([0-9a-f]{64})$/mu;
18888
+ var issuedToken = (claimed) => {
18889
+ const cut = claimed.lastIndexOf(":");
18890
+ if (cut <= 0)
18891
+ return { stored: null, leadBound: false };
18892
+ const dir = path5.join(userTokenRoot(), hash(claimed.slice(0, cut)));
18893
+ try {
18894
+ const text = fs5.readFileSync(path5.join(dir, hash(claimed)), "utf8");
18895
+ return { stored: TOKEN_HASH.exec(text)?.[1] ?? null, leadBound: true };
18896
+ } catch {
18897
+ return { stored: null, leadBound: safeList(dir).length > 0 };
18898
+ }
18899
+ };
18900
+ function issuedBinding(cwd, claimed) {
18901
+ const record = issuedRecord(cwd, claimed);
18902
+ const { stored, leadBound } = issuedToken(claimed);
18903
+ if (stored)
18904
+ return "token";
18905
+ if (record === null)
18906
+ return null;
18907
+ return leadBound ? "token" : "legacy";
18908
+ }
18804
18909
  var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
18805
18910
 
18806
18911
  // packages/workit-core/src/core/package-root.ts
18807
18912
  import { existsSync } from "node:fs";
18808
- import path4 from "node:path";
18913
+ import path6 from "node:path";
18809
18914
  import { fileURLToPath } from "node:url";
18810
18915
  var packageRoot = () => {
18811
- let dir = path4.dirname(fileURLToPath(import.meta.url));
18916
+ let dir = path6.dirname(fileURLToPath(import.meta.url));
18812
18917
  while (true) {
18813
- const parent = path4.dirname(dir);
18814
- if (existsSync(path4.join(dir, "package.json")) || parent === dir)
18918
+ const parent = path6.dirname(dir);
18919
+ if (existsSync(path6.join(dir, "package.json")) || parent === dir)
18815
18920
  return dir;
18816
18921
  dir = parent;
18817
18922
  }
18818
18923
  };
18819
18924
  var assetRoot = () => {
18820
18925
  const root = packageRoot();
18821
- const assets = path4.join(root, "assets");
18926
+ const assets = path6.join(root, "assets");
18822
18927
  return existsSync(assets) ? assets : root;
18823
18928
  };
18824
18929
 
18825
18930
  // packages/workit-core/src/core/store-lock.ts
18826
18931
  import { spawnSync as spawnSync2 } from "node:child_process";
18827
- import fs5 from "node:fs";
18932
+ import fs6 from "node:fs";
18828
18933
  import { hostname } from "node:os";
18829
18934
  var metadataLockSchema = object2({
18830
18935
  pid: number2().int().nonnegative().safe(),
@@ -18836,8 +18941,10 @@ var metadataLockSchema = object2({
18836
18941
  var FOREIGN_LOCK_TTL_MS = 10 * 60000;
18837
18942
  var UNREADABLE_LOCK_TTL_MS = 30000;
18838
18943
  var RECLAIM_GUARD_TTL_MS = 30000;
18839
- var defaultLockTimeoutMs = 250;
18944
+ var IN_PROCESS_LOCK_TIMEOUT_MS = 250;
18945
+ var defaultLockTimeoutMs = IN_PROCESS_LOCK_TIMEOUT_MS;
18840
18946
  var defaultLockTimeout = () => defaultLockTimeoutMs;
18947
+ var hostAwareLockTimeout = (cliMs) => defaultLockTimeoutMs > IN_PROCESS_LOCK_TIMEOUT_MS ? cliMs : IN_PROCESS_LOCK_TIMEOUT_MS;
18841
18948
  var parseMetadataLock = (raw) => {
18842
18949
  let value;
18843
18950
  try {
@@ -18866,7 +18973,7 @@ var parseProcStatStart = (stat) => {
18866
18973
  var processStartOf = (pid) => {
18867
18974
  if (process.platform === "linux") {
18868
18975
  try {
18869
- return parseProcStatStart(fs5.readFileSync(`/proc/${pid}/stat`, "utf8"));
18976
+ return parseProcStatStart(fs6.readFileSync(`/proc/${pid}/stat`, "utf8"));
18870
18977
  } catch {
18871
18978
  return null;
18872
18979
  }
@@ -18887,7 +18994,7 @@ var processStartOf = (pid) => {
18887
18994
  };
18888
18995
  var readTrimmed = (file) => {
18889
18996
  try {
18890
- return fs5.readFileSync(file, "utf8").trim() || null;
18997
+ return fs6.readFileSync(file, "utf8").trim() || null;
18891
18998
  } catch {
18892
18999
  return null;
18893
19000
  }
@@ -18898,7 +19005,7 @@ var localLockHost = () => {
18898
19005
  return cachedLockHost;
18899
19006
  let pidns = null;
18900
19007
  try {
18901
- pidns = /\[(\d+)\]/.exec(fs5.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
19008
+ pidns = /\[(\d+)\]/.exec(fs6.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
18902
19009
  } catch {}
18903
19010
  const boot = readTrimmed("/proc/sys/kernel/random/boot_id");
18904
19011
  cachedLockHost = pidns || boot ? `${hostname()}#${pidns ?? "?"}:${boot ?? "?"}` : hostname();
@@ -18944,7 +19051,7 @@ var classifyLockOwner = (payload, ageMs, localHost = localLockHost(), options =
18944
19051
  };
18945
19052
  var ageOf = (file, nowMs) => {
18946
19053
  try {
18947
- return nowMs - fs5.lstatSync(file).mtimeMs;
19054
+ return nowMs - fs6.lstatSync(file).mtimeMs;
18948
19055
  } catch {
18949
19056
  return null;
18950
19057
  }
@@ -18955,7 +19062,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
18955
19062
  if (age === null || age <= RECLAIM_GUARD_TTL_MS)
18956
19063
  return false;
18957
19064
  try {
18958
- fs5.rmdirSync(guard);
19065
+ fs6.rmdirSync(guard);
18959
19066
  return true;
18960
19067
  } catch {
18961
19068
  return false;
@@ -18964,8 +19071,8 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
18964
19071
 
18965
19072
  // packages/workit-core/src/store/event-log.ts
18966
19073
  import { randomUUID as randomUUID2 } from "node:crypto";
18967
- import fs6 from "node:fs";
18968
- import path5 from "node:path";
19074
+ import fs7 from "node:fs";
19075
+ import path7 from "node:path";
18969
19076
  var EVENT_VERSION = 1;
18970
19077
 
18971
19078
  class LogDamage extends Error {
@@ -18994,7 +19101,7 @@ var parseEvent = (line, file, offset) => {
18994
19101
  function readLog(file, from = 0, expectSeq = null) {
18995
19102
  let fd;
18996
19103
  try {
18997
- fd = fs6.openSync(file, "r");
19104
+ fd = fs7.openSync(file, "r");
18998
19105
  } catch (error) {
18999
19106
  if (error.code === "ENOENT")
19000
19107
  return null;
@@ -19003,13 +19110,13 @@ function readLog(file, from = 0, expectSeq = null) {
19003
19110
  let bytes;
19004
19111
  let size;
19005
19112
  try {
19006
- size = fs6.fstatSync(fd).size;
19113
+ size = fs7.fstatSync(fd).size;
19007
19114
  if (from > size)
19008
19115
  throw new LogDamage(`${file}: shorter than its snapshot`);
19009
19116
  bytes = Buffer.alloc(size - from);
19010
19117
  let read = 0;
19011
19118
  while (read < bytes.length) {
19012
- const got = fs6.readSync(fd, bytes, read, bytes.length - read, from + read);
19119
+ const got = fs7.readSync(fd, bytes, read, bytes.length - read, from + read);
19013
19120
  if (got === 0)
19014
19121
  break;
19015
19122
  read += got;
@@ -19017,7 +19124,7 @@ function readLog(file, from = 0, expectSeq = null) {
19017
19124
  bytes = bytes.subarray(0, read);
19018
19125
  size = from + read;
19019
19126
  } finally {
19020
- fs6.closeSync(fd);
19127
+ fs7.closeSync(fd);
19021
19128
  }
19022
19129
  const events = [];
19023
19130
  let start = 0;
@@ -19042,11 +19149,11 @@ function readLog(file, from = 0, expectSeq = null) {
19042
19149
  }
19043
19150
  var fsyncDirectory = (dir) => {
19044
19151
  try {
19045
- const fd = fs6.openSync(dir, "r");
19152
+ const fd = fs7.openSync(dir, "r");
19046
19153
  try {
19047
- fs6.fsyncSync(fd);
19154
+ fs7.fsyncSync(fd);
19048
19155
  } finally {
19049
- fs6.closeSync(fd);
19156
+ fs7.closeSync(fd);
19050
19157
  }
19051
19158
  } catch (error) {
19052
19159
  if (process.platform !== "win32")
@@ -19056,46 +19163,46 @@ var fsyncDirectory = (dir) => {
19056
19163
  function appendEvent(file, event, validEnd) {
19057
19164
  const line = Buffer.from(`${JSON.stringify(event)}
19058
19165
  `, "utf8");
19059
- const created = !fs6.existsSync(file);
19060
- if (!created && fs6.statSync(file).size !== validEnd) {
19061
- const cut = fs6.openSync(file, "r+");
19166
+ const created = !fs7.existsSync(file);
19167
+ if (!created && fs7.statSync(file).size !== validEnd) {
19168
+ const cut = fs7.openSync(file, "r+");
19062
19169
  try {
19063
- fs6.ftruncateSync(cut, validEnd);
19064
- fs6.fsyncSync(cut);
19170
+ fs7.ftruncateSync(cut, validEnd);
19171
+ fs7.fsyncSync(cut);
19065
19172
  } finally {
19066
- fs6.closeSync(cut);
19173
+ fs7.closeSync(cut);
19067
19174
  }
19068
19175
  }
19069
- const fd = fs6.openSync(file, "a", 384);
19176
+ const fd = fs7.openSync(file, "a", 384);
19070
19177
  try {
19071
19178
  let written = 0;
19072
19179
  while (written < line.length)
19073
- written += fs6.writeSync(fd, line, written, line.length - written);
19074
- fs6.fsyncSync(fd);
19180
+ written += fs7.writeSync(fd, line, written, line.length - written);
19181
+ fs7.fsyncSync(fd);
19075
19182
  } finally {
19076
- fs6.closeSync(fd);
19183
+ fs7.closeSync(fd);
19077
19184
  }
19078
19185
  if (created)
19079
- fsyncDirectory(path5.dirname(file));
19186
+ fsyncDirectory(path7.dirname(file));
19080
19187
  return validEnd;
19081
19188
  }
19082
19189
  function replaceFile(file, bytes, durable) {
19083
19190
  const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
19084
19191
  try {
19085
- const fd = fs6.openSync(temporary, "wx", 384);
19192
+ const fd = fs7.openSync(temporary, "wx", 384);
19086
19193
  try {
19087
- fs6.writeSync(fd, bytes);
19194
+ fs7.writeSync(fd, bytes);
19088
19195
  if (durable)
19089
- fs6.fsyncSync(fd);
19196
+ fs7.fsyncSync(fd);
19090
19197
  } finally {
19091
- fs6.closeSync(fd);
19198
+ fs7.closeSync(fd);
19092
19199
  }
19093
19200
  renameWithRetry(temporary, file);
19094
19201
  if (durable)
19095
- fsyncDirectory(path5.dirname(file));
19202
+ fsyncDirectory(path7.dirname(file));
19096
19203
  } catch (error) {
19097
19204
  try {
19098
- fs6.unlinkSync(temporary);
19205
+ fs7.unlinkSync(temporary);
19099
19206
  } catch {}
19100
19207
  throw error;
19101
19208
  }
@@ -19120,7 +19227,7 @@ var retryTransient = (run) => {
19120
19227
  }
19121
19228
  }
19122
19229
  };
19123
- var renameWithRetry = (from, to) => retryTransient(() => fs6.renameSync(from, to));
19230
+ var renameWithRetry = (from, to) => retryTransient(() => fs7.renameSync(from, to));
19124
19231
 
19125
19232
  // packages/workit-core/src/store/patch.ts
19126
19233
  var isPlainObject3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -19233,7 +19340,7 @@ var isPatch = (value) => Array.isArray(value) && value.every((op) => {
19233
19340
  });
19234
19341
 
19235
19342
  // packages/workit-core/src/store/reduce.ts
19236
- import { createHash as createHash3 } from "node:crypto";
19343
+ import { createHash as createHash4 } from "node:crypto";
19237
19344
  var OPENING_TYPES = new Set([
19238
19345
  "task.opened",
19239
19346
  "task.imported",
@@ -19262,7 +19369,7 @@ var isObject4 = (value) => typeof value === "object" && value !== null && !Array
19262
19369
  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");
19263
19370
  var BLOB_REF = "$blob";
19264
19371
  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;
19265
- var blobDigest = (value) => createHash3("sha256").update(JSON.stringify(value)).digest("hex");
19372
+ var blobDigest = (value) => createHash4("sha256").update(JSON.stringify(value)).digest("hex");
19266
19373
  var toBlob = (value, blobs) => {
19267
19374
  if (!isObject4(value))
19268
19375
  return value;
@@ -19417,7 +19524,7 @@ var indexEntry = (task, key, legacy, file) => {
19417
19524
  };
19418
19525
  var fileSignature = (file) => {
19419
19526
  try {
19420
- const stat = fs7.statSync(file, { bigint: true });
19527
+ const stat = fs8.statSync(file, { bigint: true });
19421
19528
  return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
19422
19529
  } catch {
19423
19530
  return null;
@@ -19435,7 +19542,7 @@ var cachedRuntimeVersion = null;
19435
19542
  var runtimeVersion = () => {
19436
19543
  if (cachedRuntimeVersion === null) {
19437
19544
  try {
19438
- const pkg = JSON.parse(fs7.readFileSync(path6.join(packageRoot(), "package.json"), "utf8"));
19545
+ const pkg = JSON.parse(fs8.readFileSync(path8.join(packageRoot(), "package.json"), "utf8"));
19439
19546
  cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
19440
19547
  } catch {
19441
19548
  cachedRuntimeVersion = "0.0.0";
@@ -19461,14 +19568,14 @@ var isNewerVersion = (candidate, current) => {
19461
19568
  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);
19462
19569
  var readText = (file) => {
19463
19570
  try {
19464
- return fs7.readFileSync(file, "utf8");
19571
+ return fs8.readFileSync(file, "utf8");
19465
19572
  } catch {
19466
19573
  return "";
19467
19574
  }
19468
19575
  };
19469
19576
  var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
19470
19577
  var branchStart = (location, branch, aliases) => {
19471
- const first = readText(path6.join(path6.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
19578
+ const first = readText(path8.join(path8.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
19472
19579
  `, 1)[0];
19473
19580
  const created = REFLOG_LINE.exec(first);
19474
19581
  const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
@@ -19478,7 +19585,7 @@ var branchStart = (location, branch, aliases) => {
19478
19585
  return start;
19479
19586
  if (!location.git)
19480
19587
  return null;
19481
- for (const line of readText(path6.join(location.git.gitDir, "logs", "HEAD")).split(`
19588
+ for (const line of readText(path8.join(location.git.gitDir, "logs", "HEAD")).split(`
19482
19589
  `)) {
19483
19590
  const entry = REFLOG_LINE.exec(line);
19484
19591
  const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
@@ -19488,23 +19595,23 @@ var branchStart = (location, branch, aliases) => {
19488
19595
  }
19489
19596
  return null;
19490
19597
  };
19491
- var refExists = (common, ref) => fs7.existsSync(path6.join(common, ref)) || readText(path6.join(common, "packed-refs")).includes(` ${ref}
19598
+ var refExists = (common, ref) => fs8.existsSync(path8.join(common, ref)) || readText(path8.join(common, "packed-refs")).includes(` ${ref}
19492
19599
  `);
19493
19600
  var origins = new Map;
19494
19601
  var sameDirectoryIdentity = (left, right) => {
19495
- if (!path6.isAbsolute(left) || !path6.isAbsolute(right))
19602
+ if (!path8.isAbsolute(left) || !path8.isAbsolute(right))
19496
19603
  return false;
19497
- const normalizedLeft = path6.resolve(left);
19498
- const normalizedRight = path6.resolve(right);
19604
+ const normalizedLeft = path8.resolve(left);
19605
+ const normalizedRight = path8.resolve(right);
19499
19606
  try {
19500
- const a = fs7.statSync(normalizedLeft, { bigint: true });
19501
- const b = fs7.statSync(normalizedRight, { bigint: true });
19607
+ const a = fs8.statSync(normalizedLeft, { bigint: true });
19608
+ const b = fs8.statSync(normalizedRight, { bigint: true });
19502
19609
  if (!a.isDirectory() || !b.isDirectory())
19503
19610
  return false;
19504
19611
  if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
19505
19612
  return true;
19506
- const canonicalLeft = fs7.realpathSync(normalizedLeft);
19507
- const canonicalRight = fs7.realpathSync(normalizedRight);
19613
+ const canonicalLeft = fs8.realpathSync(normalizedLeft);
19614
+ const canonicalRight = fs8.realpathSync(normalizedRight);
19508
19615
  if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
19509
19616
  return true;
19510
19617
  return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
@@ -19541,8 +19648,8 @@ class TaskStore {
19541
19648
  migrationChecked = false;
19542
19649
  compactDue = new Set;
19543
19650
  constructor(root, options = {}) {
19544
- const resolved = path6.resolve(root);
19545
- this.origin = fs7.existsSync(resolved) ? fs7.realpathSync(resolved) : resolved;
19651
+ const resolved = path8.resolve(root);
19652
+ this.origin = fs8.existsSync(resolved) ? fs8.realpathSync(resolved) : resolved;
19546
19653
  this.located = resolveStore(this.origin);
19547
19654
  this.root = checkoutRootOf(this.origin, this.located);
19548
19655
  this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
@@ -19550,7 +19657,7 @@ class TaskStore {
19550
19657
  this.migrateOnRead = options.migrateOnRead;
19551
19658
  }
19552
19659
  location() {
19553
- if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs7.existsSync(path6.join(this.root, ".git"))) {
19660
+ if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs8.existsSync(path8.join(this.root, ".git"))) {
19554
19661
  this.located = undefined;
19555
19662
  this.migrationChecked = false;
19556
19663
  }
@@ -19614,7 +19721,7 @@ class TaskStore {
19614
19721
  const tasksDir = this.paths().tasks;
19615
19722
  let names;
19616
19723
  try {
19617
- names = fs7.existsSync(tasksDir) ? fs7.readdirSync(tasksDir).filter((name) => validId(name)) : [];
19724
+ names = fs8.existsSync(tasksDir) ? fs8.readdirSync(tasksDir).filter((name) => validId(name)) : [];
19618
19725
  } catch (error) {
19619
19726
  return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
19620
19727
  path: tasksDir
@@ -19655,7 +19762,7 @@ class TaskStore {
19655
19762
  const file = this.paths().workspace;
19656
19763
  let bytes;
19657
19764
  try {
19658
- bytes = retryTransient(() => fs7.readFileSync(file, "utf8"));
19765
+ bytes = retryTransient(() => fs8.readFileSync(file, "utf8"));
19659
19766
  } catch (error) {
19660
19767
  if (error.code === "ENOENT")
19661
19768
  return success(null, null, null);
@@ -19706,7 +19813,7 @@ class TaskStore {
19706
19813
  const moved = this.bindLocked(again.data.id, key, input.now);
19707
19814
  return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
19708
19815
  }
19709
- const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path6.basename(this.root) || this.root;
19816
+ const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path8.basename(this.root) || this.root;
19710
19817
  const intent = {
19711
19818
  objective: input.objective?.trim() || `Work on ${label}`,
19712
19819
  scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
@@ -19766,14 +19873,14 @@ class TaskStore {
19766
19873
  const branch = key.ok ? key.data.branch : null;
19767
19874
  if (!branch || !location.ok)
19768
19875
  return success(null, null, null);
19769
- const common = path6.dirname(location.data.dir);
19770
- const heads = path6.join(common, "logs", "refs", "heads");
19771
- const headLog = location.data.git ? path6.join(location.data.git.gitDir, "logs", "HEAD") : "";
19876
+ const common = path8.dirname(location.data.dir);
19877
+ const heads = path8.join(common, "logs", "refs", "heads");
19878
+ const headLog = location.data.git ? path8.join(location.data.git.gitDir, "logs", "HEAD") : "";
19772
19879
  const signatures = [
19773
- path6.join(heads, branch),
19880
+ path8.join(heads, branch),
19774
19881
  headLog,
19775
19882
  heads,
19776
- path6.join(common, "packed-refs")
19883
+ path8.join(common, "packed-refs")
19777
19884
  ].map((file) => fileSignature(file) ?? "-");
19778
19885
  const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
19779
19886
  let resolved = origins.get(slot);
@@ -19785,7 +19892,7 @@ class TaskStore {
19785
19892
  aliases.push(rename.from);
19786
19893
  const start = branchStart(location.data, branch, aliases);
19787
19894
  const slash = start?.indexOf("/") ?? -1;
19788
- 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)}"]`));
19895
+ 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)}"]`));
19789
19896
  const name = start && (remote ? start.slice(slash + 1) : start);
19790
19897
  resolved = {
19791
19898
  signature: signatures.join("|"),
@@ -20023,13 +20130,13 @@ class TaskStore {
20023
20130
  if (!ready.ok)
20024
20131
  return ready;
20025
20132
  const dirs = this.paths();
20026
- const recovery = path6.join(this.root, ".workit", "recovery");
20027
- if (fs7.existsSync(recovery)) {
20133
+ const recovery = path8.join(this.root, ".workit", "recovery");
20134
+ if (fs8.existsSync(recovery)) {
20028
20135
  let files = 0;
20029
20136
  let bytes = 0;
20030
20137
  try {
20031
- for (const name of fs7.readdirSync(recovery)) {
20032
- const stat = fs7.lstatSync(path6.join(recovery, name));
20138
+ for (const name of fs8.readdirSync(recovery)) {
20139
+ const stat = fs8.lstatSync(path8.join(recovery, name));
20033
20140
  if (!stat.isFile())
20034
20141
  continue;
20035
20142
  files += 1;
@@ -20038,17 +20145,17 @@ class TaskStore {
20038
20145
  } catch {}
20039
20146
  const remove = options.pruneRecovery === true && !dryRun;
20040
20147
  if (remove)
20041
- fs7.rmSync(recovery, { recursive: true, force: true });
20148
+ fs8.rmSync(recovery, { recursive: true, force: true });
20042
20149
  report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
20043
20150
  }
20044
- if (!fs7.existsSync(dirs.tasks))
20151
+ if (!fs8.existsSync(dirs.tasks))
20045
20152
  return success(null, null, report);
20046
- const names = fs7.readdirSync(dirs.tasks).filter((name) => validId(name));
20153
+ const names = fs8.readdirSync(dirs.tasks).filter((name) => validId(name));
20047
20154
  for (const name of names) {
20048
20155
  const file = this.eventsPath(name);
20049
20156
  let size = 0;
20050
20157
  try {
20051
- size = fs7.statSync(file).size;
20158
+ size = fs8.statSync(file).size;
20052
20159
  } catch {
20053
20160
  continue;
20054
20161
  }
@@ -20076,16 +20183,16 @@ class TaskStore {
20076
20183
  const references = new Set;
20077
20184
  for (const name of names)
20078
20185
  try {
20079
- for (const match of fs7.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
20186
+ for (const match of fs8.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
20080
20187
  references.add(match[1]);
20081
20188
  } catch {}
20082
- if (fs7.existsSync(dirs.blobs))
20083
- for (const name of fs7.readdirSync(dirs.blobs)) {
20189
+ if (fs8.existsSync(dirs.blobs))
20190
+ for (const name of fs8.readdirSync(dirs.blobs)) {
20084
20191
  const digest = name.replace(/\.json$/, "");
20085
- const file = path6.join(dirs.blobs, name);
20192
+ const file = path8.join(dirs.blobs, name);
20086
20193
  let stat;
20087
20194
  try {
20088
- stat = fs7.lstatSync(file);
20195
+ stat = fs8.lstatSync(file);
20089
20196
  } catch {
20090
20197
  continue;
20091
20198
  }
@@ -20096,11 +20203,11 @@ class TaskStore {
20096
20203
  report.blobs.removed += 1;
20097
20204
  report.blobs.removedBytes += stat.size;
20098
20205
  if (!dryRun)
20099
- fs7.rmSync(file, { force: true });
20206
+ fs8.rmSync(file, { force: true });
20100
20207
  }
20101
20208
  return success(null, null, null);
20102
20209
  };
20103
- const swept = dryRun ? sweep() : this.withLock(path6.join(dirs.dir, "gc.lock"), sweep);
20210
+ const swept = dryRun ? sweep() : this.withLock(path8.join(dirs.dir, "gc.lock"), sweep);
20104
20211
  if (!swept.ok)
20105
20212
  return swept;
20106
20213
  const temporaryDirs = [
@@ -20108,17 +20215,17 @@ class TaskStore {
20108
20215
  dirs.tasks,
20109
20216
  dirs.blobs,
20110
20217
  dirs.checkout,
20111
- ...names.map((name) => path6.join(dirs.tasks, name))
20218
+ ...names.map((name) => path8.join(dirs.tasks, name))
20112
20219
  ];
20113
20220
  for (const directory of temporaryDirs) {
20114
- if (!fs7.existsSync(directory))
20221
+ if (!fs8.existsSync(directory))
20115
20222
  continue;
20116
- for (const name of fs7.readdirSync(directory)) {
20223
+ for (const name of fs8.readdirSync(directory)) {
20117
20224
  if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
20118
20225
  continue;
20119
- const file = path6.join(directory, name);
20226
+ const file = path8.join(directory, name);
20120
20227
  try {
20121
- const stat = fs7.lstatSync(file);
20228
+ const stat = fs8.lstatSync(file);
20122
20229
  if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
20123
20230
  continue;
20124
20231
  } catch {
@@ -20126,37 +20233,37 @@ class TaskStore {
20126
20233
  }
20127
20234
  report.temporary.removed += 1;
20128
20235
  if (!dryRun)
20129
- fs7.rmSync(file, { force: true });
20236
+ fs8.rmSync(file, { force: true });
20130
20237
  }
20131
20238
  }
20132
20239
  return success(null, null, report);
20133
20240
  }
20134
20241
  paths() {
20135
20242
  const location = this.location();
20136
- const dir = location.ok ? location.data.dir : path6.join(this.root, ".workit");
20137
- const checkout = path6.join(dir, "checkouts", checkoutSlug(this.root));
20243
+ const dir = location.ok ? location.data.dir : path8.join(this.root, ".workit");
20244
+ const checkout = path8.join(dir, "checkouts", checkoutSlug(this.root));
20138
20245
  return {
20139
20246
  dir,
20140
20247
  shared: location.ok ? location.data.shared : false,
20141
- marker: path6.join(dir, "store.json"),
20248
+ marker: path8.join(dir, "store.json"),
20142
20249
  checkout,
20143
- workspace: path6.join(checkout, "workspace.json"),
20144
- checkoutLock: path6.join(checkout, "metadata.lock"),
20145
- tasks: path6.join(dir, "tasks"),
20146
- index: path6.join(dir, "task-index.json"),
20147
- blobs: path6.join(dir, "blobs", "candidates"),
20148
- legacy: path6.join(dir, "legacy", checkoutSlug(this.root), "v2"),
20149
- v2: path6.join(this.root, ".workit")
20250
+ workspace: path8.join(checkout, "workspace.json"),
20251
+ checkoutLock: path8.join(checkout, "metadata.lock"),
20252
+ tasks: path8.join(dir, "tasks"),
20253
+ index: path8.join(dir, "task-index.json"),
20254
+ blobs: path8.join(dir, "blobs", "candidates"),
20255
+ legacy: path8.join(dir, "legacy", checkoutSlug(this.root), "v2"),
20256
+ v2: path8.join(this.root, ".workit")
20150
20257
  };
20151
20258
  }
20152
20259
  eventsPath(taskId) {
20153
- return path6.join(this.paths().tasks, taskId, "events.jsonl");
20260
+ return path8.join(this.paths().tasks, taskId, "events.jsonl");
20154
20261
  }
20155
20262
  snapshotPath(taskId) {
20156
- return path6.join(this.paths().tasks, taskId, "snapshot.json");
20263
+ return path8.join(this.paths().tasks, taskId, "snapshot.json");
20157
20264
  }
20158
20265
  taskLockPath(taskId) {
20159
- return path6.join(this.paths().tasks, taskId, "lock");
20266
+ return path8.join(this.paths().tasks, taskId, "lock");
20160
20267
  }
20161
20268
  ready(write = false) {
20162
20269
  const location = this.location();
@@ -20166,7 +20273,7 @@ class TaskStore {
20166
20273
  return success(null, null, null);
20167
20274
  const dirs = this.paths();
20168
20275
  try {
20169
- const marker = JSON.parse(fs7.readFileSync(dirs.marker, "utf8"));
20276
+ const marker = JSON.parse(fs8.readFileSync(dirs.marker, "utf8"));
20170
20277
  if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
20171
20278
  return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
20172
20279
  } catch {}
@@ -20195,21 +20302,21 @@ class TaskStore {
20195
20302
  return {
20196
20303
  read: (digest) => {
20197
20304
  try {
20198
- return JSON.parse(fs7.readFileSync(path6.join(dir, `${digest}.json`), "utf8"));
20305
+ return JSON.parse(fs8.readFileSync(path8.join(dir, `${digest}.json`), "utf8"));
20199
20306
  } catch (error) {
20200
20307
  throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
20201
20308
  }
20202
20309
  },
20203
20310
  write: (digest, value) => {
20204
- const file = path6.join(dir, `${digest}.json`);
20205
- if (fs7.existsSync(file)) {
20311
+ const file = path8.join(dir, `${digest}.json`);
20312
+ if (fs8.existsSync(file)) {
20206
20313
  const stamp = new Date;
20207
20314
  try {
20208
- fs7.utimesSync(file, stamp, stamp);
20315
+ fs8.utimesSync(file, stamp, stamp);
20209
20316
  return;
20210
20317
  } catch {}
20211
20318
  }
20212
- fs7.mkdirSync(dir, { recursive: true });
20319
+ fs8.mkdirSync(dir, { recursive: true });
20213
20320
  replaceFile(file, JSON.stringify(value), true);
20214
20321
  }
20215
20322
  };
@@ -20291,7 +20398,7 @@ class TaskStore {
20291
20398
  }
20292
20399
  readSnapshot(taskId) {
20293
20400
  try {
20294
- const value = JSON.parse(fs7.readFileSync(this.snapshotPath(taskId), "utf8"));
20401
+ const value = JSON.parse(fs8.readFileSync(this.snapshotPath(taskId), "utf8"));
20295
20402
  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))
20296
20403
  return null;
20297
20404
  return value;
@@ -20393,8 +20500,8 @@ class TaskStore {
20393
20500
  }
20394
20501
  }
20395
20502
  openTask(record, type, key, legacy = null) {
20396
- const dir = path6.join(this.paths().tasks, record.id);
20397
- fs7.mkdirSync(dir, { recursive: true });
20503
+ const dir = path8.join(this.paths().tasks, record.id);
20504
+ fs8.mkdirSync(dir, { recursive: true });
20398
20505
  const blobs = this.blobStore();
20399
20506
  const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
20400
20507
  const event = this.event(record.id, 1, type, {
@@ -20446,11 +20553,11 @@ class TaskStore {
20446
20553
  } catch {}
20447
20554
  if (!latest || latest.events[0]?.id !== last.id)
20448
20555
  return failure2("busy", "the task log changed during compaction; retry", { taskId });
20449
- const appended = fs7.readFileSync(file).subarray(log.end, latest.end);
20556
+ const appended = fs8.readFileSync(file).subarray(log.end, latest.end);
20450
20557
  const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
20451
20558
  replaceFile(file, bytes.toString("utf8"), true);
20452
20559
  try {
20453
- fs7.rmSync(this.snapshotPath(taskId), { force: true });
20560
+ fs8.rmSync(this.snapshotPath(taskId), { force: true });
20454
20561
  } catch {}
20455
20562
  const reloaded = this.load(taskId);
20456
20563
  if (reloaded.ok && reloaded.data)
@@ -20463,7 +20570,7 @@ class TaskStore {
20463
20570
  }
20464
20571
  countEvents(file) {
20465
20572
  try {
20466
- const bytes = fs7.readFileSync(file);
20573
+ const bytes = fs8.readFileSync(file);
20467
20574
  let count = 0;
20468
20575
  for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
20469
20576
  count += 1;
@@ -20485,8 +20592,8 @@ class TaskStore {
20485
20592
  return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
20486
20593
  }
20487
20594
  withKeyLock(key, operation) {
20488
- const digest = createHash4("sha256").update(key).digest("hex").slice(0, 32);
20489
- return this.withLock(path6.join(this.paths().dir, "keys", `${digest}.lock`), operation);
20595
+ const digest = createHash5("sha256").update(key).digest("hex").slice(0, 32);
20596
+ return this.withLock(path8.join(this.paths().dir, "keys", `${digest}.lock`), operation);
20490
20597
  }
20491
20598
  bindLocked(taskId, key, timestamp) {
20492
20599
  const current = this.readWorkspace();
@@ -20627,7 +20734,7 @@ class TaskStore {
20627
20734
  writeWorkspace(record) {
20628
20735
  const file = this.paths().workspace;
20629
20736
  try {
20630
- fs7.mkdirSync(path6.dirname(file), { recursive: true });
20737
+ fs8.mkdirSync(path8.dirname(file), { recursive: true });
20631
20738
  replaceFile(file, `${canonicalJson(record)}
20632
20739
  `, true);
20633
20740
  return success(null, null, null);
@@ -20637,7 +20744,7 @@ class TaskStore {
20637
20744
  }
20638
20745
  readIndex() {
20639
20746
  try {
20640
- const value = JSON.parse(fs7.readFileSync(this.paths().index, "utf8"));
20747
+ const value = JSON.parse(fs8.readFileSync(this.paths().index, "utf8"));
20641
20748
  if (!isObject5(value) || value.version !== INDEX_VERSION || !isObject5(value.tasks))
20642
20749
  return {};
20643
20750
  const tasks = {};
@@ -20651,7 +20758,7 @@ class TaskStore {
20651
20758
  }
20652
20759
  writeIndex(entries) {
20653
20760
  try {
20654
- fs7.mkdirSync(this.paths().tasks, { recursive: true });
20761
+ fs8.mkdirSync(this.paths().tasks, { recursive: true });
20655
20762
  replaceFile(this.paths().index, JSON.stringify({
20656
20763
  version: INDEX_VERSION,
20657
20764
  tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
@@ -20705,23 +20812,23 @@ class TaskStore {
20705
20812
  return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
20706
20813
  }
20707
20814
  v2Dirs() {
20708
- return [...new Set([this.root, this.origin])].map((dir) => path6.join(dir, ".workit"));
20815
+ return [...new Set([this.root, this.origin])].map((dir) => path8.join(dir, ".workit"));
20709
20816
  }
20710
20817
  pendingMigrations() {
20711
20818
  return this.v2Dirs().filter((dir) => {
20712
- const raw = this.readV2Workspace(path6.join(dir, "workspace.json"));
20819
+ const raw = this.readV2Workspace(path8.join(dir, "workspace.json"));
20713
20820
  return raw !== null && raw !== TOMBSTONE;
20714
20821
  });
20715
20822
  }
20716
20823
  migrateV2(v2) {
20717
20824
  const dirs = this.paths();
20718
- const v2Workspace = path6.join(v2, "workspace.json");
20719
- const v2Tasks = path6.join(v2, "tasks");
20720
- const legacy = path6.join(dirs.dir, "legacy", checkoutSlug(path6.dirname(v2)), "v2");
20825
+ const v2Workspace = path8.join(v2, "workspace.json");
20826
+ const v2Tasks = path8.join(v2, "tasks");
20827
+ const legacy = path8.join(dirs.dir, "legacy", checkoutSlug(path8.dirname(v2)), "v2");
20721
20828
  const raw = this.readV2Workspace(v2Workspace);
20722
20829
  if (raw === null || raw === TOMBSTONE)
20723
20830
  return success(null, null, null);
20724
- return this.withLock(dirs.checkoutLock, () => this.withLock(path6.join(v2, "metadata.lock"), () => {
20831
+ return this.withLock(dirs.checkoutLock, () => this.withLock(path8.join(v2, "metadata.lock"), () => {
20725
20832
  const workspace = this.readV2Workspace(v2Workspace);
20726
20833
  if (workspace === null || workspace === TOMBSTONE)
20727
20834
  return success(null, null, null);
@@ -20730,7 +20837,7 @@ class TaskStore {
20730
20837
  return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
20731
20838
  let files = [];
20732
20839
  try {
20733
- files = fs7.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path6.join(v2Tasks, name)));
20840
+ files = fs8.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path8.join(v2Tasks, name)));
20734
20841
  } catch {}
20735
20842
  const current = this.readWorkspace();
20736
20843
  if (!current.ok)
@@ -20748,22 +20855,22 @@ class TaskStore {
20748
20855
  let skipped = 0;
20749
20856
  const done = new Map;
20750
20857
  try {
20751
- fs7.mkdirSync(path6.join(legacy, "tasks"), { recursive: true });
20858
+ fs8.mkdirSync(path8.join(legacy, "tasks"), { recursive: true });
20752
20859
  for (const name of ["workspace.json", "index.json"])
20753
- if (fs7.existsSync(path6.join(v2, name)))
20754
- fs7.copyFileSync(path6.join(v2, name), path6.join(legacy, name));
20860
+ if (fs8.existsSync(path8.join(v2, name)))
20861
+ fs8.copyFileSync(path8.join(v2, name), path8.join(legacy, name));
20755
20862
  for (const name of files) {
20756
20863
  const id = name.slice(0, -5);
20757
- const file = path6.join(v2Tasks, name);
20758
- const bytes = fs7.readFileSync(file, "utf8");
20864
+ const file = path8.join(v2Tasks, name);
20865
+ const bytes = fs8.readFileSync(file, "utf8");
20759
20866
  const digest = sha256(bytes);
20760
- fs7.writeFileSync(path6.join(legacy, "tasks", name), bytes);
20867
+ fs8.writeFileSync(path8.join(legacy, "tasks", name), bytes);
20761
20868
  const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
20762
20869
  if (!parsed.ok || parsed.data.id !== id)
20763
20870
  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 });
20764
20871
  const record = { ...parsed.data, workspaceId: target.id };
20765
- const origin = { path: path6.join(legacy, "tasks", name), digest };
20766
- if (!fs7.existsSync(this.eventsPath(id))) {
20872
+ const origin = { path: path8.join(legacy, "tasks", name), digest };
20873
+ if (!fs8.existsSync(this.eventsPath(id))) {
20767
20874
  this.openTask(record, "migrated.from_v2", null, origin);
20768
20875
  migrated += 1;
20769
20876
  } else {
@@ -20798,8 +20905,8 @@ class TaskStore {
20798
20905
  try {
20799
20906
  let complete = true;
20800
20907
  for (const [name, digest] of done) {
20801
- const file = path6.join(v2Tasks, name);
20802
- if (sha256(fs7.readFileSync(file, "utf8")) !== digest) {
20908
+ const file = path8.join(v2Tasks, name);
20909
+ if (sha256(fs8.readFileSync(file, "utf8")) !== digest) {
20803
20910
  complete = false;
20804
20911
  continue;
20805
20912
  }
@@ -20809,7 +20916,7 @@ class TaskStore {
20809
20916
  return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
20810
20917
  path: v2
20811
20918
  });
20812
- fs7.rmSync(path6.join(v2, "index.json"), { force: true });
20919
+ fs8.rmSync(path8.join(v2, "index.json"), { force: true });
20813
20920
  this.writeTombstone(v2, target.id);
20814
20921
  } catch (error) {
20815
20922
  return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
@@ -20829,45 +20936,45 @@ class TaskStore {
20829
20936
  }
20830
20937
  adoptLocalStore() {
20831
20938
  const dirs = this.paths();
20832
- const marker = path6.join(dirs.v2, "store.json");
20833
- if (!dirs.shared || !fs7.existsSync(marker))
20939
+ const marker = path8.join(dirs.v2, "store.json");
20940
+ if (!dirs.shared || !fs8.existsSync(marker))
20834
20941
  return success(null, null, null);
20835
20942
  return this.withLock(dirs.checkoutLock, () => {
20836
- if (!fs7.existsSync(marker))
20943
+ if (!fs8.existsSync(marker))
20837
20944
  return success(null, null, null);
20838
20945
  let tasks = 0;
20839
20946
  try {
20840
20947
  const merge = (from, to) => {
20841
- if (!fs7.existsSync(to)) {
20842
- fs7.mkdirSync(path6.dirname(to), { recursive: true });
20948
+ if (!fs8.existsSync(to)) {
20949
+ fs8.mkdirSync(path8.dirname(to), { recursive: true });
20843
20950
  try {
20844
- fs7.renameSync(from, to);
20951
+ fs8.renameSync(from, to);
20845
20952
  } catch {
20846
- fs7.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
20847
- fs7.rmSync(from, { recursive: true, force: true });
20953
+ fs8.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
20954
+ fs8.rmSync(from, { recursive: true, force: true });
20848
20955
  }
20849
20956
  return;
20850
20957
  }
20851
- if (fs7.lstatSync(from).isDirectory() && fs7.lstatSync(to).isDirectory())
20852
- for (const name of fs7.readdirSync(from))
20853
- merge(path6.join(from, name), path6.join(to, name));
20958
+ if (fs8.lstatSync(from).isDirectory() && fs8.lstatSync(to).isDirectory())
20959
+ for (const name of fs8.readdirSync(from))
20960
+ merge(path8.join(from, name), path8.join(to, name));
20854
20961
  };
20855
20962
  for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
20856
- const from = path6.join(dirs.v2, sub);
20857
- if (!fs7.existsSync(from))
20963
+ const from = path8.join(dirs.v2, sub);
20964
+ if (!fs8.existsSync(from))
20858
20965
  continue;
20859
20966
  if (sub === "tasks") {
20860
- for (const name of fs7.readdirSync(from))
20861
- if (validId(name) && !fs7.existsSync(path6.join(dirs.dir, sub, name)))
20967
+ for (const name of fs8.readdirSync(from))
20968
+ if (validId(name) && !fs8.existsSync(path8.join(dirs.dir, sub, name)))
20862
20969
  tasks += 1;
20863
20970
  }
20864
- merge(from, path6.join(dirs.dir, sub));
20971
+ merge(from, path8.join(dirs.dir, sub));
20865
20972
  }
20866
- const ledger = path6.join(dirs.v2, "ledger");
20867
- if (fs7.existsSync(ledger) && !fs7.existsSync(path6.join(dirs.dir, "ledger")))
20868
- merge(ledger, path6.join(dirs.dir, "ledger"));
20869
- fs7.rmSync(path6.join(dirs.v2, "task-index.json"), { force: true });
20870
- fs7.renameSync(marker, path6.join(dirs.v2, "store.moved.json"));
20973
+ const ledger = path8.join(dirs.v2, "ledger");
20974
+ if (fs8.existsSync(ledger) && !fs8.existsSync(path8.join(dirs.dir, "ledger")))
20975
+ merge(ledger, path8.join(dirs.dir, "ledger"));
20976
+ fs8.rmSync(path8.join(dirs.v2, "task-index.json"), { force: true });
20977
+ fs8.renameSync(marker, path8.join(dirs.v2, "store.moved.json"));
20871
20978
  } catch (error) {
20872
20979
  return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
20873
20980
  path: dirs.v2
@@ -20887,7 +20994,7 @@ class TaskStore {
20887
20994
  readV2Workspace(file) {
20888
20995
  let bytes;
20889
20996
  try {
20890
- bytes = fs7.readFileSync(file, "utf8");
20997
+ bytes = fs8.readFileSync(file, "utf8");
20891
20998
  } catch {
20892
20999
  return null;
20893
21000
  }
@@ -20905,7 +21012,7 @@ class TaskStore {
20905
21012
  schemaVersion: SCHEMA_VERSION,
20906
21013
  id: workspaceId ?? newId(),
20907
21014
  revision: newRevision(),
20908
- root: path6.dirname(v2),
21015
+ root: path8.dirname(v2),
20909
21016
  runtime: { createdWith: version, updatedWith: version },
20910
21017
  writer: null,
20911
21018
  store: {
@@ -20916,12 +21023,12 @@ class TaskStore {
20916
21023
  },
20917
21024
  critical: ["store"]
20918
21025
  };
20919
- fs7.mkdirSync(v2, { recursive: true });
20920
- const ignore = path6.join(v2, ".gitignore");
20921
- if (!fs7.existsSync(ignore))
20922
- fs7.writeFileSync(ignore, `*
21026
+ fs8.mkdirSync(v2, { recursive: true });
21027
+ const ignore = path8.join(v2, ".gitignore");
21028
+ if (!fs8.existsSync(ignore))
21029
+ fs8.writeFileSync(ignore, `*
20923
21030
  `);
20924
- replaceFile(path6.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
21031
+ replaceFile(path8.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
20925
21032
  `, true);
20926
21033
  }
20927
21034
  stubFor(taskId) {
@@ -20937,7 +21044,7 @@ class TaskStore {
20937
21044
  }
20938
21045
  isStub(file) {
20939
21046
  try {
20940
- const value = JSON.parse(fs7.readFileSync(file, "utf8"));
21047
+ const value = JSON.parse(fs8.readFileSync(file, "utf8"));
20941
21048
  return isObject5(value) && isObject5(value.store) && value.store.format === "workit-store";
20942
21049
  } catch {
20943
21050
  return false;
@@ -20945,32 +21052,32 @@ class TaskStore {
20945
21052
  }
20946
21053
  writeTombstoneIfMissing() {
20947
21054
  try {
20948
- const v2 = path6.join(this.root, ".workit");
20949
- if (fs7.existsSync(path6.join(v2, "workspace.json")))
21055
+ const v2 = path8.join(this.root, ".workit");
21056
+ if (fs8.existsSync(path8.join(v2, "workspace.json")))
20950
21057
  return;
20951
21058
  let id = null;
20952
21059
  try {
20953
- id = JSON.parse(fs7.readFileSync(this.paths().workspace, "utf8")).id ?? null;
21060
+ id = JSON.parse(fs8.readFileSync(this.paths().workspace, "utf8")).id ?? null;
20954
21061
  } catch {}
20955
21062
  this.writeTombstone(v2, id);
20956
21063
  } catch {}
20957
21064
  }
20958
21065
  initializeStorage() {
20959
21066
  const dirs = this.paths();
20960
- retryTransient(() => fs7.mkdirSync(dirs.checkout, { recursive: true }));
20961
- retryTransient(() => fs7.mkdirSync(dirs.tasks, { recursive: true }));
20962
- if (!fs7.existsSync(dirs.marker))
21067
+ retryTransient(() => fs8.mkdirSync(dirs.checkout, { recursive: true }));
21068
+ retryTransient(() => fs8.mkdirSync(dirs.tasks, { recursive: true }));
21069
+ if (!fs8.existsSync(dirs.marker))
20963
21070
  replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
20964
21071
  `, false);
20965
21072
  if (!dirs.shared) {
20966
- const ignore = path6.join(dirs.dir, ".gitignore");
21073
+ const ignore = path8.join(dirs.dir, ".gitignore");
20967
21074
  let current = null;
20968
21075
  try {
20969
- current = fs7.readFileSync(ignore, "utf8");
21076
+ current = fs8.readFileSync(ignore, "utf8");
20970
21077
  } catch {}
20971
21078
  if (current !== `*
20972
21079
  `)
20973
- retryTransient(() => fs7.writeFileSync(ignore, `*
21080
+ retryTransient(() => fs8.writeFileSync(ignore, `*
20974
21081
  `));
20975
21082
  }
20976
21083
  this.writeTombstoneIfMissing();
@@ -20986,7 +21093,7 @@ class TaskStore {
20986
21093
  shouldReclaim: ({ payload, nowMs }) => {
20987
21094
  let ageMs = null;
20988
21095
  try {
20989
- ageMs = nowMs - fs7.lstatSync(lockPath).mtimeMs;
21096
+ ageMs = nowMs - fs8.lstatSync(lockPath).mtimeMs;
20990
21097
  } catch {}
20991
21098
  return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
20992
21099
  },
@@ -21023,7 +21130,7 @@ class TaskStore {
21023
21130
  withLock(lockPath, operation) {
21024
21131
  try {
21025
21132
  this.initializeStorage();
21026
- fs7.mkdirSync(path6.dirname(lockPath), { recursive: true });
21133
+ fs8.mkdirSync(path8.dirname(lockPath), { recursive: true });
21027
21134
  } catch (error) {
21028
21135
  return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
21029
21136
  path: this.paths().dir
@@ -21063,18 +21170,18 @@ class TaskStore {
21063
21170
  lockDirWritable(lockPath) {
21064
21171
  const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
21065
21172
  try {
21066
- fs7.closeSync(fs7.openSync(probe, "wx", 384));
21173
+ fs8.closeSync(fs8.openSync(probe, "wx", 384));
21067
21174
  } catch {
21068
21175
  return false;
21069
21176
  }
21070
21177
  try {
21071
- fs7.rmSync(probe, { force: true });
21178
+ fs8.rmSync(probe, { force: true });
21072
21179
  } catch {}
21073
21180
  return true;
21074
21181
  }
21075
21182
  lockHolderPresent(lockPath) {
21076
21183
  try {
21077
- fs7.lstatSync(lockPath);
21184
+ fs8.lstatSync(lockPath);
21078
21185
  return true;
21079
21186
  } catch (error) {
21080
21187
  return error?.code !== "ENOENT";
@@ -21086,12 +21193,12 @@ class TaskStore {
21086
21193
  if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
21087
21194
  return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
21088
21195
  path: lockPath,
21089
- guidance: `Check permissions and the read-only attribute on ${path6.dirname(lockPath)}.`
21196
+ guidance: `Check permissions and the read-only attribute on ${path8.dirname(lockPath)}.`
21090
21197
  });
21091
21198
  if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
21092
21199
  let lock = null;
21093
21200
  try {
21094
- lock = parseMetadataLockOrNull(fs7.readFileSync(lockPath, "utf8"));
21201
+ lock = parseMetadataLockOrNull(fs8.readFileSync(lockPath, "utf8"));
21095
21202
  } catch {}
21096
21203
  return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
21097
21204
  outcome: "not_started",
@@ -21109,15 +21216,15 @@ var isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state);
21109
21216
  var workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state);
21110
21217
 
21111
21218
  // packages/workit-core/src/core/task-evaluation.ts
21112
- import { createHash as createHash9 } from "node:crypto";
21113
- import * as fs12 from "node:fs";
21219
+ import { createHash as createHash10 } from "node:crypto";
21220
+ import * as fs13 from "node:fs";
21114
21221
  import { spawnSync as spawnSync10 } from "node:child_process";
21115
- import path14 from "node:path";
21222
+ import path16 from "node:path";
21116
21223
 
21117
21224
  // packages/workit-core/src/check-config.ts
21118
21225
  import { spawnSync as spawnSync3 } from "node:child_process";
21119
- import fs8 from "node:fs";
21120
- import path7 from "node:path";
21226
+ import fs9 from "node:fs";
21227
+ import path9 from "node:path";
21121
21228
  var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
21122
21229
  var CHECKS_FILE = "workit.checks.json";
21123
21230
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -21170,10 +21277,10 @@ var git = (cwd, args) => {
21170
21277
  return value || null;
21171
21278
  };
21172
21279
  function checkRoot(cwd) {
21173
- return path7.resolve(git(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
21280
+ return path9.resolve(git(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
21174
21281
  }
21175
21282
  var packageManager = (root) => {
21176
- const has = (file) => fs8.existsSync(path7.join(root, file));
21283
+ const has = (file) => fs9.existsSync(path9.join(root, file));
21177
21284
  if (has("bun.lock") || has("bun.lockb"))
21178
21285
  return "bun";
21179
21286
  if (has("pnpm-lock.yaml"))
@@ -21193,7 +21300,7 @@ var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
21193
21300
  function detectedChecks(root) {
21194
21301
  const read = (file) => {
21195
21302
  try {
21196
- return fs8.readFileSync(path7.join(root, file), "utf8");
21303
+ return fs9.readFileSync(path9.join(root, file), "utf8");
21197
21304
  } catch {
21198
21305
  return null;
21199
21306
  }
@@ -21232,7 +21339,7 @@ function detectedChecks(root) {
21232
21339
  var GATES = ["testing", "verification"];
21233
21340
  function loadCheckConfig(cwd) {
21234
21341
  const root = checkRoot(cwd);
21235
- const file = path7.join(root, CHECKS_FILE);
21342
+ const file = path9.join(root, CHECKS_FILE);
21236
21343
  const none = (error = null) => ({
21237
21344
  source: error ? CHECKS_FILE : "none",
21238
21345
  root,
@@ -21242,7 +21349,7 @@ function loadCheckConfig(cwd) {
21242
21349
  });
21243
21350
  let text = null;
21244
21351
  try {
21245
- text = fs8.readFileSync(file, "utf8");
21352
+ text = fs9.readFileSync(file, "utf8");
21246
21353
  } catch (error) {
21247
21354
  if (error.code !== "ENOENT")
21248
21355
  return none(`cannot read ${CHECKS_FILE}: ${error.message}`);
@@ -21305,10 +21412,10 @@ function workitAvailable(env = process.env) {
21305
21412
  return workitOnPath;
21306
21413
  const windows = process.platform === "win32";
21307
21414
  const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
21308
- const dirs = (env.PATH ?? env.Path ?? "").split(path7.delimiter).filter(Boolean);
21415
+ const dirs = (env.PATH ?? env.Path ?? "").split(path9.delimiter).filter(Boolean);
21309
21416
  workitOnPath = dirs.some((dir) => exts.some((ext) => {
21310
21417
  try {
21311
- return fs8.statSync(path7.join(dir, `workit${ext}`)).isFile();
21418
+ return fs9.statSync(path9.join(dir, `workit${ext}`)).isFile();
21312
21419
  } catch {
21313
21420
  return false;
21314
21421
  }
@@ -21321,10 +21428,10 @@ function checkCommand(args, version, onPath = workitAvailable()) {
21321
21428
 
21322
21429
  // packages/workit-core/src/git/rev.ts
21323
21430
  import { spawnSync as spawnSync4 } from "node:child_process";
21324
- import { createHash as createHash5 } from "node:crypto";
21325
- import fs9 from "node:fs";
21431
+ import { createHash as createHash6 } from "node:crypto";
21432
+ import fs10 from "node:fs";
21326
21433
  import os2 from "node:os";
21327
- import path8 from "node:path";
21434
+ import path10 from "node:path";
21328
21435
  var MAX_BUFFER = 256 * 1024 * 1024;
21329
21436
  var GIT_TIMEOUTS = { local: 20000, worktree: 120000, network: 15000 };
21330
21437
  var git2 = (cwd, args, options = {}) => {
@@ -21359,10 +21466,10 @@ function headSha(cwd) {
21359
21466
  var emptyTree = (cwd) => line(git2(cwd, ["mktree"], { input: "" }));
21360
21467
  var MAX_UNTRACKED_BYTES = 5 * 1024 * 1024;
21361
21468
  var seedIndex = (from, to) => {
21362
- fs9.copyFileSync(from, to);
21363
- const { atimeNs, mtimeNs } = fs9.statSync(from, { bigint: true });
21469
+ fs10.copyFileSync(from, to);
21470
+ const { atimeNs, mtimeNs } = fs10.statSync(from, { bigint: true });
21364
21471
  const seconds = (ns) => (Number(ns / 1000n) - 1) / 1e6;
21365
- fs9.utimesSync(to, seconds(atimeNs), seconds(mtimeNs));
21472
+ fs10.utimesSync(to, seconds(atimeNs), seconds(mtimeNs));
21366
21473
  };
21367
21474
  function worktreeTree(cwd, options = {}) {
21368
21475
  const top = line(git2(cwd, ["rev-parse", "--show-toplevel"]));
@@ -21371,10 +21478,10 @@ function worktreeTree(cwd, options = {}) {
21371
21478
  return null;
21372
21479
  const cap = options.maxUntrackedBytes ?? MAX_UNTRACKED_BYTES;
21373
21480
  const timeoutMs = options.timeoutMs ?? GIT_TIMEOUTS.worktree;
21374
- const scratch = fs9.mkdtempSync(path8.join(os2.tmpdir(), "workit-tree-"));
21481
+ const scratch = fs10.mkdtempSync(path10.join(os2.tmpdir(), "workit-tree-"));
21375
21482
  try {
21376
- const tempIndex = path8.join(scratch, "index");
21377
- if (fs9.existsSync(indexPath))
21483
+ const tempIndex = path10.join(scratch, "index");
21484
+ if (fs10.existsSync(indexPath))
21378
21485
  seedIndex(indexPath, tempIndex);
21379
21486
  const env = { ...process.env, GIT_INDEX_FILE: tempIndex };
21380
21487
  const untracked = git2(top, ["ls-files", "--others", "--exclude-standard", "-z"], {
@@ -21386,7 +21493,7 @@ function worktreeTree(cwd, options = {}) {
21386
21493
  const skipped = [];
21387
21494
  for (const file of untracked.stdout.split("\x00").filter(Boolean)) {
21388
21495
  try {
21389
- const stat = fs9.statSync(path8.join(top, file));
21496
+ const stat = fs10.statSync(path10.join(top, file));
21390
21497
  if (stat.isFile() && stat.size > cap)
21391
21498
  skipped.push({ path: file, size: stat.size, mtimeMs: Math.trunc(stat.mtimeMs) });
21392
21499
  } catch {}
@@ -21403,10 +21510,10 @@ function worktreeTree(cwd, options = {}) {
21403
21510
  if (!tree)
21404
21511
  return null;
21405
21512
  const base = line(git2(top, ["rev-parse", "--verify", "-q", "HEAD^{tree}"])) ?? emptyTree(top);
21406
- const key = skipped.length ? `sha256:${createHash5("sha256").update(JSON.stringify({ tree, skipped })).digest("hex")}` : tree;
21513
+ const key = skipped.length ? `sha256:${createHash6("sha256").update(JSON.stringify({ tree, skipped })).digest("hex")}` : tree;
21407
21514
  return { tree, key, dirty: tree !== base || skipped.length > 0, skipped };
21408
21515
  } finally {
21409
- fs9.rmSync(scratch, { recursive: true, force: true });
21516
+ fs10.rmSync(scratch, { recursive: true, force: true });
21410
21517
  }
21411
21518
  }
21412
21519
  function worktreeSignal(cwd, options = {}) {
@@ -21426,16 +21533,16 @@ function worktreeSignal(cwd, options = {}) {
21426
21533
  });
21427
21534
  if (!status.ok)
21428
21535
  return null;
21429
- const hash = createHash5("sha256");
21536
+ const hash = createHash6("sha256");
21430
21537
  hash.update(`${headSha(top) ?? "unborn"}\x00`);
21431
21538
  for (const entry of status.stdout.split("\x00")) {
21432
21539
  if (entry.length < 4)
21433
21540
  continue;
21434
21541
  const file = entry.slice(3);
21435
- const absolute = path8.join(top, file);
21542
+ const absolute = path10.join(top, file);
21436
21543
  let stat = "-";
21437
21544
  try {
21438
- const info = fs9.lstatSync(absolute, { bigint: true });
21545
+ const info = fs10.lstatSync(absolute, { bigint: true });
21439
21546
  stat = `${info.mode.toString(8)}:${info.size}:${info.mtimeNs}`;
21440
21547
  if (info.isDirectory())
21441
21548
  stat += `:${headSha(absolute) ?? "-"}`;
@@ -21502,17 +21609,17 @@ function pushRemoteName(cwd, branch) {
21502
21609
 
21503
21610
  // packages/workit-core/src/core/policy/derive.ts
21504
21611
  import { existsSync as existsSync4 } from "node:fs";
21505
- import path13 from "node:path";
21612
+ import path15 from "node:path";
21506
21613
 
21507
21614
  // packages/workit-core/src/ledger.ts
21508
21615
  import { spawnSync as spawnSync9 } from "node:child_process";
21509
- import { createHash as createHash8, randomBytes as randomBytes2 } from "node:crypto";
21510
- import fs11 from "node:fs";
21511
- import path12 from "node:path";
21616
+ import { createHash as createHash9, randomBytes as randomBytes3 } from "node:crypto";
21617
+ import fs12 from "node:fs";
21618
+ import path14 from "node:path";
21512
21619
 
21513
21620
  // packages/workit-core/src/core/vcs-config.ts
21514
- import fs10 from "node:fs";
21515
- import path11 from "node:path";
21621
+ import fs11 from "node:fs";
21622
+ import path13 from "node:path";
21516
21623
  import { spawnSync as spawnSync8 } from "node:child_process";
21517
21624
 
21518
21625
  // packages/workit-core/src/core/config.ts
@@ -21526,7 +21633,7 @@ import {
21526
21633
  writeFileSync as writeFileSync2
21527
21634
  } from "node:fs";
21528
21635
  import os3 from "node:os";
21529
- import path9 from "node:path";
21636
+ import path11 from "node:path";
21530
21637
 
21531
21638
  // packages/workit-core/src/core/boundary.ts
21532
21639
  import { statSync as statSync2 } from "node:fs";
@@ -21585,7 +21692,7 @@ var mergePreset = (preset, input = {}, current = {
21585
21692
  protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
21586
21693
  };
21587
21694
  };
21588
- 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");
21695
+ 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");
21589
21696
  var migratedDir = null;
21590
21697
  var migrationFailed = false;
21591
21698
  var ensureConfigDir = (dir = resolveConfigDir()) => {
@@ -21595,7 +21702,7 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
21595
21702
  migratedDir = dir;
21596
21703
  return dir;
21597
21704
  }
21598
- const legacy = path9.join(process.env.XDG_CONFIG_HOME || path9.join(os3.homedir(), ".config"), "workflow-toolkit");
21705
+ const legacy = path11.join(process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config"), "workflow-toolkit");
21599
21706
  if (!existsSync3(legacy)) {
21600
21707
  migratedDir = dir;
21601
21708
  return dir;
@@ -21608,8 +21715,8 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
21608
21715
  mkdirSync2(dir, { recursive: true });
21609
21716
  diagnosticLogger?.info(EVENT.migration, { from: legacy, to: dir });
21610
21717
  for (const entry of readdirSync2(legacy, { withFileTypes: true })) {
21611
- const src = path9.join(legacy, entry.name);
21612
- const dest = path9.join(dir, entry.name);
21718
+ const src = path11.join(legacy, entry.name);
21719
+ const dest = path11.join(dir, entry.name);
21613
21720
  if (existsSync3(dest))
21614
21721
  continue;
21615
21722
  try {
@@ -21681,7 +21788,7 @@ var parseConfigResult = (raw, file) => {
21681
21788
  return { status: "valid", path: file, config };
21682
21789
  };
21683
21790
  var readConfigTyped = (dir) => {
21684
- const file = path9.join(dir ?? configDir(), "config.json");
21791
+ const file = path11.join(dir ?? configDir(), "config.json");
21685
21792
  return parseConfigResult(readSafe(file), file);
21686
21793
  };
21687
21794
  var readConfig = () => {
@@ -21690,7 +21797,7 @@ var readConfig = () => {
21690
21797
  throw new Error(result.error);
21691
21798
  return result.config ?? DEFAULTS;
21692
21799
  };
21693
- var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path9.join(configDir(), "vcs.json");
21800
+ var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path11.join(configDir(), "vcs.json");
21694
21801
  var branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i");
21695
21802
  var resolveBranchPolicy = (config, workspace, repoPreset) => {
21696
21803
  const wp = workspace?.branchPolicy ?? {};
@@ -21722,9 +21829,9 @@ var COMMIT_PRESETS = [
21722
21829
 
21723
21830
  // packages/workit-core/src/core/workspaces.ts
21724
21831
  import { spawnSync as spawnSync6 } from "node:child_process";
21725
- import { createHash as createHash6 } from "node:crypto";
21832
+ import { createHash as createHash7 } from "node:crypto";
21726
21833
  import { readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
21727
- import path10 from "node:path";
21834
+ import path12 from "node:path";
21728
21835
 
21729
21836
  // packages/workit-core/src/core/branch-policy.ts
21730
21837
  import { spawnSync as spawnSync5 } from "node:child_process";
@@ -21849,7 +21956,7 @@ var releaseTrackSchema = object2({
21849
21956
  context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
21850
21957
  }
21851
21958
  }
21852
- 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(".."))) {
21959
+ 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(".."))) {
21853
21960
  context.addIssue({
21854
21961
  code: "custom",
21855
21962
  path: ["versionSource", "path"],
@@ -21870,6 +21977,8 @@ var workspaceConfigSchema = object2({
21870
21977
  defaultEndpoint: unknown().optional(),
21871
21978
  verification: _enum(["self", "independent"]).optional(),
21872
21979
  trailers: boolean2().optional(),
21980
+ liveSessionGuard: boolean2().optional(),
21981
+ fanout: object2({ tierModels: unknown().optional() }).passthrough().optional(),
21873
21982
  autonomy: object2(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
21874
21983
  kind,
21875
21984
  union([boolean2(), literal("verified")]).optional()
@@ -21910,7 +22019,7 @@ var workspacesFileSchema = object2({ workspaces: array(workspaceConfigSchema).op
21910
22019
  names.add(workspace.name);
21911
22020
  }
21912
22021
  });
21913
- var workspacesRevision = (contents) => createHash6("sha256").update(contents ?? "<missing>").digest("hex");
22022
+ var workspacesRevision = (contents) => createHash7("sha256").update(contents ?? "<missing>").digest("hex");
21914
22023
  var validateWorkspacesDocument = (parsed, file) => {
21915
22024
  if (!isConfigObject(parsed)) {
21916
22025
  return { status: "malformed", path: file, entries: [], error: `${file} is not a JSON object` };
@@ -21948,7 +22057,7 @@ var validateWorkspacesDocument = (parsed, file) => {
21948
22057
  };
21949
22058
  };
21950
22059
  var readWorkspacesResult = (dir = configDir()) => {
21951
- const file = path10.join(dir, "workspaces.json");
22060
+ const file = path12.join(dir, "workspaces.json");
21952
22061
  let raw;
21953
22062
  try {
21954
22063
  raw = readFileSync3(file, "utf8");
@@ -22059,9 +22168,9 @@ var mainCheckoutOf = (cwd) => {
22059
22168
  let main = null;
22060
22169
  const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
22061
22170
  const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
22062
- if (gitDir && common && path10.resolve(gitDir) !== path10.resolve(common)) {
22171
+ if (gitDir && common && path12.resolve(gitDir) !== path12.resolve(common)) {
22063
22172
  const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
22064
- main = listed?.trim() || (path10.basename(common) === ".git" ? path10.dirname(common) : common);
22173
+ main = listed?.trim() || (path12.basename(common) === ".git" ? path12.dirname(common) : common);
22065
22174
  }
22066
22175
  mainCheckouts.set(cwd, main);
22067
22176
  return main;
@@ -22152,7 +22261,7 @@ var runtimeWorkspaceIndexSchema = object2({
22152
22261
  workspaces: array(object2({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
22153
22262
  }).passthrough();
22154
22263
  var matchRuntimeWorkspace = (cwd, dir = configDir()) => {
22155
- const file = path10.join(dir, "workspaces.json");
22264
+ const file = path12.join(dir, "workspaces.json");
22156
22265
  let raw;
22157
22266
  try {
22158
22267
  raw = readFileSync3(file, "utf8");
@@ -22187,6 +22296,17 @@ var resolveRuntimeReleaseTracks = (cwd) => {
22187
22296
  const matched = matchRuntimeWorkspace(cwd);
22188
22297
  return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
22189
22298
  };
22299
+ var TIER_KEYS = new Set(["mundane", "standard", "hard"]);
22300
+ var TIER_HOSTS = new Set([
22301
+ "claude_code",
22302
+ "opencode",
22303
+ "codex",
22304
+ "codex_cli",
22305
+ "codex_desktop",
22306
+ "cursor",
22307
+ "pi",
22308
+ "default"
22309
+ ]);
22190
22310
  var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
22191
22311
  const matched = matchRuntimeWorkspace(cwd);
22192
22312
  if (!matched)
@@ -22227,7 +22347,7 @@ function workspaceDefaultTarget(cwd, globalDefault) {
22227
22347
  }
22228
22348
 
22229
22349
  // packages/workit-core/src/core/release-tracks.ts
22230
- import { createHash as createHash7 } from "node:crypto";
22350
+ import { createHash as createHash8 } from "node:crypto";
22231
22351
  import { spawnSync as spawnSync7 } from "node:child_process";
22232
22352
  var KNOWN_FIELDS = new Set([
22233
22353
  "strategy",
@@ -22597,7 +22717,7 @@ function resolveTrackFor(cwd, options) {
22597
22717
  ]) ?? "",
22598
22718
  git3(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
22599
22719
  ] : [];
22600
- key = createHash7("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
22720
+ key = createHash8("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
22601
22721
  const hit = memo2.get(key);
22602
22722
  if (hit)
22603
22723
  return hit;
@@ -22612,7 +22732,7 @@ function resolveTrackFor(cwd, options) {
22612
22732
  }
22613
22733
 
22614
22734
  // packages/workit-core/src/core/vcs-config.ts
22615
- var workspacesPath = () => path11.join(configDir(), "workspaces.json");
22735
+ var workspacesPath = () => path13.join(configDir(), "workspaces.json");
22616
22736
  var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
22617
22737
  var remoteProvider = (cwd) => {
22618
22738
  const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
@@ -22702,7 +22822,7 @@ var readVcsConfig = () => {
22702
22822
  const file = vcsConfigPath();
22703
22823
  let raw;
22704
22824
  try {
22705
- raw = fs10.readFileSync(file, "utf8");
22825
+ raw = fs11.readFileSync(file, "utf8");
22706
22826
  } catch {
22707
22827
  return { status: "missing", path: file, config: {} };
22708
22828
  }
@@ -22787,7 +22907,7 @@ function vcsConfig(mode, cwd, options = {}) {
22787
22907
  const prov = cfg[provider] ?? {};
22788
22908
  const out = {
22789
22909
  ok: true,
22790
- configPath: path11.resolve(cfgPath),
22910
+ configPath: path13.resolve(cfgPath),
22791
22911
  provider,
22792
22912
  defaultTargetBranch: workspaceDefault,
22793
22913
  pr: cfg.pr ?? {},
@@ -22998,7 +23118,7 @@ function diffHash(cwd, base, head) {
22998
23118
  ], GIT_TIMEOUTS.worktree);
22999
23119
  if (!diff.ok || !diff.stdout)
23000
23120
  return null;
23001
- const hash = createHash8("sha256");
23121
+ const hash = createHash9("sha256");
23002
23122
  for (const line of diff.stdout.split(`
23003
23123
  `)) {
23004
23124
  if (line.startsWith("index "))
@@ -23010,16 +23130,16 @@ function diffHash(cwd, base, head) {
23010
23130
  return `sha256:${hash.digest("hex")}`;
23011
23131
  }
23012
23132
  function storeRoot(cwd) {
23013
- const location = resolveStore(path12.resolve(cwd));
23133
+ const location = resolveStore(path14.resolve(cwd));
23014
23134
  if (location instanceof Error)
23015
23135
  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");
23016
23136
  return { ok: true, value: { root: location.dir, shared: location.shared } };
23017
23137
  }
23018
23138
  function ledgerPath(cwd) {
23019
23139
  const root = storeRoot(cwd);
23020
- return root.ok ? { ok: true, value: path12.join(root.value.root, "ledger", "ledger.jsonl") } : root;
23140
+ return root.ok ? { ok: true, value: path14.join(root.value.root, "ledger", "ledger.jsonl") } : root;
23021
23141
  }
23022
- var newId2 = () => `${Date.now().toString(36)}-${randomBytes2(6).toString("hex")}`;
23142
+ var newId2 = () => `${Date.now().toString(36)}-${randomBytes3(6).toString("hex")}`;
23023
23143
  var NETWORK_FS_TYPES = new Set([
23024
23144
  26985,
23025
23145
  20859,
@@ -23037,7 +23157,7 @@ var onNetworkFs = (dir) => {
23037
23157
  if (process.platform !== "linux")
23038
23158
  return false;
23039
23159
  try {
23040
- return isNetworkFsType(fs11.statfsSync(dir).type);
23160
+ return isNetworkFsType(fs12.statfsSync(dir).type);
23041
23161
  } catch {
23042
23162
  return false;
23043
23163
  }
@@ -23047,15 +23167,15 @@ var LOCK_STALE_MS = 30000;
23047
23167
  var LOCK_OWNER = "owner";
23048
23168
  var lockToken = (lock) => {
23049
23169
  try {
23050
- return fs11.readFileSync(path12.join(lock, LOCK_OWNER), "utf8");
23170
+ return fs12.readFileSync(path14.join(lock, LOCK_OWNER), "utf8");
23051
23171
  } catch {
23052
23172
  return null;
23053
23173
  }
23054
23174
  };
23055
23175
  var lockAgeMs = (lock) => {
23056
- for (const target of [path12.join(lock, LOCK_OWNER), lock]) {
23176
+ for (const target of [path14.join(lock, LOCK_OWNER), lock]) {
23057
23177
  try {
23058
- return Date.now() - fs11.statSync(target).mtimeMs;
23178
+ return Date.now() - fs12.statSync(target).mtimeMs;
23059
23179
  } catch {}
23060
23180
  }
23061
23181
  return null;
@@ -23063,55 +23183,55 @@ var lockAgeMs = (lock) => {
23063
23183
  var ledgerLock = {
23064
23184
  acquire(lock) {
23065
23185
  try {
23066
- fs11.mkdirSync(lock);
23186
+ fs12.mkdirSync(lock);
23067
23187
  } catch (error) {
23068
23188
  if (error.code === "EEXIST")
23069
23189
  return null;
23070
23190
  throw error;
23071
23191
  }
23072
- const token = `${process.pid}-${randomBytes2(8).toString("hex")}`;
23073
- fs11.writeFileSync(path12.join(lock, LOCK_OWNER), token);
23192
+ const token = `${process.pid}-${randomBytes3(8).toString("hex")}`;
23193
+ fs12.writeFileSync(path14.join(lock, LOCK_OWNER), token);
23074
23194
  return token;
23075
23195
  },
23076
23196
  release(lock, token) {
23077
23197
  if (lockToken(lock) !== token)
23078
23198
  return false;
23079
- const tomb = `${lock}.release-${randomBytes2(6).toString("hex")}`;
23199
+ const tomb = `${lock}.release-${randomBytes3(6).toString("hex")}`;
23080
23200
  try {
23081
- fs11.renameSync(lock, tomb);
23201
+ fs12.renameSync(lock, tomb);
23082
23202
  } catch {
23083
23203
  return false;
23084
23204
  }
23085
23205
  if (lockToken(tomb) !== token) {
23086
23206
  try {
23087
- fs11.renameSync(tomb, lock);
23207
+ fs12.renameSync(tomb, lock);
23088
23208
  } catch {}
23089
23209
  return false;
23090
23210
  }
23091
- fs11.rmSync(tomb, { recursive: true, force: true });
23211
+ fs12.rmSync(tomb, { recursive: true, force: true });
23092
23212
  return true;
23093
23213
  },
23094
23214
  token: lockToken,
23095
23215
  reap(lock, observed) {
23096
- const tomb = `${lock}.reap-${randomBytes2(6).toString("hex")}`;
23216
+ const tomb = `${lock}.reap-${randomBytes3(6).toString("hex")}`;
23097
23217
  try {
23098
- fs11.renameSync(lock, tomb);
23218
+ fs12.renameSync(lock, tomb);
23099
23219
  } catch {
23100
23220
  return false;
23101
23221
  }
23102
23222
  if (lockToken(tomb) === observed) {
23103
- fs11.rmSync(tomb, { recursive: true, force: true });
23223
+ fs12.rmSync(tomb, { recursive: true, force: true });
23104
23224
  return true;
23105
23225
  }
23106
23226
  try {
23107
- fs11.renameSync(tomb, lock);
23227
+ fs12.renameSync(tomb, lock);
23108
23228
  } catch {
23109
- fs11.rmSync(tomb, { recursive: true, force: true });
23229
+ fs12.rmSync(tomb, { recursive: true, force: true });
23110
23230
  }
23111
23231
  return false;
23112
23232
  }
23113
23233
  };
23114
- function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
23234
+ function withLedgerLock(file, fn, waitMs = hostAwareLockTimeout(LOCK_WAIT_MS)) {
23115
23235
  const lock = `${file}.lock`;
23116
23236
  const deadline = Date.now() + waitMs;
23117
23237
  let token = null;
@@ -23133,14 +23253,14 @@ function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
23133
23253
  ledgerLock.release(lock, token);
23134
23254
  }
23135
23255
  }
23136
- var sha2562 = (text) => createHash8("sha256").update(text).digest("hex");
23256
+ var sha2562 = (text) => createHash9("sha256").update(text).digest("hex");
23137
23257
  var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
23138
23258
  ${body}`);
23139
23259
  var TAIL_BYTES = 64 * 1024;
23140
23260
  var lastLine = (fd, size) => {
23141
23261
  for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
23142
23262
  const buffer = Buffer.alloc(span);
23143
- fs11.readSync(fd, buffer, 0, span, size - span);
23263
+ fs12.readSync(fd, buffer, 0, span, size - span);
23144
23264
  const end = buffer.lastIndexOf(10);
23145
23265
  if (end < 0) {
23146
23266
  if (span === size)
@@ -23169,15 +23289,23 @@ var lastLine = (fd, size) => {
23169
23289
  }
23170
23290
  return null;
23171
23291
  };
23292
+ var tighten = (fd) => {
23293
+ try {
23294
+ if ((fs12.fstatSync(fd).mode & 63) !== 0)
23295
+ fs12.fchmodSync(fd, 384);
23296
+ } catch {}
23297
+ };
23172
23298
  function appendLine(file, build, options) {
23173
23299
  const write = () => {
23174
- const fd = fs11.openSync(file, "a+");
23300
+ const fd = fs12.openSync(file, "a+", 384);
23175
23301
  try {
23176
- const size = fs11.fstatSync(fd).size;
23302
+ if (process.platform !== "win32")
23303
+ tighten(fd);
23304
+ const size = fs12.fstatSync(fd).size;
23177
23305
  let fence = "";
23178
23306
  if (size > 0) {
23179
23307
  const last = Buffer.alloc(1);
23180
- fs11.readSync(fd, last, 0, 1, size - 1);
23308
+ fs12.readSync(fd, last, 0, 1, size - 1);
23181
23309
  if (last[0] !== 10)
23182
23310
  fence = `
23183
23311
  `;
@@ -23186,17 +23314,17 @@ function appendLine(file, build, options) {
23186
23314
  if (!line.ok)
23187
23315
  return line;
23188
23316
  const bytes = Buffer.from(fence + line.value);
23189
- const written = fs11.writeSync(fd, bytes);
23317
+ const written = fs12.writeSync(fd, bytes);
23190
23318
  if (written !== bytes.length)
23191
23319
  return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
23192
23320
  return { ok: true, value: undefined };
23193
23321
  } finally {
23194
- fs11.closeSync(fd);
23322
+ fs12.closeSync(fd);
23195
23323
  }
23196
23324
  };
23197
23325
  try {
23198
- fs11.mkdirSync(path12.dirname(file), { recursive: true });
23199
- if (!options.forceLock && !onNetworkFs(path12.dirname(file)))
23326
+ fs12.mkdirSync(path14.dirname(file), { recursive: true });
23327
+ if (!options.forceLock && !onNetworkFs(path14.dirname(file)))
23200
23328
  return write();
23201
23329
  const locked = withLedgerLock(file, write);
23202
23330
  return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
@@ -23264,8 +23392,10 @@ function readLedger(cwd, options = {}) {
23264
23392
  if (!file.ok)
23265
23393
  return file;
23266
23394
  let text = "";
23395
+ let stat = null;
23267
23396
  try {
23268
- text = fs11.readFileSync(file.value, "utf8");
23397
+ stat = fs12.statSync(file.value);
23398
+ text = fs12.readFileSync(file.value, "utf8");
23269
23399
  } catch (error) {
23270
23400
  if (error.code === "ENOENT")
23271
23401
  return {
@@ -23284,6 +23414,7 @@ function readLedger(cwd, options = {}) {
23284
23414
  const integrity = { chained: 0, legacy: 0, unverified: [] };
23285
23415
  const earlier = new Set([null]);
23286
23416
  let chainStarted = false;
23417
+ const ids = new Set;
23287
23418
  for (const raw of text.split(`
23288
23419
  `)) {
23289
23420
  const trimmed = raw.trim();
@@ -23317,6 +23448,10 @@ function readLedger(cwd, options = {}) {
23317
23448
  reason = "unsigned";
23318
23449
  else
23319
23450
  rowIntegrity = "legacy";
23451
+ if (options.integrity && !reason && ids.has(parsed.id))
23452
+ reason = "duplicate_id";
23453
+ if (options.integrity)
23454
+ ids.add(parsed.id);
23320
23455
  if (reason)
23321
23456
  rowIntegrity = "unverified";
23322
23457
  const pr = typeof parsed.pr === "number" && Number.isInteger(parsed.pr) ? parsed.pr : undefined;
@@ -23340,7 +23475,8 @@ function readLedger(cwd, options = {}) {
23340
23475
  seq: rows.length + 1,
23341
23476
  superseded: false,
23342
23477
  supersedeIgnored: false,
23343
- ...rowIntegrity ? { integrity: rowIntegrity } : {}
23478
+ ...rowIntegrity ? { integrity: rowIntegrity } : {},
23479
+ ...reason ? { integrityReason: reason } : {}
23344
23480
  };
23345
23481
  rows.push(row);
23346
23482
  if (!options.integrity)
@@ -23368,18 +23504,48 @@ function readLedger(cwd, options = {}) {
23368
23504
  const byId = new Map;
23369
23505
  for (const row of rows) {
23370
23506
  const target = row.supersedes ? byId.get(row.supersedes) : undefined;
23371
- if (target && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
23507
+ if (target && row.integrity !== "unverified" && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
23372
23508
  target.superseded = true;
23373
23509
  else if (row.supersedes)
23374
23510
  row.supersedeIgnored = true;
23375
23511
  if (!byId.has(row.id))
23376
23512
  byId.set(row.id, row);
23377
23513
  }
23514
+ if (options.integrity && stat && Buffer.byteLength(text) === stat.size)
23515
+ tamperCache.set(file.value, {
23516
+ size: stat.size,
23517
+ stamp: fileStamp(stat),
23518
+ breaks: integrity.unverified.filter((row) => TAMPER_REASONS.has(row.reason))
23519
+ });
23378
23520
  return {
23379
23521
  ok: true,
23380
23522
  value: { path: file.value, rows, skipped, integrity: options.integrity ? integrity : null }
23381
23523
  };
23382
23524
  }
23525
+ var TAMPER_REASONS = new Set(["hash_mismatch", "broken_link"]);
23526
+ var tamperCache = new Map;
23527
+ var fileStamp = (stat) => `${stat.ino}:${stat.mtimeMs}:${stat.ctimeMs}`;
23528
+ function ledgerTampering(cwd) {
23529
+ const file = ledgerPath(cwd);
23530
+ if (!file.ok)
23531
+ return [];
23532
+ try {
23533
+ const stat = fs12.statSync(file.value);
23534
+ const cached = tamperCache.get(file.value);
23535
+ if (cached && cached.size === stat.size && cached.stamp === fileStamp(stat))
23536
+ return cached.breaks;
23537
+ } catch {
23538
+ return [];
23539
+ }
23540
+ const read = readLedger(cwd, { integrity: true });
23541
+ return read.ok ? (read.value.integrity?.unverified ?? []).filter((row) => TAMPER_REASONS.has(row.reason)) : [];
23542
+ }
23543
+ function tamperedUnblock(cwd) {
23544
+ const file = ledgerPath(cwd);
23545
+ const where = file.ok ? file.value : "the ledger file";
23546
+ 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`;
23547
+ }
23548
+ 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)}`;
23383
23549
  function verdictBasis(verdict, current) {
23384
23550
  if (verdict.head && verdict.head === current.head)
23385
23551
  return "fresh";
@@ -23387,7 +23553,7 @@ function verdictBasis(verdict, current) {
23387
23553
  return "carried";
23388
23554
  return "stale";
23389
23555
  }
23390
- var isLiveVerdict = (row) => row.type === "verdict" && typeof row.result === "string" && !row.superseded;
23556
+ var isLiveVerdict = (row, retired) => row.type === "verdict" && typeof row.result === "string" && !retired.has(row.id);
23391
23557
  function trailerSessions(cwd, base, head) {
23392
23558
  if (!base || !head || !safeRef(base) || !safeRef(head))
23393
23559
  return [];
@@ -23468,6 +23634,56 @@ var authoredBy = (authors, session) => {
23468
23634
  return true;
23469
23635
  return false;
23470
23636
  };
23637
+ var TRUST_REASONS = new Set([
23638
+ "unsigned",
23639
+ "hash_mismatch",
23640
+ "broken_link",
23641
+ "duplicate_id",
23642
+ "unissued_session",
23643
+ "unbound_session"
23644
+ ]);
23645
+ var SHELL_VOUCHED_HOSTS = new Set([
23646
+ "cli",
23647
+ "opencode",
23648
+ "pi",
23649
+ "codex_cli",
23650
+ "codex_desktop"
23651
+ ]);
23652
+ function sessionTrust(cwd, row) {
23653
+ const session = row.actor.session;
23654
+ if (!session || row.self === true)
23655
+ return null;
23656
+ const source = typeof row.sessionSource === "string" ? row.sessionSource : "env";
23657
+ const host = row.actor.host;
23658
+ const issuedOnly = source === "flag" ? host !== "cli" : source === "env" && session.includes(":") && !SHELL_VOUCHED_HOSTS.has(host);
23659
+ if (!issuedOnly)
23660
+ return null;
23661
+ const binding = issuedBinding(cwd, session);
23662
+ if (binding === null)
23663
+ return "unissued_session";
23664
+ return binding === "token" && row.sessionBound !== true ? "unbound_session" : null;
23665
+ }
23666
+ function trustReasons(cwd, row) {
23667
+ if (row.integrity === "unverified")
23668
+ return [row.integrityReason ?? "unsigned"];
23669
+ if (row.integrity !== "verified")
23670
+ return ["unsigned"];
23671
+ const session = sessionTrust(cwd, row);
23672
+ return session ? [session] : [];
23673
+ }
23674
+ function withIntegrity(cwd, rows) {
23675
+ if (rows.every((row) => row.integrity !== undefined))
23676
+ return rows;
23677
+ const read = readLedger(cwd, { integrity: true });
23678
+ const bySeq = new Map(read.ok ? read.value.rows.map((row) => [row.seq, row]) : []);
23679
+ return rows.map((row) => {
23680
+ if (row.integrity !== undefined)
23681
+ return row;
23682
+ const fresh = bySeq.get(row.seq);
23683
+ return fresh && fresh.id === row.id && fresh.at === row.at ? fresh : row;
23684
+ });
23685
+ }
23686
+ var untrusted = (reasons) => reasons.some((reason) => TRUST_REASONS.has(reason));
23471
23687
  var independenceReasons = (row, authors) => {
23472
23688
  const reasons = [];
23473
23689
  if (!row.actor.session)
@@ -23478,15 +23694,17 @@ var independenceReasons = (row, authors) => {
23478
23694
  reasons.push("self");
23479
23695
  return reasons;
23480
23696
  };
23481
- function effectiveOf(rows, authors, sameCode, isCurrent) {
23697
+ function effectiveOf(rows, reasonsOf, sameCode, isCurrent) {
23482
23698
  let effective = null;
23483
23699
  for (const row of rows) {
23484
23700
  if (!effective) {
23485
23701
  effective = row;
23486
23702
  continue;
23487
23703
  }
23488
- const rowIndependent = independenceReasons(row, authors).length === 0;
23489
- const effIndependent = independenceReasons(effective, authors).length === 0;
23704
+ if (untrusted(reasonsOf(row)) && !untrusted(reasonsOf(effective)))
23705
+ continue;
23706
+ const rowIndependent = reasonsOf(row).length === 0;
23707
+ const effIndependent = reasonsOf(effective).length === 0;
23490
23708
  if (effIndependent && !rowIndependent && isCurrent(effective))
23491
23709
  continue;
23492
23710
  if (effIndependent && FAILING.has(String(effective.result)) && row.actor.session === effective.actor.session && sameCode(effective, row))
@@ -23500,7 +23718,7 @@ function restackCarries(rows, branch, from, to) {
23500
23718
  return false;
23501
23719
  const edges = new Map;
23502
23720
  for (const row of rows)
23503
- if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
23721
+ if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.integrity === "verified" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
23504
23722
  edges.set(row.fromHead, [...edges.get(row.fromHead) ?? [], row.head]);
23505
23723
  const seen = new Set([from]);
23506
23724
  const queue = [from];
@@ -23516,7 +23734,8 @@ function restackCarries(rows, branch, from, to) {
23516
23734
  }
23517
23735
  return false;
23518
23736
  }
23519
- function checkVerdicts(cwd, branch, rows) {
23737
+ function checkVerdicts(cwd, branch, ledgerRows) {
23738
+ const rows = withIntegrity(cwd, ledgerRows);
23520
23739
  const head = branchHead(cwd, branch);
23521
23740
  const fallbackBase = defaultBase(cwd);
23522
23741
  const scope = branchScope(cwd, branch);
@@ -23546,21 +23765,47 @@ function checkVerdicts(cwd, branch, rows) {
23546
23765
  return verdictBasis(failed, { head: row.head, ...keys }) !== "stale" || restackCarries(rows, branch, failed.head, row.head);
23547
23766
  };
23548
23767
  const authors = authorSessions(cwd, rows, branch, { base: fallbackBase, head }, scope);
23768
+ const failureAuthorCache = new Map;
23769
+ const failureAuthors = (row) => {
23770
+ let set = failureAuthorCache.get(row.seq);
23771
+ if (!set) {
23772
+ set = authorSessions(cwd, rows.filter((other) => other.integrity === "verified" && other.seq < row.seq), branch, { base: null, head: null }, scope);
23773
+ failureAuthorCache.set(row.seq, set);
23774
+ }
23775
+ return set;
23776
+ };
23777
+ const reasonCache = new Map;
23778
+ const reasonsOf = (row) => {
23779
+ let reasons = reasonCache.get(row);
23780
+ if (!reasons) {
23781
+ const failing = FAILING.has(String(row.result));
23782
+ reasons = [
23783
+ ...trustReasons(cwd, row),
23784
+ ...independenceReasons(row, failing ? failureAuthors(row) : authors)
23785
+ ];
23786
+ reasonCache.set(row, reasons);
23787
+ }
23788
+ return reasons;
23789
+ };
23790
+ const retired = new Set;
23791
+ for (const row of rows)
23792
+ if (row.type === "verdict" && row.supersedes && !row.supersedeIgnored && trustReasons(cwd, row).length === 0)
23793
+ retired.add(row.supersedes);
23549
23794
  const byKind = new Map;
23550
23795
  for (const row of rows)
23551
- if (isLiveVerdict(row) && scope(row)) {
23796
+ if (isLiveVerdict(row, retired) && scope(row)) {
23552
23797
  const kind = typeof row.kind === "string" ? row.kind : "review";
23553
23798
  byKind.set(kind, [...byKind.get(kind) ?? [], row]);
23554
23799
  }
23555
23800
  const verdicts = [];
23556
23801
  const warnings = [];
23557
23802
  for (const [kind, list] of byKind) {
23558
- const row = effectiveOf(list, authors, sameCode, (candidate) => basisOf(candidate) !== "stale");
23803
+ const row = effectiveOf(list, reasonsOf, sameCode, (candidate) => basisOf(candidate) !== "stale");
23559
23804
  if (!row)
23560
23805
  continue;
23561
23806
  const basis = basisOf(row);
23562
23807
  const current = basis !== "stale";
23563
- const independence = independenceReasons(row, authors);
23808
+ const independence = reasonsOf(row);
23564
23809
  const reasons = [
23565
23810
  ...current ? [] : ["stale"],
23566
23811
  ...PASSING.has(String(row.result)) ? [] : ["not_passing"],
@@ -23577,23 +23822,31 @@ function checkVerdicts(cwd, branch, rows) {
23577
23822
  });
23578
23823
  if (reasons.length === 0) {
23579
23824
  for (const later of list)
23580
- if (later.seq > row.seq && independenceReasons(later, authors).length > 0 && FAILING.has(String(later.result)) && basisOf(later) !== "stale")
23825
+ if (later.seq > row.seq && reasonsOf(later).length > 0 && !untrusted(reasonsOf(later)) && FAILING.has(String(later.result)) && basisOf(later) !== "stale")
23581
23826
  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`);
23582
23827
  }
23583
23828
  }
23584
23829
  for (const row of rows)
23585
23830
  if (row.integrity === "unverified" && scope(row))
23586
23831
  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)`);
23832
+ const tampered = ledgerTampering(cwd);
23833
+ if (tampered.length) {
23834
+ warnings.push(tamperedWarning(cwd, tampered));
23835
+ for (const entry of verdicts) {
23836
+ entry.accepted = false;
23837
+ entry.reasons = [...entry.reasons, "ledger_tampered"];
23838
+ }
23839
+ }
23587
23840
  verdicts.sort((a, b) => a.verdict.seq - b.verdict.seq);
23588
23841
  const newestCurrent = verdicts.findLast((entry) => entry.current) ?? verdicts.at(-1) ?? null;
23589
23842
  const failing = verdicts.find((entry) => entry.current && entry.independent && FAILING.has(String(entry.verdict.result)));
23590
23843
  const newestAccepted = verdicts.findLast((entry) => entry.accepted && STRONG_RESULTS.has(String(entry.verdict.result))) ?? null;
23591
- const accepted = newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
23844
+ const accepted = tampered.length ? { accepted: false, verdict: null, reasons: ["ledger_tampered"] } : newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
23592
23845
  accepted: false,
23593
23846
  verdict: failing?.verdict ?? null,
23594
23847
  reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
23595
23848
  };
23596
- const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && STRONG_RESULTS.has(String(entry.verdict.result)));
23849
+ const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && !untrusted(entry.reasons) && STRONG_RESULTS.has(String(entry.verdict.result)));
23597
23850
  return {
23598
23851
  branch,
23599
23852
  head,
@@ -23756,7 +24009,7 @@ var productDecision = (task, ledger) => {
23756
24009
  };
23757
24010
  };
23758
24011
  var planRecorded = (task, root) => {
23759
- const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path13.resolve(root, ref.path)));
24012
+ const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path15.resolve(root, ref.path)));
23760
24013
  if (cited)
23761
24014
  return {
23762
24015
  met: true,
@@ -23804,15 +24057,15 @@ function derivedRuleStatus(task, requirement, root, ledger) {
23804
24057
  }
23805
24058
 
23806
24059
  // packages/workit-core/src/core/task-evaluation.ts
23807
- var digestBytes = (value) => createHash9("sha256").update(value).digest("hex");
23808
- var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path14.sep}`);
23809
- var relative = (root, candidate) => path14.relative(root, candidate).split(path14.sep).join("/") || ".";
24060
+ var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
24061
+ var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
24062
+ var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
23810
24063
  var canonicalPath = (value) => {
23811
24064
  if (typeof value !== "string" || !value)
23812
24065
  return null;
23813
24066
  if (value.includes("\\") || value.split("/").includes(".."))
23814
24067
  return null;
23815
- const normalized = path14.posix.normalize(value);
24068
+ const normalized = path16.posix.normalize(value);
23816
24069
  if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
23817
24070
  return null;
23818
24071
  return normalized === "." ? "." : normalized.replace(/\/$/, "");
@@ -23860,21 +24113,21 @@ var gitPaths = (root) => {
23860
24113
  git: !/not a git repository/i.test(stderr)
23861
24114
  };
23862
24115
  }
23863
- const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path14.sep).join("/")) : [];
24116
+ const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
23864
24117
  const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
23865
24118
  if (stagedDeleted.status !== 0) {
23866
24119
  const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
23867
24120
  if (!/not a git repository/i.test(stderr))
23868
24121
  return { paths, uncertain: true, git: true };
23869
24122
  } else if (stagedDeleted.stdout) {
23870
- paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path14.sep).join("/")));
24123
+ paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
23871
24124
  }
23872
24125
  return { paths: [...new Set(paths)], uncertain: false, git: true };
23873
24126
  };
23874
24127
  var walk = (root, directory, output) => {
23875
24128
  let names;
23876
24129
  try {
23877
- names = fs12.readdirSync(directory);
24130
+ names = fs13.readdirSync(directory);
23878
24131
  } catch {
23879
24132
  return true;
23880
24133
  }
@@ -23882,10 +24135,10 @@ var walk = (root, directory, output) => {
23882
24135
  for (const name of names) {
23883
24136
  if (name === ".git" || name === ".workit")
23884
24137
  continue;
23885
- const target = path14.join(directory, name);
24138
+ const target = path16.join(directory, name);
23886
24139
  let stat;
23887
24140
  try {
23888
- stat = fs12.lstatSync(target);
24141
+ stat = fs13.lstatSync(target);
23889
24142
  } catch {
23890
24143
  uncertain = true;
23891
24144
  continue;
@@ -23900,14 +24153,14 @@ var walk = (root, directory, output) => {
23900
24153
  var scopeRoots = (root, scope) => {
23901
24154
  const roots = [];
23902
24155
  for (const item of scope.paths.length ? scope.paths : ["."]) {
23903
- const target = path14.resolve(root, item);
24156
+ const target = path16.resolve(root, item);
23904
24157
  if (!inside(root, target))
23905
24158
  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` }] });
23906
24159
  let ancestor = target;
23907
- while (!fs12.existsSync(ancestor) && ancestor !== root)
23908
- ancestor = path14.dirname(ancestor);
24160
+ while (!fs13.existsSync(ancestor) && ancestor !== root)
24161
+ ancestor = path16.dirname(ancestor);
23909
24162
  try {
23910
- if (!inside(root, fs12.realpathSync(ancestor)))
24163
+ if (!inside(root, fs13.realpathSync(ancestor)))
23911
24164
  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` }] });
23912
24165
  } catch {
23913
24166
  return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
@@ -23919,7 +24172,7 @@ var scopeRoots = (root, scope) => {
23919
24172
  function captureCandidate(root, scope, environment = []) {
23920
24173
  let checkout;
23921
24174
  try {
23922
- checkout = fs12.realpathSync(root);
24175
+ checkout = fs13.realpathSync(root);
23923
24176
  } catch {
23924
24177
  return failure2("invalid_input", "candidate root does not exist");
23925
24178
  }
@@ -23937,11 +24190,11 @@ function captureCandidate(root, scope, environment = []) {
23937
24190
  if (item === ".git" || item === ".workit")
23938
24191
  continue;
23939
24192
  names.add(item);
23940
- if (!fs12.existsSync(target))
24193
+ if (!fs13.existsSync(target))
23941
24194
  continue;
23942
24195
  let stat;
23943
24196
  try {
23944
- stat = fs12.lstatSync(target);
24197
+ stat = fs13.lstatSync(target);
23945
24198
  } catch {
23946
24199
  uncertain = true;
23947
24200
  continue;
@@ -23957,17 +24210,17 @@ function captureCandidate(root, scope, environment = []) {
23957
24210
  for (const item of [...names].toSorted()) {
23958
24211
  if (!scopeMatches(item, normalizedScope))
23959
24212
  continue;
23960
- const target = path14.join(checkout, item);
24213
+ const target = path16.join(checkout, item);
23961
24214
  try {
23962
- const stat = fs12.lstatSync(target);
24215
+ const stat = fs13.lstatSync(target);
23963
24216
  if (stat.isSymbolicLink()) {
23964
- const link = fs12.readlinkSync(target);
24217
+ const link = fs13.readlinkSync(target);
23965
24218
  files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
23966
24219
  } else if (stat.isFile()) {
23967
24220
  files.push({
23968
24221
  path: item,
23969
24222
  kind: "file",
23970
- digest: digestBytes(fs12.readFileSync(target)),
24223
+ digest: digestBytes(fs13.readFileSync(target)),
23971
24224
  executable: (stat.mode & 73) !== 0
23972
24225
  });
23973
24226
  } else if (!stat.isDirectory()) {
@@ -24132,7 +24385,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
24132
24385
  var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
24133
24386
  let root;
24134
24387
  try {
24135
- root = fs12.realpathSync(checkoutRoot);
24388
+ root = fs13.realpathSync(checkoutRoot);
24136
24389
  } catch {
24137
24390
  return failure2("permission_denied", "checkout root is unavailable");
24138
24391
  }
@@ -24141,23 +24394,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
24141
24394
  continue;
24142
24395
  if (!reference.digest)
24143
24396
  return failure2("invalid_input", "document references require a byte digest");
24144
- const target = path14.resolve(root, reference.path);
24145
- if (target !== root && !target.startsWith(`${root}${path14.sep}`))
24397
+ const target = path16.resolve(root, reference.path);
24398
+ if (target !== root && !target.startsWith(`${root}${path16.sep}`))
24146
24399
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
24147
24400
  fields: [
24148
24401
  { path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
24149
24402
  ]
24150
24403
  });
24151
24404
  try {
24152
- const below = path14.relative(root, target);
24405
+ const below = path16.relative(root, target);
24153
24406
  let current = root;
24154
- for (const segment of below.split(path14.sep)) {
24407
+ for (const segment of below.split(path16.sep)) {
24155
24408
  if (!segment)
24156
24409
  continue;
24157
- current = path14.join(current, segment);
24158
- const stat = fs12.lstatSync(current);
24159
- const real = fs12.realpathSync(current);
24160
- if (real !== root && !real.startsWith(`${root}${path14.sep}`))
24410
+ current = path16.join(current, segment);
24411
+ const stat = fs13.lstatSync(current);
24412
+ const real = fs13.realpathSync(current);
24413
+ if (real !== root && !real.startsWith(`${root}${path16.sep}`))
24161
24414
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
24162
24415
  fields: [
24163
24416
  {
@@ -24173,7 +24426,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
24173
24426
  if (current !== target && !stat.isDirectory())
24174
24427
  return failure2("invalid_input", "document reference ancestor is not a directory");
24175
24428
  }
24176
- if (digestBytes(fs12.readFileSync(target)) !== reference.digest)
24429
+ if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
24177
24430
  return failure2("permission_denied", "decision document bytes have changed");
24178
24431
  } catch {
24179
24432
  return failure2("invalid_input", "decision document is unavailable");
@@ -25031,7 +25284,7 @@ var judgeInputSummary = (raw) => {
25031
25284
 
25032
25285
  // packages/workit-core/src/autonomy.ts
25033
25286
  import os4 from "node:os";
25034
- import path15 from "node:path";
25287
+ import path17 from "node:path";
25035
25288
  var accountHome = () => {
25036
25289
  try {
25037
25290
  return os4.userInfo().homedir;
@@ -25040,10 +25293,10 @@ var accountHome = () => {
25040
25293
  }
25041
25294
  };
25042
25295
  var grantsHome = { resolve: accountHome };
25043
- var grantsDir = () => path15.join(grantsHome.resolve(), ".config", "workit");
25296
+ var grantsDir = () => path17.join(grantsHome.resolve(), ".config", "workit");
25044
25297
  var grantsOverride = () => {
25045
- const configured = path15.resolve(resolveConfigDir());
25046
- 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`;
25298
+ const configured = path17.resolve(resolveConfigDir());
25299
+ 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`;
25047
25300
  };
25048
25301
  var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
25049
25302
  var DEFAULT_GRANTS = Object.freeze({
@@ -26815,7 +27068,7 @@ class WorkitCore {
26815
27068
  // packages/workit-core/src/core/repo-context.ts
26816
27069
  import { spawnSync as spawnSync11 } from "node:child_process";
26817
27070
  import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
26818
- import path16 from "node:path";
27071
+ import path18 from "node:path";
26819
27072
  var isSafeContextRange = (value) => value.length <= 4096 && (() => {
26820
27073
  try {
26821
27074
  gitRevisionParts(value);
@@ -26949,7 +27202,7 @@ var findPrTemplate = (cwd) => {
26949
27202
  ]) {
26950
27203
  const parts = rel.split("/");
26951
27204
  const base = parts[parts.length - 1];
26952
- const dir = parts.length > 1 ? path16.join(cwd, ...parts.slice(0, -1)) : cwd;
27205
+ const dir = parts.length > 1 ? path18.join(cwd, ...parts.slice(0, -1)) : cwd;
26953
27206
  const actual = probeCaseInsensitive(dir, base);
26954
27207
  if (actual)
26955
27208
  return [...parts.slice(0, -1), actual].join("/");
@@ -26980,7 +27233,7 @@ var diffStatForRange = (cwd, range) => {
26980
27233
  return runGit(cwd, ["diff", "--stat", "--"]).stdout;
26981
27234
  };
26982
27235
  var packageScripts = (cwd, keys) => {
26983
- const pkgPath = path16.join(cwd, "package.json");
27236
+ const pkgPath = path18.join(cwd, "package.json");
26984
27237
  if (!existsSync6(pkgPath))
26985
27238
  return [];
26986
27239
  try {
@@ -27006,9 +27259,9 @@ var documentationFiles = (cwd) => {
27006
27259
  if (entry.isDirectory()) {
27007
27260
  if (excluded.has(entry.name))
27008
27261
  continue;
27009
- walk(path16.join(dir, entry.name), depth + 1);
27262
+ walk(path18.join(dir, entry.name), depth + 1);
27010
27263
  } else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
27011
- matches.push("./" + path16.relative(cwd, path16.join(dir, entry.name)).replaceAll("\\", "/"));
27264
+ matches.push("./" + path18.relative(cwd, path18.join(dir, entry.name)).replaceAll("\\", "/"));
27012
27265
  }
27013
27266
  }
27014
27267
  };
@@ -27024,7 +27277,7 @@ var readTrimmed2 = (file, maxLines) => {
27024
27277
  `);
27025
27278
  };
27026
27279
  function prReadyContext(root, range) {
27027
- const cwd = path16.resolve(repoRoot(root));
27280
+ const cwd = path18.resolve(repoRoot(root));
27028
27281
  if (range !== undefined && !isResolvableContextRange(cwd, range))
27029
27282
  return invalidRange(cwd);
27030
27283
  let stdout = "";
@@ -27082,7 +27335,7 @@ ${status.stderr}` : "");
27082
27335
  stdout += `template_path: ${template}
27083
27336
 
27084
27337
  `;
27085
- stdout += readTrimmed2(path16.join(cwd, template), 220);
27338
+ stdout += readTrimmed2(path18.join(cwd, template), 220);
27086
27339
  } else {
27087
27340
  stdout += `template_path: none
27088
27341
 
@@ -27092,7 +27345,7 @@ ${status.stderr}` : "");
27092
27345
  stdout += `
27093
27346
  `;
27094
27347
  stdout += printSection("Recent Validation Signals");
27095
- if (existsSync6(path16.join(cwd, "package.json"))) {
27348
+ if (existsSync6(path18.join(cwd, "package.json"))) {
27096
27349
  stdout += `package.json detected. Common scripts:
27097
27350
  `;
27098
27351
  const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
@@ -27101,7 +27354,7 @@ ${status.stderr}` : "");
27101
27354
  `) + `
27102
27355
  `;
27103
27356
  }
27104
- if (existsSync6(path16.join(cwd, "Cargo.toml")) || existsSync6(path16.join(cwd, "src-tauri/Cargo.toml"))) {
27357
+ if (existsSync6(path18.join(cwd, "Cargo.toml")) || existsSync6(path18.join(cwd, "src-tauri/Cargo.toml"))) {
27105
27358
  stdout += `Rust project detected.
27106
27359
  `;
27107
27360
  }
@@ -27134,7 +27387,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
27134
27387
  - Apply with the host-native editor, preserving the repository changelog conventions.
27135
27388
  - If Unreleased already has duplicate category headings, normalize_only first.`;
27136
27389
  function changelogContext(root, range) {
27137
- const cwd = path16.resolve(repoRoot(root));
27390
+ const cwd = path18.resolve(repoRoot(root));
27138
27391
  if (range !== undefined && !isResolvableContextRange(cwd, range))
27139
27392
  return invalidRange(cwd);
27140
27393
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -27152,7 +27405,7 @@ function changelogContext(root, range) {
27152
27405
  stdout += CHANGELOG_RULES + `
27153
27406
  `;
27154
27407
  stdout += printSection("Existing CHANGELOG.md");
27155
- const changelogPath = path16.join(cwd, "CHANGELOG.md");
27408
+ const changelogPath = path18.join(cwd, "CHANGELOG.md");
27156
27409
  if (existsSync6(changelogPath)) {
27157
27410
  stdout += readTrimmed2(changelogPath, 260) + `
27158
27411
  `;
@@ -27172,7 +27425,7 @@ function changelogContext(root, range) {
27172
27425
  return { stdout, stderr: "", exitCode: 0, cwd };
27173
27426
  }
27174
27427
  function docsRefreshContext(root, range) {
27175
- const cwd = path16.resolve(repoRoot(root));
27428
+ const cwd = path18.resolve(repoRoot(root));
27176
27429
  if (range !== undefined && !isResolvableContextRange(cwd, range))
27177
27430
  return invalidRange(cwd);
27178
27431
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -27194,7 +27447,7 @@ function docsRefreshContext(root, range) {
27194
27447
  `) + `
27195
27448
  `;
27196
27449
  stdout += printSection("README Preview");
27197
- const readme = path16.join(cwd, "README.md");
27450
+ const readme = path18.join(cwd, "README.md");
27198
27451
  if (existsSync6(readme)) {
27199
27452
  stdout += readTrimmed2(readme, 220) + `
27200
27453
  `;
@@ -27203,7 +27456,7 @@ function docsRefreshContext(root, range) {
27203
27456
  `;
27204
27457
  }
27205
27458
  stdout += printSection("Package Scripts");
27206
- const pkgPath = path16.join(cwd, "package.json");
27459
+ const pkgPath = path18.join(cwd, "package.json");
27207
27460
  if (existsSync6(pkgPath)) {
27208
27461
  try {
27209
27462
  const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
@@ -27217,7 +27470,7 @@ function docsRefreshContext(root, range) {
27217
27470
  return { stdout, stderr: "", exitCode: 0, cwd };
27218
27471
  }
27219
27472
  function releaseNotesContext(root, rangeOrTag) {
27220
- const cwd = path16.resolve(repoRoot(root));
27473
+ const cwd = path18.resolve(repoRoot(root));
27221
27474
  if (!rangeOrTag) {
27222
27475
  return { stdout: "", stderr: `ERROR: release tag or range required
27223
27476
  `, exitCode: 1, cwd };
@@ -27255,7 +27508,7 @@ function releaseNotesContext(root, rangeOrTag) {
27255
27508
  `;
27256
27509
  stdout += printSection("Existing Release Files");
27257
27510
  for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
27258
- if (existsSync6(path16.join(cwd, rel)))
27511
+ if (existsSync6(path18.join(cwd, rel)))
27259
27512
  stdout += rel + `
27260
27513
  `;
27261
27514
  }
@@ -27286,8 +27539,8 @@ function releaseNotesContext(root, rangeOrTag) {
27286
27539
  import { spawnSync as spawnSync13 } from "node:child_process";
27287
27540
 
27288
27541
  // packages/workit-core/src/core/pr-create.ts
27289
- import fs13 from "node:fs";
27290
- import path17 from "node:path";
27542
+ import fs14 from "node:fs";
27543
+ import path19 from "node:path";
27291
27544
  import { spawnSync as spawnSync12 } from "node:child_process";
27292
27545
  // packages/workit-core/src/forge/pr-body.ts
27293
27546
  function parseGhIssue(value) {
@@ -27298,13 +27551,13 @@ function parseGhIssue(value) {
27298
27551
  // packages/workit-core/src/core/pr-create.ts
27299
27552
  function whichOnPath(tool) {
27300
27553
  const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
27301
- for (const dir of (process.env.PATH ?? "").split(path17.delimiter)) {
27554
+ for (const dir of (process.env.PATH ?? "").split(path19.delimiter)) {
27302
27555
  if (!dir)
27303
27556
  continue;
27304
27557
  for (const name of names) {
27305
- const candidate = path17.join(dir, name);
27558
+ const candidate = path19.join(dir, name);
27306
27559
  try {
27307
- fs13.accessSync(candidate, fs13.constants.X_OK);
27560
+ fs14.accessSync(candidate, fs14.constants.X_OK);
27308
27561
  return candidate;
27309
27562
  } catch {}
27310
27563
  }
@@ -27422,8 +27675,8 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
27422
27675
  };
27423
27676
 
27424
27677
  // packages/workit-core/src/core/youtrack.ts
27425
- import fs14 from "node:fs";
27426
- import path18 from "node:path";
27678
+ import fs15 from "node:fs";
27679
+ import path20 from "node:path";
27427
27680
 
27428
27681
  // packages/workit-core/src/core/templates.ts
27429
27682
  var repoRoot2 = assetRoot();
@@ -27436,22 +27689,22 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
27436
27689
  // packages/workit-core/src/core/youtrack.ts
27437
27690
  var ISSUE_RE = /^[A-Z]+-\d+$/;
27438
27691
  var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
27439
- var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path18.join(configDir(), "youtrack.json");
27440
- var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path18.join(resolveConfigDir(), "youtrack.json");
27692
+ var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(configDir(), "youtrack.json");
27693
+ var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(resolveConfigDir(), "youtrack.json");
27441
27694
  var youTrackTokenModeOk = (p) => {
27442
27695
  if (process.platform === "win32")
27443
27696
  return true;
27444
- const mode = fs14.statSync(p).mode & 511;
27697
+ const mode = fs15.statSync(p).mode & 511;
27445
27698
  return mode === 384;
27446
27699
  };
27447
27700
  function readYouTrackConfig(required) {
27448
27701
  const cfgPath = youTrackConfigPath();
27449
- if (!fs14.existsSync(cfgPath)) {
27702
+ if (!fs15.existsSync(cfgPath)) {
27450
27703
  return required ? { error: "ERROR: missing youtrack.json", path: cfgPath } : { config: {}, path: cfgPath };
27451
27704
  }
27452
27705
  let parsed;
27453
27706
  try {
27454
- parsed = JSON.parse(fs14.readFileSync(cfgPath, "utf8"));
27707
+ parsed = JSON.parse(fs15.readFileSync(cfgPath, "utf8"));
27455
27708
  } catch {
27456
27709
  return { error: `${cfgPath} is not valid JSON`, path: cfgPath };
27457
27710
  }
@@ -27462,11 +27715,11 @@ function readYouTrackConfig(required) {
27462
27715
  }
27463
27716
  var readYouTrackContextConfig = () => {
27464
27717
  const cfgPath = youTrackReadOnlyConfigPath();
27465
- if (!fs14.existsSync(cfgPath))
27718
+ if (!fs15.existsSync(cfgPath))
27466
27719
  return { data: {} };
27467
27720
  let parsed;
27468
27721
  try {
27469
- parsed = JSON.parse(fs14.readFileSync(cfgPath, "utf8"));
27722
+ parsed = JSON.parse(fs15.readFileSync(cfgPath, "utf8"));
27470
27723
  } catch {
27471
27724
  return { error: "YouTrack configuration is unavailable" };
27472
27725
  }
@@ -27505,12 +27758,12 @@ var youTrackToken = () => {
27505
27758
  if ("error" in loaded)
27506
27759
  return loaded;
27507
27760
  const tokenFile = String(loaded.config.tokenFile ?? "");
27508
- const tokenPath = tokenFile ? path18.isAbsolute(tokenFile) ? path18.resolve(tokenFile) : path18.resolve(process.cwd(), tokenFile) : "";
27509
- if (!tokenPath || !fs14.existsSync(tokenPath))
27761
+ const tokenPath = tokenFile ? path20.isAbsolute(tokenFile) ? path20.resolve(tokenFile) : path20.resolve(process.cwd(), tokenFile) : "";
27762
+ if (!tokenPath || !fs15.existsSync(tokenPath))
27510
27763
  return { error: "missing youtrack.token" };
27511
27764
  if (!youTrackTokenModeOk(tokenPath))
27512
27765
  return { error: "youtrack.token mode must be 0600" };
27513
- const token = fs14.readFileSync(tokenPath, "utf8").trim();
27766
+ const token = fs15.readFileSync(tokenPath, "utf8").trim();
27514
27767
  if (!token)
27515
27768
  return { error: "empty token file" };
27516
27769
  if (token === TOKEN_PLACEHOLDER || token.startsWith(TOKEN_PLACEHOLDER)) {
@@ -27575,9 +27828,9 @@ function resolveYouTrackFromPaths(spec_path, plan_path, workspace_root) {
27575
27828
  } catch {
27576
27829
  continue;
27577
27830
  }
27578
- if (!fs14.existsSync(full))
27831
+ if (!fs15.existsSync(full))
27579
27832
  continue;
27580
- const text = fs14.readFileSync(full, "utf8");
27833
+ const text = fs15.readFileSync(full, "utf8");
27581
27834
  const m = text.match(/^\*\*YouTrack:\*\*\s*`?([A-Z]+-\d+)`?/m);
27582
27835
  if (m)
27583
27836
  return m[1];
@@ -27847,15 +28100,15 @@ function resolveGitRevision(root, value) {
27847
28100
  }
27848
28101
  function resolveInside(root, candidate) {
27849
28102
  const base = realpathSync5(root);
27850
- const target = path19.resolve(base, candidate);
27851
- if (target !== base && !target.startsWith(base + path19.sep)) {
28103
+ const target = path21.resolve(base, candidate);
28104
+ if (target !== base && !target.startsWith(base + path21.sep)) {
27852
28105
  throw new Error("path must stay inside repository root");
27853
28106
  }
27854
28107
  let ancestor = target;
27855
28108
  while (!existsSync7(ancestor))
27856
- ancestor = path19.dirname(ancestor);
28109
+ ancestor = path21.dirname(ancestor);
27857
28110
  const canonicalAncestor = realpathSync5(ancestor);
27858
- if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path19.sep)) {
28111
+ if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path21.sep)) {
27859
28112
  throw new Error("path must stay inside repository root");
27860
28113
  }
27861
28114
  return target;
@@ -27913,13 +28166,13 @@ var rootVariants = (workspaceRoot) => {
27913
28166
  if (!workspaceRoot)
27914
28167
  return [];
27915
28168
  const roots = new Set;
27916
- for (const candidate of [workspaceRoot, path20.resolve(workspaceRoot)]) {
27917
- if (path20.isAbsolute(candidate) && candidate !== path20.parse(candidate).root)
28169
+ for (const candidate of [workspaceRoot, path22.resolve(workspaceRoot)]) {
28170
+ if (path22.isAbsolute(candidate) && candidate !== path22.parse(candidate).root)
27918
28171
  roots.add(candidate);
27919
28172
  }
27920
28173
  try {
27921
28174
  const canonical = realpathSync6(workspaceRoot);
27922
- if (canonical !== path20.parse(canonical).root)
28175
+ if (canonical !== path22.parse(canonical).root)
27923
28176
  roots.add(canonical);
27924
28177
  } catch {}
27925
28178
  return [...roots].toSorted((left, right) => right.length - left.length);
@@ -28001,11 +28254,11 @@ var thrownResult = (tool, error, workspaceRoot) => {
28001
28254
  };
28002
28255
  function createMcpServer(host, contextProvider) {
28003
28256
  assertMcpHost(host);
28004
- const here = path20.dirname(fileURLToPath2(import.meta.url));
28257
+ const here = path22.dirname(fileURLToPath2(import.meta.url));
28005
28258
  const sourceMarker = markSourcesLoaded([
28006
- path20.join(here, "server.ts"),
28007
- path20.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
28008
- path20.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
28259
+ path22.join(here, "server.ts"),
28260
+ path22.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
28261
+ path22.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
28009
28262
  ].filter((file) => existsSync8(file)));
28010
28263
  let staleWarned = false;
28011
28264
  const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
@@ -28185,8 +28438,8 @@ var main = async () => {
28185
28438
  process.exitCode = 2;
28186
28439
  }
28187
28440
  };
28188
- var entryPath = process.argv[1] ? path21.resolve(process.argv[1]) : "";
28189
- if (entryPath === path21.resolve(fileURLToPath3(import.meta.url)))
28441
+ var entryPath = process.argv[1] ? path23.resolve(process.argv[1]) : "";
28442
+ if (entryPath === path23.resolve(fileURLToPath3(import.meta.url)))
28190
28443
  await main();
28191
28444
  export {
28192
28445
  McpCapabilityUnavailableError,