@brainervirus/workit-cursor 8.13.0 → 8.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6622,15 +6622,15 @@ var require_dist = __commonJS(function(exports, module) {
6622
6622
 
6623
6623
  // packages/workit-cursor/mcp/run-server.ts
6624
6624
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
6625
- import path23 from "node:path";
6625
+ import path24 from "node:path";
6626
6626
 
6627
6627
  // packages/workit-mcp/src/index.ts
6628
6628
  import { fileURLToPath as fileURLToPath3 } from "node:url";
6629
- import path22 from "node:path";
6629
+ import path23 from "node:path";
6630
6630
 
6631
6631
  // packages/workit-mcp/src/server.ts
6632
6632
  import { existsSync as existsSync8, readFileSync as readFileSync6, realpathSync as realpathSync6 } from "node:fs";
6633
- import path21 from "node:path";
6633
+ import path22 from "node:path";
6634
6634
 
6635
6635
  // node_modules/zod/v4/core/util.js
6636
6636
  function getEnumValues(entries) {
@@ -16582,7 +16582,7 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
16582
16582
  // packages/workit-core/src/core.ts
16583
16583
  import { spawnSync as spawnSync14 } from "node:child_process";
16584
16584
  import { existsSync as existsSync7, realpathSync as realpathSync5 } from "node:fs";
16585
- import path20 from "node:path";
16585
+ import path21 from "node:path";
16586
16586
 
16587
16587
  // packages/workit-core/src/core/task-contract.ts
16588
16588
  import { createHash, randomUUID } from "node:crypto";
@@ -17837,9 +17837,9 @@ function parseAdvertisedOperation(family, input, host) {
17837
17837
  });
17838
17838
  }
17839
17839
  // packages/workit-core/src/core/task-store.ts
17840
- import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
17841
- import * as fs7 from "node:fs";
17842
- import path7 from "node:path";
17840
+ import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
17841
+ import * as fs8 from "node:fs";
17842
+ import path8 from "node:path";
17843
17843
 
17844
17844
  // node_modules/@openclaw/fs-safe/dist/errors.js
17845
17845
  var OPERATIONAL_CODES = new Set([
@@ -18442,6 +18442,11 @@ function acquireFileLockSync(targetPath, options) {
18442
18442
  }
18443
18443
  }
18444
18444
  }
18445
+ // packages/workit-core/src/host-session.ts
18446
+ import { createHash as createHash3, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
18447
+ import fs5 from "node:fs";
18448
+ import path5 from "node:path";
18449
+
18445
18450
  // packages/workit-core/src/core/logger.ts
18446
18451
  import os from "node:os";
18447
18452
  import path3 from "node:path";
@@ -18824,30 +18829,113 @@ function hostSessionFromEnv(env) {
18824
18829
  }
18825
18830
  return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
18826
18831
  }
18832
+ var hash = (value) => createHash3("sha256").update(value).digest("hex").slice(0, 32);
18833
+ var userIssuedRoot = () => path5.join(resolveStateDir(), "issued");
18834
+ var userTokenRoot = () => path5.join(resolveStateDir(), "issued-tokens");
18835
+ function migrateRepoIssued(cwd) {
18836
+ if (cwd === undefined)
18837
+ return;
18838
+ let old;
18839
+ try {
18840
+ const location = resolveStore(cwd);
18841
+ if (location instanceof Error)
18842
+ return;
18843
+ old = path5.join(location.dir, "hooks", "issued");
18844
+ if (!fs5.existsSync(old))
18845
+ return;
18846
+ } catch {
18847
+ return;
18848
+ }
18849
+ for (const lead of safeList(old)) {
18850
+ try {
18851
+ const from = path5.join(old, lead);
18852
+ if (!fs5.statSync(from).isDirectory())
18853
+ continue;
18854
+ const to = path5.join(userIssuedRoot(), lead);
18855
+ fs5.mkdirSync(to, { recursive: true, mode: 448 });
18856
+ for (const id of fs5.readdirSync(from)) {
18857
+ try {
18858
+ fs5.copyFileSync(path5.join(from, id), path5.join(to, id), fs5.constants.COPYFILE_EXCL);
18859
+ } catch (error) {
18860
+ if (error.code !== "EEXIST")
18861
+ throw error;
18862
+ }
18863
+ fs5.rmSync(path5.join(from, id), { force: true });
18864
+ }
18865
+ removeIfEmpty(from);
18866
+ } catch {}
18867
+ }
18868
+ removeIfEmpty(old);
18869
+ }
18870
+ var safeList = (dir) => {
18871
+ try {
18872
+ return fs5.readdirSync(dir);
18873
+ } catch {
18874
+ return [];
18875
+ }
18876
+ };
18877
+ var removeIfEmpty = (dir) => {
18878
+ try {
18879
+ fs5.rmdirSync(dir);
18880
+ } catch {}
18881
+ };
18882
+ var issuedRecord = (cwd, claimed) => {
18883
+ const cut = claimed.lastIndexOf(":");
18884
+ if (cut <= 0)
18885
+ return null;
18886
+ migrateRepoIssued(cwd);
18887
+ try {
18888
+ return fs5.readFileSync(path5.join(userIssuedRoot(), hash(claimed.slice(0, cut)), hash(claimed)), "utf8");
18889
+ } catch {
18890
+ return null;
18891
+ }
18892
+ };
18893
+ var TOKEN_HASH = /^([0-9a-f]{64})$/mu;
18894
+ var issuedToken = (claimed) => {
18895
+ const cut = claimed.lastIndexOf(":");
18896
+ if (cut <= 0)
18897
+ return { stored: null, leadBound: false };
18898
+ const dir = path5.join(userTokenRoot(), hash(claimed.slice(0, cut)));
18899
+ try {
18900
+ const text = fs5.readFileSync(path5.join(dir, hash(claimed)), "utf8");
18901
+ return { stored: TOKEN_HASH.exec(text)?.[1] ?? null, leadBound: true };
18902
+ } catch {
18903
+ return { stored: null, leadBound: safeList(dir).length > 0 };
18904
+ }
18905
+ };
18906
+ function issuedBinding(cwd, claimed) {
18907
+ const record = issuedRecord(cwd, claimed);
18908
+ const { stored, leadBound } = issuedToken(claimed);
18909
+ if (stored)
18910
+ return "token";
18911
+ if (record === null)
18912
+ return null;
18913
+ return leadBound ? "token" : "legacy";
18914
+ }
18827
18915
  var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
18828
18916
 
18829
18917
  // packages/workit-core/src/core/package-root.ts
18830
18918
  import { existsSync } from "node:fs";
18831
- import path5 from "node:path";
18919
+ import path6 from "node:path";
18832
18920
  import { fileURLToPath } from "node:url";
18833
18921
  var packageRoot = () => {
18834
- let dir = path5.dirname(fileURLToPath(import.meta.url));
18922
+ let dir = path6.dirname(fileURLToPath(import.meta.url));
18835
18923
  while (true) {
18836
- const parent = path5.dirname(dir);
18837
- if (existsSync(path5.join(dir, "package.json")) || parent === dir)
18924
+ const parent = path6.dirname(dir);
18925
+ if (existsSync(path6.join(dir, "package.json")) || parent === dir)
18838
18926
  return dir;
18839
18927
  dir = parent;
18840
18928
  }
18841
18929
  };
18842
18930
  var assetRoot = () => {
18843
18931
  const root = packageRoot();
18844
- const assets = path5.join(root, "assets");
18932
+ const assets = path6.join(root, "assets");
18845
18933
  return existsSync(assets) ? assets : root;
18846
18934
  };
18847
18935
 
18848
18936
  // packages/workit-core/src/core/store-lock.ts
18849
18937
  import { spawnSync as spawnSync2 } from "node:child_process";
18850
- import fs5 from "node:fs";
18938
+ import fs6 from "node:fs";
18851
18939
  import { hostname } from "node:os";
18852
18940
  var metadataLockSchema = object2({
18853
18941
  pid: number2().int().nonnegative().safe(),
@@ -18859,8 +18947,10 @@ var metadataLockSchema = object2({
18859
18947
  var FOREIGN_LOCK_TTL_MS = 10 * 60000;
18860
18948
  var UNREADABLE_LOCK_TTL_MS = 30000;
18861
18949
  var RECLAIM_GUARD_TTL_MS = 30000;
18862
- var defaultLockTimeoutMs = 250;
18950
+ var IN_PROCESS_LOCK_TIMEOUT_MS = 250;
18951
+ var defaultLockTimeoutMs = IN_PROCESS_LOCK_TIMEOUT_MS;
18863
18952
  var defaultLockTimeout = () => defaultLockTimeoutMs;
18953
+ var hostAwareLockTimeout = (cliMs) => defaultLockTimeoutMs > IN_PROCESS_LOCK_TIMEOUT_MS ? cliMs : IN_PROCESS_LOCK_TIMEOUT_MS;
18864
18954
  var parseMetadataLock = (raw) => {
18865
18955
  let value;
18866
18956
  try {
@@ -18889,7 +18979,7 @@ var parseProcStatStart = (stat) => {
18889
18979
  var processStartOf = (pid) => {
18890
18980
  if (process.platform === "linux") {
18891
18981
  try {
18892
- return parseProcStatStart(fs5.readFileSync(`/proc/${pid}/stat`, "utf8"));
18982
+ return parseProcStatStart(fs6.readFileSync(`/proc/${pid}/stat`, "utf8"));
18893
18983
  } catch {
18894
18984
  return null;
18895
18985
  }
@@ -18910,7 +19000,7 @@ var processStartOf = (pid) => {
18910
19000
  };
18911
19001
  var readTrimmed = (file) => {
18912
19002
  try {
18913
- return fs5.readFileSync(file, "utf8").trim() || null;
19003
+ return fs6.readFileSync(file, "utf8").trim() || null;
18914
19004
  } catch {
18915
19005
  return null;
18916
19006
  }
@@ -18921,7 +19011,7 @@ var localLockHost = () => {
18921
19011
  return cachedLockHost;
18922
19012
  let pidns = null;
18923
19013
  try {
18924
- pidns = /\[(\d+)\]/.exec(fs5.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
19014
+ pidns = /\[(\d+)\]/.exec(fs6.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
18925
19015
  } catch {}
18926
19016
  const boot = readTrimmed("/proc/sys/kernel/random/boot_id");
18927
19017
  cachedLockHost = pidns || boot ? `${hostname()}#${pidns ?? "?"}:${boot ?? "?"}` : hostname();
@@ -18967,7 +19057,7 @@ var classifyLockOwner = (payload, ageMs, localHost = localLockHost(), options =
18967
19057
  };
18968
19058
  var ageOf = (file, nowMs) => {
18969
19059
  try {
18970
- return nowMs - fs5.lstatSync(file).mtimeMs;
19060
+ return nowMs - fs6.lstatSync(file).mtimeMs;
18971
19061
  } catch {
18972
19062
  return null;
18973
19063
  }
@@ -18978,7 +19068,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
18978
19068
  if (age === null || age <= RECLAIM_GUARD_TTL_MS)
18979
19069
  return false;
18980
19070
  try {
18981
- fs5.rmdirSync(guard);
19071
+ fs6.rmdirSync(guard);
18982
19072
  return true;
18983
19073
  } catch {
18984
19074
  return false;
@@ -18987,8 +19077,8 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
18987
19077
 
18988
19078
  // packages/workit-core/src/store/event-log.ts
18989
19079
  import { randomUUID as randomUUID2 } from "node:crypto";
18990
- import fs6 from "node:fs";
18991
- import path6 from "node:path";
19080
+ import fs7 from "node:fs";
19081
+ import path7 from "node:path";
18992
19082
  var EVENT_VERSION = 1;
18993
19083
 
18994
19084
  class LogDamage extends Error {
@@ -19017,7 +19107,7 @@ var parseEvent = (line, file, offset) => {
19017
19107
  function readLog(file, from = 0, expectSeq = null) {
19018
19108
  let fd;
19019
19109
  try {
19020
- fd = fs6.openSync(file, "r");
19110
+ fd = fs7.openSync(file, "r");
19021
19111
  } catch (error) {
19022
19112
  if (error.code === "ENOENT")
19023
19113
  return null;
@@ -19026,13 +19116,13 @@ function readLog(file, from = 0, expectSeq = null) {
19026
19116
  let bytes;
19027
19117
  let size;
19028
19118
  try {
19029
- size = fs6.fstatSync(fd).size;
19119
+ size = fs7.fstatSync(fd).size;
19030
19120
  if (from > size)
19031
19121
  throw new LogDamage(`${file}: shorter than its snapshot`);
19032
19122
  bytes = Buffer.alloc(size - from);
19033
19123
  let read = 0;
19034
19124
  while (read < bytes.length) {
19035
- const got = fs6.readSync(fd, bytes, read, bytes.length - read, from + read);
19125
+ const got = fs7.readSync(fd, bytes, read, bytes.length - read, from + read);
19036
19126
  if (got === 0)
19037
19127
  break;
19038
19128
  read += got;
@@ -19040,7 +19130,7 @@ function readLog(file, from = 0, expectSeq = null) {
19040
19130
  bytes = bytes.subarray(0, read);
19041
19131
  size = from + read;
19042
19132
  } finally {
19043
- fs6.closeSync(fd);
19133
+ fs7.closeSync(fd);
19044
19134
  }
19045
19135
  const events = [];
19046
19136
  let start = 0;
@@ -19065,11 +19155,11 @@ function readLog(file, from = 0, expectSeq = null) {
19065
19155
  }
19066
19156
  var fsyncDirectory = (dir) => {
19067
19157
  try {
19068
- const fd = fs6.openSync(dir, "r");
19158
+ const fd = fs7.openSync(dir, "r");
19069
19159
  try {
19070
- fs6.fsyncSync(fd);
19160
+ fs7.fsyncSync(fd);
19071
19161
  } finally {
19072
- fs6.closeSync(fd);
19162
+ fs7.closeSync(fd);
19073
19163
  }
19074
19164
  } catch (error) {
19075
19165
  if (process.platform !== "win32")
@@ -19079,46 +19169,46 @@ var fsyncDirectory = (dir) => {
19079
19169
  function appendEvent(file, event, validEnd) {
19080
19170
  const line = Buffer.from(`${JSON.stringify(event)}
19081
19171
  `, "utf8");
19082
- const created = !fs6.existsSync(file);
19083
- if (!created && fs6.statSync(file).size !== validEnd) {
19084
- const cut = fs6.openSync(file, "r+");
19172
+ const created = !fs7.existsSync(file);
19173
+ if (!created && fs7.statSync(file).size !== validEnd) {
19174
+ const cut = fs7.openSync(file, "r+");
19085
19175
  try {
19086
- fs6.ftruncateSync(cut, validEnd);
19087
- fs6.fsyncSync(cut);
19176
+ fs7.ftruncateSync(cut, validEnd);
19177
+ fs7.fsyncSync(cut);
19088
19178
  } finally {
19089
- fs6.closeSync(cut);
19179
+ fs7.closeSync(cut);
19090
19180
  }
19091
19181
  }
19092
- const fd = fs6.openSync(file, "a", 384);
19182
+ const fd = fs7.openSync(file, "a", 384);
19093
19183
  try {
19094
19184
  let written = 0;
19095
19185
  while (written < line.length)
19096
- written += fs6.writeSync(fd, line, written, line.length - written);
19097
- fs6.fsyncSync(fd);
19186
+ written += fs7.writeSync(fd, line, written, line.length - written);
19187
+ fs7.fsyncSync(fd);
19098
19188
  } finally {
19099
- fs6.closeSync(fd);
19189
+ fs7.closeSync(fd);
19100
19190
  }
19101
19191
  if (created)
19102
- fsyncDirectory(path6.dirname(file));
19192
+ fsyncDirectory(path7.dirname(file));
19103
19193
  return validEnd;
19104
19194
  }
19105
19195
  function replaceFile(file, bytes, durable) {
19106
19196
  const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
19107
19197
  try {
19108
- const fd = fs6.openSync(temporary, "wx", 384);
19198
+ const fd = fs7.openSync(temporary, "wx", 384);
19109
19199
  try {
19110
- fs6.writeSync(fd, bytes);
19200
+ fs7.writeSync(fd, bytes);
19111
19201
  if (durable)
19112
- fs6.fsyncSync(fd);
19202
+ fs7.fsyncSync(fd);
19113
19203
  } finally {
19114
- fs6.closeSync(fd);
19204
+ fs7.closeSync(fd);
19115
19205
  }
19116
19206
  renameWithRetry(temporary, file);
19117
19207
  if (durable)
19118
- fsyncDirectory(path6.dirname(file));
19208
+ fsyncDirectory(path7.dirname(file));
19119
19209
  } catch (error) {
19120
19210
  try {
19121
- fs6.unlinkSync(temporary);
19211
+ fs7.unlinkSync(temporary);
19122
19212
  } catch {}
19123
19213
  throw error;
19124
19214
  }
@@ -19143,7 +19233,7 @@ var retryTransient = (run) => {
19143
19233
  }
19144
19234
  }
19145
19235
  };
19146
- var renameWithRetry = (from, to) => retryTransient(() => fs6.renameSync(from, to));
19236
+ var renameWithRetry = (from, to) => retryTransient(() => fs7.renameSync(from, to));
19147
19237
 
19148
19238
  // packages/workit-core/src/store/patch.ts
19149
19239
  var isPlainObject3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -19256,7 +19346,7 @@ var isPatch = (value) => Array.isArray(value) && value.every((op) => {
19256
19346
  });
19257
19347
 
19258
19348
  // packages/workit-core/src/store/reduce.ts
19259
- import { createHash as createHash3 } from "node:crypto";
19349
+ import { createHash as createHash4 } from "node:crypto";
19260
19350
  var OPENING_TYPES = new Set([
19261
19351
  "task.opened",
19262
19352
  "task.imported",
@@ -19285,7 +19375,7 @@ var isObject4 = (value) => typeof value === "object" && value !== null && !Array
19285
19375
  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");
19286
19376
  var BLOB_REF = "$blob";
19287
19377
  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;
19288
- var blobDigest = (value) => createHash3("sha256").update(JSON.stringify(value)).digest("hex");
19378
+ var blobDigest = (value) => createHash4("sha256").update(JSON.stringify(value)).digest("hex");
19289
19379
  var toBlob = (value, blobs) => {
19290
19380
  if (!isObject4(value))
19291
19381
  return value;
@@ -19440,7 +19530,7 @@ var indexEntry = (task, key, legacy, file) => {
19440
19530
  };
19441
19531
  var fileSignature = (file) => {
19442
19532
  try {
19443
- const stat = fs7.statSync(file, { bigint: true });
19533
+ const stat = fs8.statSync(file, { bigint: true });
19444
19534
  return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
19445
19535
  } catch {
19446
19536
  return null;
@@ -19458,7 +19548,7 @@ var cachedRuntimeVersion = null;
19458
19548
  var runtimeVersion = () => {
19459
19549
  if (cachedRuntimeVersion === null) {
19460
19550
  try {
19461
- const pkg = JSON.parse(fs7.readFileSync(path7.join(packageRoot(), "package.json"), "utf8"));
19551
+ const pkg = JSON.parse(fs8.readFileSync(path8.join(packageRoot(), "package.json"), "utf8"));
19462
19552
  cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
19463
19553
  } catch {
19464
19554
  cachedRuntimeVersion = "0.0.0";
@@ -19484,14 +19574,14 @@ var isNewerVersion = (candidate, current) => {
19484
19574
  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);
19485
19575
  var readText = (file) => {
19486
19576
  try {
19487
- return fs7.readFileSync(file, "utf8");
19577
+ return fs8.readFileSync(file, "utf8");
19488
19578
  } catch {
19489
19579
  return "";
19490
19580
  }
19491
19581
  };
19492
19582
  var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
19493
19583
  var branchStart = (location, branch, aliases) => {
19494
- const first = readText(path7.join(path7.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
19584
+ const first = readText(path8.join(path8.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
19495
19585
  `, 1)[0];
19496
19586
  const created = REFLOG_LINE.exec(first);
19497
19587
  const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
@@ -19501,7 +19591,7 @@ var branchStart = (location, branch, aliases) => {
19501
19591
  return start;
19502
19592
  if (!location.git)
19503
19593
  return null;
19504
- for (const line of readText(path7.join(location.git.gitDir, "logs", "HEAD")).split(`
19594
+ for (const line of readText(path8.join(location.git.gitDir, "logs", "HEAD")).split(`
19505
19595
  `)) {
19506
19596
  const entry = REFLOG_LINE.exec(line);
19507
19597
  const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
@@ -19511,23 +19601,23 @@ var branchStart = (location, branch, aliases) => {
19511
19601
  }
19512
19602
  return null;
19513
19603
  };
19514
- var refExists = (common, ref) => fs7.existsSync(path7.join(common, ref)) || readText(path7.join(common, "packed-refs")).includes(` ${ref}
19604
+ var refExists = (common, ref) => fs8.existsSync(path8.join(common, ref)) || readText(path8.join(common, "packed-refs")).includes(` ${ref}
19515
19605
  `);
19516
19606
  var origins = new Map;
19517
19607
  var sameDirectoryIdentity = (left, right) => {
19518
- if (!path7.isAbsolute(left) || !path7.isAbsolute(right))
19608
+ if (!path8.isAbsolute(left) || !path8.isAbsolute(right))
19519
19609
  return false;
19520
- const normalizedLeft = path7.resolve(left);
19521
- const normalizedRight = path7.resolve(right);
19610
+ const normalizedLeft = path8.resolve(left);
19611
+ const normalizedRight = path8.resolve(right);
19522
19612
  try {
19523
- const a = fs7.statSync(normalizedLeft, { bigint: true });
19524
- const b = fs7.statSync(normalizedRight, { bigint: true });
19613
+ const a = fs8.statSync(normalizedLeft, { bigint: true });
19614
+ const b = fs8.statSync(normalizedRight, { bigint: true });
19525
19615
  if (!a.isDirectory() || !b.isDirectory())
19526
19616
  return false;
19527
19617
  if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
19528
19618
  return true;
19529
- const canonicalLeft = fs7.realpathSync(normalizedLeft);
19530
- const canonicalRight = fs7.realpathSync(normalizedRight);
19619
+ const canonicalLeft = fs8.realpathSync(normalizedLeft);
19620
+ const canonicalRight = fs8.realpathSync(normalizedRight);
19531
19621
  if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
19532
19622
  return true;
19533
19623
  return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
@@ -19564,8 +19654,8 @@ class TaskStore {
19564
19654
  migrationChecked = false;
19565
19655
  compactDue = new Set;
19566
19656
  constructor(root, options = {}) {
19567
- const resolved = path7.resolve(root);
19568
- this.origin = fs7.existsSync(resolved) ? fs7.realpathSync(resolved) : resolved;
19657
+ const resolved = path8.resolve(root);
19658
+ this.origin = fs8.existsSync(resolved) ? fs8.realpathSync(resolved) : resolved;
19569
19659
  this.located = resolveStore(this.origin);
19570
19660
  this.root = checkoutRootOf(this.origin, this.located);
19571
19661
  this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
@@ -19573,7 +19663,7 @@ class TaskStore {
19573
19663
  this.migrateOnRead = options.migrateOnRead;
19574
19664
  }
19575
19665
  location() {
19576
- if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs7.existsSync(path7.join(this.root, ".git"))) {
19666
+ if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs8.existsSync(path8.join(this.root, ".git"))) {
19577
19667
  this.located = undefined;
19578
19668
  this.migrationChecked = false;
19579
19669
  }
@@ -19637,7 +19727,7 @@ class TaskStore {
19637
19727
  const tasksDir = this.paths().tasks;
19638
19728
  let names;
19639
19729
  try {
19640
- names = fs7.existsSync(tasksDir) ? fs7.readdirSync(tasksDir).filter((name) => validId(name)) : [];
19730
+ names = fs8.existsSync(tasksDir) ? fs8.readdirSync(tasksDir).filter((name) => validId(name)) : [];
19641
19731
  } catch (error) {
19642
19732
  return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
19643
19733
  path: tasksDir
@@ -19678,7 +19768,7 @@ class TaskStore {
19678
19768
  const file = this.paths().workspace;
19679
19769
  let bytes;
19680
19770
  try {
19681
- bytes = retryTransient(() => fs7.readFileSync(file, "utf8"));
19771
+ bytes = retryTransient(() => fs8.readFileSync(file, "utf8"));
19682
19772
  } catch (error) {
19683
19773
  if (error.code === "ENOENT")
19684
19774
  return success(null, null, null);
@@ -19729,7 +19819,7 @@ class TaskStore {
19729
19819
  const moved = this.bindLocked(again.data.id, key, input.now);
19730
19820
  return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
19731
19821
  }
19732
- const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path7.basename(this.root) || this.root;
19822
+ const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path8.basename(this.root) || this.root;
19733
19823
  const intent = {
19734
19824
  objective: input.objective?.trim() || `Work on ${label}`,
19735
19825
  scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
@@ -19789,14 +19879,14 @@ class TaskStore {
19789
19879
  const branch = key.ok ? key.data.branch : null;
19790
19880
  if (!branch || !location.ok)
19791
19881
  return success(null, null, null);
19792
- const common = path7.dirname(location.data.dir);
19793
- const heads = path7.join(common, "logs", "refs", "heads");
19794
- const headLog = location.data.git ? path7.join(location.data.git.gitDir, "logs", "HEAD") : "";
19882
+ const common = path8.dirname(location.data.dir);
19883
+ const heads = path8.join(common, "logs", "refs", "heads");
19884
+ const headLog = location.data.git ? path8.join(location.data.git.gitDir, "logs", "HEAD") : "";
19795
19885
  const signatures = [
19796
- path7.join(heads, branch),
19886
+ path8.join(heads, branch),
19797
19887
  headLog,
19798
19888
  heads,
19799
- path7.join(common, "packed-refs")
19889
+ path8.join(common, "packed-refs")
19800
19890
  ].map((file) => fileSignature(file) ?? "-");
19801
19891
  const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
19802
19892
  let resolved = origins.get(slot);
@@ -19808,7 +19898,7 @@ class TaskStore {
19808
19898
  aliases.push(rename.from);
19809
19899
  const start = branchStart(location.data, branch, aliases);
19810
19900
  const slash = start?.indexOf("/") ?? -1;
19811
- const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path7.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
19901
+ 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)}"]`));
19812
19902
  const name = start && (remote ? start.slice(slash + 1) : start);
19813
19903
  resolved = {
19814
19904
  signature: signatures.join("|"),
@@ -20046,13 +20136,13 @@ class TaskStore {
20046
20136
  if (!ready.ok)
20047
20137
  return ready;
20048
20138
  const dirs = this.paths();
20049
- const recovery = path7.join(this.root, ".workit", "recovery");
20050
- if (fs7.existsSync(recovery)) {
20139
+ const recovery = path8.join(this.root, ".workit", "recovery");
20140
+ if (fs8.existsSync(recovery)) {
20051
20141
  let files = 0;
20052
20142
  let bytes = 0;
20053
20143
  try {
20054
- for (const name of fs7.readdirSync(recovery)) {
20055
- const stat = fs7.lstatSync(path7.join(recovery, name));
20144
+ for (const name of fs8.readdirSync(recovery)) {
20145
+ const stat = fs8.lstatSync(path8.join(recovery, name));
20056
20146
  if (!stat.isFile())
20057
20147
  continue;
20058
20148
  files += 1;
@@ -20061,17 +20151,17 @@ class TaskStore {
20061
20151
  } catch {}
20062
20152
  const remove = options.pruneRecovery === true && !dryRun;
20063
20153
  if (remove)
20064
- fs7.rmSync(recovery, { recursive: true, force: true });
20154
+ fs8.rmSync(recovery, { recursive: true, force: true });
20065
20155
  report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
20066
20156
  }
20067
- if (!fs7.existsSync(dirs.tasks))
20157
+ if (!fs8.existsSync(dirs.tasks))
20068
20158
  return success(null, null, report);
20069
- const names = fs7.readdirSync(dirs.tasks).filter((name) => validId(name));
20159
+ const names = fs8.readdirSync(dirs.tasks).filter((name) => validId(name));
20070
20160
  for (const name of names) {
20071
20161
  const file = this.eventsPath(name);
20072
20162
  let size = 0;
20073
20163
  try {
20074
- size = fs7.statSync(file).size;
20164
+ size = fs8.statSync(file).size;
20075
20165
  } catch {
20076
20166
  continue;
20077
20167
  }
@@ -20099,16 +20189,16 @@ class TaskStore {
20099
20189
  const references = new Set;
20100
20190
  for (const name of names)
20101
20191
  try {
20102
- for (const match of fs7.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
20192
+ for (const match of fs8.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
20103
20193
  references.add(match[1]);
20104
20194
  } catch {}
20105
- if (fs7.existsSync(dirs.blobs))
20106
- for (const name of fs7.readdirSync(dirs.blobs)) {
20195
+ if (fs8.existsSync(dirs.blobs))
20196
+ for (const name of fs8.readdirSync(dirs.blobs)) {
20107
20197
  const digest = name.replace(/\.json$/, "");
20108
- const file = path7.join(dirs.blobs, name);
20198
+ const file = path8.join(dirs.blobs, name);
20109
20199
  let stat;
20110
20200
  try {
20111
- stat = fs7.lstatSync(file);
20201
+ stat = fs8.lstatSync(file);
20112
20202
  } catch {
20113
20203
  continue;
20114
20204
  }
@@ -20119,11 +20209,11 @@ class TaskStore {
20119
20209
  report.blobs.removed += 1;
20120
20210
  report.blobs.removedBytes += stat.size;
20121
20211
  if (!dryRun)
20122
- fs7.rmSync(file, { force: true });
20212
+ fs8.rmSync(file, { force: true });
20123
20213
  }
20124
20214
  return success(null, null, null);
20125
20215
  };
20126
- const swept = dryRun ? sweep() : this.withLock(path7.join(dirs.dir, "gc.lock"), sweep);
20216
+ const swept = dryRun ? sweep() : this.withLock(path8.join(dirs.dir, "gc.lock"), sweep);
20127
20217
  if (!swept.ok)
20128
20218
  return swept;
20129
20219
  const temporaryDirs = [
@@ -20131,17 +20221,17 @@ class TaskStore {
20131
20221
  dirs.tasks,
20132
20222
  dirs.blobs,
20133
20223
  dirs.checkout,
20134
- ...names.map((name) => path7.join(dirs.tasks, name))
20224
+ ...names.map((name) => path8.join(dirs.tasks, name))
20135
20225
  ];
20136
20226
  for (const directory of temporaryDirs) {
20137
- if (!fs7.existsSync(directory))
20227
+ if (!fs8.existsSync(directory))
20138
20228
  continue;
20139
- for (const name of fs7.readdirSync(directory)) {
20229
+ for (const name of fs8.readdirSync(directory)) {
20140
20230
  if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
20141
20231
  continue;
20142
- const file = path7.join(directory, name);
20232
+ const file = path8.join(directory, name);
20143
20233
  try {
20144
- const stat = fs7.lstatSync(file);
20234
+ const stat = fs8.lstatSync(file);
20145
20235
  if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
20146
20236
  continue;
20147
20237
  } catch {
@@ -20149,37 +20239,37 @@ class TaskStore {
20149
20239
  }
20150
20240
  report.temporary.removed += 1;
20151
20241
  if (!dryRun)
20152
- fs7.rmSync(file, { force: true });
20242
+ fs8.rmSync(file, { force: true });
20153
20243
  }
20154
20244
  }
20155
20245
  return success(null, null, report);
20156
20246
  }
20157
20247
  paths() {
20158
20248
  const location = this.location();
20159
- const dir = location.ok ? location.data.dir : path7.join(this.root, ".workit");
20160
- const checkout = path7.join(dir, "checkouts", checkoutSlug(this.root));
20249
+ const dir = location.ok ? location.data.dir : path8.join(this.root, ".workit");
20250
+ const checkout = path8.join(dir, "checkouts", checkoutSlug(this.root));
20161
20251
  return {
20162
20252
  dir,
20163
20253
  shared: location.ok ? location.data.shared : false,
20164
- marker: path7.join(dir, "store.json"),
20254
+ marker: path8.join(dir, "store.json"),
20165
20255
  checkout,
20166
- workspace: path7.join(checkout, "workspace.json"),
20167
- checkoutLock: path7.join(checkout, "metadata.lock"),
20168
- tasks: path7.join(dir, "tasks"),
20169
- index: path7.join(dir, "task-index.json"),
20170
- blobs: path7.join(dir, "blobs", "candidates"),
20171
- legacy: path7.join(dir, "legacy", checkoutSlug(this.root), "v2"),
20172
- v2: path7.join(this.root, ".workit")
20256
+ workspace: path8.join(checkout, "workspace.json"),
20257
+ checkoutLock: path8.join(checkout, "metadata.lock"),
20258
+ tasks: path8.join(dir, "tasks"),
20259
+ index: path8.join(dir, "task-index.json"),
20260
+ blobs: path8.join(dir, "blobs", "candidates"),
20261
+ legacy: path8.join(dir, "legacy", checkoutSlug(this.root), "v2"),
20262
+ v2: path8.join(this.root, ".workit")
20173
20263
  };
20174
20264
  }
20175
20265
  eventsPath(taskId) {
20176
- return path7.join(this.paths().tasks, taskId, "events.jsonl");
20266
+ return path8.join(this.paths().tasks, taskId, "events.jsonl");
20177
20267
  }
20178
20268
  snapshotPath(taskId) {
20179
- return path7.join(this.paths().tasks, taskId, "snapshot.json");
20269
+ return path8.join(this.paths().tasks, taskId, "snapshot.json");
20180
20270
  }
20181
20271
  taskLockPath(taskId) {
20182
- return path7.join(this.paths().tasks, taskId, "lock");
20272
+ return path8.join(this.paths().tasks, taskId, "lock");
20183
20273
  }
20184
20274
  ready(write = false) {
20185
20275
  const location = this.location();
@@ -20189,7 +20279,7 @@ class TaskStore {
20189
20279
  return success(null, null, null);
20190
20280
  const dirs = this.paths();
20191
20281
  try {
20192
- const marker = JSON.parse(fs7.readFileSync(dirs.marker, "utf8"));
20282
+ const marker = JSON.parse(fs8.readFileSync(dirs.marker, "utf8"));
20193
20283
  if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
20194
20284
  return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
20195
20285
  } catch {}
@@ -20218,21 +20308,21 @@ class TaskStore {
20218
20308
  return {
20219
20309
  read: (digest) => {
20220
20310
  try {
20221
- return JSON.parse(fs7.readFileSync(path7.join(dir, `${digest}.json`), "utf8"));
20311
+ return JSON.parse(fs8.readFileSync(path8.join(dir, `${digest}.json`), "utf8"));
20222
20312
  } catch (error) {
20223
20313
  throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
20224
20314
  }
20225
20315
  },
20226
20316
  write: (digest, value) => {
20227
- const file = path7.join(dir, `${digest}.json`);
20228
- if (fs7.existsSync(file)) {
20317
+ const file = path8.join(dir, `${digest}.json`);
20318
+ if (fs8.existsSync(file)) {
20229
20319
  const stamp = new Date;
20230
20320
  try {
20231
- fs7.utimesSync(file, stamp, stamp);
20321
+ fs8.utimesSync(file, stamp, stamp);
20232
20322
  return;
20233
20323
  } catch {}
20234
20324
  }
20235
- fs7.mkdirSync(dir, { recursive: true });
20325
+ fs8.mkdirSync(dir, { recursive: true });
20236
20326
  replaceFile(file, JSON.stringify(value), true);
20237
20327
  }
20238
20328
  };
@@ -20314,7 +20404,7 @@ class TaskStore {
20314
20404
  }
20315
20405
  readSnapshot(taskId) {
20316
20406
  try {
20317
- const value = JSON.parse(fs7.readFileSync(this.snapshotPath(taskId), "utf8"));
20407
+ const value = JSON.parse(fs8.readFileSync(this.snapshotPath(taskId), "utf8"));
20318
20408
  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))
20319
20409
  return null;
20320
20410
  return value;
@@ -20416,8 +20506,8 @@ class TaskStore {
20416
20506
  }
20417
20507
  }
20418
20508
  openTask(record, type, key, legacy = null) {
20419
- const dir = path7.join(this.paths().tasks, record.id);
20420
- fs7.mkdirSync(dir, { recursive: true });
20509
+ const dir = path8.join(this.paths().tasks, record.id);
20510
+ fs8.mkdirSync(dir, { recursive: true });
20421
20511
  const blobs = this.blobStore();
20422
20512
  const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
20423
20513
  const event = this.event(record.id, 1, type, {
@@ -20469,11 +20559,11 @@ class TaskStore {
20469
20559
  } catch {}
20470
20560
  if (!latest || latest.events[0]?.id !== last.id)
20471
20561
  return failure2("busy", "the task log changed during compaction; retry", { taskId });
20472
- const appended = fs7.readFileSync(file).subarray(log.end, latest.end);
20562
+ const appended = fs8.readFileSync(file).subarray(log.end, latest.end);
20473
20563
  const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
20474
20564
  replaceFile(file, bytes.toString("utf8"), true);
20475
20565
  try {
20476
- fs7.rmSync(this.snapshotPath(taskId), { force: true });
20566
+ fs8.rmSync(this.snapshotPath(taskId), { force: true });
20477
20567
  } catch {}
20478
20568
  const reloaded = this.load(taskId);
20479
20569
  if (reloaded.ok && reloaded.data)
@@ -20486,7 +20576,7 @@ class TaskStore {
20486
20576
  }
20487
20577
  countEvents(file) {
20488
20578
  try {
20489
- const bytes = fs7.readFileSync(file);
20579
+ const bytes = fs8.readFileSync(file);
20490
20580
  let count = 0;
20491
20581
  for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
20492
20582
  count += 1;
@@ -20508,8 +20598,8 @@ class TaskStore {
20508
20598
  return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
20509
20599
  }
20510
20600
  withKeyLock(key, operation) {
20511
- const digest = createHash4("sha256").update(key).digest("hex").slice(0, 32);
20512
- return this.withLock(path7.join(this.paths().dir, "keys", `${digest}.lock`), operation);
20601
+ const digest = createHash5("sha256").update(key).digest("hex").slice(0, 32);
20602
+ return this.withLock(path8.join(this.paths().dir, "keys", `${digest}.lock`), operation);
20513
20603
  }
20514
20604
  bindLocked(taskId, key, timestamp) {
20515
20605
  const current = this.readWorkspace();
@@ -20650,7 +20740,7 @@ class TaskStore {
20650
20740
  writeWorkspace(record) {
20651
20741
  const file = this.paths().workspace;
20652
20742
  try {
20653
- fs7.mkdirSync(path7.dirname(file), { recursive: true });
20743
+ fs8.mkdirSync(path8.dirname(file), { recursive: true });
20654
20744
  replaceFile(file, `${canonicalJson(record)}
20655
20745
  `, true);
20656
20746
  return success(null, null, null);
@@ -20660,7 +20750,7 @@ class TaskStore {
20660
20750
  }
20661
20751
  readIndex() {
20662
20752
  try {
20663
- const value = JSON.parse(fs7.readFileSync(this.paths().index, "utf8"));
20753
+ const value = JSON.parse(fs8.readFileSync(this.paths().index, "utf8"));
20664
20754
  if (!isObject5(value) || value.version !== INDEX_VERSION || !isObject5(value.tasks))
20665
20755
  return {};
20666
20756
  const tasks = {};
@@ -20674,7 +20764,7 @@ class TaskStore {
20674
20764
  }
20675
20765
  writeIndex(entries) {
20676
20766
  try {
20677
- fs7.mkdirSync(this.paths().tasks, { recursive: true });
20767
+ fs8.mkdirSync(this.paths().tasks, { recursive: true });
20678
20768
  replaceFile(this.paths().index, JSON.stringify({
20679
20769
  version: INDEX_VERSION,
20680
20770
  tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
@@ -20728,23 +20818,23 @@ class TaskStore {
20728
20818
  return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
20729
20819
  }
20730
20820
  v2Dirs() {
20731
- return [...new Set([this.root, this.origin])].map((dir) => path7.join(dir, ".workit"));
20821
+ return [...new Set([this.root, this.origin])].map((dir) => path8.join(dir, ".workit"));
20732
20822
  }
20733
20823
  pendingMigrations() {
20734
20824
  return this.v2Dirs().filter((dir) => {
20735
- const raw = this.readV2Workspace(path7.join(dir, "workspace.json"));
20825
+ const raw = this.readV2Workspace(path8.join(dir, "workspace.json"));
20736
20826
  return raw !== null && raw !== TOMBSTONE;
20737
20827
  });
20738
20828
  }
20739
20829
  migrateV2(v2) {
20740
20830
  const dirs = this.paths();
20741
- const v2Workspace = path7.join(v2, "workspace.json");
20742
- const v2Tasks = path7.join(v2, "tasks");
20743
- const legacy = path7.join(dirs.dir, "legacy", checkoutSlug(path7.dirname(v2)), "v2");
20831
+ const v2Workspace = path8.join(v2, "workspace.json");
20832
+ const v2Tasks = path8.join(v2, "tasks");
20833
+ const legacy = path8.join(dirs.dir, "legacy", checkoutSlug(path8.dirname(v2)), "v2");
20744
20834
  const raw = this.readV2Workspace(v2Workspace);
20745
20835
  if (raw === null || raw === TOMBSTONE)
20746
20836
  return success(null, null, null);
20747
- return this.withLock(dirs.checkoutLock, () => this.withLock(path7.join(v2, "metadata.lock"), () => {
20837
+ return this.withLock(dirs.checkoutLock, () => this.withLock(path8.join(v2, "metadata.lock"), () => {
20748
20838
  const workspace = this.readV2Workspace(v2Workspace);
20749
20839
  if (workspace === null || workspace === TOMBSTONE)
20750
20840
  return success(null, null, null);
@@ -20753,7 +20843,7 @@ class TaskStore {
20753
20843
  return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
20754
20844
  let files = [];
20755
20845
  try {
20756
- files = fs7.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path7.join(v2Tasks, name)));
20846
+ files = fs8.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path8.join(v2Tasks, name)));
20757
20847
  } catch {}
20758
20848
  const current = this.readWorkspace();
20759
20849
  if (!current.ok)
@@ -20771,22 +20861,22 @@ class TaskStore {
20771
20861
  let skipped = 0;
20772
20862
  const done = new Map;
20773
20863
  try {
20774
- fs7.mkdirSync(path7.join(legacy, "tasks"), { recursive: true });
20864
+ fs8.mkdirSync(path8.join(legacy, "tasks"), { recursive: true });
20775
20865
  for (const name of ["workspace.json", "index.json"])
20776
- if (fs7.existsSync(path7.join(v2, name)))
20777
- fs7.copyFileSync(path7.join(v2, name), path7.join(legacy, name));
20866
+ if (fs8.existsSync(path8.join(v2, name)))
20867
+ fs8.copyFileSync(path8.join(v2, name), path8.join(legacy, name));
20778
20868
  for (const name of files) {
20779
20869
  const id = name.slice(0, -5);
20780
- const file = path7.join(v2Tasks, name);
20781
- const bytes = fs7.readFileSync(file, "utf8");
20870
+ const file = path8.join(v2Tasks, name);
20871
+ const bytes = fs8.readFileSync(file, "utf8");
20782
20872
  const digest = sha256(bytes);
20783
- fs7.writeFileSync(path7.join(legacy, "tasks", name), bytes);
20873
+ fs8.writeFileSync(path8.join(legacy, "tasks", name), bytes);
20784
20874
  const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
20785
20875
  if (!parsed.ok || parsed.data.id !== id)
20786
20876
  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 });
20787
20877
  const record = { ...parsed.data, workspaceId: target.id };
20788
- const origin = { path: path7.join(legacy, "tasks", name), digest };
20789
- if (!fs7.existsSync(this.eventsPath(id))) {
20878
+ const origin = { path: path8.join(legacy, "tasks", name), digest };
20879
+ if (!fs8.existsSync(this.eventsPath(id))) {
20790
20880
  this.openTask(record, "migrated.from_v2", null, origin);
20791
20881
  migrated += 1;
20792
20882
  } else {
@@ -20821,8 +20911,8 @@ class TaskStore {
20821
20911
  try {
20822
20912
  let complete = true;
20823
20913
  for (const [name, digest] of done) {
20824
- const file = path7.join(v2Tasks, name);
20825
- if (sha256(fs7.readFileSync(file, "utf8")) !== digest) {
20914
+ const file = path8.join(v2Tasks, name);
20915
+ if (sha256(fs8.readFileSync(file, "utf8")) !== digest) {
20826
20916
  complete = false;
20827
20917
  continue;
20828
20918
  }
@@ -20832,7 +20922,7 @@ class TaskStore {
20832
20922
  return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
20833
20923
  path: v2
20834
20924
  });
20835
- fs7.rmSync(path7.join(v2, "index.json"), { force: true });
20925
+ fs8.rmSync(path8.join(v2, "index.json"), { force: true });
20836
20926
  this.writeTombstone(v2, target.id);
20837
20927
  } catch (error) {
20838
20928
  return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
@@ -20852,45 +20942,45 @@ class TaskStore {
20852
20942
  }
20853
20943
  adoptLocalStore() {
20854
20944
  const dirs = this.paths();
20855
- const marker = path7.join(dirs.v2, "store.json");
20856
- if (!dirs.shared || !fs7.existsSync(marker))
20945
+ const marker = path8.join(dirs.v2, "store.json");
20946
+ if (!dirs.shared || !fs8.existsSync(marker))
20857
20947
  return success(null, null, null);
20858
20948
  return this.withLock(dirs.checkoutLock, () => {
20859
- if (!fs7.existsSync(marker))
20949
+ if (!fs8.existsSync(marker))
20860
20950
  return success(null, null, null);
20861
20951
  let tasks = 0;
20862
20952
  try {
20863
20953
  const merge = (from, to) => {
20864
- if (!fs7.existsSync(to)) {
20865
- fs7.mkdirSync(path7.dirname(to), { recursive: true });
20954
+ if (!fs8.existsSync(to)) {
20955
+ fs8.mkdirSync(path8.dirname(to), { recursive: true });
20866
20956
  try {
20867
- fs7.renameSync(from, to);
20957
+ fs8.renameSync(from, to);
20868
20958
  } catch {
20869
- fs7.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
20870
- fs7.rmSync(from, { recursive: true, force: true });
20959
+ fs8.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
20960
+ fs8.rmSync(from, { recursive: true, force: true });
20871
20961
  }
20872
20962
  return;
20873
20963
  }
20874
- if (fs7.lstatSync(from).isDirectory() && fs7.lstatSync(to).isDirectory())
20875
- for (const name of fs7.readdirSync(from))
20876
- merge(path7.join(from, name), path7.join(to, name));
20964
+ if (fs8.lstatSync(from).isDirectory() && fs8.lstatSync(to).isDirectory())
20965
+ for (const name of fs8.readdirSync(from))
20966
+ merge(path8.join(from, name), path8.join(to, name));
20877
20967
  };
20878
20968
  for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
20879
- const from = path7.join(dirs.v2, sub);
20880
- if (!fs7.existsSync(from))
20969
+ const from = path8.join(dirs.v2, sub);
20970
+ if (!fs8.existsSync(from))
20881
20971
  continue;
20882
20972
  if (sub === "tasks") {
20883
- for (const name of fs7.readdirSync(from))
20884
- if (validId(name) && !fs7.existsSync(path7.join(dirs.dir, sub, name)))
20973
+ for (const name of fs8.readdirSync(from))
20974
+ if (validId(name) && !fs8.existsSync(path8.join(dirs.dir, sub, name)))
20885
20975
  tasks += 1;
20886
20976
  }
20887
- merge(from, path7.join(dirs.dir, sub));
20977
+ merge(from, path8.join(dirs.dir, sub));
20888
20978
  }
20889
- const ledger = path7.join(dirs.v2, "ledger");
20890
- if (fs7.existsSync(ledger) && !fs7.existsSync(path7.join(dirs.dir, "ledger")))
20891
- merge(ledger, path7.join(dirs.dir, "ledger"));
20892
- fs7.rmSync(path7.join(dirs.v2, "task-index.json"), { force: true });
20893
- fs7.renameSync(marker, path7.join(dirs.v2, "store.moved.json"));
20979
+ const ledger = path8.join(dirs.v2, "ledger");
20980
+ if (fs8.existsSync(ledger) && !fs8.existsSync(path8.join(dirs.dir, "ledger")))
20981
+ merge(ledger, path8.join(dirs.dir, "ledger"));
20982
+ fs8.rmSync(path8.join(dirs.v2, "task-index.json"), { force: true });
20983
+ fs8.renameSync(marker, path8.join(dirs.v2, "store.moved.json"));
20894
20984
  } catch (error) {
20895
20985
  return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
20896
20986
  path: dirs.v2
@@ -20910,7 +21000,7 @@ class TaskStore {
20910
21000
  readV2Workspace(file) {
20911
21001
  let bytes;
20912
21002
  try {
20913
- bytes = fs7.readFileSync(file, "utf8");
21003
+ bytes = fs8.readFileSync(file, "utf8");
20914
21004
  } catch {
20915
21005
  return null;
20916
21006
  }
@@ -20928,7 +21018,7 @@ class TaskStore {
20928
21018
  schemaVersion: SCHEMA_VERSION,
20929
21019
  id: workspaceId ?? newId(),
20930
21020
  revision: newRevision(),
20931
- root: path7.dirname(v2),
21021
+ root: path8.dirname(v2),
20932
21022
  runtime: { createdWith: version, updatedWith: version },
20933
21023
  writer: null,
20934
21024
  store: {
@@ -20939,12 +21029,12 @@ class TaskStore {
20939
21029
  },
20940
21030
  critical: ["store"]
20941
21031
  };
20942
- fs7.mkdirSync(v2, { recursive: true });
20943
- const ignore = path7.join(v2, ".gitignore");
20944
- if (!fs7.existsSync(ignore))
20945
- fs7.writeFileSync(ignore, `*
21032
+ fs8.mkdirSync(v2, { recursive: true });
21033
+ const ignore = path8.join(v2, ".gitignore");
21034
+ if (!fs8.existsSync(ignore))
21035
+ fs8.writeFileSync(ignore, `*
20946
21036
  `);
20947
- replaceFile(path7.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
21037
+ replaceFile(path8.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
20948
21038
  `, true);
20949
21039
  }
20950
21040
  stubFor(taskId) {
@@ -20960,7 +21050,7 @@ class TaskStore {
20960
21050
  }
20961
21051
  isStub(file) {
20962
21052
  try {
20963
- const value = JSON.parse(fs7.readFileSync(file, "utf8"));
21053
+ const value = JSON.parse(fs8.readFileSync(file, "utf8"));
20964
21054
  return isObject5(value) && isObject5(value.store) && value.store.format === "workit-store";
20965
21055
  } catch {
20966
21056
  return false;
@@ -20968,32 +21058,32 @@ class TaskStore {
20968
21058
  }
20969
21059
  writeTombstoneIfMissing() {
20970
21060
  try {
20971
- const v2 = path7.join(this.root, ".workit");
20972
- if (fs7.existsSync(path7.join(v2, "workspace.json")))
21061
+ const v2 = path8.join(this.root, ".workit");
21062
+ if (fs8.existsSync(path8.join(v2, "workspace.json")))
20973
21063
  return;
20974
21064
  let id = null;
20975
21065
  try {
20976
- id = JSON.parse(fs7.readFileSync(this.paths().workspace, "utf8")).id ?? null;
21066
+ id = JSON.parse(fs8.readFileSync(this.paths().workspace, "utf8")).id ?? null;
20977
21067
  } catch {}
20978
21068
  this.writeTombstone(v2, id);
20979
21069
  } catch {}
20980
21070
  }
20981
21071
  initializeStorage() {
20982
21072
  const dirs = this.paths();
20983
- retryTransient(() => fs7.mkdirSync(dirs.checkout, { recursive: true }));
20984
- retryTransient(() => fs7.mkdirSync(dirs.tasks, { recursive: true }));
20985
- if (!fs7.existsSync(dirs.marker))
21073
+ retryTransient(() => fs8.mkdirSync(dirs.checkout, { recursive: true }));
21074
+ retryTransient(() => fs8.mkdirSync(dirs.tasks, { recursive: true }));
21075
+ if (!fs8.existsSync(dirs.marker))
20986
21076
  replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
20987
21077
  `, false);
20988
21078
  if (!dirs.shared) {
20989
- const ignore = path7.join(dirs.dir, ".gitignore");
21079
+ const ignore = path8.join(dirs.dir, ".gitignore");
20990
21080
  let current = null;
20991
21081
  try {
20992
- current = fs7.readFileSync(ignore, "utf8");
21082
+ current = fs8.readFileSync(ignore, "utf8");
20993
21083
  } catch {}
20994
21084
  if (current !== `*
20995
21085
  `)
20996
- retryTransient(() => fs7.writeFileSync(ignore, `*
21086
+ retryTransient(() => fs8.writeFileSync(ignore, `*
20997
21087
  `));
20998
21088
  }
20999
21089
  this.writeTombstoneIfMissing();
@@ -21009,7 +21099,7 @@ class TaskStore {
21009
21099
  shouldReclaim: ({ payload, nowMs }) => {
21010
21100
  let ageMs = null;
21011
21101
  try {
21012
- ageMs = nowMs - fs7.lstatSync(lockPath).mtimeMs;
21102
+ ageMs = nowMs - fs8.lstatSync(lockPath).mtimeMs;
21013
21103
  } catch {}
21014
21104
  return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
21015
21105
  },
@@ -21046,7 +21136,7 @@ class TaskStore {
21046
21136
  withLock(lockPath, operation) {
21047
21137
  try {
21048
21138
  this.initializeStorage();
21049
- fs7.mkdirSync(path7.dirname(lockPath), { recursive: true });
21139
+ fs8.mkdirSync(path8.dirname(lockPath), { recursive: true });
21050
21140
  } catch (error) {
21051
21141
  return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
21052
21142
  path: this.paths().dir
@@ -21086,18 +21176,18 @@ class TaskStore {
21086
21176
  lockDirWritable(lockPath) {
21087
21177
  const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
21088
21178
  try {
21089
- fs7.closeSync(fs7.openSync(probe, "wx", 384));
21179
+ fs8.closeSync(fs8.openSync(probe, "wx", 384));
21090
21180
  } catch {
21091
21181
  return false;
21092
21182
  }
21093
21183
  try {
21094
- fs7.rmSync(probe, { force: true });
21184
+ fs8.rmSync(probe, { force: true });
21095
21185
  } catch {}
21096
21186
  return true;
21097
21187
  }
21098
21188
  lockHolderPresent(lockPath) {
21099
21189
  try {
21100
- fs7.lstatSync(lockPath);
21190
+ fs8.lstatSync(lockPath);
21101
21191
  return true;
21102
21192
  } catch (error) {
21103
21193
  return error?.code !== "ENOENT";
@@ -21109,12 +21199,12 @@ class TaskStore {
21109
21199
  if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
21110
21200
  return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
21111
21201
  path: lockPath,
21112
- guidance: `Check permissions and the read-only attribute on ${path7.dirname(lockPath)}.`
21202
+ guidance: `Check permissions and the read-only attribute on ${path8.dirname(lockPath)}.`
21113
21203
  });
21114
21204
  if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
21115
21205
  let lock = null;
21116
21206
  try {
21117
- lock = parseMetadataLockOrNull(fs7.readFileSync(lockPath, "utf8"));
21207
+ lock = parseMetadataLockOrNull(fs8.readFileSync(lockPath, "utf8"));
21118
21208
  } catch {}
21119
21209
  return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
21120
21210
  outcome: "not_started",
@@ -21132,15 +21222,15 @@ var isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state);
21132
21222
  var workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state);
21133
21223
 
21134
21224
  // packages/workit-core/src/core/task-evaluation.ts
21135
- import { createHash as createHash9 } from "node:crypto";
21136
- import * as fs12 from "node:fs";
21225
+ import { createHash as createHash10 } from "node:crypto";
21226
+ import * as fs13 from "node:fs";
21137
21227
  import { spawnSync as spawnSync10 } from "node:child_process";
21138
- import path15 from "node:path";
21228
+ import path16 from "node:path";
21139
21229
 
21140
21230
  // packages/workit-core/src/check-config.ts
21141
21231
  import { spawnSync as spawnSync3 } from "node:child_process";
21142
- import fs8 from "node:fs";
21143
- import path8 from "node:path";
21232
+ import fs9 from "node:fs";
21233
+ import path9 from "node:path";
21144
21234
  var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
21145
21235
  var CHECKS_FILE = "workit.checks.json";
21146
21236
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -21193,10 +21283,10 @@ var git = (cwd, args) => {
21193
21283
  return value || null;
21194
21284
  };
21195
21285
  function checkRoot(cwd) {
21196
- return path8.resolve(git(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
21286
+ return path9.resolve(git(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
21197
21287
  }
21198
21288
  var packageManager = (root) => {
21199
- const has = (file) => fs8.existsSync(path8.join(root, file));
21289
+ const has = (file) => fs9.existsSync(path9.join(root, file));
21200
21290
  if (has("bun.lock") || has("bun.lockb"))
21201
21291
  return "bun";
21202
21292
  if (has("pnpm-lock.yaml"))
@@ -21216,7 +21306,7 @@ var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
21216
21306
  function detectedChecks(root) {
21217
21307
  const read = (file) => {
21218
21308
  try {
21219
- return fs8.readFileSync(path8.join(root, file), "utf8");
21309
+ return fs9.readFileSync(path9.join(root, file), "utf8");
21220
21310
  } catch {
21221
21311
  return null;
21222
21312
  }
@@ -21255,7 +21345,7 @@ function detectedChecks(root) {
21255
21345
  var GATES = ["testing", "verification"];
21256
21346
  function loadCheckConfig(cwd) {
21257
21347
  const root = checkRoot(cwd);
21258
- const file = path8.join(root, CHECKS_FILE);
21348
+ const file = path9.join(root, CHECKS_FILE);
21259
21349
  const none = (error = null) => ({
21260
21350
  source: error ? CHECKS_FILE : "none",
21261
21351
  root,
@@ -21265,7 +21355,7 @@ function loadCheckConfig(cwd) {
21265
21355
  });
21266
21356
  let text = null;
21267
21357
  try {
21268
- text = fs8.readFileSync(file, "utf8");
21358
+ text = fs9.readFileSync(file, "utf8");
21269
21359
  } catch (error) {
21270
21360
  if (error.code !== "ENOENT")
21271
21361
  return none(`cannot read ${CHECKS_FILE}: ${error.message}`);
@@ -21328,10 +21418,10 @@ function workitAvailable(env = process.env) {
21328
21418
  return workitOnPath;
21329
21419
  const windows = process.platform === "win32";
21330
21420
  const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
21331
- const dirs = (env.PATH ?? env.Path ?? "").split(path8.delimiter).filter(Boolean);
21421
+ const dirs = (env.PATH ?? env.Path ?? "").split(path9.delimiter).filter(Boolean);
21332
21422
  workitOnPath = dirs.some((dir) => exts.some((ext) => {
21333
21423
  try {
21334
- return fs8.statSync(path8.join(dir, `workit${ext}`)).isFile();
21424
+ return fs9.statSync(path9.join(dir, `workit${ext}`)).isFile();
21335
21425
  } catch {
21336
21426
  return false;
21337
21427
  }
@@ -21344,10 +21434,10 @@ function checkCommand(args, version, onPath = workitAvailable()) {
21344
21434
 
21345
21435
  // packages/workit-core/src/git/rev.ts
21346
21436
  import { spawnSync as spawnSync4 } from "node:child_process";
21347
- import { createHash as createHash5 } from "node:crypto";
21348
- import fs9 from "node:fs";
21437
+ import { createHash as createHash6 } from "node:crypto";
21438
+ import fs10 from "node:fs";
21349
21439
  import os2 from "node:os";
21350
- import path9 from "node:path";
21440
+ import path10 from "node:path";
21351
21441
  var MAX_BUFFER = 256 * 1024 * 1024;
21352
21442
  var GIT_TIMEOUTS = { local: 20000, worktree: 120000, network: 15000 };
21353
21443
  var git2 = (cwd, args, options = {}) => {
@@ -21382,10 +21472,10 @@ function headSha(cwd) {
21382
21472
  var emptyTree = (cwd) => line(git2(cwd, ["mktree"], { input: "" }));
21383
21473
  var MAX_UNTRACKED_BYTES = 5 * 1024 * 1024;
21384
21474
  var seedIndex = (from, to) => {
21385
- fs9.copyFileSync(from, to);
21386
- const { atimeNs, mtimeNs } = fs9.statSync(from, { bigint: true });
21475
+ fs10.copyFileSync(from, to);
21476
+ const { atimeNs, mtimeNs } = fs10.statSync(from, { bigint: true });
21387
21477
  const seconds = (ns) => (Number(ns / 1000n) - 1) / 1e6;
21388
- fs9.utimesSync(to, seconds(atimeNs), seconds(mtimeNs));
21478
+ fs10.utimesSync(to, seconds(atimeNs), seconds(mtimeNs));
21389
21479
  };
21390
21480
  function worktreeTree(cwd, options = {}) {
21391
21481
  const top = line(git2(cwd, ["rev-parse", "--show-toplevel"]));
@@ -21394,10 +21484,10 @@ function worktreeTree(cwd, options = {}) {
21394
21484
  return null;
21395
21485
  const cap = options.maxUntrackedBytes ?? MAX_UNTRACKED_BYTES;
21396
21486
  const timeoutMs = options.timeoutMs ?? GIT_TIMEOUTS.worktree;
21397
- const scratch = fs9.mkdtempSync(path9.join(os2.tmpdir(), "workit-tree-"));
21487
+ const scratch = fs10.mkdtempSync(path10.join(os2.tmpdir(), "workit-tree-"));
21398
21488
  try {
21399
- const tempIndex = path9.join(scratch, "index");
21400
- if (fs9.existsSync(indexPath))
21489
+ const tempIndex = path10.join(scratch, "index");
21490
+ if (fs10.existsSync(indexPath))
21401
21491
  seedIndex(indexPath, tempIndex);
21402
21492
  const env = { ...process.env, GIT_INDEX_FILE: tempIndex };
21403
21493
  const untracked = git2(top, ["ls-files", "--others", "--exclude-standard", "-z"], {
@@ -21409,7 +21499,7 @@ function worktreeTree(cwd, options = {}) {
21409
21499
  const skipped = [];
21410
21500
  for (const file of untracked.stdout.split("\x00").filter(Boolean)) {
21411
21501
  try {
21412
- const stat = fs9.statSync(path9.join(top, file));
21502
+ const stat = fs10.statSync(path10.join(top, file));
21413
21503
  if (stat.isFile() && stat.size > cap)
21414
21504
  skipped.push({ path: file, size: stat.size, mtimeMs: Math.trunc(stat.mtimeMs) });
21415
21505
  } catch {}
@@ -21426,10 +21516,10 @@ function worktreeTree(cwd, options = {}) {
21426
21516
  if (!tree)
21427
21517
  return null;
21428
21518
  const base = line(git2(top, ["rev-parse", "--verify", "-q", "HEAD^{tree}"])) ?? emptyTree(top);
21429
- const key = skipped.length ? `sha256:${createHash5("sha256").update(JSON.stringify({ tree, skipped })).digest("hex")}` : tree;
21519
+ const key = skipped.length ? `sha256:${createHash6("sha256").update(JSON.stringify({ tree, skipped })).digest("hex")}` : tree;
21430
21520
  return { tree, key, dirty: tree !== base || skipped.length > 0, skipped };
21431
21521
  } finally {
21432
- fs9.rmSync(scratch, { recursive: true, force: true });
21522
+ fs10.rmSync(scratch, { recursive: true, force: true });
21433
21523
  }
21434
21524
  }
21435
21525
  function worktreeSignal(cwd, options = {}) {
@@ -21449,16 +21539,16 @@ function worktreeSignal(cwd, options = {}) {
21449
21539
  });
21450
21540
  if (!status.ok)
21451
21541
  return null;
21452
- const hash = createHash5("sha256");
21542
+ const hash = createHash6("sha256");
21453
21543
  hash.update(`${headSha(top) ?? "unborn"}\x00`);
21454
21544
  for (const entry of status.stdout.split("\x00")) {
21455
21545
  if (entry.length < 4)
21456
21546
  continue;
21457
21547
  const file = entry.slice(3);
21458
- const absolute = path9.join(top, file);
21548
+ const absolute = path10.join(top, file);
21459
21549
  let stat = "-";
21460
21550
  try {
21461
- const info = fs9.lstatSync(absolute, { bigint: true });
21551
+ const info = fs10.lstatSync(absolute, { bigint: true });
21462
21552
  stat = `${info.mode.toString(8)}:${info.size}:${info.mtimeNs}`;
21463
21553
  if (info.isDirectory())
21464
21554
  stat += `:${headSha(absolute) ?? "-"}`;
@@ -21525,17 +21615,17 @@ function pushRemoteName(cwd, branch) {
21525
21615
 
21526
21616
  // packages/workit-core/src/core/policy/derive.ts
21527
21617
  import { existsSync as existsSync4 } from "node:fs";
21528
- import path14 from "node:path";
21618
+ import path15 from "node:path";
21529
21619
 
21530
21620
  // packages/workit-core/src/ledger.ts
21531
21621
  import { spawnSync as spawnSync9 } from "node:child_process";
21532
- import { createHash as createHash8, randomBytes as randomBytes2 } from "node:crypto";
21533
- import fs11 from "node:fs";
21534
- import path13 from "node:path";
21622
+ import { createHash as createHash9, randomBytes as randomBytes3 } from "node:crypto";
21623
+ import fs12 from "node:fs";
21624
+ import path14 from "node:path";
21535
21625
 
21536
21626
  // packages/workit-core/src/core/vcs-config.ts
21537
- import fs10 from "node:fs";
21538
- import path12 from "node:path";
21627
+ import fs11 from "node:fs";
21628
+ import path13 from "node:path";
21539
21629
  import { spawnSync as spawnSync8 } from "node:child_process";
21540
21630
 
21541
21631
  // packages/workit-core/src/core/config.ts
@@ -21549,7 +21639,7 @@ import {
21549
21639
  writeFileSync as writeFileSync2
21550
21640
  } from "node:fs";
21551
21641
  import os3 from "node:os";
21552
- import path10 from "node:path";
21642
+ import path11 from "node:path";
21553
21643
 
21554
21644
  // packages/workit-core/src/core/boundary.ts
21555
21645
  import { statSync as statSync2 } from "node:fs";
@@ -21608,7 +21698,7 @@ var mergePreset = (preset, input = {}, current = {
21608
21698
  protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
21609
21699
  };
21610
21700
  };
21611
- var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path10.join(process.env.XDG_CONFIG_HOME || path10.join(os3.homedir(), ".config"), "workit");
21701
+ 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");
21612
21702
  var migratedDir = null;
21613
21703
  var migrationFailed = false;
21614
21704
  var ensureConfigDir = (dir = resolveConfigDir()) => {
@@ -21618,7 +21708,7 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
21618
21708
  migratedDir = dir;
21619
21709
  return dir;
21620
21710
  }
21621
- const legacy = path10.join(process.env.XDG_CONFIG_HOME || path10.join(os3.homedir(), ".config"), "workflow-toolkit");
21711
+ const legacy = path11.join(process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config"), "workflow-toolkit");
21622
21712
  if (!existsSync3(legacy)) {
21623
21713
  migratedDir = dir;
21624
21714
  return dir;
@@ -21631,8 +21721,8 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
21631
21721
  mkdirSync2(dir, { recursive: true });
21632
21722
  diagnosticLogger?.info(EVENT.migration, { from: legacy, to: dir });
21633
21723
  for (const entry of readdirSync2(legacy, { withFileTypes: true })) {
21634
- const src = path10.join(legacy, entry.name);
21635
- const dest = path10.join(dir, entry.name);
21724
+ const src = path11.join(legacy, entry.name);
21725
+ const dest = path11.join(dir, entry.name);
21636
21726
  if (existsSync3(dest))
21637
21727
  continue;
21638
21728
  try {
@@ -21704,7 +21794,7 @@ var parseConfigResult = (raw, file) => {
21704
21794
  return { status: "valid", path: file, config };
21705
21795
  };
21706
21796
  var readConfigTyped = (dir) => {
21707
- const file = path10.join(dir ?? configDir(), "config.json");
21797
+ const file = path11.join(dir ?? configDir(), "config.json");
21708
21798
  return parseConfigResult(readSafe(file), file);
21709
21799
  };
21710
21800
  var readConfig = () => {
@@ -21713,7 +21803,7 @@ var readConfig = () => {
21713
21803
  throw new Error(result.error);
21714
21804
  return result.config ?? DEFAULTS;
21715
21805
  };
21716
- var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path10.join(configDir(), "vcs.json");
21806
+ var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path11.join(configDir(), "vcs.json");
21717
21807
  var branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i");
21718
21808
  var resolveBranchPolicy = (config, workspace, repoPreset) => {
21719
21809
  const wp = workspace?.branchPolicy ?? {};
@@ -21745,9 +21835,9 @@ var COMMIT_PRESETS = [
21745
21835
 
21746
21836
  // packages/workit-core/src/core/workspaces.ts
21747
21837
  import { spawnSync as spawnSync6 } from "node:child_process";
21748
- import { createHash as createHash6 } from "node:crypto";
21838
+ import { createHash as createHash7 } from "node:crypto";
21749
21839
  import { readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
21750
- import path11 from "node:path";
21840
+ import path12 from "node:path";
21751
21841
 
21752
21842
  // packages/workit-core/src/core/branch-policy.ts
21753
21843
  import { spawnSync as spawnSync5 } from "node:child_process";
@@ -21872,7 +21962,7 @@ var releaseTrackSchema = object2({
21872
21962
  context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
21873
21963
  }
21874
21964
  }
21875
- if (track.versionSource?.kind === "package-json" && (path11.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
21965
+ 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(".."))) {
21876
21966
  context.addIssue({
21877
21967
  code: "custom",
21878
21968
  path: ["versionSource", "path"],
@@ -21893,6 +21983,8 @@ var workspaceConfigSchema = object2({
21893
21983
  defaultEndpoint: unknown().optional(),
21894
21984
  verification: _enum(["self", "independent"]).optional(),
21895
21985
  trailers: boolean2().optional(),
21986
+ liveSessionGuard: boolean2().optional(),
21987
+ fanout: object2({ tierModels: unknown().optional() }).passthrough().optional(),
21896
21988
  autonomy: object2(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
21897
21989
  kind,
21898
21990
  union([boolean2(), literal("verified")]).optional()
@@ -21933,7 +22025,7 @@ var workspacesFileSchema = object2({ workspaces: array(workspaceConfigSchema).op
21933
22025
  names.add(workspace.name);
21934
22026
  }
21935
22027
  });
21936
- var workspacesRevision = (contents) => createHash6("sha256").update(contents ?? "<missing>").digest("hex");
22028
+ var workspacesRevision = (contents) => createHash7("sha256").update(contents ?? "<missing>").digest("hex");
21937
22029
  var validateWorkspacesDocument = (parsed, file) => {
21938
22030
  if (!isConfigObject(parsed)) {
21939
22031
  return { status: "malformed", path: file, entries: [], error: `${file} is not a JSON object` };
@@ -21971,7 +22063,7 @@ var validateWorkspacesDocument = (parsed, file) => {
21971
22063
  };
21972
22064
  };
21973
22065
  var readWorkspacesResult = (dir = configDir()) => {
21974
- const file = path11.join(dir, "workspaces.json");
22066
+ const file = path12.join(dir, "workspaces.json");
21975
22067
  let raw;
21976
22068
  try {
21977
22069
  raw = readFileSync3(file, "utf8");
@@ -22082,9 +22174,9 @@ var mainCheckoutOf = (cwd) => {
22082
22174
  let main = null;
22083
22175
  const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
22084
22176
  const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
22085
- if (gitDir && common && path11.resolve(gitDir) !== path11.resolve(common)) {
22177
+ if (gitDir && common && path12.resolve(gitDir) !== path12.resolve(common)) {
22086
22178
  const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
22087
- main = listed?.trim() || (path11.basename(common) === ".git" ? path11.dirname(common) : common);
22179
+ main = listed?.trim() || (path12.basename(common) === ".git" ? path12.dirname(common) : common);
22088
22180
  }
22089
22181
  mainCheckouts.set(cwd, main);
22090
22182
  return main;
@@ -22175,7 +22267,7 @@ var runtimeWorkspaceIndexSchema = object2({
22175
22267
  workspaces: array(object2({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
22176
22268
  }).passthrough();
22177
22269
  var matchRuntimeWorkspace = (cwd, dir = configDir()) => {
22178
- const file = path11.join(dir, "workspaces.json");
22270
+ const file = path12.join(dir, "workspaces.json");
22179
22271
  let raw;
22180
22272
  try {
22181
22273
  raw = readFileSync3(file, "utf8");
@@ -22210,6 +22302,17 @@ var resolveRuntimeReleaseTracks = (cwd) => {
22210
22302
  const matched = matchRuntimeWorkspace(cwd);
22211
22303
  return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
22212
22304
  };
22305
+ var TIER_KEYS = new Set(["mundane", "standard", "hard"]);
22306
+ var TIER_HOSTS = new Set([
22307
+ "claude_code",
22308
+ "opencode",
22309
+ "codex",
22310
+ "codex_cli",
22311
+ "codex_desktop",
22312
+ "cursor",
22313
+ "pi",
22314
+ "default"
22315
+ ]);
22213
22316
  var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
22214
22317
  const matched = matchRuntimeWorkspace(cwd);
22215
22318
  if (!matched)
@@ -22250,7 +22353,7 @@ function workspaceDefaultTarget(cwd, globalDefault) {
22250
22353
  }
22251
22354
 
22252
22355
  // packages/workit-core/src/core/release-tracks.ts
22253
- import { createHash as createHash7 } from "node:crypto";
22356
+ import { createHash as createHash8 } from "node:crypto";
22254
22357
  import { spawnSync as spawnSync7 } from "node:child_process";
22255
22358
  var KNOWN_FIELDS = new Set([
22256
22359
  "strategy",
@@ -22620,7 +22723,7 @@ function resolveTrackFor(cwd, options) {
22620
22723
  ]) ?? "",
22621
22724
  git3(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
22622
22725
  ] : [];
22623
- key = createHash7("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
22726
+ key = createHash8("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
22624
22727
  const hit = memo2.get(key);
22625
22728
  if (hit)
22626
22729
  return hit;
@@ -22635,7 +22738,7 @@ function resolveTrackFor(cwd, options) {
22635
22738
  }
22636
22739
 
22637
22740
  // packages/workit-core/src/core/vcs-config.ts
22638
- var workspacesPath = () => path12.join(configDir(), "workspaces.json");
22741
+ var workspacesPath = () => path13.join(configDir(), "workspaces.json");
22639
22742
  var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
22640
22743
  var remoteProvider = (cwd) => {
22641
22744
  const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
@@ -22725,7 +22828,7 @@ var readVcsConfig = () => {
22725
22828
  const file = vcsConfigPath();
22726
22829
  let raw;
22727
22830
  try {
22728
- raw = fs10.readFileSync(file, "utf8");
22831
+ raw = fs11.readFileSync(file, "utf8");
22729
22832
  } catch {
22730
22833
  return { status: "missing", path: file, config: {} };
22731
22834
  }
@@ -22810,7 +22913,7 @@ function vcsConfig(mode, cwd, options = {}) {
22810
22913
  const prov = cfg[provider] ?? {};
22811
22914
  const out = {
22812
22915
  ok: true,
22813
- configPath: path12.resolve(cfgPath),
22916
+ configPath: path13.resolve(cfgPath),
22814
22917
  provider,
22815
22918
  defaultTargetBranch: workspaceDefault,
22816
22919
  pr: cfg.pr ?? {},
@@ -23021,7 +23124,7 @@ function diffHash(cwd, base, head) {
23021
23124
  ], GIT_TIMEOUTS.worktree);
23022
23125
  if (!diff.ok || !diff.stdout)
23023
23126
  return null;
23024
- const hash = createHash8("sha256");
23127
+ const hash = createHash9("sha256");
23025
23128
  for (const line of diff.stdout.split(`
23026
23129
  `)) {
23027
23130
  if (line.startsWith("index "))
@@ -23033,16 +23136,16 @@ function diffHash(cwd, base, head) {
23033
23136
  return `sha256:${hash.digest("hex")}`;
23034
23137
  }
23035
23138
  function storeRoot(cwd) {
23036
- const location = resolveStore(path13.resolve(cwd));
23139
+ const location = resolveStore(path14.resolve(cwd));
23037
23140
  if (location instanceof Error)
23038
23141
  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");
23039
23142
  return { ok: true, value: { root: location.dir, shared: location.shared } };
23040
23143
  }
23041
23144
  function ledgerPath(cwd) {
23042
23145
  const root = storeRoot(cwd);
23043
- return root.ok ? { ok: true, value: path13.join(root.value.root, "ledger", "ledger.jsonl") } : root;
23146
+ return root.ok ? { ok: true, value: path14.join(root.value.root, "ledger", "ledger.jsonl") } : root;
23044
23147
  }
23045
- var newId2 = () => `${Date.now().toString(36)}-${randomBytes2(6).toString("hex")}`;
23148
+ var newId2 = () => `${Date.now().toString(36)}-${randomBytes3(6).toString("hex")}`;
23046
23149
  var NETWORK_FS_TYPES = new Set([
23047
23150
  26985,
23048
23151
  20859,
@@ -23060,7 +23163,7 @@ var onNetworkFs = (dir) => {
23060
23163
  if (process.platform !== "linux")
23061
23164
  return false;
23062
23165
  try {
23063
- return isNetworkFsType(fs11.statfsSync(dir).type);
23166
+ return isNetworkFsType(fs12.statfsSync(dir).type);
23064
23167
  } catch {
23065
23168
  return false;
23066
23169
  }
@@ -23070,15 +23173,15 @@ var LOCK_STALE_MS = 30000;
23070
23173
  var LOCK_OWNER = "owner";
23071
23174
  var lockToken = (lock) => {
23072
23175
  try {
23073
- return fs11.readFileSync(path13.join(lock, LOCK_OWNER), "utf8");
23176
+ return fs12.readFileSync(path14.join(lock, LOCK_OWNER), "utf8");
23074
23177
  } catch {
23075
23178
  return null;
23076
23179
  }
23077
23180
  };
23078
23181
  var lockAgeMs = (lock) => {
23079
- for (const target of [path13.join(lock, LOCK_OWNER), lock]) {
23182
+ for (const target of [path14.join(lock, LOCK_OWNER), lock]) {
23080
23183
  try {
23081
- return Date.now() - fs11.statSync(target).mtimeMs;
23184
+ return Date.now() - fs12.statSync(target).mtimeMs;
23082
23185
  } catch {}
23083
23186
  }
23084
23187
  return null;
@@ -23086,55 +23189,55 @@ var lockAgeMs = (lock) => {
23086
23189
  var ledgerLock = {
23087
23190
  acquire(lock) {
23088
23191
  try {
23089
- fs11.mkdirSync(lock);
23192
+ fs12.mkdirSync(lock);
23090
23193
  } catch (error) {
23091
23194
  if (error.code === "EEXIST")
23092
23195
  return null;
23093
23196
  throw error;
23094
23197
  }
23095
- const token = `${process.pid}-${randomBytes2(8).toString("hex")}`;
23096
- fs11.writeFileSync(path13.join(lock, LOCK_OWNER), token);
23198
+ const token = `${process.pid}-${randomBytes3(8).toString("hex")}`;
23199
+ fs12.writeFileSync(path14.join(lock, LOCK_OWNER), token);
23097
23200
  return token;
23098
23201
  },
23099
23202
  release(lock, token) {
23100
23203
  if (lockToken(lock) !== token)
23101
23204
  return false;
23102
- const tomb = `${lock}.release-${randomBytes2(6).toString("hex")}`;
23205
+ const tomb = `${lock}.release-${randomBytes3(6).toString("hex")}`;
23103
23206
  try {
23104
- fs11.renameSync(lock, tomb);
23207
+ fs12.renameSync(lock, tomb);
23105
23208
  } catch {
23106
23209
  return false;
23107
23210
  }
23108
23211
  if (lockToken(tomb) !== token) {
23109
23212
  try {
23110
- fs11.renameSync(tomb, lock);
23213
+ fs12.renameSync(tomb, lock);
23111
23214
  } catch {}
23112
23215
  return false;
23113
23216
  }
23114
- fs11.rmSync(tomb, { recursive: true, force: true });
23217
+ fs12.rmSync(tomb, { recursive: true, force: true });
23115
23218
  return true;
23116
23219
  },
23117
23220
  token: lockToken,
23118
23221
  reap(lock, observed) {
23119
- const tomb = `${lock}.reap-${randomBytes2(6).toString("hex")}`;
23222
+ const tomb = `${lock}.reap-${randomBytes3(6).toString("hex")}`;
23120
23223
  try {
23121
- fs11.renameSync(lock, tomb);
23224
+ fs12.renameSync(lock, tomb);
23122
23225
  } catch {
23123
23226
  return false;
23124
23227
  }
23125
23228
  if (lockToken(tomb) === observed) {
23126
- fs11.rmSync(tomb, { recursive: true, force: true });
23229
+ fs12.rmSync(tomb, { recursive: true, force: true });
23127
23230
  return true;
23128
23231
  }
23129
23232
  try {
23130
- fs11.renameSync(tomb, lock);
23233
+ fs12.renameSync(tomb, lock);
23131
23234
  } catch {
23132
- fs11.rmSync(tomb, { recursive: true, force: true });
23235
+ fs12.rmSync(tomb, { recursive: true, force: true });
23133
23236
  }
23134
23237
  return false;
23135
23238
  }
23136
23239
  };
23137
- function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
23240
+ function withLedgerLock(file, fn, waitMs = hostAwareLockTimeout(LOCK_WAIT_MS)) {
23138
23241
  const lock = `${file}.lock`;
23139
23242
  const deadline = Date.now() + waitMs;
23140
23243
  let token = null;
@@ -23156,14 +23259,14 @@ function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
23156
23259
  ledgerLock.release(lock, token);
23157
23260
  }
23158
23261
  }
23159
- var sha2562 = (text) => createHash8("sha256").update(text).digest("hex");
23262
+ var sha2562 = (text) => createHash9("sha256").update(text).digest("hex");
23160
23263
  var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
23161
23264
  ${body}`);
23162
23265
  var TAIL_BYTES = 64 * 1024;
23163
23266
  var lastLine = (fd, size) => {
23164
23267
  for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
23165
23268
  const buffer = Buffer.alloc(span);
23166
- fs11.readSync(fd, buffer, 0, span, size - span);
23269
+ fs12.readSync(fd, buffer, 0, span, size - span);
23167
23270
  const end = buffer.lastIndexOf(10);
23168
23271
  if (end < 0) {
23169
23272
  if (span === size)
@@ -23192,15 +23295,23 @@ var lastLine = (fd, size) => {
23192
23295
  }
23193
23296
  return null;
23194
23297
  };
23298
+ var tighten = (fd) => {
23299
+ try {
23300
+ if ((fs12.fstatSync(fd).mode & 63) !== 0)
23301
+ fs12.fchmodSync(fd, 384);
23302
+ } catch {}
23303
+ };
23195
23304
  function appendLine(file, build, options) {
23196
23305
  const write = () => {
23197
- const fd = fs11.openSync(file, "a+");
23306
+ const fd = fs12.openSync(file, "a+", 384);
23198
23307
  try {
23199
- const size = fs11.fstatSync(fd).size;
23308
+ if (process.platform !== "win32")
23309
+ tighten(fd);
23310
+ const size = fs12.fstatSync(fd).size;
23200
23311
  let fence = "";
23201
23312
  if (size > 0) {
23202
23313
  const last = Buffer.alloc(1);
23203
- fs11.readSync(fd, last, 0, 1, size - 1);
23314
+ fs12.readSync(fd, last, 0, 1, size - 1);
23204
23315
  if (last[0] !== 10)
23205
23316
  fence = `
23206
23317
  `;
@@ -23209,17 +23320,17 @@ function appendLine(file, build, options) {
23209
23320
  if (!line.ok)
23210
23321
  return line;
23211
23322
  const bytes = Buffer.from(fence + line.value);
23212
- const written = fs11.writeSync(fd, bytes);
23323
+ const written = fs12.writeSync(fd, bytes);
23213
23324
  if (written !== bytes.length)
23214
23325
  return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
23215
23326
  return { ok: true, value: undefined };
23216
23327
  } finally {
23217
- fs11.closeSync(fd);
23328
+ fs12.closeSync(fd);
23218
23329
  }
23219
23330
  };
23220
23331
  try {
23221
- fs11.mkdirSync(path13.dirname(file), { recursive: true });
23222
- if (!options.forceLock && !onNetworkFs(path13.dirname(file)))
23332
+ fs12.mkdirSync(path14.dirname(file), { recursive: true });
23333
+ if (!options.forceLock && !onNetworkFs(path14.dirname(file)))
23223
23334
  return write();
23224
23335
  const locked = withLedgerLock(file, write);
23225
23336
  return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
@@ -23287,8 +23398,10 @@ function readLedger(cwd, options = {}) {
23287
23398
  if (!file.ok)
23288
23399
  return file;
23289
23400
  let text = "";
23401
+ let stat = null;
23290
23402
  try {
23291
- text = fs11.readFileSync(file.value, "utf8");
23403
+ stat = fs12.statSync(file.value);
23404
+ text = fs12.readFileSync(file.value, "utf8");
23292
23405
  } catch (error) {
23293
23406
  if (error.code === "ENOENT")
23294
23407
  return {
@@ -23307,6 +23420,7 @@ function readLedger(cwd, options = {}) {
23307
23420
  const integrity = { chained: 0, legacy: 0, unverified: [] };
23308
23421
  const earlier = new Set([null]);
23309
23422
  let chainStarted = false;
23423
+ const ids = new Set;
23310
23424
  for (const raw of text.split(`
23311
23425
  `)) {
23312
23426
  const trimmed = raw.trim();
@@ -23340,6 +23454,10 @@ function readLedger(cwd, options = {}) {
23340
23454
  reason = "unsigned";
23341
23455
  else
23342
23456
  rowIntegrity = "legacy";
23457
+ if (options.integrity && !reason && ids.has(parsed.id))
23458
+ reason = "duplicate_id";
23459
+ if (options.integrity)
23460
+ ids.add(parsed.id);
23343
23461
  if (reason)
23344
23462
  rowIntegrity = "unverified";
23345
23463
  const pr = typeof parsed.pr === "number" && Number.isInteger(parsed.pr) ? parsed.pr : undefined;
@@ -23363,7 +23481,8 @@ function readLedger(cwd, options = {}) {
23363
23481
  seq: rows.length + 1,
23364
23482
  superseded: false,
23365
23483
  supersedeIgnored: false,
23366
- ...rowIntegrity ? { integrity: rowIntegrity } : {}
23484
+ ...rowIntegrity ? { integrity: rowIntegrity } : {},
23485
+ ...reason ? { integrityReason: reason } : {}
23367
23486
  };
23368
23487
  rows.push(row);
23369
23488
  if (!options.integrity)
@@ -23391,18 +23510,48 @@ function readLedger(cwd, options = {}) {
23391
23510
  const byId = new Map;
23392
23511
  for (const row of rows) {
23393
23512
  const target = row.supersedes ? byId.get(row.supersedes) : undefined;
23394
- if (target && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
23513
+ if (target && row.integrity !== "unverified" && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
23395
23514
  target.superseded = true;
23396
23515
  else if (row.supersedes)
23397
23516
  row.supersedeIgnored = true;
23398
23517
  if (!byId.has(row.id))
23399
23518
  byId.set(row.id, row);
23400
23519
  }
23520
+ if (options.integrity && stat && Buffer.byteLength(text) === stat.size)
23521
+ tamperCache.set(file.value, {
23522
+ size: stat.size,
23523
+ stamp: fileStamp(stat),
23524
+ breaks: integrity.unverified.filter((row) => TAMPER_REASONS.has(row.reason))
23525
+ });
23401
23526
  return {
23402
23527
  ok: true,
23403
23528
  value: { path: file.value, rows, skipped, integrity: options.integrity ? integrity : null }
23404
23529
  };
23405
23530
  }
23531
+ var TAMPER_REASONS = new Set(["hash_mismatch", "broken_link"]);
23532
+ var tamperCache = new Map;
23533
+ var fileStamp = (stat) => `${stat.ino}:${stat.mtimeMs}:${stat.ctimeMs}`;
23534
+ function ledgerTampering(cwd) {
23535
+ const file = ledgerPath(cwd);
23536
+ if (!file.ok)
23537
+ return [];
23538
+ try {
23539
+ const stat = fs12.statSync(file.value);
23540
+ const cached = tamperCache.get(file.value);
23541
+ if (cached && cached.size === stat.size && cached.stamp === fileStamp(stat))
23542
+ return cached.breaks;
23543
+ } catch {
23544
+ return [];
23545
+ }
23546
+ const read = readLedger(cwd, { integrity: true });
23547
+ return read.ok ? (read.value.integrity?.unverified ?? []).filter((row) => TAMPER_REASONS.has(row.reason)) : [];
23548
+ }
23549
+ function tamperedUnblock(cwd) {
23550
+ const file = ledgerPath(cwd);
23551
+ const where = file.ok ? file.value : "the ledger file";
23552
+ 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`;
23553
+ }
23554
+ 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)}`;
23406
23555
  function verdictBasis(verdict, current) {
23407
23556
  if (verdict.head && verdict.head === current.head)
23408
23557
  return "fresh";
@@ -23410,7 +23559,7 @@ function verdictBasis(verdict, current) {
23410
23559
  return "carried";
23411
23560
  return "stale";
23412
23561
  }
23413
- var isLiveVerdict = (row) => row.type === "verdict" && typeof row.result === "string" && !row.superseded;
23562
+ var isLiveVerdict = (row, retired) => row.type === "verdict" && typeof row.result === "string" && !retired.has(row.id);
23414
23563
  function trailerSessions(cwd, base, head) {
23415
23564
  if (!base || !head || !safeRef(base) || !safeRef(head))
23416
23565
  return [];
@@ -23491,6 +23640,56 @@ var authoredBy = (authors, session) => {
23491
23640
  return true;
23492
23641
  return false;
23493
23642
  };
23643
+ var TRUST_REASONS = new Set([
23644
+ "unsigned",
23645
+ "hash_mismatch",
23646
+ "broken_link",
23647
+ "duplicate_id",
23648
+ "unissued_session",
23649
+ "unbound_session"
23650
+ ]);
23651
+ var SHELL_VOUCHED_HOSTS = new Set([
23652
+ "cli",
23653
+ "opencode",
23654
+ "pi",
23655
+ "codex_cli",
23656
+ "codex_desktop"
23657
+ ]);
23658
+ function sessionTrust(cwd, row) {
23659
+ const session = row.actor.session;
23660
+ if (!session || row.self === true)
23661
+ return null;
23662
+ const source = typeof row.sessionSource === "string" ? row.sessionSource : "env";
23663
+ const host = row.actor.host;
23664
+ const issuedOnly = source === "flag" ? host !== "cli" : source === "env" && session.includes(":") && !SHELL_VOUCHED_HOSTS.has(host);
23665
+ if (!issuedOnly)
23666
+ return null;
23667
+ const binding = issuedBinding(cwd, session);
23668
+ if (binding === null)
23669
+ return "unissued_session";
23670
+ return binding === "token" && row.sessionBound !== true ? "unbound_session" : null;
23671
+ }
23672
+ function trustReasons(cwd, row) {
23673
+ if (row.integrity === "unverified")
23674
+ return [row.integrityReason ?? "unsigned"];
23675
+ if (row.integrity !== "verified")
23676
+ return ["unsigned"];
23677
+ const session = sessionTrust(cwd, row);
23678
+ return session ? [session] : [];
23679
+ }
23680
+ function withIntegrity(cwd, rows) {
23681
+ if (rows.every((row) => row.integrity !== undefined))
23682
+ return rows;
23683
+ const read = readLedger(cwd, { integrity: true });
23684
+ const bySeq = new Map(read.ok ? read.value.rows.map((row) => [row.seq, row]) : []);
23685
+ return rows.map((row) => {
23686
+ if (row.integrity !== undefined)
23687
+ return row;
23688
+ const fresh = bySeq.get(row.seq);
23689
+ return fresh && fresh.id === row.id && fresh.at === row.at ? fresh : row;
23690
+ });
23691
+ }
23692
+ var untrusted = (reasons) => reasons.some((reason) => TRUST_REASONS.has(reason));
23494
23693
  var independenceReasons = (row, authors) => {
23495
23694
  const reasons = [];
23496
23695
  if (!row.actor.session)
@@ -23501,15 +23700,17 @@ var independenceReasons = (row, authors) => {
23501
23700
  reasons.push("self");
23502
23701
  return reasons;
23503
23702
  };
23504
- function effectiveOf(rows, authors, sameCode, isCurrent) {
23703
+ function effectiveOf(rows, reasonsOf, sameCode, isCurrent) {
23505
23704
  let effective = null;
23506
23705
  for (const row of rows) {
23507
23706
  if (!effective) {
23508
23707
  effective = row;
23509
23708
  continue;
23510
23709
  }
23511
- const rowIndependent = independenceReasons(row, authors).length === 0;
23512
- const effIndependent = independenceReasons(effective, authors).length === 0;
23710
+ if (untrusted(reasonsOf(row)) && !untrusted(reasonsOf(effective)))
23711
+ continue;
23712
+ const rowIndependent = reasonsOf(row).length === 0;
23713
+ const effIndependent = reasonsOf(effective).length === 0;
23513
23714
  if (effIndependent && !rowIndependent && isCurrent(effective))
23514
23715
  continue;
23515
23716
  if (effIndependent && FAILING.has(String(effective.result)) && row.actor.session === effective.actor.session && sameCode(effective, row))
@@ -23523,7 +23724,7 @@ function restackCarries(rows, branch, from, to) {
23523
23724
  return false;
23524
23725
  const edges = new Map;
23525
23726
  for (const row of rows)
23526
- if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
23727
+ if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.integrity === "verified" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
23527
23728
  edges.set(row.fromHead, [...edges.get(row.fromHead) ?? [], row.head]);
23528
23729
  const seen = new Set([from]);
23529
23730
  const queue = [from];
@@ -23539,7 +23740,8 @@ function restackCarries(rows, branch, from, to) {
23539
23740
  }
23540
23741
  return false;
23541
23742
  }
23542
- function checkVerdicts(cwd, branch, rows) {
23743
+ function checkVerdicts(cwd, branch, ledgerRows) {
23744
+ const rows = withIntegrity(cwd, ledgerRows);
23543
23745
  const head = branchHead(cwd, branch);
23544
23746
  const fallbackBase = defaultBase(cwd);
23545
23747
  const scope = branchScope(cwd, branch);
@@ -23569,21 +23771,47 @@ function checkVerdicts(cwd, branch, rows) {
23569
23771
  return verdictBasis(failed, { head: row.head, ...keys }) !== "stale" || restackCarries(rows, branch, failed.head, row.head);
23570
23772
  };
23571
23773
  const authors = authorSessions(cwd, rows, branch, { base: fallbackBase, head }, scope);
23774
+ const failureAuthorCache = new Map;
23775
+ const failureAuthors = (row) => {
23776
+ let set = failureAuthorCache.get(row.seq);
23777
+ if (!set) {
23778
+ set = authorSessions(cwd, rows.filter((other) => other.integrity === "verified" && other.seq < row.seq), branch, { base: null, head: null }, scope);
23779
+ failureAuthorCache.set(row.seq, set);
23780
+ }
23781
+ return set;
23782
+ };
23783
+ const reasonCache = new Map;
23784
+ const reasonsOf = (row) => {
23785
+ let reasons = reasonCache.get(row);
23786
+ if (!reasons) {
23787
+ const failing = FAILING.has(String(row.result));
23788
+ reasons = [
23789
+ ...trustReasons(cwd, row),
23790
+ ...independenceReasons(row, failing ? failureAuthors(row) : authors)
23791
+ ];
23792
+ reasonCache.set(row, reasons);
23793
+ }
23794
+ return reasons;
23795
+ };
23796
+ const retired = new Set;
23797
+ for (const row of rows)
23798
+ if (row.type === "verdict" && row.supersedes && !row.supersedeIgnored && trustReasons(cwd, row).length === 0)
23799
+ retired.add(row.supersedes);
23572
23800
  const byKind = new Map;
23573
23801
  for (const row of rows)
23574
- if (isLiveVerdict(row) && scope(row)) {
23802
+ if (isLiveVerdict(row, retired) && scope(row)) {
23575
23803
  const kind = typeof row.kind === "string" ? row.kind : "review";
23576
23804
  byKind.set(kind, [...byKind.get(kind) ?? [], row]);
23577
23805
  }
23578
23806
  const verdicts = [];
23579
23807
  const warnings = [];
23580
23808
  for (const [kind, list] of byKind) {
23581
- const row = effectiveOf(list, authors, sameCode, (candidate) => basisOf(candidate) !== "stale");
23809
+ const row = effectiveOf(list, reasonsOf, sameCode, (candidate) => basisOf(candidate) !== "stale");
23582
23810
  if (!row)
23583
23811
  continue;
23584
23812
  const basis = basisOf(row);
23585
23813
  const current = basis !== "stale";
23586
- const independence = independenceReasons(row, authors);
23814
+ const independence = reasonsOf(row);
23587
23815
  const reasons = [
23588
23816
  ...current ? [] : ["stale"],
23589
23817
  ...PASSING.has(String(row.result)) ? [] : ["not_passing"],
@@ -23600,23 +23828,31 @@ function checkVerdicts(cwd, branch, rows) {
23600
23828
  });
23601
23829
  if (reasons.length === 0) {
23602
23830
  for (const later of list)
23603
- if (later.seq > row.seq && independenceReasons(later, authors).length > 0 && FAILING.has(String(later.result)) && basisOf(later) !== "stale")
23831
+ if (later.seq > row.seq && reasonsOf(later).length > 0 && !untrusted(reasonsOf(later)) && FAILING.has(String(later.result)) && basisOf(later) !== "stale")
23604
23832
  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`);
23605
23833
  }
23606
23834
  }
23607
23835
  for (const row of rows)
23608
23836
  if (row.integrity === "unverified" && scope(row))
23609
23837
  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)`);
23838
+ const tampered = ledgerTampering(cwd);
23839
+ if (tampered.length) {
23840
+ warnings.push(tamperedWarning(cwd, tampered));
23841
+ for (const entry of verdicts) {
23842
+ entry.accepted = false;
23843
+ entry.reasons = [...entry.reasons, "ledger_tampered"];
23844
+ }
23845
+ }
23610
23846
  verdicts.sort((a, b) => a.verdict.seq - b.verdict.seq);
23611
23847
  const newestCurrent = verdicts.findLast((entry) => entry.current) ?? verdicts.at(-1) ?? null;
23612
23848
  const failing = verdicts.find((entry) => entry.current && entry.independent && FAILING.has(String(entry.verdict.result)));
23613
23849
  const newestAccepted = verdicts.findLast((entry) => entry.accepted && STRONG_RESULTS.has(String(entry.verdict.result))) ?? null;
23614
- const accepted = newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
23850
+ const accepted = tampered.length ? { accepted: false, verdict: null, reasons: ["ledger_tampered"] } : newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
23615
23851
  accepted: false,
23616
23852
  verdict: failing?.verdict ?? null,
23617
23853
  reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
23618
23854
  };
23619
- const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && STRONG_RESULTS.has(String(entry.verdict.result)));
23855
+ const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && !untrusted(entry.reasons) && STRONG_RESULTS.has(String(entry.verdict.result)));
23620
23856
  return {
23621
23857
  branch,
23622
23858
  head,
@@ -23779,7 +24015,7 @@ var productDecision = (task, ledger) => {
23779
24015
  };
23780
24016
  };
23781
24017
  var planRecorded = (task, root) => {
23782
- const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path14.resolve(root, ref.path)));
24018
+ const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path15.resolve(root, ref.path)));
23783
24019
  if (cited)
23784
24020
  return {
23785
24021
  met: true,
@@ -23827,15 +24063,15 @@ function derivedRuleStatus(task, requirement, root, ledger) {
23827
24063
  }
23828
24064
 
23829
24065
  // packages/workit-core/src/core/task-evaluation.ts
23830
- var digestBytes = (value) => createHash9("sha256").update(value).digest("hex");
23831
- var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path15.sep}`);
23832
- var relative = (root, candidate) => path15.relative(root, candidate).split(path15.sep).join("/") || ".";
24066
+ var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
24067
+ var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
24068
+ var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
23833
24069
  var canonicalPath = (value) => {
23834
24070
  if (typeof value !== "string" || !value)
23835
24071
  return null;
23836
24072
  if (value.includes("\\") || value.split("/").includes(".."))
23837
24073
  return null;
23838
- const normalized = path15.posix.normalize(value);
24074
+ const normalized = path16.posix.normalize(value);
23839
24075
  if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
23840
24076
  return null;
23841
24077
  return normalized === "." ? "." : normalized.replace(/\/$/, "");
@@ -23883,21 +24119,21 @@ var gitPaths = (root) => {
23883
24119
  git: !/not a git repository/i.test(stderr)
23884
24120
  };
23885
24121
  }
23886
- const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")) : [];
24122
+ const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
23887
24123
  const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
23888
24124
  if (stagedDeleted.status !== 0) {
23889
24125
  const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
23890
24126
  if (!/not a git repository/i.test(stderr))
23891
24127
  return { paths, uncertain: true, git: true };
23892
24128
  } else if (stagedDeleted.stdout) {
23893
- paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")));
24129
+ paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
23894
24130
  }
23895
24131
  return { paths: [...new Set(paths)], uncertain: false, git: true };
23896
24132
  };
23897
24133
  var walk = (root, directory, output) => {
23898
24134
  let names;
23899
24135
  try {
23900
- names = fs12.readdirSync(directory);
24136
+ names = fs13.readdirSync(directory);
23901
24137
  } catch {
23902
24138
  return true;
23903
24139
  }
@@ -23905,10 +24141,10 @@ var walk = (root, directory, output) => {
23905
24141
  for (const name of names) {
23906
24142
  if (name === ".git" || name === ".workit")
23907
24143
  continue;
23908
- const target = path15.join(directory, name);
24144
+ const target = path16.join(directory, name);
23909
24145
  let stat;
23910
24146
  try {
23911
- stat = fs12.lstatSync(target);
24147
+ stat = fs13.lstatSync(target);
23912
24148
  } catch {
23913
24149
  uncertain = true;
23914
24150
  continue;
@@ -23923,14 +24159,14 @@ var walk = (root, directory, output) => {
23923
24159
  var scopeRoots = (root, scope) => {
23924
24160
  const roots = [];
23925
24161
  for (const item of scope.paths.length ? scope.paths : ["."]) {
23926
- const target = path15.resolve(root, item);
24162
+ const target = path16.resolve(root, item);
23927
24163
  if (!inside(root, target))
23928
24164
  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` }] });
23929
24165
  let ancestor = target;
23930
- while (!fs12.existsSync(ancestor) && ancestor !== root)
23931
- ancestor = path15.dirname(ancestor);
24166
+ while (!fs13.existsSync(ancestor) && ancestor !== root)
24167
+ ancestor = path16.dirname(ancestor);
23932
24168
  try {
23933
- if (!inside(root, fs12.realpathSync(ancestor)))
24169
+ if (!inside(root, fs13.realpathSync(ancestor)))
23934
24170
  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` }] });
23935
24171
  } catch {
23936
24172
  return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
@@ -23942,7 +24178,7 @@ var scopeRoots = (root, scope) => {
23942
24178
  function captureCandidate(root, scope, environment = []) {
23943
24179
  let checkout;
23944
24180
  try {
23945
- checkout = fs12.realpathSync(root);
24181
+ checkout = fs13.realpathSync(root);
23946
24182
  } catch {
23947
24183
  return failure2("invalid_input", "candidate root does not exist");
23948
24184
  }
@@ -23960,11 +24196,11 @@ function captureCandidate(root, scope, environment = []) {
23960
24196
  if (item === ".git" || item === ".workit")
23961
24197
  continue;
23962
24198
  names.add(item);
23963
- if (!fs12.existsSync(target))
24199
+ if (!fs13.existsSync(target))
23964
24200
  continue;
23965
24201
  let stat;
23966
24202
  try {
23967
- stat = fs12.lstatSync(target);
24203
+ stat = fs13.lstatSync(target);
23968
24204
  } catch {
23969
24205
  uncertain = true;
23970
24206
  continue;
@@ -23980,17 +24216,17 @@ function captureCandidate(root, scope, environment = []) {
23980
24216
  for (const item of [...names].toSorted()) {
23981
24217
  if (!scopeMatches(item, normalizedScope))
23982
24218
  continue;
23983
- const target = path15.join(checkout, item);
24219
+ const target = path16.join(checkout, item);
23984
24220
  try {
23985
- const stat = fs12.lstatSync(target);
24221
+ const stat = fs13.lstatSync(target);
23986
24222
  if (stat.isSymbolicLink()) {
23987
- const link = fs12.readlinkSync(target);
24223
+ const link = fs13.readlinkSync(target);
23988
24224
  files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
23989
24225
  } else if (stat.isFile()) {
23990
24226
  files.push({
23991
24227
  path: item,
23992
24228
  kind: "file",
23993
- digest: digestBytes(fs12.readFileSync(target)),
24229
+ digest: digestBytes(fs13.readFileSync(target)),
23994
24230
  executable: (stat.mode & 73) !== 0
23995
24231
  });
23996
24232
  } else if (!stat.isDirectory()) {
@@ -24155,7 +24391,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
24155
24391
  var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
24156
24392
  let root;
24157
24393
  try {
24158
- root = fs12.realpathSync(checkoutRoot);
24394
+ root = fs13.realpathSync(checkoutRoot);
24159
24395
  } catch {
24160
24396
  return failure2("permission_denied", "checkout root is unavailable");
24161
24397
  }
@@ -24164,23 +24400,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
24164
24400
  continue;
24165
24401
  if (!reference.digest)
24166
24402
  return failure2("invalid_input", "document references require a byte digest");
24167
- const target = path15.resolve(root, reference.path);
24168
- if (target !== root && !target.startsWith(`${root}${path15.sep}`))
24403
+ const target = path16.resolve(root, reference.path);
24404
+ if (target !== root && !target.startsWith(`${root}${path16.sep}`))
24169
24405
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
24170
24406
  fields: [
24171
24407
  { path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
24172
24408
  ]
24173
24409
  });
24174
24410
  try {
24175
- const below = path15.relative(root, target);
24411
+ const below = path16.relative(root, target);
24176
24412
  let current = root;
24177
- for (const segment of below.split(path15.sep)) {
24413
+ for (const segment of below.split(path16.sep)) {
24178
24414
  if (!segment)
24179
24415
  continue;
24180
- current = path15.join(current, segment);
24181
- const stat = fs12.lstatSync(current);
24182
- const real = fs12.realpathSync(current);
24183
- if (real !== root && !real.startsWith(`${root}${path15.sep}`))
24416
+ current = path16.join(current, segment);
24417
+ const stat = fs13.lstatSync(current);
24418
+ const real = fs13.realpathSync(current);
24419
+ if (real !== root && !real.startsWith(`${root}${path16.sep}`))
24184
24420
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
24185
24421
  fields: [
24186
24422
  {
@@ -24196,7 +24432,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
24196
24432
  if (current !== target && !stat.isDirectory())
24197
24433
  return failure2("invalid_input", "document reference ancestor is not a directory");
24198
24434
  }
24199
- if (digestBytes(fs12.readFileSync(target)) !== reference.digest)
24435
+ if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
24200
24436
  return failure2("permission_denied", "decision document bytes have changed");
24201
24437
  } catch {
24202
24438
  return failure2("invalid_input", "decision document is unavailable");
@@ -25054,7 +25290,7 @@ var judgeInputSummary = (raw) => {
25054
25290
 
25055
25291
  // packages/workit-core/src/autonomy.ts
25056
25292
  import os4 from "node:os";
25057
- import path16 from "node:path";
25293
+ import path17 from "node:path";
25058
25294
  var accountHome = () => {
25059
25295
  try {
25060
25296
  return os4.userInfo().homedir;
@@ -25063,10 +25299,10 @@ var accountHome = () => {
25063
25299
  }
25064
25300
  };
25065
25301
  var grantsHome = { resolve: accountHome };
25066
- var grantsDir = () => path16.join(grantsHome.resolve(), ".config", "workit");
25302
+ var grantsDir = () => path17.join(grantsHome.resolve(), ".config", "workit");
25067
25303
  var grantsOverride = () => {
25068
- const configured = path16.resolve(resolveConfigDir());
25069
- return configured === path16.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 ${path16.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
25304
+ const configured = path17.resolve(resolveConfigDir());
25305
+ 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`;
25070
25306
  };
25071
25307
  var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
25072
25308
  var DEFAULT_GRANTS = Object.freeze({
@@ -26838,7 +27074,7 @@ class WorkitCore {
26838
27074
  // packages/workit-core/src/core/repo-context.ts
26839
27075
  import { spawnSync as spawnSync11 } from "node:child_process";
26840
27076
  import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
26841
- import path17 from "node:path";
27077
+ import path18 from "node:path";
26842
27078
  var isSafeContextRange = (value) => value.length <= 4096 && (() => {
26843
27079
  try {
26844
27080
  gitRevisionParts(value);
@@ -26972,7 +27208,7 @@ var findPrTemplate = (cwd) => {
26972
27208
  ]) {
26973
27209
  const parts = rel.split("/");
26974
27210
  const base = parts[parts.length - 1];
26975
- const dir = parts.length > 1 ? path17.join(cwd, ...parts.slice(0, -1)) : cwd;
27211
+ const dir = parts.length > 1 ? path18.join(cwd, ...parts.slice(0, -1)) : cwd;
26976
27212
  const actual = probeCaseInsensitive(dir, base);
26977
27213
  if (actual)
26978
27214
  return [...parts.slice(0, -1), actual].join("/");
@@ -27003,7 +27239,7 @@ var diffStatForRange = (cwd, range) => {
27003
27239
  return runGit(cwd, ["diff", "--stat", "--"]).stdout;
27004
27240
  };
27005
27241
  var packageScripts = (cwd, keys) => {
27006
- const pkgPath = path17.join(cwd, "package.json");
27242
+ const pkgPath = path18.join(cwd, "package.json");
27007
27243
  if (!existsSync6(pkgPath))
27008
27244
  return [];
27009
27245
  try {
@@ -27029,9 +27265,9 @@ var documentationFiles = (cwd) => {
27029
27265
  if (entry.isDirectory()) {
27030
27266
  if (excluded.has(entry.name))
27031
27267
  continue;
27032
- walk(path17.join(dir, entry.name), depth + 1);
27268
+ walk(path18.join(dir, entry.name), depth + 1);
27033
27269
  } else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
27034
- matches.push("./" + path17.relative(cwd, path17.join(dir, entry.name)).replaceAll("\\", "/"));
27270
+ matches.push("./" + path18.relative(cwd, path18.join(dir, entry.name)).replaceAll("\\", "/"));
27035
27271
  }
27036
27272
  }
27037
27273
  };
@@ -27047,7 +27283,7 @@ var readTrimmed2 = (file, maxLines) => {
27047
27283
  `);
27048
27284
  };
27049
27285
  function prReadyContext(root, range) {
27050
- const cwd = path17.resolve(repoRoot(root));
27286
+ const cwd = path18.resolve(repoRoot(root));
27051
27287
  if (range !== undefined && !isResolvableContextRange(cwd, range))
27052
27288
  return invalidRange(cwd);
27053
27289
  let stdout = "";
@@ -27105,7 +27341,7 @@ ${status.stderr}` : "");
27105
27341
  stdout += `template_path: ${template}
27106
27342
 
27107
27343
  `;
27108
- stdout += readTrimmed2(path17.join(cwd, template), 220);
27344
+ stdout += readTrimmed2(path18.join(cwd, template), 220);
27109
27345
  } else {
27110
27346
  stdout += `template_path: none
27111
27347
 
@@ -27115,7 +27351,7 @@ ${status.stderr}` : "");
27115
27351
  stdout += `
27116
27352
  `;
27117
27353
  stdout += printSection("Recent Validation Signals");
27118
- if (existsSync6(path17.join(cwd, "package.json"))) {
27354
+ if (existsSync6(path18.join(cwd, "package.json"))) {
27119
27355
  stdout += `package.json detected. Common scripts:
27120
27356
  `;
27121
27357
  const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
@@ -27124,7 +27360,7 @@ ${status.stderr}` : "");
27124
27360
  `) + `
27125
27361
  `;
27126
27362
  }
27127
- if (existsSync6(path17.join(cwd, "Cargo.toml")) || existsSync6(path17.join(cwd, "src-tauri/Cargo.toml"))) {
27363
+ if (existsSync6(path18.join(cwd, "Cargo.toml")) || existsSync6(path18.join(cwd, "src-tauri/Cargo.toml"))) {
27128
27364
  stdout += `Rust project detected.
27129
27365
  `;
27130
27366
  }
@@ -27157,7 +27393,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
27157
27393
  - Apply with the host-native editor, preserving the repository changelog conventions.
27158
27394
  - If Unreleased already has duplicate category headings, normalize_only first.`;
27159
27395
  function changelogContext(root, range) {
27160
- const cwd = path17.resolve(repoRoot(root));
27396
+ const cwd = path18.resolve(repoRoot(root));
27161
27397
  if (range !== undefined && !isResolvableContextRange(cwd, range))
27162
27398
  return invalidRange(cwd);
27163
27399
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -27175,7 +27411,7 @@ function changelogContext(root, range) {
27175
27411
  stdout += CHANGELOG_RULES + `
27176
27412
  `;
27177
27413
  stdout += printSection("Existing CHANGELOG.md");
27178
- const changelogPath = path17.join(cwd, "CHANGELOG.md");
27414
+ const changelogPath = path18.join(cwd, "CHANGELOG.md");
27179
27415
  if (existsSync6(changelogPath)) {
27180
27416
  stdout += readTrimmed2(changelogPath, 260) + `
27181
27417
  `;
@@ -27195,7 +27431,7 @@ function changelogContext(root, range) {
27195
27431
  return { stdout, stderr: "", exitCode: 0, cwd };
27196
27432
  }
27197
27433
  function docsRefreshContext(root, range) {
27198
- const cwd = path17.resolve(repoRoot(root));
27434
+ const cwd = path18.resolve(repoRoot(root));
27199
27435
  if (range !== undefined && !isResolvableContextRange(cwd, range))
27200
27436
  return invalidRange(cwd);
27201
27437
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -27217,7 +27453,7 @@ function docsRefreshContext(root, range) {
27217
27453
  `) + `
27218
27454
  `;
27219
27455
  stdout += printSection("README Preview");
27220
- const readme = path17.join(cwd, "README.md");
27456
+ const readme = path18.join(cwd, "README.md");
27221
27457
  if (existsSync6(readme)) {
27222
27458
  stdout += readTrimmed2(readme, 220) + `
27223
27459
  `;
@@ -27226,7 +27462,7 @@ function docsRefreshContext(root, range) {
27226
27462
  `;
27227
27463
  }
27228
27464
  stdout += printSection("Package Scripts");
27229
- const pkgPath = path17.join(cwd, "package.json");
27465
+ const pkgPath = path18.join(cwd, "package.json");
27230
27466
  if (existsSync6(pkgPath)) {
27231
27467
  try {
27232
27468
  const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
@@ -27240,7 +27476,7 @@ function docsRefreshContext(root, range) {
27240
27476
  return { stdout, stderr: "", exitCode: 0, cwd };
27241
27477
  }
27242
27478
  function releaseNotesContext(root, rangeOrTag) {
27243
- const cwd = path17.resolve(repoRoot(root));
27479
+ const cwd = path18.resolve(repoRoot(root));
27244
27480
  if (!rangeOrTag) {
27245
27481
  return { stdout: "", stderr: `ERROR: release tag or range required
27246
27482
  `, exitCode: 1, cwd };
@@ -27278,7 +27514,7 @@ function releaseNotesContext(root, rangeOrTag) {
27278
27514
  `;
27279
27515
  stdout += printSection("Existing Release Files");
27280
27516
  for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
27281
- if (existsSync6(path17.join(cwd, rel)))
27517
+ if (existsSync6(path18.join(cwd, rel)))
27282
27518
  stdout += rel + `
27283
27519
  `;
27284
27520
  }
@@ -27309,8 +27545,8 @@ function releaseNotesContext(root, rangeOrTag) {
27309
27545
  import { spawnSync as spawnSync13 } from "node:child_process";
27310
27546
 
27311
27547
  // packages/workit-core/src/core/pr-create.ts
27312
- import fs13 from "node:fs";
27313
- import path18 from "node:path";
27548
+ import fs14 from "node:fs";
27549
+ import path19 from "node:path";
27314
27550
  import { spawnSync as spawnSync12 } from "node:child_process";
27315
27551
  // packages/workit-core/src/forge/pr-body.ts
27316
27552
  function parseGhIssue(value) {
@@ -27321,13 +27557,13 @@ function parseGhIssue(value) {
27321
27557
  // packages/workit-core/src/core/pr-create.ts
27322
27558
  function whichOnPath(tool) {
27323
27559
  const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
27324
- for (const dir of (process.env.PATH ?? "").split(path18.delimiter)) {
27560
+ for (const dir of (process.env.PATH ?? "").split(path19.delimiter)) {
27325
27561
  if (!dir)
27326
27562
  continue;
27327
27563
  for (const name of names) {
27328
- const candidate = path18.join(dir, name);
27564
+ const candidate = path19.join(dir, name);
27329
27565
  try {
27330
- fs13.accessSync(candidate, fs13.constants.X_OK);
27566
+ fs14.accessSync(candidate, fs14.constants.X_OK);
27331
27567
  return candidate;
27332
27568
  } catch {}
27333
27569
  }
@@ -27445,8 +27681,8 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
27445
27681
  };
27446
27682
 
27447
27683
  // packages/workit-core/src/core/youtrack.ts
27448
- import fs14 from "node:fs";
27449
- import path19 from "node:path";
27684
+ import fs15 from "node:fs";
27685
+ import path20 from "node:path";
27450
27686
 
27451
27687
  // packages/workit-core/src/core/templates.ts
27452
27688
  var repoRoot2 = assetRoot();
@@ -27459,22 +27695,22 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
27459
27695
  // packages/workit-core/src/core/youtrack.ts
27460
27696
  var ISSUE_RE = /^[A-Z]+-\d+$/;
27461
27697
  var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
27462
- var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path19.join(configDir(), "youtrack.json");
27463
- var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path19.join(resolveConfigDir(), "youtrack.json");
27698
+ var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(configDir(), "youtrack.json");
27699
+ var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(resolveConfigDir(), "youtrack.json");
27464
27700
  var youTrackTokenModeOk = (p) => {
27465
27701
  if (process.platform === "win32")
27466
27702
  return true;
27467
- const mode = fs14.statSync(p).mode & 511;
27703
+ const mode = fs15.statSync(p).mode & 511;
27468
27704
  return mode === 384;
27469
27705
  };
27470
27706
  function readYouTrackConfig(required) {
27471
27707
  const cfgPath = youTrackConfigPath();
27472
- if (!fs14.existsSync(cfgPath)) {
27708
+ if (!fs15.existsSync(cfgPath)) {
27473
27709
  return required ? { error: "ERROR: missing youtrack.json", path: cfgPath } : { config: {}, path: cfgPath };
27474
27710
  }
27475
27711
  let parsed;
27476
27712
  try {
27477
- parsed = JSON.parse(fs14.readFileSync(cfgPath, "utf8"));
27713
+ parsed = JSON.parse(fs15.readFileSync(cfgPath, "utf8"));
27478
27714
  } catch {
27479
27715
  return { error: `${cfgPath} is not valid JSON`, path: cfgPath };
27480
27716
  }
@@ -27485,11 +27721,11 @@ function readYouTrackConfig(required) {
27485
27721
  }
27486
27722
  var readYouTrackContextConfig = () => {
27487
27723
  const cfgPath = youTrackReadOnlyConfigPath();
27488
- if (!fs14.existsSync(cfgPath))
27724
+ if (!fs15.existsSync(cfgPath))
27489
27725
  return { data: {} };
27490
27726
  let parsed;
27491
27727
  try {
27492
- parsed = JSON.parse(fs14.readFileSync(cfgPath, "utf8"));
27728
+ parsed = JSON.parse(fs15.readFileSync(cfgPath, "utf8"));
27493
27729
  } catch {
27494
27730
  return { error: "YouTrack configuration is unavailable" };
27495
27731
  }
@@ -27528,12 +27764,12 @@ var youTrackToken = () => {
27528
27764
  if ("error" in loaded)
27529
27765
  return loaded;
27530
27766
  const tokenFile = String(loaded.config.tokenFile ?? "");
27531
- const tokenPath = tokenFile ? path19.isAbsolute(tokenFile) ? path19.resolve(tokenFile) : path19.resolve(process.cwd(), tokenFile) : "";
27532
- if (!tokenPath || !fs14.existsSync(tokenPath))
27767
+ const tokenPath = tokenFile ? path20.isAbsolute(tokenFile) ? path20.resolve(tokenFile) : path20.resolve(process.cwd(), tokenFile) : "";
27768
+ if (!tokenPath || !fs15.existsSync(tokenPath))
27533
27769
  return { error: "missing youtrack.token" };
27534
27770
  if (!youTrackTokenModeOk(tokenPath))
27535
27771
  return { error: "youtrack.token mode must be 0600" };
27536
- const token = fs14.readFileSync(tokenPath, "utf8").trim();
27772
+ const token = fs15.readFileSync(tokenPath, "utf8").trim();
27537
27773
  if (!token)
27538
27774
  return { error: "empty token file" };
27539
27775
  if (token === TOKEN_PLACEHOLDER || token.startsWith(TOKEN_PLACEHOLDER)) {
@@ -27598,9 +27834,9 @@ function resolveYouTrackFromPaths(spec_path, plan_path, workspace_root) {
27598
27834
  } catch {
27599
27835
  continue;
27600
27836
  }
27601
- if (!fs14.existsSync(full))
27837
+ if (!fs15.existsSync(full))
27602
27838
  continue;
27603
- const text = fs14.readFileSync(full, "utf8");
27839
+ const text = fs15.readFileSync(full, "utf8");
27604
27840
  const m = text.match(/^\*\*YouTrack:\*\*\s*`?([A-Z]+-\d+)`?/m);
27605
27841
  if (m)
27606
27842
  return m[1];
@@ -27870,15 +28106,15 @@ function resolveGitRevision(root, value) {
27870
28106
  }
27871
28107
  function resolveInside(root, candidate) {
27872
28108
  const base = realpathSync5(root);
27873
- const target = path20.resolve(base, candidate);
27874
- if (target !== base && !target.startsWith(base + path20.sep)) {
28109
+ const target = path21.resolve(base, candidate);
28110
+ if (target !== base && !target.startsWith(base + path21.sep)) {
27875
28111
  throw new Error("path must stay inside repository root");
27876
28112
  }
27877
28113
  let ancestor = target;
27878
28114
  while (!existsSync7(ancestor))
27879
- ancestor = path20.dirname(ancestor);
28115
+ ancestor = path21.dirname(ancestor);
27880
28116
  const canonicalAncestor = realpathSync5(ancestor);
27881
- if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path20.sep)) {
28117
+ if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path21.sep)) {
27882
28118
  throw new Error("path must stay inside repository root");
27883
28119
  }
27884
28120
  return target;
@@ -27936,13 +28172,13 @@ var rootVariants = (workspaceRoot) => {
27936
28172
  if (!workspaceRoot)
27937
28173
  return [];
27938
28174
  const roots = new Set;
27939
- for (const candidate of [workspaceRoot, path21.resolve(workspaceRoot)]) {
27940
- if (path21.isAbsolute(candidate) && candidate !== path21.parse(candidate).root)
28175
+ for (const candidate of [workspaceRoot, path22.resolve(workspaceRoot)]) {
28176
+ if (path22.isAbsolute(candidate) && candidate !== path22.parse(candidate).root)
27941
28177
  roots.add(candidate);
27942
28178
  }
27943
28179
  try {
27944
28180
  const canonical = realpathSync6(workspaceRoot);
27945
- if (canonical !== path21.parse(canonical).root)
28181
+ if (canonical !== path22.parse(canonical).root)
27946
28182
  roots.add(canonical);
27947
28183
  } catch {}
27948
28184
  return [...roots].toSorted((left, right) => right.length - left.length);
@@ -28024,11 +28260,11 @@ var thrownResult = (tool, error, workspaceRoot) => {
28024
28260
  };
28025
28261
  function createMcpServer(host, contextProvider) {
28026
28262
  assertMcpHost(host);
28027
- const here = path21.dirname(fileURLToPath2(import.meta.url));
28263
+ const here = path22.dirname(fileURLToPath2(import.meta.url));
28028
28264
  const sourceMarker = markSourcesLoaded([
28029
- path21.join(here, "server.ts"),
28030
- path21.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
28031
- path21.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
28265
+ path22.join(here, "server.ts"),
28266
+ path22.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
28267
+ path22.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
28032
28268
  ].filter((file) => existsSync8(file)));
28033
28269
  let staleWarned = false;
28034
28270
  const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
@@ -28208,8 +28444,8 @@ var main = async () => {
28208
28444
  process.exitCode = 2;
28209
28445
  }
28210
28446
  };
28211
- var entryPath = process.argv[1] ? path22.resolve(process.argv[1]) : "";
28212
- if (entryPath === path22.resolve(fileURLToPath3(import.meta.url)))
28447
+ var entryPath = process.argv[1] ? path23.resolve(process.argv[1]) : "";
28448
+ if (entryPath === path23.resolve(fileURLToPath3(import.meta.url)))
28213
28449
  await main();
28214
28450
  // packages/workit-core/src/hooks/descriptor.ts
28215
28451
  var support = (descriptor, axis) => {
@@ -28239,10 +28475,44 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
28239
28475
  var signals = new Map;
28240
28476
  var cache = new Map;
28241
28477
  var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
28478
+ // packages/workit-core/src/core/live-session.ts
28479
+ import { spawnSync as spawnSync15 } from "node:child_process";
28480
+ var LIVE_SESSION_TTL_MS = 15 * 60000;
28481
+ var liveProbe = {
28482
+ platform: process.platform,
28483
+ run: (args) => spawnSync15("ps", args, { encoding: "utf8", timeout: 2000 }).stdout ?? "",
28484
+ start: (pid) => processStartOf(pid)
28485
+ };
28486
+ var PIDS = new Map;
28487
+
28242
28488
  // packages/workit-core/src/hooks/write-gate.ts
28243
28489
  var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
28244
28490
  var PREFIXES2 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "xargs"]);
28245
28491
  var cache2 = new Map;
28492
+ var MUTATING_GIT = new Set([
28493
+ "add",
28494
+ "am",
28495
+ "apply",
28496
+ "checkout",
28497
+ "cherry-pick",
28498
+ "clean",
28499
+ "commit",
28500
+ "merge",
28501
+ "mv",
28502
+ "pull",
28503
+ "rebase",
28504
+ "reset",
28505
+ "restore",
28506
+ "revert",
28507
+ "rm",
28508
+ "stash",
28509
+ "switch"
28510
+ ]);
28511
+ var DRY_N = new Set(["add", "clean", "rm", "mv"]);
28512
+ var MUTATING_WORKIT_GIT = new Set(["commit", "branch"]);
28513
+ var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
28514
+ var PUSHD2 = new Set(["pushd", "push-location"]);
28515
+ var POPD2 = new Set(["popd", "pop-location"]);
28246
28516
  // packages/workit-core/src/core/skill-manifests.ts
28247
28517
  if (false) {}
28248
28518
 
@@ -28437,7 +28707,7 @@ var cursorContextProvider = (workspaceRoot = process.env.WORKFLOW_WORKSPACE_ROOT
28437
28707
  var stampCursorSessionStart = (stateDir = resolveStateDir()) => {
28438
28708
  try {
28439
28709
  mkdirSync3(stateDir, { recursive: true });
28440
- writeFileSync3(path23.join(stateDir, "cursor-session-last-start"), `${JSON.stringify({ at: new Date().toISOString() })}
28710
+ writeFileSync3(path24.join(stateDir, "cursor-session-last-start"), `${JSON.stringify({ at: new Date().toISOString() })}
28441
28711
  `);
28442
28712
  } catch {}
28443
28713
  };