@brainervirus/workit-cursor 8.12.3 → 8.13.1

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"],
@@ -21933,7 +22023,7 @@ var workspacesFileSchema = object2({ workspaces: array(workspaceConfigSchema).op
21933
22023
  names.add(workspace.name);
21934
22024
  }
21935
22025
  });
21936
- var workspacesRevision = (contents) => createHash6("sha256").update(contents ?? "<missing>").digest("hex");
22026
+ var workspacesRevision = (contents) => createHash7("sha256").update(contents ?? "<missing>").digest("hex");
21937
22027
  var validateWorkspacesDocument = (parsed, file) => {
21938
22028
  if (!isConfigObject(parsed)) {
21939
22029
  return { status: "malformed", path: file, entries: [], error: `${file} is not a JSON object` };
@@ -21971,7 +22061,7 @@ var validateWorkspacesDocument = (parsed, file) => {
21971
22061
  };
21972
22062
  };
21973
22063
  var readWorkspacesResult = (dir = configDir()) => {
21974
- const file = path11.join(dir, "workspaces.json");
22064
+ const file = path12.join(dir, "workspaces.json");
21975
22065
  let raw;
21976
22066
  try {
21977
22067
  raw = readFileSync3(file, "utf8");
@@ -22082,9 +22172,9 @@ var mainCheckoutOf = (cwd) => {
22082
22172
  let main = null;
22083
22173
  const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
22084
22174
  const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
22085
- if (gitDir && common && path11.resolve(gitDir) !== path11.resolve(common)) {
22175
+ if (gitDir && common && path12.resolve(gitDir) !== path12.resolve(common)) {
22086
22176
  const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
22087
- main = listed?.trim() || (path11.basename(common) === ".git" ? path11.dirname(common) : common);
22177
+ main = listed?.trim() || (path12.basename(common) === ".git" ? path12.dirname(common) : common);
22088
22178
  }
22089
22179
  mainCheckouts.set(cwd, main);
22090
22180
  return main;
@@ -22175,7 +22265,7 @@ var runtimeWorkspaceIndexSchema = object2({
22175
22265
  workspaces: array(object2({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
22176
22266
  }).passthrough();
22177
22267
  var matchRuntimeWorkspace = (cwd, dir = configDir()) => {
22178
- const file = path11.join(dir, "workspaces.json");
22268
+ const file = path12.join(dir, "workspaces.json");
22179
22269
  let raw;
22180
22270
  try {
22181
22271
  raw = readFileSync3(file, "utf8");
@@ -22250,7 +22340,7 @@ function workspaceDefaultTarget(cwd, globalDefault) {
22250
22340
  }
22251
22341
 
22252
22342
  // packages/workit-core/src/core/release-tracks.ts
22253
- import { createHash as createHash7 } from "node:crypto";
22343
+ import { createHash as createHash8 } from "node:crypto";
22254
22344
  import { spawnSync as spawnSync7 } from "node:child_process";
22255
22345
  var KNOWN_FIELDS = new Set([
22256
22346
  "strategy",
@@ -22620,7 +22710,7 @@ function resolveTrackFor(cwd, options) {
22620
22710
  ]) ?? "",
22621
22711
  git3(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
22622
22712
  ] : [];
22623
- key = createHash7("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
22713
+ key = createHash8("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
22624
22714
  const hit = memo2.get(key);
22625
22715
  if (hit)
22626
22716
  return hit;
@@ -22635,7 +22725,7 @@ function resolveTrackFor(cwd, options) {
22635
22725
  }
22636
22726
 
22637
22727
  // packages/workit-core/src/core/vcs-config.ts
22638
- var workspacesPath = () => path12.join(configDir(), "workspaces.json");
22728
+ var workspacesPath = () => path13.join(configDir(), "workspaces.json");
22639
22729
  var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
22640
22730
  var remoteProvider = (cwd) => {
22641
22731
  const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
@@ -22725,7 +22815,7 @@ var readVcsConfig = () => {
22725
22815
  const file = vcsConfigPath();
22726
22816
  let raw;
22727
22817
  try {
22728
- raw = fs10.readFileSync(file, "utf8");
22818
+ raw = fs11.readFileSync(file, "utf8");
22729
22819
  } catch {
22730
22820
  return { status: "missing", path: file, config: {} };
22731
22821
  }
@@ -22810,7 +22900,7 @@ function vcsConfig(mode, cwd, options = {}) {
22810
22900
  const prov = cfg[provider] ?? {};
22811
22901
  const out = {
22812
22902
  ok: true,
22813
- configPath: path12.resolve(cfgPath),
22903
+ configPath: path13.resolve(cfgPath),
22814
22904
  provider,
22815
22905
  defaultTargetBranch: workspaceDefault,
22816
22906
  pr: cfg.pr ?? {},
@@ -23021,7 +23111,7 @@ function diffHash(cwd, base, head) {
23021
23111
  ], GIT_TIMEOUTS.worktree);
23022
23112
  if (!diff.ok || !diff.stdout)
23023
23113
  return null;
23024
- const hash = createHash8("sha256");
23114
+ const hash = createHash9("sha256");
23025
23115
  for (const line of diff.stdout.split(`
23026
23116
  `)) {
23027
23117
  if (line.startsWith("index "))
@@ -23033,16 +23123,16 @@ function diffHash(cwd, base, head) {
23033
23123
  return `sha256:${hash.digest("hex")}`;
23034
23124
  }
23035
23125
  function storeRoot(cwd) {
23036
- const location = resolveStore(path13.resolve(cwd));
23126
+ const location = resolveStore(path14.resolve(cwd));
23037
23127
  if (location instanceof Error)
23038
23128
  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
23129
  return { ok: true, value: { root: location.dir, shared: location.shared } };
23040
23130
  }
23041
23131
  function ledgerPath(cwd) {
23042
23132
  const root = storeRoot(cwd);
23043
- return root.ok ? { ok: true, value: path13.join(root.value.root, "ledger", "ledger.jsonl") } : root;
23133
+ return root.ok ? { ok: true, value: path14.join(root.value.root, "ledger", "ledger.jsonl") } : root;
23044
23134
  }
23045
- var newId2 = () => `${Date.now().toString(36)}-${randomBytes2(6).toString("hex")}`;
23135
+ var newId2 = () => `${Date.now().toString(36)}-${randomBytes3(6).toString("hex")}`;
23046
23136
  var NETWORK_FS_TYPES = new Set([
23047
23137
  26985,
23048
23138
  20859,
@@ -23060,7 +23150,7 @@ var onNetworkFs = (dir) => {
23060
23150
  if (process.platform !== "linux")
23061
23151
  return false;
23062
23152
  try {
23063
- return isNetworkFsType(fs11.statfsSync(dir).type);
23153
+ return isNetworkFsType(fs12.statfsSync(dir).type);
23064
23154
  } catch {
23065
23155
  return false;
23066
23156
  }
@@ -23070,15 +23160,15 @@ var LOCK_STALE_MS = 30000;
23070
23160
  var LOCK_OWNER = "owner";
23071
23161
  var lockToken = (lock) => {
23072
23162
  try {
23073
- return fs11.readFileSync(path13.join(lock, LOCK_OWNER), "utf8");
23163
+ return fs12.readFileSync(path14.join(lock, LOCK_OWNER), "utf8");
23074
23164
  } catch {
23075
23165
  return null;
23076
23166
  }
23077
23167
  };
23078
23168
  var lockAgeMs = (lock) => {
23079
- for (const target of [path13.join(lock, LOCK_OWNER), lock]) {
23169
+ for (const target of [path14.join(lock, LOCK_OWNER), lock]) {
23080
23170
  try {
23081
- return Date.now() - fs11.statSync(target).mtimeMs;
23171
+ return Date.now() - fs12.statSync(target).mtimeMs;
23082
23172
  } catch {}
23083
23173
  }
23084
23174
  return null;
@@ -23086,55 +23176,55 @@ var lockAgeMs = (lock) => {
23086
23176
  var ledgerLock = {
23087
23177
  acquire(lock) {
23088
23178
  try {
23089
- fs11.mkdirSync(lock);
23179
+ fs12.mkdirSync(lock);
23090
23180
  } catch (error) {
23091
23181
  if (error.code === "EEXIST")
23092
23182
  return null;
23093
23183
  throw error;
23094
23184
  }
23095
- const token = `${process.pid}-${randomBytes2(8).toString("hex")}`;
23096
- fs11.writeFileSync(path13.join(lock, LOCK_OWNER), token);
23185
+ const token = `${process.pid}-${randomBytes3(8).toString("hex")}`;
23186
+ fs12.writeFileSync(path14.join(lock, LOCK_OWNER), token);
23097
23187
  return token;
23098
23188
  },
23099
23189
  release(lock, token) {
23100
23190
  if (lockToken(lock) !== token)
23101
23191
  return false;
23102
- const tomb = `${lock}.release-${randomBytes2(6).toString("hex")}`;
23192
+ const tomb = `${lock}.release-${randomBytes3(6).toString("hex")}`;
23103
23193
  try {
23104
- fs11.renameSync(lock, tomb);
23194
+ fs12.renameSync(lock, tomb);
23105
23195
  } catch {
23106
23196
  return false;
23107
23197
  }
23108
23198
  if (lockToken(tomb) !== token) {
23109
23199
  try {
23110
- fs11.renameSync(tomb, lock);
23200
+ fs12.renameSync(tomb, lock);
23111
23201
  } catch {}
23112
23202
  return false;
23113
23203
  }
23114
- fs11.rmSync(tomb, { recursive: true, force: true });
23204
+ fs12.rmSync(tomb, { recursive: true, force: true });
23115
23205
  return true;
23116
23206
  },
23117
23207
  token: lockToken,
23118
23208
  reap(lock, observed) {
23119
- const tomb = `${lock}.reap-${randomBytes2(6).toString("hex")}`;
23209
+ const tomb = `${lock}.reap-${randomBytes3(6).toString("hex")}`;
23120
23210
  try {
23121
- fs11.renameSync(lock, tomb);
23211
+ fs12.renameSync(lock, tomb);
23122
23212
  } catch {
23123
23213
  return false;
23124
23214
  }
23125
23215
  if (lockToken(tomb) === observed) {
23126
- fs11.rmSync(tomb, { recursive: true, force: true });
23216
+ fs12.rmSync(tomb, { recursive: true, force: true });
23127
23217
  return true;
23128
23218
  }
23129
23219
  try {
23130
- fs11.renameSync(tomb, lock);
23220
+ fs12.renameSync(tomb, lock);
23131
23221
  } catch {
23132
- fs11.rmSync(tomb, { recursive: true, force: true });
23222
+ fs12.rmSync(tomb, { recursive: true, force: true });
23133
23223
  }
23134
23224
  return false;
23135
23225
  }
23136
23226
  };
23137
- function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
23227
+ function withLedgerLock(file, fn, waitMs = hostAwareLockTimeout(LOCK_WAIT_MS)) {
23138
23228
  const lock = `${file}.lock`;
23139
23229
  const deadline = Date.now() + waitMs;
23140
23230
  let token = null;
@@ -23156,14 +23246,14 @@ function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
23156
23246
  ledgerLock.release(lock, token);
23157
23247
  }
23158
23248
  }
23159
- var sha2562 = (text) => createHash8("sha256").update(text).digest("hex");
23249
+ var sha2562 = (text) => createHash9("sha256").update(text).digest("hex");
23160
23250
  var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
23161
23251
  ${body}`);
23162
23252
  var TAIL_BYTES = 64 * 1024;
23163
23253
  var lastLine = (fd, size) => {
23164
23254
  for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
23165
23255
  const buffer = Buffer.alloc(span);
23166
- fs11.readSync(fd, buffer, 0, span, size - span);
23256
+ fs12.readSync(fd, buffer, 0, span, size - span);
23167
23257
  const end = buffer.lastIndexOf(10);
23168
23258
  if (end < 0) {
23169
23259
  if (span === size)
@@ -23192,15 +23282,23 @@ var lastLine = (fd, size) => {
23192
23282
  }
23193
23283
  return null;
23194
23284
  };
23285
+ var tighten = (fd) => {
23286
+ try {
23287
+ if ((fs12.fstatSync(fd).mode & 63) !== 0)
23288
+ fs12.fchmodSync(fd, 384);
23289
+ } catch {}
23290
+ };
23195
23291
  function appendLine(file, build, options) {
23196
23292
  const write = () => {
23197
- const fd = fs11.openSync(file, "a+");
23293
+ const fd = fs12.openSync(file, "a+", 384);
23198
23294
  try {
23199
- const size = fs11.fstatSync(fd).size;
23295
+ if (process.platform !== "win32")
23296
+ tighten(fd);
23297
+ const size = fs12.fstatSync(fd).size;
23200
23298
  let fence = "";
23201
23299
  if (size > 0) {
23202
23300
  const last = Buffer.alloc(1);
23203
- fs11.readSync(fd, last, 0, 1, size - 1);
23301
+ fs12.readSync(fd, last, 0, 1, size - 1);
23204
23302
  if (last[0] !== 10)
23205
23303
  fence = `
23206
23304
  `;
@@ -23209,17 +23307,17 @@ function appendLine(file, build, options) {
23209
23307
  if (!line.ok)
23210
23308
  return line;
23211
23309
  const bytes = Buffer.from(fence + line.value);
23212
- const written = fs11.writeSync(fd, bytes);
23310
+ const written = fs12.writeSync(fd, bytes);
23213
23311
  if (written !== bytes.length)
23214
23312
  return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
23215
23313
  return { ok: true, value: undefined };
23216
23314
  } finally {
23217
- fs11.closeSync(fd);
23315
+ fs12.closeSync(fd);
23218
23316
  }
23219
23317
  };
23220
23318
  try {
23221
- fs11.mkdirSync(path13.dirname(file), { recursive: true });
23222
- if (!options.forceLock && !onNetworkFs(path13.dirname(file)))
23319
+ fs12.mkdirSync(path14.dirname(file), { recursive: true });
23320
+ if (!options.forceLock && !onNetworkFs(path14.dirname(file)))
23223
23321
  return write();
23224
23322
  const locked = withLedgerLock(file, write);
23225
23323
  return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
@@ -23287,8 +23385,10 @@ function readLedger(cwd, options = {}) {
23287
23385
  if (!file.ok)
23288
23386
  return file;
23289
23387
  let text = "";
23388
+ let stat = null;
23290
23389
  try {
23291
- text = fs11.readFileSync(file.value, "utf8");
23390
+ stat = fs12.statSync(file.value);
23391
+ text = fs12.readFileSync(file.value, "utf8");
23292
23392
  } catch (error) {
23293
23393
  if (error.code === "ENOENT")
23294
23394
  return {
@@ -23307,6 +23407,7 @@ function readLedger(cwd, options = {}) {
23307
23407
  const integrity = { chained: 0, legacy: 0, unverified: [] };
23308
23408
  const earlier = new Set([null]);
23309
23409
  let chainStarted = false;
23410
+ const ids = new Set;
23310
23411
  for (const raw of text.split(`
23311
23412
  `)) {
23312
23413
  const trimmed = raw.trim();
@@ -23340,6 +23441,10 @@ function readLedger(cwd, options = {}) {
23340
23441
  reason = "unsigned";
23341
23442
  else
23342
23443
  rowIntegrity = "legacy";
23444
+ if (options.integrity && !reason && ids.has(parsed.id))
23445
+ reason = "duplicate_id";
23446
+ if (options.integrity)
23447
+ ids.add(parsed.id);
23343
23448
  if (reason)
23344
23449
  rowIntegrity = "unverified";
23345
23450
  const pr = typeof parsed.pr === "number" && Number.isInteger(parsed.pr) ? parsed.pr : undefined;
@@ -23363,7 +23468,8 @@ function readLedger(cwd, options = {}) {
23363
23468
  seq: rows.length + 1,
23364
23469
  superseded: false,
23365
23470
  supersedeIgnored: false,
23366
- ...rowIntegrity ? { integrity: rowIntegrity } : {}
23471
+ ...rowIntegrity ? { integrity: rowIntegrity } : {},
23472
+ ...reason ? { integrityReason: reason } : {}
23367
23473
  };
23368
23474
  rows.push(row);
23369
23475
  if (!options.integrity)
@@ -23391,18 +23497,48 @@ function readLedger(cwd, options = {}) {
23391
23497
  const byId = new Map;
23392
23498
  for (const row of rows) {
23393
23499
  const target = row.supersedes ? byId.get(row.supersedes) : undefined;
23394
- if (target && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
23500
+ if (target && row.integrity !== "unverified" && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
23395
23501
  target.superseded = true;
23396
23502
  else if (row.supersedes)
23397
23503
  row.supersedeIgnored = true;
23398
23504
  if (!byId.has(row.id))
23399
23505
  byId.set(row.id, row);
23400
23506
  }
23507
+ if (options.integrity && stat && Buffer.byteLength(text) === stat.size)
23508
+ tamperCache.set(file.value, {
23509
+ size: stat.size,
23510
+ stamp: fileStamp(stat),
23511
+ breaks: integrity.unverified.filter((row) => TAMPER_REASONS.has(row.reason))
23512
+ });
23401
23513
  return {
23402
23514
  ok: true,
23403
23515
  value: { path: file.value, rows, skipped, integrity: options.integrity ? integrity : null }
23404
23516
  };
23405
23517
  }
23518
+ var TAMPER_REASONS = new Set(["hash_mismatch", "broken_link"]);
23519
+ var tamperCache = new Map;
23520
+ var fileStamp = (stat) => `${stat.ino}:${stat.mtimeMs}:${stat.ctimeMs}`;
23521
+ function ledgerTampering(cwd) {
23522
+ const file = ledgerPath(cwd);
23523
+ if (!file.ok)
23524
+ return [];
23525
+ try {
23526
+ const stat = fs12.statSync(file.value);
23527
+ const cached = tamperCache.get(file.value);
23528
+ if (cached && cached.size === stat.size && cached.stamp === fileStamp(stat))
23529
+ return cached.breaks;
23530
+ } catch {
23531
+ return [];
23532
+ }
23533
+ const read = readLedger(cwd, { integrity: true });
23534
+ return read.ok ? (read.value.integrity?.unverified ?? []).filter((row) => TAMPER_REASONS.has(row.reason)) : [];
23535
+ }
23536
+ function tamperedUnblock(cwd) {
23537
+ const file = ledgerPath(cwd);
23538
+ const where = file.ok ? file.value : "the ledger file";
23539
+ 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`;
23540
+ }
23541
+ 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
23542
  function verdictBasis(verdict, current) {
23407
23543
  if (verdict.head && verdict.head === current.head)
23408
23544
  return "fresh";
@@ -23410,7 +23546,7 @@ function verdictBasis(verdict, current) {
23410
23546
  return "carried";
23411
23547
  return "stale";
23412
23548
  }
23413
- var isLiveVerdict = (row) => row.type === "verdict" && typeof row.result === "string" && !row.superseded;
23549
+ var isLiveVerdict = (row, retired) => row.type === "verdict" && typeof row.result === "string" && !retired.has(row.id);
23414
23550
  function trailerSessions(cwd, base, head) {
23415
23551
  if (!base || !head || !safeRef(base) || !safeRef(head))
23416
23552
  return [];
@@ -23491,6 +23627,56 @@ var authoredBy = (authors, session) => {
23491
23627
  return true;
23492
23628
  return false;
23493
23629
  };
23630
+ var TRUST_REASONS = new Set([
23631
+ "unsigned",
23632
+ "hash_mismatch",
23633
+ "broken_link",
23634
+ "duplicate_id",
23635
+ "unissued_session",
23636
+ "unbound_session"
23637
+ ]);
23638
+ var SHELL_VOUCHED_HOSTS = new Set([
23639
+ "cli",
23640
+ "opencode",
23641
+ "pi",
23642
+ "codex_cli",
23643
+ "codex_desktop"
23644
+ ]);
23645
+ function sessionTrust(cwd, row) {
23646
+ const session = row.actor.session;
23647
+ if (!session || row.self === true)
23648
+ return null;
23649
+ const source = typeof row.sessionSource === "string" ? row.sessionSource : "env";
23650
+ const host = row.actor.host;
23651
+ const issuedOnly = source === "flag" ? host !== "cli" : source === "env" && session.includes(":") && !SHELL_VOUCHED_HOSTS.has(host);
23652
+ if (!issuedOnly)
23653
+ return null;
23654
+ const binding = issuedBinding(cwd, session);
23655
+ if (binding === null)
23656
+ return "unissued_session";
23657
+ return binding === "token" && row.sessionBound !== true ? "unbound_session" : null;
23658
+ }
23659
+ function trustReasons(cwd, row) {
23660
+ if (row.integrity === "unverified")
23661
+ return [row.integrityReason ?? "unsigned"];
23662
+ if (row.integrity !== "verified")
23663
+ return ["unsigned"];
23664
+ const session = sessionTrust(cwd, row);
23665
+ return session ? [session] : [];
23666
+ }
23667
+ function withIntegrity(cwd, rows) {
23668
+ if (rows.every((row) => row.integrity !== undefined))
23669
+ return rows;
23670
+ const read = readLedger(cwd, { integrity: true });
23671
+ const bySeq = new Map(read.ok ? read.value.rows.map((row) => [row.seq, row]) : []);
23672
+ return rows.map((row) => {
23673
+ if (row.integrity !== undefined)
23674
+ return row;
23675
+ const fresh = bySeq.get(row.seq);
23676
+ return fresh && fresh.id === row.id && fresh.at === row.at ? fresh : row;
23677
+ });
23678
+ }
23679
+ var untrusted = (reasons) => reasons.some((reason) => TRUST_REASONS.has(reason));
23494
23680
  var independenceReasons = (row, authors) => {
23495
23681
  const reasons = [];
23496
23682
  if (!row.actor.session)
@@ -23501,15 +23687,17 @@ var independenceReasons = (row, authors) => {
23501
23687
  reasons.push("self");
23502
23688
  return reasons;
23503
23689
  };
23504
- function effectiveOf(rows, authors, sameCode, isCurrent) {
23690
+ function effectiveOf(rows, reasonsOf, sameCode, isCurrent) {
23505
23691
  let effective = null;
23506
23692
  for (const row of rows) {
23507
23693
  if (!effective) {
23508
23694
  effective = row;
23509
23695
  continue;
23510
23696
  }
23511
- const rowIndependent = independenceReasons(row, authors).length === 0;
23512
- const effIndependent = independenceReasons(effective, authors).length === 0;
23697
+ if (untrusted(reasonsOf(row)) && !untrusted(reasonsOf(effective)))
23698
+ continue;
23699
+ const rowIndependent = reasonsOf(row).length === 0;
23700
+ const effIndependent = reasonsOf(effective).length === 0;
23513
23701
  if (effIndependent && !rowIndependent && isCurrent(effective))
23514
23702
  continue;
23515
23703
  if (effIndependent && FAILING.has(String(effective.result)) && row.actor.session === effective.actor.session && sameCode(effective, row))
@@ -23523,7 +23711,7 @@ function restackCarries(rows, branch, from, to) {
23523
23711
  return false;
23524
23712
  const edges = new Map;
23525
23713
  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)
23714
+ 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
23715
  edges.set(row.fromHead, [...edges.get(row.fromHead) ?? [], row.head]);
23528
23716
  const seen = new Set([from]);
23529
23717
  const queue = [from];
@@ -23539,7 +23727,8 @@ function restackCarries(rows, branch, from, to) {
23539
23727
  }
23540
23728
  return false;
23541
23729
  }
23542
- function checkVerdicts(cwd, branch, rows) {
23730
+ function checkVerdicts(cwd, branch, ledgerRows) {
23731
+ const rows = withIntegrity(cwd, ledgerRows);
23543
23732
  const head = branchHead(cwd, branch);
23544
23733
  const fallbackBase = defaultBase(cwd);
23545
23734
  const scope = branchScope(cwd, branch);
@@ -23569,21 +23758,47 @@ function checkVerdicts(cwd, branch, rows) {
23569
23758
  return verdictBasis(failed, { head: row.head, ...keys }) !== "stale" || restackCarries(rows, branch, failed.head, row.head);
23570
23759
  };
23571
23760
  const authors = authorSessions(cwd, rows, branch, { base: fallbackBase, head }, scope);
23761
+ const failureAuthorCache = new Map;
23762
+ const failureAuthors = (row) => {
23763
+ let set = failureAuthorCache.get(row.seq);
23764
+ if (!set) {
23765
+ set = authorSessions(cwd, rows.filter((other) => other.integrity === "verified" && other.seq < row.seq), branch, { base: null, head: null }, scope);
23766
+ failureAuthorCache.set(row.seq, set);
23767
+ }
23768
+ return set;
23769
+ };
23770
+ const reasonCache = new Map;
23771
+ const reasonsOf = (row) => {
23772
+ let reasons = reasonCache.get(row);
23773
+ if (!reasons) {
23774
+ const failing = FAILING.has(String(row.result));
23775
+ reasons = [
23776
+ ...trustReasons(cwd, row),
23777
+ ...independenceReasons(row, failing ? failureAuthors(row) : authors)
23778
+ ];
23779
+ reasonCache.set(row, reasons);
23780
+ }
23781
+ return reasons;
23782
+ };
23783
+ const retired = new Set;
23784
+ for (const row of rows)
23785
+ if (row.type === "verdict" && row.supersedes && !row.supersedeIgnored && trustReasons(cwd, row).length === 0)
23786
+ retired.add(row.supersedes);
23572
23787
  const byKind = new Map;
23573
23788
  for (const row of rows)
23574
- if (isLiveVerdict(row) && scope(row)) {
23789
+ if (isLiveVerdict(row, retired) && scope(row)) {
23575
23790
  const kind = typeof row.kind === "string" ? row.kind : "review";
23576
23791
  byKind.set(kind, [...byKind.get(kind) ?? [], row]);
23577
23792
  }
23578
23793
  const verdicts = [];
23579
23794
  const warnings = [];
23580
23795
  for (const [kind, list] of byKind) {
23581
- const row = effectiveOf(list, authors, sameCode, (candidate) => basisOf(candidate) !== "stale");
23796
+ const row = effectiveOf(list, reasonsOf, sameCode, (candidate) => basisOf(candidate) !== "stale");
23582
23797
  if (!row)
23583
23798
  continue;
23584
23799
  const basis = basisOf(row);
23585
23800
  const current = basis !== "stale";
23586
- const independence = independenceReasons(row, authors);
23801
+ const independence = reasonsOf(row);
23587
23802
  const reasons = [
23588
23803
  ...current ? [] : ["stale"],
23589
23804
  ...PASSING.has(String(row.result)) ? [] : ["not_passing"],
@@ -23600,23 +23815,31 @@ function checkVerdicts(cwd, branch, rows) {
23600
23815
  });
23601
23816
  if (reasons.length === 0) {
23602
23817
  for (const later of list)
23603
- if (later.seq > row.seq && independenceReasons(later, authors).length > 0 && FAILING.has(String(later.result)) && basisOf(later) !== "stale")
23818
+ if (later.seq > row.seq && reasonsOf(later).length > 0 && !untrusted(reasonsOf(later)) && FAILING.has(String(later.result)) && basisOf(later) !== "stale")
23604
23819
  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
23820
  }
23606
23821
  }
23607
23822
  for (const row of rows)
23608
23823
  if (row.integrity === "unverified" && scope(row))
23609
23824
  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)`);
23825
+ const tampered = ledgerTampering(cwd);
23826
+ if (tampered.length) {
23827
+ warnings.push(tamperedWarning(cwd, tampered));
23828
+ for (const entry of verdicts) {
23829
+ entry.accepted = false;
23830
+ entry.reasons = [...entry.reasons, "ledger_tampered"];
23831
+ }
23832
+ }
23610
23833
  verdicts.sort((a, b) => a.verdict.seq - b.verdict.seq);
23611
23834
  const newestCurrent = verdicts.findLast((entry) => entry.current) ?? verdicts.at(-1) ?? null;
23612
23835
  const failing = verdicts.find((entry) => entry.current && entry.independent && FAILING.has(String(entry.verdict.result)));
23613
23836
  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: [] } : {
23837
+ const accepted = tampered.length ? { accepted: false, verdict: null, reasons: ["ledger_tampered"] } : newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
23615
23838
  accepted: false,
23616
23839
  verdict: failing?.verdict ?? null,
23617
23840
  reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
23618
23841
  };
23619
- const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && STRONG_RESULTS.has(String(entry.verdict.result)));
23842
+ const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && !untrusted(entry.reasons) && STRONG_RESULTS.has(String(entry.verdict.result)));
23620
23843
  return {
23621
23844
  branch,
23622
23845
  head,
@@ -23779,7 +24002,7 @@ var productDecision = (task, ledger) => {
23779
24002
  };
23780
24003
  };
23781
24004
  var planRecorded = (task, root) => {
23782
- const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path14.resolve(root, ref.path)));
24005
+ const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path15.resolve(root, ref.path)));
23783
24006
  if (cited)
23784
24007
  return {
23785
24008
  met: true,
@@ -23827,15 +24050,15 @@ function derivedRuleStatus(task, requirement, root, ledger) {
23827
24050
  }
23828
24051
 
23829
24052
  // 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("/") || ".";
24053
+ var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
24054
+ var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
24055
+ var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
23833
24056
  var canonicalPath = (value) => {
23834
24057
  if (typeof value !== "string" || !value)
23835
24058
  return null;
23836
24059
  if (value.includes("\\") || value.split("/").includes(".."))
23837
24060
  return null;
23838
- const normalized = path15.posix.normalize(value);
24061
+ const normalized = path16.posix.normalize(value);
23839
24062
  if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
23840
24063
  return null;
23841
24064
  return normalized === "." ? "." : normalized.replace(/\/$/, "");
@@ -23883,21 +24106,21 @@ var gitPaths = (root) => {
23883
24106
  git: !/not a git repository/i.test(stderr)
23884
24107
  };
23885
24108
  }
23886
- const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")) : [];
24109
+ const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
23887
24110
  const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
23888
24111
  if (stagedDeleted.status !== 0) {
23889
24112
  const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
23890
24113
  if (!/not a git repository/i.test(stderr))
23891
24114
  return { paths, uncertain: true, git: true };
23892
24115
  } else if (stagedDeleted.stdout) {
23893
- paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")));
24116
+ paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
23894
24117
  }
23895
24118
  return { paths: [...new Set(paths)], uncertain: false, git: true };
23896
24119
  };
23897
24120
  var walk = (root, directory, output) => {
23898
24121
  let names;
23899
24122
  try {
23900
- names = fs12.readdirSync(directory);
24123
+ names = fs13.readdirSync(directory);
23901
24124
  } catch {
23902
24125
  return true;
23903
24126
  }
@@ -23905,10 +24128,10 @@ var walk = (root, directory, output) => {
23905
24128
  for (const name of names) {
23906
24129
  if (name === ".git" || name === ".workit")
23907
24130
  continue;
23908
- const target = path15.join(directory, name);
24131
+ const target = path16.join(directory, name);
23909
24132
  let stat;
23910
24133
  try {
23911
- stat = fs12.lstatSync(target);
24134
+ stat = fs13.lstatSync(target);
23912
24135
  } catch {
23913
24136
  uncertain = true;
23914
24137
  continue;
@@ -23923,14 +24146,14 @@ var walk = (root, directory, output) => {
23923
24146
  var scopeRoots = (root, scope) => {
23924
24147
  const roots = [];
23925
24148
  for (const item of scope.paths.length ? scope.paths : ["."]) {
23926
- const target = path15.resolve(root, item);
24149
+ const target = path16.resolve(root, item);
23927
24150
  if (!inside(root, target))
23928
24151
  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
24152
  let ancestor = target;
23930
- while (!fs12.existsSync(ancestor) && ancestor !== root)
23931
- ancestor = path15.dirname(ancestor);
24153
+ while (!fs13.existsSync(ancestor) && ancestor !== root)
24154
+ ancestor = path16.dirname(ancestor);
23932
24155
  try {
23933
- if (!inside(root, fs12.realpathSync(ancestor)))
24156
+ if (!inside(root, fs13.realpathSync(ancestor)))
23934
24157
  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
24158
  } catch {
23936
24159
  return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
@@ -23942,7 +24165,7 @@ var scopeRoots = (root, scope) => {
23942
24165
  function captureCandidate(root, scope, environment = []) {
23943
24166
  let checkout;
23944
24167
  try {
23945
- checkout = fs12.realpathSync(root);
24168
+ checkout = fs13.realpathSync(root);
23946
24169
  } catch {
23947
24170
  return failure2("invalid_input", "candidate root does not exist");
23948
24171
  }
@@ -23960,11 +24183,11 @@ function captureCandidate(root, scope, environment = []) {
23960
24183
  if (item === ".git" || item === ".workit")
23961
24184
  continue;
23962
24185
  names.add(item);
23963
- if (!fs12.existsSync(target))
24186
+ if (!fs13.existsSync(target))
23964
24187
  continue;
23965
24188
  let stat;
23966
24189
  try {
23967
- stat = fs12.lstatSync(target);
24190
+ stat = fs13.lstatSync(target);
23968
24191
  } catch {
23969
24192
  uncertain = true;
23970
24193
  continue;
@@ -23980,17 +24203,17 @@ function captureCandidate(root, scope, environment = []) {
23980
24203
  for (const item of [...names].toSorted()) {
23981
24204
  if (!scopeMatches(item, normalizedScope))
23982
24205
  continue;
23983
- const target = path15.join(checkout, item);
24206
+ const target = path16.join(checkout, item);
23984
24207
  try {
23985
- const stat = fs12.lstatSync(target);
24208
+ const stat = fs13.lstatSync(target);
23986
24209
  if (stat.isSymbolicLink()) {
23987
- const link = fs12.readlinkSync(target);
24210
+ const link = fs13.readlinkSync(target);
23988
24211
  files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
23989
24212
  } else if (stat.isFile()) {
23990
24213
  files.push({
23991
24214
  path: item,
23992
24215
  kind: "file",
23993
- digest: digestBytes(fs12.readFileSync(target)),
24216
+ digest: digestBytes(fs13.readFileSync(target)),
23994
24217
  executable: (stat.mode & 73) !== 0
23995
24218
  });
23996
24219
  } else if (!stat.isDirectory()) {
@@ -24155,7 +24378,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
24155
24378
  var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
24156
24379
  let root;
24157
24380
  try {
24158
- root = fs12.realpathSync(checkoutRoot);
24381
+ root = fs13.realpathSync(checkoutRoot);
24159
24382
  } catch {
24160
24383
  return failure2("permission_denied", "checkout root is unavailable");
24161
24384
  }
@@ -24164,23 +24387,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
24164
24387
  continue;
24165
24388
  if (!reference.digest)
24166
24389
  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}`))
24390
+ const target = path16.resolve(root, reference.path);
24391
+ if (target !== root && !target.startsWith(`${root}${path16.sep}`))
24169
24392
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
24170
24393
  fields: [
24171
24394
  { path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
24172
24395
  ]
24173
24396
  });
24174
24397
  try {
24175
- const below = path15.relative(root, target);
24398
+ const below = path16.relative(root, target);
24176
24399
  let current = root;
24177
- for (const segment of below.split(path15.sep)) {
24400
+ for (const segment of below.split(path16.sep)) {
24178
24401
  if (!segment)
24179
24402
  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}`))
24403
+ current = path16.join(current, segment);
24404
+ const stat = fs13.lstatSync(current);
24405
+ const real = fs13.realpathSync(current);
24406
+ if (real !== root && !real.startsWith(`${root}${path16.sep}`))
24184
24407
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
24185
24408
  fields: [
24186
24409
  {
@@ -24196,7 +24419,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
24196
24419
  if (current !== target && !stat.isDirectory())
24197
24420
  return failure2("invalid_input", "document reference ancestor is not a directory");
24198
24421
  }
24199
- if (digestBytes(fs12.readFileSync(target)) !== reference.digest)
24422
+ if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
24200
24423
  return failure2("permission_denied", "decision document bytes have changed");
24201
24424
  } catch {
24202
24425
  return failure2("invalid_input", "decision document is unavailable");
@@ -25054,7 +25277,7 @@ var judgeInputSummary = (raw) => {
25054
25277
 
25055
25278
  // packages/workit-core/src/autonomy.ts
25056
25279
  import os4 from "node:os";
25057
- import path16 from "node:path";
25280
+ import path17 from "node:path";
25058
25281
  var accountHome = () => {
25059
25282
  try {
25060
25283
  return os4.userInfo().homedir;
@@ -25063,10 +25286,10 @@ var accountHome = () => {
25063
25286
  }
25064
25287
  };
25065
25288
  var grantsHome = { resolve: accountHome };
25066
- var grantsDir = () => path16.join(grantsHome.resolve(), ".config", "workit");
25289
+ var grantsDir = () => path17.join(grantsHome.resolve(), ".config", "workit");
25067
25290
  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`;
25291
+ const configured = path17.resolve(resolveConfigDir());
25292
+ 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
25293
  };
25071
25294
  var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
25072
25295
  var DEFAULT_GRANTS = Object.freeze({
@@ -26838,7 +27061,7 @@ class WorkitCore {
26838
27061
  // packages/workit-core/src/core/repo-context.ts
26839
27062
  import { spawnSync as spawnSync11 } from "node:child_process";
26840
27063
  import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
26841
- import path17 from "node:path";
27064
+ import path18 from "node:path";
26842
27065
  var isSafeContextRange = (value) => value.length <= 4096 && (() => {
26843
27066
  try {
26844
27067
  gitRevisionParts(value);
@@ -26972,7 +27195,7 @@ var findPrTemplate = (cwd) => {
26972
27195
  ]) {
26973
27196
  const parts = rel.split("/");
26974
27197
  const base = parts[parts.length - 1];
26975
- const dir = parts.length > 1 ? path17.join(cwd, ...parts.slice(0, -1)) : cwd;
27198
+ const dir = parts.length > 1 ? path18.join(cwd, ...parts.slice(0, -1)) : cwd;
26976
27199
  const actual = probeCaseInsensitive(dir, base);
26977
27200
  if (actual)
26978
27201
  return [...parts.slice(0, -1), actual].join("/");
@@ -27003,7 +27226,7 @@ var diffStatForRange = (cwd, range) => {
27003
27226
  return runGit(cwd, ["diff", "--stat", "--"]).stdout;
27004
27227
  };
27005
27228
  var packageScripts = (cwd, keys) => {
27006
- const pkgPath = path17.join(cwd, "package.json");
27229
+ const pkgPath = path18.join(cwd, "package.json");
27007
27230
  if (!existsSync6(pkgPath))
27008
27231
  return [];
27009
27232
  try {
@@ -27029,9 +27252,9 @@ var documentationFiles = (cwd) => {
27029
27252
  if (entry.isDirectory()) {
27030
27253
  if (excluded.has(entry.name))
27031
27254
  continue;
27032
- walk(path17.join(dir, entry.name), depth + 1);
27255
+ walk(path18.join(dir, entry.name), depth + 1);
27033
27256
  } else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
27034
- matches.push("./" + path17.relative(cwd, path17.join(dir, entry.name)).replaceAll("\\", "/"));
27257
+ matches.push("./" + path18.relative(cwd, path18.join(dir, entry.name)).replaceAll("\\", "/"));
27035
27258
  }
27036
27259
  }
27037
27260
  };
@@ -27047,7 +27270,7 @@ var readTrimmed2 = (file, maxLines) => {
27047
27270
  `);
27048
27271
  };
27049
27272
  function prReadyContext(root, range) {
27050
- const cwd = path17.resolve(repoRoot(root));
27273
+ const cwd = path18.resolve(repoRoot(root));
27051
27274
  if (range !== undefined && !isResolvableContextRange(cwd, range))
27052
27275
  return invalidRange(cwd);
27053
27276
  let stdout = "";
@@ -27105,7 +27328,7 @@ ${status.stderr}` : "");
27105
27328
  stdout += `template_path: ${template}
27106
27329
 
27107
27330
  `;
27108
- stdout += readTrimmed2(path17.join(cwd, template), 220);
27331
+ stdout += readTrimmed2(path18.join(cwd, template), 220);
27109
27332
  } else {
27110
27333
  stdout += `template_path: none
27111
27334
 
@@ -27115,7 +27338,7 @@ ${status.stderr}` : "");
27115
27338
  stdout += `
27116
27339
  `;
27117
27340
  stdout += printSection("Recent Validation Signals");
27118
- if (existsSync6(path17.join(cwd, "package.json"))) {
27341
+ if (existsSync6(path18.join(cwd, "package.json"))) {
27119
27342
  stdout += `package.json detected. Common scripts:
27120
27343
  `;
27121
27344
  const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
@@ -27124,7 +27347,7 @@ ${status.stderr}` : "");
27124
27347
  `) + `
27125
27348
  `;
27126
27349
  }
27127
- if (existsSync6(path17.join(cwd, "Cargo.toml")) || existsSync6(path17.join(cwd, "src-tauri/Cargo.toml"))) {
27350
+ if (existsSync6(path18.join(cwd, "Cargo.toml")) || existsSync6(path18.join(cwd, "src-tauri/Cargo.toml"))) {
27128
27351
  stdout += `Rust project detected.
27129
27352
  `;
27130
27353
  }
@@ -27157,7 +27380,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
27157
27380
  - Apply with the host-native editor, preserving the repository changelog conventions.
27158
27381
  - If Unreleased already has duplicate category headings, normalize_only first.`;
27159
27382
  function changelogContext(root, range) {
27160
- const cwd = path17.resolve(repoRoot(root));
27383
+ const cwd = path18.resolve(repoRoot(root));
27161
27384
  if (range !== undefined && !isResolvableContextRange(cwd, range))
27162
27385
  return invalidRange(cwd);
27163
27386
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -27175,7 +27398,7 @@ function changelogContext(root, range) {
27175
27398
  stdout += CHANGELOG_RULES + `
27176
27399
  `;
27177
27400
  stdout += printSection("Existing CHANGELOG.md");
27178
- const changelogPath = path17.join(cwd, "CHANGELOG.md");
27401
+ const changelogPath = path18.join(cwd, "CHANGELOG.md");
27179
27402
  if (existsSync6(changelogPath)) {
27180
27403
  stdout += readTrimmed2(changelogPath, 260) + `
27181
27404
  `;
@@ -27195,7 +27418,7 @@ function changelogContext(root, range) {
27195
27418
  return { stdout, stderr: "", exitCode: 0, cwd };
27196
27419
  }
27197
27420
  function docsRefreshContext(root, range) {
27198
- const cwd = path17.resolve(repoRoot(root));
27421
+ const cwd = path18.resolve(repoRoot(root));
27199
27422
  if (range !== undefined && !isResolvableContextRange(cwd, range))
27200
27423
  return invalidRange(cwd);
27201
27424
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -27217,7 +27440,7 @@ function docsRefreshContext(root, range) {
27217
27440
  `) + `
27218
27441
  `;
27219
27442
  stdout += printSection("README Preview");
27220
- const readme = path17.join(cwd, "README.md");
27443
+ const readme = path18.join(cwd, "README.md");
27221
27444
  if (existsSync6(readme)) {
27222
27445
  stdout += readTrimmed2(readme, 220) + `
27223
27446
  `;
@@ -27226,7 +27449,7 @@ function docsRefreshContext(root, range) {
27226
27449
  `;
27227
27450
  }
27228
27451
  stdout += printSection("Package Scripts");
27229
- const pkgPath = path17.join(cwd, "package.json");
27452
+ const pkgPath = path18.join(cwd, "package.json");
27230
27453
  if (existsSync6(pkgPath)) {
27231
27454
  try {
27232
27455
  const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
@@ -27240,7 +27463,7 @@ function docsRefreshContext(root, range) {
27240
27463
  return { stdout, stderr: "", exitCode: 0, cwd };
27241
27464
  }
27242
27465
  function releaseNotesContext(root, rangeOrTag) {
27243
- const cwd = path17.resolve(repoRoot(root));
27466
+ const cwd = path18.resolve(repoRoot(root));
27244
27467
  if (!rangeOrTag) {
27245
27468
  return { stdout: "", stderr: `ERROR: release tag or range required
27246
27469
  `, exitCode: 1, cwd };
@@ -27278,7 +27501,7 @@ function releaseNotesContext(root, rangeOrTag) {
27278
27501
  `;
27279
27502
  stdout += printSection("Existing Release Files");
27280
27503
  for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
27281
- if (existsSync6(path17.join(cwd, rel)))
27504
+ if (existsSync6(path18.join(cwd, rel)))
27282
27505
  stdout += rel + `
27283
27506
  `;
27284
27507
  }
@@ -27309,8 +27532,8 @@ function releaseNotesContext(root, rangeOrTag) {
27309
27532
  import { spawnSync as spawnSync13 } from "node:child_process";
27310
27533
 
27311
27534
  // packages/workit-core/src/core/pr-create.ts
27312
- import fs13 from "node:fs";
27313
- import path18 from "node:path";
27535
+ import fs14 from "node:fs";
27536
+ import path19 from "node:path";
27314
27537
  import { spawnSync as spawnSync12 } from "node:child_process";
27315
27538
  // packages/workit-core/src/forge/pr-body.ts
27316
27539
  function parseGhIssue(value) {
@@ -27321,13 +27544,13 @@ function parseGhIssue(value) {
27321
27544
  // packages/workit-core/src/core/pr-create.ts
27322
27545
  function whichOnPath(tool) {
27323
27546
  const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
27324
- for (const dir of (process.env.PATH ?? "").split(path18.delimiter)) {
27547
+ for (const dir of (process.env.PATH ?? "").split(path19.delimiter)) {
27325
27548
  if (!dir)
27326
27549
  continue;
27327
27550
  for (const name of names) {
27328
- const candidate = path18.join(dir, name);
27551
+ const candidate = path19.join(dir, name);
27329
27552
  try {
27330
- fs13.accessSync(candidate, fs13.constants.X_OK);
27553
+ fs14.accessSync(candidate, fs14.constants.X_OK);
27331
27554
  return candidate;
27332
27555
  } catch {}
27333
27556
  }
@@ -27445,8 +27668,8 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
27445
27668
  };
27446
27669
 
27447
27670
  // packages/workit-core/src/core/youtrack.ts
27448
- import fs14 from "node:fs";
27449
- import path19 from "node:path";
27671
+ import fs15 from "node:fs";
27672
+ import path20 from "node:path";
27450
27673
 
27451
27674
  // packages/workit-core/src/core/templates.ts
27452
27675
  var repoRoot2 = assetRoot();
@@ -27459,22 +27682,22 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
27459
27682
  // packages/workit-core/src/core/youtrack.ts
27460
27683
  var ISSUE_RE = /^[A-Z]+-\d+$/;
27461
27684
  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");
27685
+ var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(configDir(), "youtrack.json");
27686
+ var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(resolveConfigDir(), "youtrack.json");
27464
27687
  var youTrackTokenModeOk = (p) => {
27465
27688
  if (process.platform === "win32")
27466
27689
  return true;
27467
- const mode = fs14.statSync(p).mode & 511;
27690
+ const mode = fs15.statSync(p).mode & 511;
27468
27691
  return mode === 384;
27469
27692
  };
27470
27693
  function readYouTrackConfig(required) {
27471
27694
  const cfgPath = youTrackConfigPath();
27472
- if (!fs14.existsSync(cfgPath)) {
27695
+ if (!fs15.existsSync(cfgPath)) {
27473
27696
  return required ? { error: "ERROR: missing youtrack.json", path: cfgPath } : { config: {}, path: cfgPath };
27474
27697
  }
27475
27698
  let parsed;
27476
27699
  try {
27477
- parsed = JSON.parse(fs14.readFileSync(cfgPath, "utf8"));
27700
+ parsed = JSON.parse(fs15.readFileSync(cfgPath, "utf8"));
27478
27701
  } catch {
27479
27702
  return { error: `${cfgPath} is not valid JSON`, path: cfgPath };
27480
27703
  }
@@ -27485,11 +27708,11 @@ function readYouTrackConfig(required) {
27485
27708
  }
27486
27709
  var readYouTrackContextConfig = () => {
27487
27710
  const cfgPath = youTrackReadOnlyConfigPath();
27488
- if (!fs14.existsSync(cfgPath))
27711
+ if (!fs15.existsSync(cfgPath))
27489
27712
  return { data: {} };
27490
27713
  let parsed;
27491
27714
  try {
27492
- parsed = JSON.parse(fs14.readFileSync(cfgPath, "utf8"));
27715
+ parsed = JSON.parse(fs15.readFileSync(cfgPath, "utf8"));
27493
27716
  } catch {
27494
27717
  return { error: "YouTrack configuration is unavailable" };
27495
27718
  }
@@ -27528,12 +27751,12 @@ var youTrackToken = () => {
27528
27751
  if ("error" in loaded)
27529
27752
  return loaded;
27530
27753
  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))
27754
+ const tokenPath = tokenFile ? path20.isAbsolute(tokenFile) ? path20.resolve(tokenFile) : path20.resolve(process.cwd(), tokenFile) : "";
27755
+ if (!tokenPath || !fs15.existsSync(tokenPath))
27533
27756
  return { error: "missing youtrack.token" };
27534
27757
  if (!youTrackTokenModeOk(tokenPath))
27535
27758
  return { error: "youtrack.token mode must be 0600" };
27536
- const token = fs14.readFileSync(tokenPath, "utf8").trim();
27759
+ const token = fs15.readFileSync(tokenPath, "utf8").trim();
27537
27760
  if (!token)
27538
27761
  return { error: "empty token file" };
27539
27762
  if (token === TOKEN_PLACEHOLDER || token.startsWith(TOKEN_PLACEHOLDER)) {
@@ -27598,9 +27821,9 @@ function resolveYouTrackFromPaths(spec_path, plan_path, workspace_root) {
27598
27821
  } catch {
27599
27822
  continue;
27600
27823
  }
27601
- if (!fs14.existsSync(full))
27824
+ if (!fs15.existsSync(full))
27602
27825
  continue;
27603
- const text = fs14.readFileSync(full, "utf8");
27826
+ const text = fs15.readFileSync(full, "utf8");
27604
27827
  const m = text.match(/^\*\*YouTrack:\*\*\s*`?([A-Z]+-\d+)`?/m);
27605
27828
  if (m)
27606
27829
  return m[1];
@@ -27870,15 +28093,15 @@ function resolveGitRevision(root, value) {
27870
28093
  }
27871
28094
  function resolveInside(root, candidate) {
27872
28095
  const base = realpathSync5(root);
27873
- const target = path20.resolve(base, candidate);
27874
- if (target !== base && !target.startsWith(base + path20.sep)) {
28096
+ const target = path21.resolve(base, candidate);
28097
+ if (target !== base && !target.startsWith(base + path21.sep)) {
27875
28098
  throw new Error("path must stay inside repository root");
27876
28099
  }
27877
28100
  let ancestor = target;
27878
28101
  while (!existsSync7(ancestor))
27879
- ancestor = path20.dirname(ancestor);
28102
+ ancestor = path21.dirname(ancestor);
27880
28103
  const canonicalAncestor = realpathSync5(ancestor);
27881
- if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path20.sep)) {
28104
+ if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path21.sep)) {
27882
28105
  throw new Error("path must stay inside repository root");
27883
28106
  }
27884
28107
  return target;
@@ -27936,13 +28159,13 @@ var rootVariants = (workspaceRoot) => {
27936
28159
  if (!workspaceRoot)
27937
28160
  return [];
27938
28161
  const roots = new Set;
27939
- for (const candidate of [workspaceRoot, path21.resolve(workspaceRoot)]) {
27940
- if (path21.isAbsolute(candidate) && candidate !== path21.parse(candidate).root)
28162
+ for (const candidate of [workspaceRoot, path22.resolve(workspaceRoot)]) {
28163
+ if (path22.isAbsolute(candidate) && candidate !== path22.parse(candidate).root)
27941
28164
  roots.add(candidate);
27942
28165
  }
27943
28166
  try {
27944
28167
  const canonical = realpathSync6(workspaceRoot);
27945
- if (canonical !== path21.parse(canonical).root)
28168
+ if (canonical !== path22.parse(canonical).root)
27946
28169
  roots.add(canonical);
27947
28170
  } catch {}
27948
28171
  return [...roots].toSorted((left, right) => right.length - left.length);
@@ -28024,11 +28247,11 @@ var thrownResult = (tool, error, workspaceRoot) => {
28024
28247
  };
28025
28248
  function createMcpServer(host, contextProvider) {
28026
28249
  assertMcpHost(host);
28027
- const here = path21.dirname(fileURLToPath2(import.meta.url));
28250
+ const here = path22.dirname(fileURLToPath2(import.meta.url));
28028
28251
  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")
28252
+ path22.join(here, "server.ts"),
28253
+ path22.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
28254
+ path22.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
28032
28255
  ].filter((file) => existsSync8(file)));
28033
28256
  let staleWarned = false;
28034
28257
  const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
@@ -28208,8 +28431,8 @@ var main = async () => {
28208
28431
  process.exitCode = 2;
28209
28432
  }
28210
28433
  };
28211
- var entryPath = process.argv[1] ? path22.resolve(process.argv[1]) : "";
28212
- if (entryPath === path22.resolve(fileURLToPath3(import.meta.url)))
28434
+ var entryPath = process.argv[1] ? path23.resolve(process.argv[1]) : "";
28435
+ if (entryPath === path23.resolve(fileURLToPath3(import.meta.url)))
28213
28436
  await main();
28214
28437
  // packages/workit-core/src/hooks/descriptor.ts
28215
28438
  var support = (descriptor, axis) => {
@@ -28437,7 +28660,7 @@ var cursorContextProvider = (workspaceRoot = process.env.WORKFLOW_WORKSPACE_ROOT
28437
28660
  var stampCursorSessionStart = (stateDir = resolveStateDir()) => {
28438
28661
  try {
28439
28662
  mkdirSync3(stateDir, { recursive: true });
28440
- writeFileSync3(path23.join(stateDir, "cursor-session-last-start"), `${JSON.stringify({ at: new Date().toISOString() })}
28663
+ writeFileSync3(path24.join(stateDir, "cursor-session-last-start"), `${JSON.stringify({ at: new Date().toISOString() })}
28441
28664
  `);
28442
28665
  } catch {}
28443
28666
  };