@brainervirus/workit-codex 8.9.0 → 8.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,9 +24,9 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
24
24
  };
25
25
  });
26
26
  // packages/workit-core/src/hooks/context.ts
27
- import { createHash as createHash10 } from "node:crypto";
28
- import fs13 from "node:fs";
29
- import path16 from "node:path";
27
+ import { createHash as createHash11 } from "node:crypto";
28
+ import fs14 from "node:fs";
29
+ import path17 from "node:path";
30
30
 
31
31
  // packages/workit-core/src/core/methods.ts
32
32
  var METHODS = {
@@ -101,7 +101,8 @@ Autonomy contract:
101
101
  satisfies a gate; an ad-hoc \`workit check -- <cmd>\` never does.
102
102
  - Author is not verifier: your own verdict is \`--self\`, shown as
103
103
  self-reviewed, never verified. High risk, \`verification: independent\` and
104
- merge need a verifier with its own session (\`WORKIT_SESSION_ID=<lead>-v<n>\`).
104
+ merge need a verifier with its own host-derived session (a subagent's
105
+ \`<lead>:<child>\`, set by the host); never hand-mint one such as \`<lead>-v1\`.
105
106
  - A local-commit endpoint does not imply PR readiness, and a local commit alone
106
107
  is not evidence of a requested remote push. Before reporting delivery,
107
108
  reconcile every requested item and observe it (\`workit verify-delivery\`).
@@ -8787,10 +8788,10 @@ function requirementId(input) {
8787
8788
  }
8788
8789
 
8789
8790
  // packages/workit-core/src/core/task-evaluation.ts
8790
- import { createHash as createHash9 } from "node:crypto";
8791
- import * as fs12 from "node:fs";
8791
+ import { createHash as createHash10 } from "node:crypto";
8792
+ import * as fs13 from "node:fs";
8792
8793
  import { spawnSync as spawnSync10 } from "node:child_process";
8793
- import path14 from "node:path";
8794
+ import path15 from "node:path";
8794
8795
 
8795
8796
  // packages/workit-core/src/check-config.ts
8796
8797
  import { spawnSync as spawnSync2 } from "node:child_process";
@@ -9179,9 +9180,9 @@ function pushRemoteName(cwd, branch) {
9179
9180
  }
9180
9181
 
9181
9182
  // packages/workit-core/src/core/task-store.ts
9182
- import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
9183
- import * as fs9 from "node:fs";
9184
- import path8 from "node:path";
9183
+ import { createHash as createHash6, randomUUID as randomUUID3 } from "node:crypto";
9184
+ import * as fs10 from "node:fs";
9185
+ import path9 from "node:path";
9185
9186
 
9186
9187
  // node_modules/@openclaw/fs-safe/dist/errors.js
9187
9188
  var OPERATIONAL_CODES = new Set([
@@ -9785,6 +9786,9 @@ function acquireFileLockSync(targetPath, options) {
9785
9786
  }
9786
9787
  }
9787
9788
  // packages/workit-core/src/host-session.ts
9789
+ import { createHash as createHash4 } from "node:crypto";
9790
+ import fs7 from "node:fs";
9791
+ import path6 from "node:path";
9788
9792
  var HOST_SESSION_VARS = [
9789
9793
  ["OPENCODE_SESSION_ID", () => "opencode"],
9790
9794
  ["PI_SESSION_ID", () => "pi"],
@@ -9812,16 +9816,44 @@ function hostSessionFromEnv(env) {
9812
9816
  }
9813
9817
  return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
9814
9818
  }
9819
+ var ISSUED_PER_LEAD = 64;
9820
+ var ISSUED_SESSIONS_MARKER = "workit-issued-sessions/1";
9821
+ var hash = (value) => createHash4("sha256").update(value).digest("hex").slice(0, 32);
9822
+ var issuedRoot = (cwd) => {
9823
+ const location = resolveStore(cwd);
9824
+ return location instanceof Error ? null : path6.join(location.dir, "hooks", "issued");
9825
+ };
9826
+ var issuedDir = (cwd, lead) => {
9827
+ const root = issuedRoot(cwd);
9828
+ return root === null ? null : path6.join(root, hash(lead));
9829
+ };
9830
+ function recordIssuedSession(cwd, lead, issued) {
9831
+ try {
9832
+ const dir = issuedDir(cwd, lead);
9833
+ if (!dir)
9834
+ return;
9835
+ fs7.mkdirSync(dir, { recursive: true });
9836
+ const own = hash(issued);
9837
+ fs7.writeFileSync(path6.join(dir, own), ISSUED_SESSIONS_MARKER);
9838
+ const entries = fs7.readdirSync(dir);
9839
+ if (entries.length <= ISSUED_PER_LEAD)
9840
+ return;
9841
+ const byAge = entries.filter((name) => name !== own).map((name) => ({ name, at: fs7.statSync(path6.join(dir, name)).mtimeMs })).toSorted((a, b) => a.at - b.at);
9842
+ for (const { name } of byAge.slice(0, entries.length - ISSUED_PER_LEAD))
9843
+ fs7.rmSync(path6.join(dir, name), { force: true });
9844
+ } catch {}
9845
+ }
9846
+ var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
9815
9847
 
9816
9848
  // packages/workit-core/src/core/package-root.ts
9817
9849
  import { existsSync } from "node:fs";
9818
- import path6 from "node:path";
9850
+ import path7 from "node:path";
9819
9851
  import { fileURLToPath } from "node:url";
9820
9852
  var packageRoot = () => {
9821
- let dir = path6.dirname(fileURLToPath(import.meta.url));
9853
+ let dir = path7.dirname(fileURLToPath(import.meta.url));
9822
9854
  while (true) {
9823
- const parent = path6.dirname(dir);
9824
- if (existsSync(path6.join(dir, "package.json")) || parent === dir)
9855
+ const parent = path7.dirname(dir);
9856
+ if (existsSync(path7.join(dir, "package.json")) || parent === dir)
9825
9857
  return dir;
9826
9858
  dir = parent;
9827
9859
  }
@@ -9829,7 +9861,7 @@ var packageRoot = () => {
9829
9861
 
9830
9862
  // packages/workit-core/src/core/store-lock.ts
9831
9863
  import { spawnSync as spawnSync4 } from "node:child_process";
9832
- import fs7 from "node:fs";
9864
+ import fs8 from "node:fs";
9833
9865
  import { hostname } from "node:os";
9834
9866
  var metadataLockSchema = object({
9835
9867
  pid: number2().int().nonnegative().safe(),
@@ -9871,7 +9903,7 @@ var parseProcStatStart = (stat) => {
9871
9903
  var processStartOf = (pid) => {
9872
9904
  if (process.platform === "linux") {
9873
9905
  try {
9874
- return parseProcStatStart(fs7.readFileSync(`/proc/${pid}/stat`, "utf8"));
9906
+ return parseProcStatStart(fs8.readFileSync(`/proc/${pid}/stat`, "utf8"));
9875
9907
  } catch {
9876
9908
  return null;
9877
9909
  }
@@ -9892,7 +9924,7 @@ var processStartOf = (pid) => {
9892
9924
  };
9893
9925
  var readTrimmed = (file) => {
9894
9926
  try {
9895
- return fs7.readFileSync(file, "utf8").trim() || null;
9927
+ return fs8.readFileSync(file, "utf8").trim() || null;
9896
9928
  } catch {
9897
9929
  return null;
9898
9930
  }
@@ -9903,7 +9935,7 @@ var localLockHost = () => {
9903
9935
  return cachedLockHost;
9904
9936
  let pidns = null;
9905
9937
  try {
9906
- pidns = /\[(\d+)\]/.exec(fs7.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
9938
+ pidns = /\[(\d+)\]/.exec(fs8.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
9907
9939
  } catch {}
9908
9940
  const boot = readTrimmed("/proc/sys/kernel/random/boot_id");
9909
9941
  cachedLockHost = pidns || boot ? `${hostname()}#${pidns ?? "?"}:${boot ?? "?"}` : hostname();
@@ -9949,7 +9981,7 @@ var classifyLockOwner = (payload, ageMs, localHost = localLockHost(), options =
9949
9981
  };
9950
9982
  var ageOf = (file, nowMs) => {
9951
9983
  try {
9952
- return nowMs - fs7.lstatSync(file).mtimeMs;
9984
+ return nowMs - fs8.lstatSync(file).mtimeMs;
9953
9985
  } catch {
9954
9986
  return null;
9955
9987
  }
@@ -9960,7 +9992,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
9960
9992
  if (age === null || age <= RECLAIM_GUARD_TTL_MS)
9961
9993
  return false;
9962
9994
  try {
9963
- fs7.rmdirSync(guard);
9995
+ fs8.rmdirSync(guard);
9964
9996
  return true;
9965
9997
  } catch {
9966
9998
  return false;
@@ -9969,8 +10001,8 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
9969
10001
 
9970
10002
  // packages/workit-core/src/store/event-log.ts
9971
10003
  import { randomUUID as randomUUID2 } from "node:crypto";
9972
- import fs8 from "node:fs";
9973
- import path7 from "node:path";
10004
+ import fs9 from "node:fs";
10005
+ import path8 from "node:path";
9974
10006
  var EVENT_VERSION = 1;
9975
10007
 
9976
10008
  class LogDamage extends Error {
@@ -9999,7 +10031,7 @@ var parseEvent = (line, file, offset) => {
9999
10031
  function readLog(file, from = 0, expectSeq = null) {
10000
10032
  let fd;
10001
10033
  try {
10002
- fd = fs8.openSync(file, "r");
10034
+ fd = fs9.openSync(file, "r");
10003
10035
  } catch (error) {
10004
10036
  if (error.code === "ENOENT")
10005
10037
  return null;
@@ -10008,13 +10040,13 @@ function readLog(file, from = 0, expectSeq = null) {
10008
10040
  let bytes;
10009
10041
  let size;
10010
10042
  try {
10011
- size = fs8.fstatSync(fd).size;
10043
+ size = fs9.fstatSync(fd).size;
10012
10044
  if (from > size)
10013
10045
  throw new LogDamage(`${file}: shorter than its snapshot`);
10014
10046
  bytes = Buffer.alloc(size - from);
10015
10047
  let read = 0;
10016
10048
  while (read < bytes.length) {
10017
- const got = fs8.readSync(fd, bytes, read, bytes.length - read, from + read);
10049
+ const got = fs9.readSync(fd, bytes, read, bytes.length - read, from + read);
10018
10050
  if (got === 0)
10019
10051
  break;
10020
10052
  read += got;
@@ -10022,7 +10054,7 @@ function readLog(file, from = 0, expectSeq = null) {
10022
10054
  bytes = bytes.subarray(0, read);
10023
10055
  size = from + read;
10024
10056
  } finally {
10025
- fs8.closeSync(fd);
10057
+ fs9.closeSync(fd);
10026
10058
  }
10027
10059
  const events = [];
10028
10060
  let start = 0;
@@ -10047,11 +10079,11 @@ function readLog(file, from = 0, expectSeq = null) {
10047
10079
  }
10048
10080
  var fsyncDirectory = (dir) => {
10049
10081
  try {
10050
- const fd = fs8.openSync(dir, "r");
10082
+ const fd = fs9.openSync(dir, "r");
10051
10083
  try {
10052
- fs8.fsyncSync(fd);
10084
+ fs9.fsyncSync(fd);
10053
10085
  } finally {
10054
- fs8.closeSync(fd);
10086
+ fs9.closeSync(fd);
10055
10087
  }
10056
10088
  } catch (error) {
10057
10089
  if (process.platform !== "win32")
@@ -10061,46 +10093,46 @@ var fsyncDirectory = (dir) => {
10061
10093
  function appendEvent(file, event, validEnd) {
10062
10094
  const line = Buffer.from(`${JSON.stringify(event)}
10063
10095
  `, "utf8");
10064
- const created = !fs8.existsSync(file);
10065
- if (!created && fs8.statSync(file).size !== validEnd) {
10066
- const cut = fs8.openSync(file, "r+");
10096
+ const created = !fs9.existsSync(file);
10097
+ if (!created && fs9.statSync(file).size !== validEnd) {
10098
+ const cut = fs9.openSync(file, "r+");
10067
10099
  try {
10068
- fs8.ftruncateSync(cut, validEnd);
10069
- fs8.fsyncSync(cut);
10100
+ fs9.ftruncateSync(cut, validEnd);
10101
+ fs9.fsyncSync(cut);
10070
10102
  } finally {
10071
- fs8.closeSync(cut);
10103
+ fs9.closeSync(cut);
10072
10104
  }
10073
10105
  }
10074
- const fd = fs8.openSync(file, "a", 384);
10106
+ const fd = fs9.openSync(file, "a", 384);
10075
10107
  try {
10076
10108
  let written = 0;
10077
10109
  while (written < line.length)
10078
- written += fs8.writeSync(fd, line, written, line.length - written);
10079
- fs8.fsyncSync(fd);
10110
+ written += fs9.writeSync(fd, line, written, line.length - written);
10111
+ fs9.fsyncSync(fd);
10080
10112
  } finally {
10081
- fs8.closeSync(fd);
10113
+ fs9.closeSync(fd);
10082
10114
  }
10083
10115
  if (created)
10084
- fsyncDirectory(path7.dirname(file));
10116
+ fsyncDirectory(path8.dirname(file));
10085
10117
  return validEnd;
10086
10118
  }
10087
10119
  function replaceFile(file, bytes, durable) {
10088
10120
  const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
10089
10121
  try {
10090
- const fd = fs8.openSync(temporary, "wx", 384);
10122
+ const fd = fs9.openSync(temporary, "wx", 384);
10091
10123
  try {
10092
- fs8.writeSync(fd, bytes);
10124
+ fs9.writeSync(fd, bytes);
10093
10125
  if (durable)
10094
- fs8.fsyncSync(fd);
10126
+ fs9.fsyncSync(fd);
10095
10127
  } finally {
10096
- fs8.closeSync(fd);
10128
+ fs9.closeSync(fd);
10097
10129
  }
10098
10130
  renameWithRetry(temporary, file);
10099
10131
  if (durable)
10100
- fsyncDirectory(path7.dirname(file));
10132
+ fsyncDirectory(path8.dirname(file));
10101
10133
  } catch (error) {
10102
10134
  try {
10103
- fs8.unlinkSync(temporary);
10135
+ fs9.unlinkSync(temporary);
10104
10136
  } catch {}
10105
10137
  throw error;
10106
10138
  }
@@ -10125,7 +10157,7 @@ var retryTransient = (run) => {
10125
10157
  }
10126
10158
  }
10127
10159
  };
10128
- var renameWithRetry = (from, to) => retryTransient(() => fs8.renameSync(from, to));
10160
+ var renameWithRetry = (from, to) => retryTransient(() => fs9.renameSync(from, to));
10129
10161
 
10130
10162
  // packages/workit-core/src/store/patch.ts
10131
10163
  var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -10238,7 +10270,7 @@ var isPatch = (value) => Array.isArray(value) && value.every((op) => {
10238
10270
  });
10239
10271
 
10240
10272
  // packages/workit-core/src/store/reduce.ts
10241
- import { createHash as createHash4 } from "node:crypto";
10273
+ import { createHash as createHash5 } from "node:crypto";
10242
10274
  var OPENING_TYPES = new Set([
10243
10275
  "task.opened",
10244
10276
  "task.imported",
@@ -10267,7 +10299,7 @@ var isObject3 = (value) => typeof value === "object" && value !== null && !Array
10267
10299
  var isKey = (value) => isObject3(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string");
10268
10300
  var BLOB_REF = "$blob";
10269
10301
  var blobRef = (value) => isObject3(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null;
10270
- var blobDigest = (value) => createHash4("sha256").update(JSON.stringify(value)).digest("hex");
10302
+ var blobDigest = (value) => createHash5("sha256").update(JSON.stringify(value)).digest("hex");
10271
10303
  var toBlob = (value, blobs) => {
10272
10304
  if (!isObject3(value))
10273
10305
  return value;
@@ -10422,7 +10454,7 @@ var indexEntry = (task, key, legacy, file) => {
10422
10454
  };
10423
10455
  var fileSignature = (file) => {
10424
10456
  try {
10425
- const stat = fs9.statSync(file, { bigint: true });
10457
+ const stat = fs10.statSync(file, { bigint: true });
10426
10458
  return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
10427
10459
  } catch {
10428
10460
  return null;
@@ -10440,7 +10472,7 @@ var cachedRuntimeVersion = null;
10440
10472
  var runtimeVersion = () => {
10441
10473
  if (cachedRuntimeVersion === null) {
10442
10474
  try {
10443
- const pkg = JSON.parse(fs9.readFileSync(path8.join(packageRoot(), "package.json"), "utf8"));
10475
+ const pkg = JSON.parse(fs10.readFileSync(path9.join(packageRoot(), "package.json"), "utf8"));
10444
10476
  cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
10445
10477
  } catch {
10446
10478
  cachedRuntimeVersion = "0.0.0";
@@ -10464,20 +10496,52 @@ var isNewerVersion = (candidate, current) => {
10464
10496
  return false;
10465
10497
  };
10466
10498
  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);
10499
+ var readText = (file) => {
10500
+ try {
10501
+ return fs10.readFileSync(file, "utf8");
10502
+ } catch {
10503
+ return "";
10504
+ }
10505
+ };
10506
+ var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
10507
+ var branchStart = (location, branch, aliases) => {
10508
+ const first = readText(path9.join(path9.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
10509
+ `, 1)[0];
10510
+ const created = REFLOG_LINE.exec(first);
10511
+ const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
10512
+ if (!created || !start)
10513
+ return null;
10514
+ if (start !== "HEAD")
10515
+ return start;
10516
+ if (!location.git)
10517
+ return null;
10518
+ for (const line of readText(path9.join(location.git.gitDir, "logs", "HEAD")).split(`
10519
+ `)) {
10520
+ const entry = REFLOG_LINE.exec(line);
10521
+ const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
10522
+ const seconds = entry ? Number(entry[2]) - Number(created[2]) : -1;
10523
+ if (moved && entry[1] === created[1] && seconds >= 0 && seconds <= 1 && aliases.includes(moved[2]))
10524
+ return moved[1];
10525
+ }
10526
+ return null;
10527
+ };
10528
+ var refExists = (common, ref) => fs10.existsSync(path9.join(common, ref)) || readText(path9.join(common, "packed-refs")).includes(` ${ref}
10529
+ `);
10530
+ var origins = new Map;
10467
10531
  var sameDirectoryIdentity = (left, right) => {
10468
- if (!path8.isAbsolute(left) || !path8.isAbsolute(right))
10532
+ if (!path9.isAbsolute(left) || !path9.isAbsolute(right))
10469
10533
  return false;
10470
- const normalizedLeft = path8.resolve(left);
10471
- const normalizedRight = path8.resolve(right);
10534
+ const normalizedLeft = path9.resolve(left);
10535
+ const normalizedRight = path9.resolve(right);
10472
10536
  try {
10473
- const a = fs9.statSync(normalizedLeft, { bigint: true });
10474
- const b = fs9.statSync(normalizedRight, { bigint: true });
10537
+ const a = fs10.statSync(normalizedLeft, { bigint: true });
10538
+ const b = fs10.statSync(normalizedRight, { bigint: true });
10475
10539
  if (!a.isDirectory() || !b.isDirectory())
10476
10540
  return false;
10477
10541
  if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
10478
10542
  return true;
10479
- const canonicalLeft = fs9.realpathSync(normalizedLeft);
10480
- const canonicalRight = fs9.realpathSync(normalizedRight);
10543
+ const canonicalLeft = fs10.realpathSync(normalizedLeft);
10544
+ const canonicalRight = fs10.realpathSync(normalizedRight);
10481
10545
  if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
10482
10546
  return true;
10483
10547
  return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
@@ -10514,8 +10578,8 @@ class TaskStore {
10514
10578
  migrationChecked = false;
10515
10579
  compactDue = new Set;
10516
10580
  constructor(root, options = {}) {
10517
- const resolved = path8.resolve(root);
10518
- this.origin = fs9.existsSync(resolved) ? fs9.realpathSync(resolved) : resolved;
10581
+ const resolved = path9.resolve(root);
10582
+ this.origin = fs10.existsSync(resolved) ? fs10.realpathSync(resolved) : resolved;
10519
10583
  this.located = resolveStore(this.origin);
10520
10584
  this.root = checkoutRootOf(this.origin, this.located);
10521
10585
  this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
@@ -10523,7 +10587,7 @@ class TaskStore {
10523
10587
  this.migrateOnRead = options.migrateOnRead;
10524
10588
  }
10525
10589
  location() {
10526
- if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs9.existsSync(path8.join(this.root, ".git"))) {
10590
+ if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs10.existsSync(path9.join(this.root, ".git"))) {
10527
10591
  this.located = undefined;
10528
10592
  this.migrationChecked = false;
10529
10593
  }
@@ -10587,7 +10651,7 @@ class TaskStore {
10587
10651
  const tasksDir = this.paths().tasks;
10588
10652
  let names;
10589
10653
  try {
10590
- names = fs9.existsSync(tasksDir) ? fs9.readdirSync(tasksDir).filter((name) => validId(name)) : [];
10654
+ names = fs10.existsSync(tasksDir) ? fs10.readdirSync(tasksDir).filter((name) => validId(name)) : [];
10591
10655
  } catch (error) {
10592
10656
  return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
10593
10657
  path: tasksDir
@@ -10628,7 +10692,7 @@ class TaskStore {
10628
10692
  const file = this.paths().workspace;
10629
10693
  let bytes;
10630
10694
  try {
10631
- bytes = retryTransient(() => fs9.readFileSync(file, "utf8"));
10695
+ bytes = retryTransient(() => fs10.readFileSync(file, "utf8"));
10632
10696
  } catch (error) {
10633
10697
  if (error.code === "ENOENT")
10634
10698
  return success(null, null, null);
@@ -10679,7 +10743,7 @@ class TaskStore {
10679
10743
  const moved = this.bindLocked(again.data.id, key, input.now);
10680
10744
  return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
10681
10745
  }
10682
- const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path8.basename(this.root) || this.root;
10746
+ const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path9.basename(this.root) || this.root;
10683
10747
  const intent = {
10684
10748
  objective: input.objective?.trim() || `Work on ${label}`,
10685
10749
  scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
@@ -10716,6 +10780,66 @@ class TaskStore {
10716
10780
  return bound;
10717
10781
  return success(null, null, { key: key.data, bound: bound.data });
10718
10782
  }
10783
+ taskForWorker(workerId) {
10784
+ if (typeof workerId !== "string" || !validId(workerId))
10785
+ return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
10786
+ const listed = this.listTaskIndex();
10787
+ if (!listed.ok)
10788
+ return listed;
10789
+ for (const entry of listed.data) {
10790
+ if (entry.status === "closed")
10791
+ continue;
10792
+ const loaded = this.load(entry.id);
10793
+ if (!loaded.ok)
10794
+ return loaded;
10795
+ if (loaded.data?.record.workers.some((worker) => worker.id === workerId))
10796
+ return success(null, null, entry.id);
10797
+ }
10798
+ return success(null, null, null);
10799
+ }
10800
+ originTaskEntry() {
10801
+ const key = this.currentKey();
10802
+ const location = this.location();
10803
+ const branch = key.ok ? key.data.branch : null;
10804
+ if (!branch || !location.ok)
10805
+ return success(null, null, null);
10806
+ const common = path9.dirname(location.data.dir);
10807
+ const heads = path9.join(common, "logs", "refs", "heads");
10808
+ const headLog = location.data.git ? path9.join(location.data.git.gitDir, "logs", "HEAD") : "";
10809
+ const signatures = [
10810
+ path9.join(heads, branch),
10811
+ headLog,
10812
+ heads,
10813
+ path9.join(common, "packed-refs")
10814
+ ].map((file) => fileSignature(file) ?? "-");
10815
+ const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
10816
+ let resolved = origins.get(slot);
10817
+ if (resolved?.signature !== signatures.join("|")) {
10818
+ const renames = branchRenames(location.data);
10819
+ const aliases = [branch];
10820
+ for (const rename of renames.toReversed())
10821
+ if (rename.to === aliases.at(-1))
10822
+ aliases.push(rename.from);
10823
+ const start = branchStart(location.data, branch, aliases);
10824
+ const slash = start?.indexOf("/") ?? -1;
10825
+ const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path9.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
10826
+ const name = start && (remote ? start.slice(slash + 1) : start);
10827
+ resolved = {
10828
+ signature: signatures.join("|"),
10829
+ name: name && !aliases.includes(name) ? name : null,
10830
+ renames
10831
+ };
10832
+ origins.set(slot, resolved);
10833
+ }
10834
+ const entry = resolved.name ? this.openTasksForKey(resolved.name, resolved.renames) : null;
10835
+ if (entry && !entry.ok)
10836
+ return entry;
10837
+ return success(null, null, entry?.data[0] ? { origin: `branch ${resolved.name}`, entry: entry.data[0] } : null);
10838
+ }
10839
+ readStoreTask(taskId) {
10840
+ const loaded = this.load(taskId);
10841
+ return loaded.ok ? success(null, null, loaded.data?.record ?? null) : loaded;
10842
+ }
10719
10843
  create(input, provenance, expectedWorkspaceRevision) {
10720
10844
  const value = "intent" in input ? input : {
10721
10845
  intent: input,
@@ -10936,13 +11060,13 @@ class TaskStore {
10936
11060
  if (!ready.ok)
10937
11061
  return ready;
10938
11062
  const dirs = this.paths();
10939
- const recovery = path8.join(this.root, ".workit", "recovery");
10940
- if (fs9.existsSync(recovery)) {
11063
+ const recovery = path9.join(this.root, ".workit", "recovery");
11064
+ if (fs10.existsSync(recovery)) {
10941
11065
  let files = 0;
10942
11066
  let bytes = 0;
10943
11067
  try {
10944
- for (const name of fs9.readdirSync(recovery)) {
10945
- const stat = fs9.lstatSync(path8.join(recovery, name));
11068
+ for (const name of fs10.readdirSync(recovery)) {
11069
+ const stat = fs10.lstatSync(path9.join(recovery, name));
10946
11070
  if (!stat.isFile())
10947
11071
  continue;
10948
11072
  files += 1;
@@ -10951,17 +11075,17 @@ class TaskStore {
10951
11075
  } catch {}
10952
11076
  const remove = options.pruneRecovery === true && !dryRun;
10953
11077
  if (remove)
10954
- fs9.rmSync(recovery, { recursive: true, force: true });
11078
+ fs10.rmSync(recovery, { recursive: true, force: true });
10955
11079
  report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
10956
11080
  }
10957
- if (!fs9.existsSync(dirs.tasks))
11081
+ if (!fs10.existsSync(dirs.tasks))
10958
11082
  return success(null, null, report);
10959
- const names = fs9.readdirSync(dirs.tasks).filter((name) => validId(name));
11083
+ const names = fs10.readdirSync(dirs.tasks).filter((name) => validId(name));
10960
11084
  for (const name of names) {
10961
11085
  const file = this.eventsPath(name);
10962
11086
  let size = 0;
10963
11087
  try {
10964
- size = fs9.statSync(file).size;
11088
+ size = fs10.statSync(file).size;
10965
11089
  } catch {
10966
11090
  continue;
10967
11091
  }
@@ -10989,16 +11113,16 @@ class TaskStore {
10989
11113
  const references = new Set;
10990
11114
  for (const name of names)
10991
11115
  try {
10992
- for (const match of fs9.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
11116
+ for (const match of fs10.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
10993
11117
  references.add(match[1]);
10994
11118
  } catch {}
10995
- if (fs9.existsSync(dirs.blobs))
10996
- for (const name of fs9.readdirSync(dirs.blobs)) {
11119
+ if (fs10.existsSync(dirs.blobs))
11120
+ for (const name of fs10.readdirSync(dirs.blobs)) {
10997
11121
  const digest = name.replace(/\.json$/, "");
10998
- const file = path8.join(dirs.blobs, name);
11122
+ const file = path9.join(dirs.blobs, name);
10999
11123
  let stat;
11000
11124
  try {
11001
- stat = fs9.lstatSync(file);
11125
+ stat = fs10.lstatSync(file);
11002
11126
  } catch {
11003
11127
  continue;
11004
11128
  }
@@ -11009,11 +11133,11 @@ class TaskStore {
11009
11133
  report.blobs.removed += 1;
11010
11134
  report.blobs.removedBytes += stat.size;
11011
11135
  if (!dryRun)
11012
- fs9.rmSync(file, { force: true });
11136
+ fs10.rmSync(file, { force: true });
11013
11137
  }
11014
11138
  return success(null, null, null);
11015
11139
  };
11016
- const swept = dryRun ? sweep() : this.withLock(path8.join(dirs.dir, "gc.lock"), sweep);
11140
+ const swept = dryRun ? sweep() : this.withLock(path9.join(dirs.dir, "gc.lock"), sweep);
11017
11141
  if (!swept.ok)
11018
11142
  return swept;
11019
11143
  const temporaryDirs = [
@@ -11021,17 +11145,17 @@ class TaskStore {
11021
11145
  dirs.tasks,
11022
11146
  dirs.blobs,
11023
11147
  dirs.checkout,
11024
- ...names.map((name) => path8.join(dirs.tasks, name))
11148
+ ...names.map((name) => path9.join(dirs.tasks, name))
11025
11149
  ];
11026
11150
  for (const directory of temporaryDirs) {
11027
- if (!fs9.existsSync(directory))
11151
+ if (!fs10.existsSync(directory))
11028
11152
  continue;
11029
- for (const name of fs9.readdirSync(directory)) {
11153
+ for (const name of fs10.readdirSync(directory)) {
11030
11154
  if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
11031
11155
  continue;
11032
- const file = path8.join(directory, name);
11156
+ const file = path9.join(directory, name);
11033
11157
  try {
11034
- const stat = fs9.lstatSync(file);
11158
+ const stat = fs10.lstatSync(file);
11035
11159
  if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
11036
11160
  continue;
11037
11161
  } catch {
@@ -11039,37 +11163,37 @@ class TaskStore {
11039
11163
  }
11040
11164
  report.temporary.removed += 1;
11041
11165
  if (!dryRun)
11042
- fs9.rmSync(file, { force: true });
11166
+ fs10.rmSync(file, { force: true });
11043
11167
  }
11044
11168
  }
11045
11169
  return success(null, null, report);
11046
11170
  }
11047
11171
  paths() {
11048
11172
  const location = this.location();
11049
- const dir = location.ok ? location.data.dir : path8.join(this.root, ".workit");
11050
- const checkout = path8.join(dir, "checkouts", checkoutSlug(this.root));
11173
+ const dir = location.ok ? location.data.dir : path9.join(this.root, ".workit");
11174
+ const checkout = path9.join(dir, "checkouts", checkoutSlug(this.root));
11051
11175
  return {
11052
11176
  dir,
11053
11177
  shared: location.ok ? location.data.shared : false,
11054
- marker: path8.join(dir, "store.json"),
11178
+ marker: path9.join(dir, "store.json"),
11055
11179
  checkout,
11056
- workspace: path8.join(checkout, "workspace.json"),
11057
- checkoutLock: path8.join(checkout, "metadata.lock"),
11058
- tasks: path8.join(dir, "tasks"),
11059
- index: path8.join(dir, "task-index.json"),
11060
- blobs: path8.join(dir, "blobs", "candidates"),
11061
- legacy: path8.join(dir, "legacy", checkoutSlug(this.root), "v2"),
11062
- v2: path8.join(this.root, ".workit")
11180
+ workspace: path9.join(checkout, "workspace.json"),
11181
+ checkoutLock: path9.join(checkout, "metadata.lock"),
11182
+ tasks: path9.join(dir, "tasks"),
11183
+ index: path9.join(dir, "task-index.json"),
11184
+ blobs: path9.join(dir, "blobs", "candidates"),
11185
+ legacy: path9.join(dir, "legacy", checkoutSlug(this.root), "v2"),
11186
+ v2: path9.join(this.root, ".workit")
11063
11187
  };
11064
11188
  }
11065
11189
  eventsPath(taskId) {
11066
- return path8.join(this.paths().tasks, taskId, "events.jsonl");
11190
+ return path9.join(this.paths().tasks, taskId, "events.jsonl");
11067
11191
  }
11068
11192
  snapshotPath(taskId) {
11069
- return path8.join(this.paths().tasks, taskId, "snapshot.json");
11193
+ return path9.join(this.paths().tasks, taskId, "snapshot.json");
11070
11194
  }
11071
11195
  taskLockPath(taskId) {
11072
- return path8.join(this.paths().tasks, taskId, "lock");
11196
+ return path9.join(this.paths().tasks, taskId, "lock");
11073
11197
  }
11074
11198
  ready(write = false) {
11075
11199
  const location = this.location();
@@ -11079,7 +11203,7 @@ class TaskStore {
11079
11203
  return success(null, null, null);
11080
11204
  const dirs = this.paths();
11081
11205
  try {
11082
- const marker = JSON.parse(fs9.readFileSync(dirs.marker, "utf8"));
11206
+ const marker = JSON.parse(fs10.readFileSync(dirs.marker, "utf8"));
11083
11207
  if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
11084
11208
  return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
11085
11209
  } catch {}
@@ -11108,21 +11232,21 @@ class TaskStore {
11108
11232
  return {
11109
11233
  read: (digest) => {
11110
11234
  try {
11111
- return JSON.parse(fs9.readFileSync(path8.join(dir, `${digest}.json`), "utf8"));
11235
+ return JSON.parse(fs10.readFileSync(path9.join(dir, `${digest}.json`), "utf8"));
11112
11236
  } catch (error) {
11113
11237
  throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
11114
11238
  }
11115
11239
  },
11116
11240
  write: (digest, value) => {
11117
- const file = path8.join(dir, `${digest}.json`);
11118
- if (fs9.existsSync(file)) {
11241
+ const file = path9.join(dir, `${digest}.json`);
11242
+ if (fs10.existsSync(file)) {
11119
11243
  const stamp = new Date;
11120
11244
  try {
11121
- fs9.utimesSync(file, stamp, stamp);
11245
+ fs10.utimesSync(file, stamp, stamp);
11122
11246
  return;
11123
11247
  } catch {}
11124
11248
  }
11125
- fs9.mkdirSync(dir, { recursive: true });
11249
+ fs10.mkdirSync(dir, { recursive: true });
11126
11250
  replaceFile(file, JSON.stringify(value), true);
11127
11251
  }
11128
11252
  };
@@ -11204,7 +11328,7 @@ class TaskStore {
11204
11328
  }
11205
11329
  readSnapshot(taskId) {
11206
11330
  try {
11207
- const value = JSON.parse(fs9.readFileSync(this.snapshotPath(taskId), "utf8"));
11331
+ const value = JSON.parse(fs10.readFileSync(this.snapshotPath(taskId), "utf8"));
11208
11332
  if (!isObject4(value) || value.v !== 1 || value.task !== taskId || typeof value.seq !== "number" || typeof value.lastId !== "string" || typeof value.lastStart !== "number" || typeof value.end !== "number" || !isObject4(value.record))
11209
11333
  return null;
11210
11334
  return value;
@@ -11306,8 +11430,8 @@ class TaskStore {
11306
11430
  }
11307
11431
  }
11308
11432
  openTask(record, type, key, legacy = null) {
11309
- const dir = path8.join(this.paths().tasks, record.id);
11310
- fs9.mkdirSync(dir, { recursive: true });
11433
+ const dir = path9.join(this.paths().tasks, record.id);
11434
+ fs10.mkdirSync(dir, { recursive: true });
11311
11435
  const blobs = this.blobStore();
11312
11436
  const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
11313
11437
  const event = this.event(record.id, 1, type, {
@@ -11359,11 +11483,11 @@ class TaskStore {
11359
11483
  } catch {}
11360
11484
  if (!latest || latest.events[0]?.id !== last.id)
11361
11485
  return failure2("busy", "the task log changed during compaction; retry", { taskId });
11362
- const appended = fs9.readFileSync(file).subarray(log.end, latest.end);
11486
+ const appended = fs10.readFileSync(file).subarray(log.end, latest.end);
11363
11487
  const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
11364
11488
  replaceFile(file, bytes.toString("utf8"), true);
11365
11489
  try {
11366
- fs9.rmSync(this.snapshotPath(taskId), { force: true });
11490
+ fs10.rmSync(this.snapshotPath(taskId), { force: true });
11367
11491
  } catch {}
11368
11492
  const reloaded = this.load(taskId);
11369
11493
  if (reloaded.ok && reloaded.data)
@@ -11376,7 +11500,7 @@ class TaskStore {
11376
11500
  }
11377
11501
  countEvents(file) {
11378
11502
  try {
11379
- const bytes = fs9.readFileSync(file);
11503
+ const bytes = fs10.readFileSync(file);
11380
11504
  let count = 0;
11381
11505
  for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
11382
11506
  count += 1;
@@ -11385,12 +11509,12 @@ class TaskStore {
11385
11509
  return 0;
11386
11510
  }
11387
11511
  }
11388
- openTasksForKey(key) {
11512
+ openTasksForKey(key, known) {
11389
11513
  const all = this.listStoreIndex();
11390
11514
  if (!all.ok)
11391
11515
  return all;
11392
- const location = this.location();
11393
- const renames = location.ok ? branchRenames(location.data) : [];
11516
+ const location = known ? null : this.location();
11517
+ const renames = known ?? (location?.ok ? branchRenames(location.data) : []);
11394
11518
  return success(null, null, all.data.filter((entry) => entry.key !== null && entry.status !== "closed").filter((entry) => (renames.length ? followRenames(entry.key, entry.boundAt ?? entry.createdAt, renames) : entry.key) === key).toSorted(oldestFirst));
11395
11519
  }
11396
11520
  openTaskForKey(key) {
@@ -11398,8 +11522,8 @@ class TaskStore {
11398
11522
  return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
11399
11523
  }
11400
11524
  withKeyLock(key, operation) {
11401
- const digest = createHash5("sha256").update(key).digest("hex").slice(0, 32);
11402
- return this.withLock(path8.join(this.paths().dir, "keys", `${digest}.lock`), operation);
11525
+ const digest = createHash6("sha256").update(key).digest("hex").slice(0, 32);
11526
+ return this.withLock(path9.join(this.paths().dir, "keys", `${digest}.lock`), operation);
11403
11527
  }
11404
11528
  bindLocked(taskId, key, timestamp) {
11405
11529
  const current = this.readWorkspace();
@@ -11540,7 +11664,7 @@ class TaskStore {
11540
11664
  writeWorkspace(record) {
11541
11665
  const file = this.paths().workspace;
11542
11666
  try {
11543
- fs9.mkdirSync(path8.dirname(file), { recursive: true });
11667
+ fs10.mkdirSync(path9.dirname(file), { recursive: true });
11544
11668
  replaceFile(file, `${canonicalJson(record)}
11545
11669
  `, true);
11546
11670
  return success(null, null, null);
@@ -11550,7 +11674,7 @@ class TaskStore {
11550
11674
  }
11551
11675
  readIndex() {
11552
11676
  try {
11553
- const value = JSON.parse(fs9.readFileSync(this.paths().index, "utf8"));
11677
+ const value = JSON.parse(fs10.readFileSync(this.paths().index, "utf8"));
11554
11678
  if (!isObject4(value) || value.version !== INDEX_VERSION || !isObject4(value.tasks))
11555
11679
  return {};
11556
11680
  const tasks = {};
@@ -11564,7 +11688,7 @@ class TaskStore {
11564
11688
  }
11565
11689
  writeIndex(entries) {
11566
11690
  try {
11567
- fs9.mkdirSync(this.paths().tasks, { recursive: true });
11691
+ fs10.mkdirSync(this.paths().tasks, { recursive: true });
11568
11692
  replaceFile(this.paths().index, JSON.stringify({
11569
11693
  version: INDEX_VERSION,
11570
11694
  tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
@@ -11618,23 +11742,23 @@ class TaskStore {
11618
11742
  return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
11619
11743
  }
11620
11744
  v2Dirs() {
11621
- return [...new Set([this.root, this.origin])].map((dir) => path8.join(dir, ".workit"));
11745
+ return [...new Set([this.root, this.origin])].map((dir) => path9.join(dir, ".workit"));
11622
11746
  }
11623
11747
  pendingMigrations() {
11624
11748
  return this.v2Dirs().filter((dir) => {
11625
- const raw = this.readV2Workspace(path8.join(dir, "workspace.json"));
11749
+ const raw = this.readV2Workspace(path9.join(dir, "workspace.json"));
11626
11750
  return raw !== null && raw !== TOMBSTONE;
11627
11751
  });
11628
11752
  }
11629
11753
  migrateV2(v2) {
11630
11754
  const dirs = this.paths();
11631
- const v2Workspace = path8.join(v2, "workspace.json");
11632
- const v2Tasks = path8.join(v2, "tasks");
11633
- const legacy = path8.join(dirs.dir, "legacy", checkoutSlug(path8.dirname(v2)), "v2");
11755
+ const v2Workspace = path9.join(v2, "workspace.json");
11756
+ const v2Tasks = path9.join(v2, "tasks");
11757
+ const legacy = path9.join(dirs.dir, "legacy", checkoutSlug(path9.dirname(v2)), "v2");
11634
11758
  const raw = this.readV2Workspace(v2Workspace);
11635
11759
  if (raw === null || raw === TOMBSTONE)
11636
11760
  return success(null, null, null);
11637
- return this.withLock(dirs.checkoutLock, () => this.withLock(path8.join(v2, "metadata.lock"), () => {
11761
+ return this.withLock(dirs.checkoutLock, () => this.withLock(path9.join(v2, "metadata.lock"), () => {
11638
11762
  const workspace = this.readV2Workspace(v2Workspace);
11639
11763
  if (workspace === null || workspace === TOMBSTONE)
11640
11764
  return success(null, null, null);
@@ -11643,7 +11767,7 @@ class TaskStore {
11643
11767
  return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
11644
11768
  let files = [];
11645
11769
  try {
11646
- files = fs9.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path8.join(v2Tasks, name)));
11770
+ files = fs10.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path9.join(v2Tasks, name)));
11647
11771
  } catch {}
11648
11772
  const current = this.readWorkspace();
11649
11773
  if (!current.ok)
@@ -11661,22 +11785,22 @@ class TaskStore {
11661
11785
  let skipped = 0;
11662
11786
  const done = new Map;
11663
11787
  try {
11664
- fs9.mkdirSync(path8.join(legacy, "tasks"), { recursive: true });
11788
+ fs10.mkdirSync(path9.join(legacy, "tasks"), { recursive: true });
11665
11789
  for (const name of ["workspace.json", "index.json"])
11666
- if (fs9.existsSync(path8.join(v2, name)))
11667
- fs9.copyFileSync(path8.join(v2, name), path8.join(legacy, name));
11790
+ if (fs10.existsSync(path9.join(v2, name)))
11791
+ fs10.copyFileSync(path9.join(v2, name), path9.join(legacy, name));
11668
11792
  for (const name of files) {
11669
11793
  const id = name.slice(0, -5);
11670
- const file = path8.join(v2Tasks, name);
11671
- const bytes = fs9.readFileSync(file, "utf8");
11794
+ const file = path9.join(v2Tasks, name);
11795
+ const bytes = fs10.readFileSync(file, "utf8");
11672
11796
  const digest = sha256(bytes);
11673
- fs9.writeFileSync(path8.join(legacy, "tasks", name), bytes);
11797
+ fs10.writeFileSync(path9.join(legacy, "tasks", name), bytes);
11674
11798
  const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
11675
11799
  if (!parsed.ok || parsed.data.id !== id)
11676
11800
  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 });
11677
11801
  const record = { ...parsed.data, workspaceId: target.id };
11678
- const origin = { path: path8.join(legacy, "tasks", name), digest };
11679
- if (!fs9.existsSync(this.eventsPath(id))) {
11802
+ const origin = { path: path9.join(legacy, "tasks", name), digest };
11803
+ if (!fs10.existsSync(this.eventsPath(id))) {
11680
11804
  this.openTask(record, "migrated.from_v2", null, origin);
11681
11805
  migrated += 1;
11682
11806
  } else {
@@ -11711,8 +11835,8 @@ class TaskStore {
11711
11835
  try {
11712
11836
  let complete = true;
11713
11837
  for (const [name, digest] of done) {
11714
- const file = path8.join(v2Tasks, name);
11715
- if (sha256(fs9.readFileSync(file, "utf8")) !== digest) {
11838
+ const file = path9.join(v2Tasks, name);
11839
+ if (sha256(fs10.readFileSync(file, "utf8")) !== digest) {
11716
11840
  complete = false;
11717
11841
  continue;
11718
11842
  }
@@ -11722,7 +11846,7 @@ class TaskStore {
11722
11846
  return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
11723
11847
  path: v2
11724
11848
  });
11725
- fs9.rmSync(path8.join(v2, "index.json"), { force: true });
11849
+ fs10.rmSync(path9.join(v2, "index.json"), { force: true });
11726
11850
  this.writeTombstone(v2, target.id);
11727
11851
  } catch (error) {
11728
11852
  return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
@@ -11742,45 +11866,45 @@ class TaskStore {
11742
11866
  }
11743
11867
  adoptLocalStore() {
11744
11868
  const dirs = this.paths();
11745
- const marker = path8.join(dirs.v2, "store.json");
11746
- if (!dirs.shared || !fs9.existsSync(marker))
11869
+ const marker = path9.join(dirs.v2, "store.json");
11870
+ if (!dirs.shared || !fs10.existsSync(marker))
11747
11871
  return success(null, null, null);
11748
11872
  return this.withLock(dirs.checkoutLock, () => {
11749
- if (!fs9.existsSync(marker))
11873
+ if (!fs10.existsSync(marker))
11750
11874
  return success(null, null, null);
11751
11875
  let tasks = 0;
11752
11876
  try {
11753
11877
  const merge = (from, to) => {
11754
- if (!fs9.existsSync(to)) {
11755
- fs9.mkdirSync(path8.dirname(to), { recursive: true });
11878
+ if (!fs10.existsSync(to)) {
11879
+ fs10.mkdirSync(path9.dirname(to), { recursive: true });
11756
11880
  try {
11757
- fs9.renameSync(from, to);
11881
+ fs10.renameSync(from, to);
11758
11882
  } catch {
11759
- fs9.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
11760
- fs9.rmSync(from, { recursive: true, force: true });
11883
+ fs10.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
11884
+ fs10.rmSync(from, { recursive: true, force: true });
11761
11885
  }
11762
11886
  return;
11763
11887
  }
11764
- if (fs9.lstatSync(from).isDirectory() && fs9.lstatSync(to).isDirectory())
11765
- for (const name of fs9.readdirSync(from))
11766
- merge(path8.join(from, name), path8.join(to, name));
11888
+ if (fs10.lstatSync(from).isDirectory() && fs10.lstatSync(to).isDirectory())
11889
+ for (const name of fs10.readdirSync(from))
11890
+ merge(path9.join(from, name), path9.join(to, name));
11767
11891
  };
11768
11892
  for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
11769
- const from = path8.join(dirs.v2, sub);
11770
- if (!fs9.existsSync(from))
11893
+ const from = path9.join(dirs.v2, sub);
11894
+ if (!fs10.existsSync(from))
11771
11895
  continue;
11772
11896
  if (sub === "tasks") {
11773
- for (const name of fs9.readdirSync(from))
11774
- if (validId(name) && !fs9.existsSync(path8.join(dirs.dir, sub, name)))
11897
+ for (const name of fs10.readdirSync(from))
11898
+ if (validId(name) && !fs10.existsSync(path9.join(dirs.dir, sub, name)))
11775
11899
  tasks += 1;
11776
11900
  }
11777
- merge(from, path8.join(dirs.dir, sub));
11901
+ merge(from, path9.join(dirs.dir, sub));
11778
11902
  }
11779
- const ledger = path8.join(dirs.v2, "ledger");
11780
- if (fs9.existsSync(ledger) && !fs9.existsSync(path8.join(dirs.dir, "ledger")))
11781
- merge(ledger, path8.join(dirs.dir, "ledger"));
11782
- fs9.rmSync(path8.join(dirs.v2, "task-index.json"), { force: true });
11783
- fs9.renameSync(marker, path8.join(dirs.v2, "store.moved.json"));
11903
+ const ledger = path9.join(dirs.v2, "ledger");
11904
+ if (fs10.existsSync(ledger) && !fs10.existsSync(path9.join(dirs.dir, "ledger")))
11905
+ merge(ledger, path9.join(dirs.dir, "ledger"));
11906
+ fs10.rmSync(path9.join(dirs.v2, "task-index.json"), { force: true });
11907
+ fs10.renameSync(marker, path9.join(dirs.v2, "store.moved.json"));
11784
11908
  } catch (error) {
11785
11909
  return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
11786
11910
  path: dirs.v2
@@ -11800,7 +11924,7 @@ class TaskStore {
11800
11924
  readV2Workspace(file) {
11801
11925
  let bytes;
11802
11926
  try {
11803
- bytes = fs9.readFileSync(file, "utf8");
11927
+ bytes = fs10.readFileSync(file, "utf8");
11804
11928
  } catch {
11805
11929
  return null;
11806
11930
  }
@@ -11818,7 +11942,7 @@ class TaskStore {
11818
11942
  schemaVersion: SCHEMA_VERSION,
11819
11943
  id: workspaceId ?? newId(),
11820
11944
  revision: newRevision(),
11821
- root: path8.dirname(v2),
11945
+ root: path9.dirname(v2),
11822
11946
  runtime: { createdWith: version, updatedWith: version },
11823
11947
  writer: null,
11824
11948
  store: {
@@ -11829,12 +11953,12 @@ class TaskStore {
11829
11953
  },
11830
11954
  critical: ["store"]
11831
11955
  };
11832
- fs9.mkdirSync(v2, { recursive: true });
11833
- const ignore = path8.join(v2, ".gitignore");
11834
- if (!fs9.existsSync(ignore))
11835
- fs9.writeFileSync(ignore, `*
11956
+ fs10.mkdirSync(v2, { recursive: true });
11957
+ const ignore = path9.join(v2, ".gitignore");
11958
+ if (!fs10.existsSync(ignore))
11959
+ fs10.writeFileSync(ignore, `*
11836
11960
  `);
11837
- replaceFile(path8.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
11961
+ replaceFile(path9.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
11838
11962
  `, true);
11839
11963
  }
11840
11964
  stubFor(taskId) {
@@ -11850,7 +11974,7 @@ class TaskStore {
11850
11974
  }
11851
11975
  isStub(file) {
11852
11976
  try {
11853
- const value = JSON.parse(fs9.readFileSync(file, "utf8"));
11977
+ const value = JSON.parse(fs10.readFileSync(file, "utf8"));
11854
11978
  return isObject4(value) && isObject4(value.store) && value.store.format === "workit-store";
11855
11979
  } catch {
11856
11980
  return false;
@@ -11858,32 +11982,32 @@ class TaskStore {
11858
11982
  }
11859
11983
  writeTombstoneIfMissing() {
11860
11984
  try {
11861
- const v2 = path8.join(this.root, ".workit");
11862
- if (fs9.existsSync(path8.join(v2, "workspace.json")))
11985
+ const v2 = path9.join(this.root, ".workit");
11986
+ if (fs10.existsSync(path9.join(v2, "workspace.json")))
11863
11987
  return;
11864
11988
  let id = null;
11865
11989
  try {
11866
- id = JSON.parse(fs9.readFileSync(this.paths().workspace, "utf8")).id ?? null;
11990
+ id = JSON.parse(fs10.readFileSync(this.paths().workspace, "utf8")).id ?? null;
11867
11991
  } catch {}
11868
11992
  this.writeTombstone(v2, id);
11869
11993
  } catch {}
11870
11994
  }
11871
11995
  initializeStorage() {
11872
11996
  const dirs = this.paths();
11873
- retryTransient(() => fs9.mkdirSync(dirs.checkout, { recursive: true }));
11874
- retryTransient(() => fs9.mkdirSync(dirs.tasks, { recursive: true }));
11875
- if (!fs9.existsSync(dirs.marker))
11997
+ retryTransient(() => fs10.mkdirSync(dirs.checkout, { recursive: true }));
11998
+ retryTransient(() => fs10.mkdirSync(dirs.tasks, { recursive: true }));
11999
+ if (!fs10.existsSync(dirs.marker))
11876
12000
  replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
11877
12001
  `, false);
11878
12002
  if (!dirs.shared) {
11879
- const ignore = path8.join(dirs.dir, ".gitignore");
12003
+ const ignore = path9.join(dirs.dir, ".gitignore");
11880
12004
  let current = null;
11881
12005
  try {
11882
- current = fs9.readFileSync(ignore, "utf8");
12006
+ current = fs10.readFileSync(ignore, "utf8");
11883
12007
  } catch {}
11884
12008
  if (current !== `*
11885
12009
  `)
11886
- retryTransient(() => fs9.writeFileSync(ignore, `*
12010
+ retryTransient(() => fs10.writeFileSync(ignore, `*
11887
12011
  `));
11888
12012
  }
11889
12013
  this.writeTombstoneIfMissing();
@@ -11899,7 +12023,7 @@ class TaskStore {
11899
12023
  shouldReclaim: ({ payload, nowMs }) => {
11900
12024
  let ageMs = null;
11901
12025
  try {
11902
- ageMs = nowMs - fs9.lstatSync(lockPath).mtimeMs;
12026
+ ageMs = nowMs - fs10.lstatSync(lockPath).mtimeMs;
11903
12027
  } catch {}
11904
12028
  return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
11905
12029
  },
@@ -11936,7 +12060,7 @@ class TaskStore {
11936
12060
  withLock(lockPath, operation) {
11937
12061
  try {
11938
12062
  this.initializeStorage();
11939
- fs9.mkdirSync(path8.dirname(lockPath), { recursive: true });
12063
+ fs10.mkdirSync(path9.dirname(lockPath), { recursive: true });
11940
12064
  } catch (error) {
11941
12065
  return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
11942
12066
  path: this.paths().dir
@@ -11976,18 +12100,18 @@ class TaskStore {
11976
12100
  lockDirWritable(lockPath) {
11977
12101
  const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
11978
12102
  try {
11979
- fs9.closeSync(fs9.openSync(probe, "wx", 384));
12103
+ fs10.closeSync(fs10.openSync(probe, "wx", 384));
11980
12104
  } catch {
11981
12105
  return false;
11982
12106
  }
11983
12107
  try {
11984
- fs9.rmSync(probe, { force: true });
12108
+ fs10.rmSync(probe, { force: true });
11985
12109
  } catch {}
11986
12110
  return true;
11987
12111
  }
11988
12112
  lockHolderPresent(lockPath) {
11989
12113
  try {
11990
- fs9.lstatSync(lockPath);
12114
+ fs10.lstatSync(lockPath);
11991
12115
  return true;
11992
12116
  } catch (error) {
11993
12117
  return error?.code !== "ENOENT";
@@ -11999,12 +12123,12 @@ class TaskStore {
11999
12123
  if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
12000
12124
  return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
12001
12125
  path: lockPath,
12002
- guidance: `Check permissions and the read-only attribute on ${path8.dirname(lockPath)}.`
12126
+ guidance: `Check permissions and the read-only attribute on ${path9.dirname(lockPath)}.`
12003
12127
  });
12004
12128
  if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
12005
12129
  let lock = null;
12006
12130
  try {
12007
- lock = parseMetadataLockOrNull(fs9.readFileSync(lockPath, "utf8"));
12131
+ lock = parseMetadataLockOrNull(fs10.readFileSync(lockPath, "utf8"));
12008
12132
  } catch {}
12009
12133
  return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
12010
12134
  outcome: "not_started",
@@ -12019,17 +12143,17 @@ class TaskStore {
12019
12143
 
12020
12144
  // packages/workit-core/src/core/policy/derive.ts
12021
12145
  import { existsSync as existsSync4 } from "node:fs";
12022
- import path13 from "node:path";
12146
+ import path14 from "node:path";
12023
12147
 
12024
12148
  // packages/workit-core/src/ledger.ts
12025
12149
  import { spawnSync as spawnSync9 } from "node:child_process";
12026
- import { createHash as createHash8, randomBytes as randomBytes2 } from "node:crypto";
12027
- import fs11 from "node:fs";
12028
- import path12 from "node:path";
12150
+ import { createHash as createHash9, randomBytes as randomBytes2 } from "node:crypto";
12151
+ import fs12 from "node:fs";
12152
+ import path13 from "node:path";
12029
12153
 
12030
12154
  // packages/workit-core/src/core/vcs-config.ts
12031
- import fs10 from "node:fs";
12032
- import path11 from "node:path";
12155
+ import fs11 from "node:fs";
12156
+ import path12 from "node:path";
12033
12157
  import { spawnSync as spawnSync8 } from "node:child_process";
12034
12158
 
12035
12159
  // packages/workit-core/src/core/config.ts
@@ -12043,7 +12167,7 @@ import {
12043
12167
  writeFileSync as writeFileSync2
12044
12168
  } from "node:fs";
12045
12169
  import os2 from "node:os";
12046
- import path9 from "node:path";
12170
+ import path10 from "node:path";
12047
12171
 
12048
12172
  // packages/workit-core/src/core/boundary.ts
12049
12173
  var EVENT = {
@@ -12087,7 +12211,7 @@ var mergePreset = (preset, input = {}, current = {
12087
12211
  protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
12088
12212
  };
12089
12213
  };
12090
- var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path9.join(process.env.XDG_CONFIG_HOME || path9.join(os2.homedir(), ".config"), "workit");
12214
+ var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path10.join(process.env.XDG_CONFIG_HOME || path10.join(os2.homedir(), ".config"), "workit");
12091
12215
  var migratedDir = null;
12092
12216
  var migrationFailed = false;
12093
12217
  var ensureConfigDir = (dir = resolveConfigDir()) => {
@@ -12097,7 +12221,7 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
12097
12221
  migratedDir = dir;
12098
12222
  return dir;
12099
12223
  }
12100
- const legacy = path9.join(process.env.XDG_CONFIG_HOME || path9.join(os2.homedir(), ".config"), "workflow-toolkit");
12224
+ const legacy = path10.join(process.env.XDG_CONFIG_HOME || path10.join(os2.homedir(), ".config"), "workflow-toolkit");
12101
12225
  if (!existsSync3(legacy)) {
12102
12226
  migratedDir = dir;
12103
12227
  return dir;
@@ -12110,8 +12234,8 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
12110
12234
  mkdirSync2(dir, { recursive: true });
12111
12235
  diagnosticLogger?.info(EVENT.migration, { from: legacy, to: dir });
12112
12236
  for (const entry of readdirSync2(legacy, { withFileTypes: true })) {
12113
- const src = path9.join(legacy, entry.name);
12114
- const dest = path9.join(dir, entry.name);
12237
+ const src = path10.join(legacy, entry.name);
12238
+ const dest = path10.join(dir, entry.name);
12115
12239
  if (existsSync3(dest))
12116
12240
  continue;
12117
12241
  try {
@@ -12183,7 +12307,7 @@ var parseConfigResult = (raw, file) => {
12183
12307
  return { status: "valid", path: file, config };
12184
12308
  };
12185
12309
  var readConfigTyped = (dir) => {
12186
- const file = path9.join(dir ?? configDir(), "config.json");
12310
+ const file = path10.join(dir ?? configDir(), "config.json");
12187
12311
  return parseConfigResult(readSafe(file), file);
12188
12312
  };
12189
12313
  var readConfig = () => {
@@ -12192,7 +12316,7 @@ var readConfig = () => {
12192
12316
  throw new Error(result.error);
12193
12317
  return result.config ?? DEFAULTS;
12194
12318
  };
12195
- var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path9.join(configDir(), "vcs.json");
12319
+ var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path10.join(configDir(), "vcs.json");
12196
12320
  var branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i");
12197
12321
  var resolveBranchPolicy = (config, workspace, repoPreset) => {
12198
12322
  const wp = workspace?.branchPolicy ?? {};
@@ -12234,9 +12358,9 @@ var resolveCommitPolicy = (config, workspace) => {
12234
12358
 
12235
12359
  // packages/workit-core/src/core/workspaces.ts
12236
12360
  import { spawnSync as spawnSync6 } from "node:child_process";
12237
- import { createHash as createHash6 } from "node:crypto";
12361
+ import { createHash as createHash7 } from "node:crypto";
12238
12362
  import { readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
12239
- import path10 from "node:path";
12363
+ import path11 from "node:path";
12240
12364
 
12241
12365
  // packages/workit-core/src/core/branch-policy.ts
12242
12366
  import { spawnSync as spawnSync5 } from "node:child_process";
@@ -12361,7 +12485,7 @@ var releaseTrackSchema = object({
12361
12485
  context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
12362
12486
  }
12363
12487
  }
12364
- if (track.versionSource?.kind === "package-json" && (path10.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
12488
+ 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(".."))) {
12365
12489
  context.addIssue({
12366
12490
  code: "custom",
12367
12491
  path: ["versionSource", "path"],
@@ -12421,7 +12545,7 @@ var workspacesFileSchema = object({ workspaces: array(workspaceConfigSchema).opt
12421
12545
  names.add(workspace.name);
12422
12546
  }
12423
12547
  });
12424
- var workspacesRevision = (contents) => createHash6("sha256").update(contents ?? "<missing>").digest("hex");
12548
+ var workspacesRevision = (contents) => createHash7("sha256").update(contents ?? "<missing>").digest("hex");
12425
12549
  var validateWorkspacesDocument = (parsed, file) => {
12426
12550
  if (!isConfigObject(parsed)) {
12427
12551
  return { status: "malformed", path: file, entries: [], error: `${file} is not a JSON object` };
@@ -12459,7 +12583,7 @@ var validateWorkspacesDocument = (parsed, file) => {
12459
12583
  };
12460
12584
  };
12461
12585
  var readWorkspacesResult = (dir = configDir()) => {
12462
- const file = path10.join(dir, "workspaces.json");
12586
+ const file = path11.join(dir, "workspaces.json");
12463
12587
  let raw;
12464
12588
  try {
12465
12589
  raw = readFileSync3(file, "utf8");
@@ -12570,9 +12694,9 @@ var mainCheckoutOf = (cwd) => {
12570
12694
  let main = null;
12571
12695
  const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
12572
12696
  const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
12573
- if (gitDir && common && path10.resolve(gitDir) !== path10.resolve(common)) {
12697
+ if (gitDir && common && path11.resolve(gitDir) !== path11.resolve(common)) {
12574
12698
  const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
12575
- main = listed?.trim() || (path10.basename(common) === ".git" ? path10.dirname(common) : common);
12699
+ main = listed?.trim() || (path11.basename(common) === ".git" ? path11.dirname(common) : common);
12576
12700
  }
12577
12701
  mainCheckouts.set(cwd, main);
12578
12702
  return main;
@@ -12663,7 +12787,7 @@ var runtimeWorkspaceIndexSchema = object({
12663
12787
  workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
12664
12788
  }).passthrough();
12665
12789
  var matchRuntimeWorkspace = (cwd) => {
12666
- const file = path10.join(configDir(), "workspaces.json");
12790
+ const file = path11.join(configDir(), "workspaces.json");
12667
12791
  let raw;
12668
12792
  try {
12669
12793
  raw = readFileSync3(file, "utf8");
@@ -12738,7 +12862,7 @@ function workspaceDefaultTarget(cwd, globalDefault) {
12738
12862
  }
12739
12863
 
12740
12864
  // packages/workit-core/src/core/release-tracks.ts
12741
- import { createHash as createHash7 } from "node:crypto";
12865
+ import { createHash as createHash8 } from "node:crypto";
12742
12866
  import { spawnSync as spawnSync7 } from "node:child_process";
12743
12867
  class ReleaseTrackError extends Error {
12744
12868
  }
@@ -13121,7 +13245,7 @@ function resolveTrackFor(cwd, options) {
13121
13245
  ]) ?? "",
13122
13246
  git3(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
13123
13247
  ] : [];
13124
- key = createHash7("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
13248
+ key = createHash8("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
13125
13249
  const hit = memo2.get(key);
13126
13250
  if (hit)
13127
13251
  return hit;
@@ -13136,7 +13260,7 @@ function resolveTrackFor(cwd, options) {
13136
13260
  }
13137
13261
 
13138
13262
  // packages/workit-core/src/core/vcs-config.ts
13139
- var workspacesPath = () => path11.join(configDir(), "workspaces.json");
13263
+ var workspacesPath = () => path12.join(configDir(), "workspaces.json");
13140
13264
  var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
13141
13265
  var remoteProvider = (cwd) => {
13142
13266
  const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
@@ -13153,7 +13277,7 @@ var readVcsConfig = () => {
13153
13277
  const file = vcsConfigPath();
13154
13278
  let raw;
13155
13279
  try {
13156
- raw = fs10.readFileSync(file, "utf8");
13280
+ raw = fs11.readFileSync(file, "utf8");
13157
13281
  } catch {
13158
13282
  return { status: "missing", path: file, config: {} };
13159
13283
  }
@@ -13238,7 +13362,7 @@ function vcsConfig(mode, cwd, options = {}) {
13238
13362
  const prov = cfg[provider] ?? {};
13239
13363
  const out = {
13240
13364
  ok: true,
13241
- configPath: path11.resolve(cfgPath),
13365
+ configPath: path12.resolve(cfgPath),
13242
13366
  provider,
13243
13367
  defaultTargetBranch: workspaceDefault,
13244
13368
  pr: cfg.pr ?? {},
@@ -13364,7 +13488,7 @@ function diffHash(cwd, base, head) {
13364
13488
  ], GIT_TIMEOUTS.worktree);
13365
13489
  if (!diff.ok || !diff.stdout)
13366
13490
  return null;
13367
- const hash = createHash8("sha256");
13491
+ const hash = createHash9("sha256");
13368
13492
  for (const line of diff.stdout.split(`
13369
13493
  `)) {
13370
13494
  if (line.startsWith("index "))
@@ -13376,14 +13500,14 @@ function diffHash(cwd, base, head) {
13376
13500
  return `sha256:${hash.digest("hex")}`;
13377
13501
  }
13378
13502
  function storeRoot(cwd) {
13379
- const location = resolveStore(path12.resolve(cwd));
13503
+ const location = resolveStore(path13.resolve(cwd));
13380
13504
  if (location instanceof Error)
13381
13505
  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");
13382
13506
  return { ok: true, value: { root: location.dir, shared: location.shared } };
13383
13507
  }
13384
13508
  function ledgerPath(cwd) {
13385
13509
  const root = storeRoot(cwd);
13386
- return root.ok ? { ok: true, value: path12.join(root.value.root, "ledger", "ledger.jsonl") } : root;
13510
+ return root.ok ? { ok: true, value: path13.join(root.value.root, "ledger", "ledger.jsonl") } : root;
13387
13511
  }
13388
13512
  var newId2 = () => `${Date.now().toString(36)}-${randomBytes2(6).toString("hex")}`;
13389
13513
  var NETWORK_FS_TYPES = new Set([
@@ -13403,7 +13527,7 @@ var onNetworkFs = (dir) => {
13403
13527
  if (process.platform !== "linux")
13404
13528
  return false;
13405
13529
  try {
13406
- return isNetworkFsType(fs11.statfsSync(dir).type);
13530
+ return isNetworkFsType(fs12.statfsSync(dir).type);
13407
13531
  } catch {
13408
13532
  return false;
13409
13533
  }
@@ -13413,15 +13537,15 @@ var LOCK_STALE_MS = 30000;
13413
13537
  var LOCK_OWNER = "owner";
13414
13538
  var lockToken = (lock) => {
13415
13539
  try {
13416
- return fs11.readFileSync(path12.join(lock, LOCK_OWNER), "utf8");
13540
+ return fs12.readFileSync(path13.join(lock, LOCK_OWNER), "utf8");
13417
13541
  } catch {
13418
13542
  return null;
13419
13543
  }
13420
13544
  };
13421
13545
  var lockAgeMs = (lock) => {
13422
- for (const target of [path12.join(lock, LOCK_OWNER), lock]) {
13546
+ for (const target of [path13.join(lock, LOCK_OWNER), lock]) {
13423
13547
  try {
13424
- return Date.now() - fs11.statSync(target).mtimeMs;
13548
+ return Date.now() - fs12.statSync(target).mtimeMs;
13425
13549
  } catch {}
13426
13550
  }
13427
13551
  return null;
@@ -13429,14 +13553,14 @@ var lockAgeMs = (lock) => {
13429
13553
  var ledgerLock = {
13430
13554
  acquire(lock) {
13431
13555
  try {
13432
- fs11.mkdirSync(lock);
13556
+ fs12.mkdirSync(lock);
13433
13557
  } catch (error) {
13434
13558
  if (error.code === "EEXIST")
13435
13559
  return null;
13436
13560
  throw error;
13437
13561
  }
13438
13562
  const token = `${process.pid}-${randomBytes2(8).toString("hex")}`;
13439
- fs11.writeFileSync(path12.join(lock, LOCK_OWNER), token);
13563
+ fs12.writeFileSync(path13.join(lock, LOCK_OWNER), token);
13440
13564
  return token;
13441
13565
  },
13442
13566
  release(lock, token) {
@@ -13444,35 +13568,35 @@ var ledgerLock = {
13444
13568
  return false;
13445
13569
  const tomb = `${lock}.release-${randomBytes2(6).toString("hex")}`;
13446
13570
  try {
13447
- fs11.renameSync(lock, tomb);
13571
+ fs12.renameSync(lock, tomb);
13448
13572
  } catch {
13449
13573
  return false;
13450
13574
  }
13451
13575
  if (lockToken(tomb) !== token) {
13452
13576
  try {
13453
- fs11.renameSync(tomb, lock);
13577
+ fs12.renameSync(tomb, lock);
13454
13578
  } catch {}
13455
13579
  return false;
13456
13580
  }
13457
- fs11.rmSync(tomb, { recursive: true, force: true });
13581
+ fs12.rmSync(tomb, { recursive: true, force: true });
13458
13582
  return true;
13459
13583
  },
13460
13584
  token: lockToken,
13461
13585
  reap(lock, observed) {
13462
13586
  const tomb = `${lock}.reap-${randomBytes2(6).toString("hex")}`;
13463
13587
  try {
13464
- fs11.renameSync(lock, tomb);
13588
+ fs12.renameSync(lock, tomb);
13465
13589
  } catch {
13466
13590
  return false;
13467
13591
  }
13468
13592
  if (lockToken(tomb) === observed) {
13469
- fs11.rmSync(tomb, { recursive: true, force: true });
13593
+ fs12.rmSync(tomb, { recursive: true, force: true });
13470
13594
  return true;
13471
13595
  }
13472
13596
  try {
13473
- fs11.renameSync(tomb, lock);
13597
+ fs12.renameSync(tomb, lock);
13474
13598
  } catch {
13475
- fs11.rmSync(tomb, { recursive: true, force: true });
13599
+ fs12.rmSync(tomb, { recursive: true, force: true });
13476
13600
  }
13477
13601
  return false;
13478
13602
  }
@@ -13499,14 +13623,14 @@ function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
13499
13623
  ledgerLock.release(lock, token);
13500
13624
  }
13501
13625
  }
13502
- var sha2562 = (text) => createHash8("sha256").update(text).digest("hex");
13626
+ var sha2562 = (text) => createHash9("sha256").update(text).digest("hex");
13503
13627
  var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
13504
13628
  ${body}`);
13505
13629
  var TAIL_BYTES = 64 * 1024;
13506
13630
  var lastLine = (fd, size) => {
13507
13631
  for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
13508
13632
  const buffer = Buffer.alloc(span);
13509
- fs11.readSync(fd, buffer, 0, span, size - span);
13633
+ fs12.readSync(fd, buffer, 0, span, size - span);
13510
13634
  const end = buffer.lastIndexOf(10);
13511
13635
  if (end < 0) {
13512
13636
  if (span === size)
@@ -13537,13 +13661,13 @@ var lastLine = (fd, size) => {
13537
13661
  };
13538
13662
  function appendLine(file, build, options) {
13539
13663
  const write = () => {
13540
- const fd = fs11.openSync(file, "a+");
13664
+ const fd = fs12.openSync(file, "a+");
13541
13665
  try {
13542
- const size = fs11.fstatSync(fd).size;
13666
+ const size = fs12.fstatSync(fd).size;
13543
13667
  let fence = "";
13544
13668
  if (size > 0) {
13545
13669
  const last = Buffer.alloc(1);
13546
- fs11.readSync(fd, last, 0, 1, size - 1);
13670
+ fs12.readSync(fd, last, 0, 1, size - 1);
13547
13671
  if (last[0] !== 10)
13548
13672
  fence = `
13549
13673
  `;
@@ -13552,17 +13676,17 @@ function appendLine(file, build, options) {
13552
13676
  if (!line.ok)
13553
13677
  return line;
13554
13678
  const bytes = Buffer.from(fence + line.value);
13555
- const written = fs11.writeSync(fd, bytes);
13679
+ const written = fs12.writeSync(fd, bytes);
13556
13680
  if (written !== bytes.length)
13557
13681
  return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
13558
13682
  return { ok: true, value: undefined };
13559
13683
  } finally {
13560
- fs11.closeSync(fd);
13684
+ fs12.closeSync(fd);
13561
13685
  }
13562
13686
  };
13563
13687
  try {
13564
- fs11.mkdirSync(path12.dirname(file), { recursive: true });
13565
- if (!options.forceLock && !onNetworkFs(path12.dirname(file)))
13688
+ fs12.mkdirSync(path13.dirname(file), { recursive: true });
13689
+ if (!options.forceLock && !onNetworkFs(path13.dirname(file)))
13566
13690
  return write();
13567
13691
  const locked = withLedgerLock(file, write);
13568
13692
  return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
@@ -13634,7 +13758,7 @@ function readLedger(cwd, options = {}) {
13634
13758
  return file;
13635
13759
  let text = "";
13636
13760
  try {
13637
- text = fs11.readFileSync(file.value, "utf8");
13761
+ text = fs12.readFileSync(file.value, "utf8");
13638
13762
  } catch (error) {
13639
13763
  if (error.code === "ENOENT")
13640
13764
  return {
@@ -13828,11 +13952,20 @@ function authorSessions(cwd, rows, branch, range = { base: null, head: null }, s
13828
13952
  sessions.add(session);
13829
13953
  return sessions;
13830
13954
  }
13955
+ var derivesFrom = (derived, bare) => !bare.includes(":") && derived.endsWith(`:${bare}`);
13956
+ var authoredBy = (authors, session) => {
13957
+ if (authors.has(session))
13958
+ return true;
13959
+ for (const author of authors)
13960
+ if (derivesFrom(author, session) || derivesFrom(session, author))
13961
+ return true;
13962
+ return false;
13963
+ };
13831
13964
  var independenceReasons = (row, authors) => {
13832
13965
  const reasons = [];
13833
13966
  if (!row.actor.session)
13834
13967
  reasons.push("no_session");
13835
- else if (authors.has(row.actor.session))
13968
+ else if (authoredBy(authors, row.actor.session))
13836
13969
  reasons.push("author_session");
13837
13970
  if (row.self === true && !reasons.includes("no_session"))
13838
13971
  reasons.push("self");
@@ -14116,7 +14249,7 @@ var productDecision = (task, ledger) => {
14116
14249
  };
14117
14250
  };
14118
14251
  var planRecorded = (task, root) => {
14119
- const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path13.resolve(root, ref.path)));
14252
+ const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path14.resolve(root, ref.path)));
14120
14253
  if (cited)
14121
14254
  return {
14122
14255
  met: true,
@@ -14175,15 +14308,15 @@ function writeBlockers(task, root) {
14175
14308
  }
14176
14309
 
14177
14310
  // packages/workit-core/src/core/task-evaluation.ts
14178
- var digestBytes = (value) => createHash9("sha256").update(value).digest("hex");
14179
- var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path14.sep}`);
14180
- var relative = (root, candidate) => path14.relative(root, candidate).split(path14.sep).join("/") || ".";
14311
+ var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
14312
+ var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path15.sep}`);
14313
+ var relative = (root, candidate) => path15.relative(root, candidate).split(path15.sep).join("/") || ".";
14181
14314
  var canonicalPath = (value) => {
14182
14315
  if (typeof value !== "string" || !value)
14183
14316
  return null;
14184
14317
  if (value.includes("\\") || value.split("/").includes(".."))
14185
14318
  return null;
14186
- const normalized = path14.posix.normalize(value);
14319
+ const normalized = path15.posix.normalize(value);
14187
14320
  if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
14188
14321
  return null;
14189
14322
  return normalized === "." ? "." : normalized.replace(/\/$/, "");
@@ -14231,21 +14364,21 @@ var gitPaths = (root) => {
14231
14364
  git: !/not a git repository/i.test(stderr)
14232
14365
  };
14233
14366
  }
14234
- const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path14.sep).join("/")) : [];
14367
+ const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")) : [];
14235
14368
  const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
14236
14369
  if (stagedDeleted.status !== 0) {
14237
14370
  const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
14238
14371
  if (!/not a git repository/i.test(stderr))
14239
14372
  return { paths, uncertain: true, git: true };
14240
14373
  } else if (stagedDeleted.stdout) {
14241
- paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path14.sep).join("/")));
14374
+ paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")));
14242
14375
  }
14243
14376
  return { paths: [...new Set(paths)], uncertain: false, git: true };
14244
14377
  };
14245
14378
  var walk = (root, directory, output) => {
14246
14379
  let names;
14247
14380
  try {
14248
- names = fs12.readdirSync(directory);
14381
+ names = fs13.readdirSync(directory);
14249
14382
  } catch {
14250
14383
  return true;
14251
14384
  }
@@ -14253,10 +14386,10 @@ var walk = (root, directory, output) => {
14253
14386
  for (const name of names) {
14254
14387
  if (name === ".git" || name === ".workit")
14255
14388
  continue;
14256
- const target = path14.join(directory, name);
14389
+ const target = path15.join(directory, name);
14257
14390
  let stat;
14258
14391
  try {
14259
- stat = fs12.lstatSync(target);
14392
+ stat = fs13.lstatSync(target);
14260
14393
  } catch {
14261
14394
  uncertain = true;
14262
14395
  continue;
@@ -14271,14 +14404,14 @@ var walk = (root, directory, output) => {
14271
14404
  var scopeRoots = (root, scope) => {
14272
14405
  const roots = [];
14273
14406
  for (const item of scope.paths.length ? scope.paths : ["."]) {
14274
- const target = path14.resolve(root, item);
14407
+ const target = path15.resolve(root, item);
14275
14408
  if (!inside(root, target))
14276
14409
  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` }] });
14277
14410
  let ancestor = target;
14278
- while (!fs12.existsSync(ancestor) && ancestor !== root)
14279
- ancestor = path14.dirname(ancestor);
14411
+ while (!fs13.existsSync(ancestor) && ancestor !== root)
14412
+ ancestor = path15.dirname(ancestor);
14280
14413
  try {
14281
- if (!inside(root, fs12.realpathSync(ancestor)))
14414
+ if (!inside(root, fs13.realpathSync(ancestor)))
14282
14415
  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` }] });
14283
14416
  } catch {
14284
14417
  return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
@@ -14290,7 +14423,7 @@ var scopeRoots = (root, scope) => {
14290
14423
  function captureCandidate(root, scope, environment = []) {
14291
14424
  let checkout;
14292
14425
  try {
14293
- checkout = fs12.realpathSync(root);
14426
+ checkout = fs13.realpathSync(root);
14294
14427
  } catch {
14295
14428
  return failure2("invalid_input", "candidate root does not exist");
14296
14429
  }
@@ -14308,11 +14441,11 @@ function captureCandidate(root, scope, environment = []) {
14308
14441
  if (item === ".git" || item === ".workit")
14309
14442
  continue;
14310
14443
  names.add(item);
14311
- if (!fs12.existsSync(target))
14444
+ if (!fs13.existsSync(target))
14312
14445
  continue;
14313
14446
  let stat;
14314
14447
  try {
14315
- stat = fs12.lstatSync(target);
14448
+ stat = fs13.lstatSync(target);
14316
14449
  } catch {
14317
14450
  uncertain = true;
14318
14451
  continue;
@@ -14328,17 +14461,17 @@ function captureCandidate(root, scope, environment = []) {
14328
14461
  for (const item of [...names].toSorted()) {
14329
14462
  if (!scopeMatches(item, normalizedScope))
14330
14463
  continue;
14331
- const target = path14.join(checkout, item);
14464
+ const target = path15.join(checkout, item);
14332
14465
  try {
14333
- const stat = fs12.lstatSync(target);
14466
+ const stat = fs13.lstatSync(target);
14334
14467
  if (stat.isSymbolicLink()) {
14335
- const link = fs12.readlinkSync(target);
14468
+ const link = fs13.readlinkSync(target);
14336
14469
  files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
14337
14470
  } else if (stat.isFile()) {
14338
14471
  files.push({
14339
14472
  path: item,
14340
14473
  kind: "file",
14341
- digest: digestBytes(fs12.readFileSync(target)),
14474
+ digest: digestBytes(fs13.readFileSync(target)),
14342
14475
  executable: (stat.mode & 73) !== 0
14343
14476
  });
14344
14477
  } else if (!stat.isDirectory()) {
@@ -14503,7 +14636,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
14503
14636
  var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
14504
14637
  let root;
14505
14638
  try {
14506
- root = fs12.realpathSync(checkoutRoot);
14639
+ root = fs13.realpathSync(checkoutRoot);
14507
14640
  } catch {
14508
14641
  return failure2("permission_denied", "checkout root is unavailable");
14509
14642
  }
@@ -14512,23 +14645,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
14512
14645
  continue;
14513
14646
  if (!reference.digest)
14514
14647
  return failure2("invalid_input", "document references require a byte digest");
14515
- const target = path14.resolve(root, reference.path);
14516
- if (target !== root && !target.startsWith(`${root}${path14.sep}`))
14648
+ const target = path15.resolve(root, reference.path);
14649
+ if (target !== root && !target.startsWith(`${root}${path15.sep}`))
14517
14650
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
14518
14651
  fields: [
14519
14652
  { path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
14520
14653
  ]
14521
14654
  });
14522
14655
  try {
14523
- const below = path14.relative(root, target);
14656
+ const below = path15.relative(root, target);
14524
14657
  let current = root;
14525
- for (const segment of below.split(path14.sep)) {
14658
+ for (const segment of below.split(path15.sep)) {
14526
14659
  if (!segment)
14527
14660
  continue;
14528
- current = path14.join(current, segment);
14529
- const stat = fs12.lstatSync(current);
14530
- const real = fs12.realpathSync(current);
14531
- if (real !== root && !real.startsWith(`${root}${path14.sep}`))
14661
+ current = path15.join(current, segment);
14662
+ const stat = fs13.lstatSync(current);
14663
+ const real = fs13.realpathSync(current);
14664
+ if (real !== root && !real.startsWith(`${root}${path15.sep}`))
14532
14665
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
14533
14666
  fields: [
14534
14667
  {
@@ -14544,7 +14677,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
14544
14677
  if (current !== target && !stat.isDirectory())
14545
14678
  return failure2("invalid_input", "document reference ancestor is not a directory");
14546
14679
  }
14547
- if (digestBytes(fs12.readFileSync(target)) !== reference.digest)
14680
+ if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
14548
14681
  return failure2("permission_denied", "decision document bytes have changed");
14549
14682
  } catch {
14550
14683
  return failure2("invalid_input", "decision document is unavailable");
@@ -15401,7 +15534,7 @@ var judgeInputSummary = (raw) => {
15401
15534
 
15402
15535
  // packages/workit-core/src/autonomy.ts
15403
15536
  import os3 from "node:os";
15404
- import path15 from "node:path";
15537
+ import path16 from "node:path";
15405
15538
  var accountHome = () => {
15406
15539
  try {
15407
15540
  return os3.userInfo().homedir;
@@ -15410,10 +15543,10 @@ var accountHome = () => {
15410
15543
  }
15411
15544
  };
15412
15545
  var grantsHome = { resolve: accountHome };
15413
- var grantsDir = () => path15.join(grantsHome.resolve(), ".config", "workit");
15546
+ var grantsDir = () => path16.join(grantsHome.resolve(), ".config", "workit");
15414
15547
  var grantsOverride = () => {
15415
- const configured = path15.resolve(resolveConfigDir());
15416
- return configured === path15.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path15.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
15548
+ const configured = path16.resolve(resolveConfigDir());
15549
+ 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`;
15417
15550
  };
15418
15551
  var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
15419
15552
  var DEFAULT_GRANTS = Object.freeze({
@@ -15599,38 +15732,45 @@ var compactReference = (ref) => {
15599
15732
  };
15600
15733
  return { kind: ref.kind };
15601
15734
  };
15602
- function compactTaskContext(view) {
15603
- const decisions = view.task.decisions.slice().toSorted((left, right) => {
15604
- const leftAt = compactTimestamp(left.recordedAt);
15605
- const rightAt = compactTimestamp(right.recordedAt);
15606
- if (leftAt !== rightAt)
15607
- return leftAt > rightAt ? -1 : 1;
15608
- return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
15609
- }).slice(0, COMPACT_MAX_ITEMS).map((entry) => ({
15610
- id: entry.id,
15611
- purpose: entry.data.purpose,
15612
- status: entry.data.response,
15613
- digest: entry.data.digest,
15614
- choice: compactDecisionChoice(entry) || `task.inspect taskId=${view.task.id} view=full; decision=${entry.id}`,
15615
- references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
15616
- }));
15617
- const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
15735
+ var newestDecisionFirst = (left, right) => {
15736
+ const leftAt = compactTimestamp(left.recordedAt);
15737
+ const rightAt = compactTimestamp(right.recordedAt);
15738
+ if (leftAt !== rightAt)
15739
+ return leftAt > rightAt ? -1 : 1;
15740
+ return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
15741
+ };
15742
+ var compactDecisions = (sources) => sources.flatMap((source) => source ? source.decisions.toSorted(newestDecisionFirst).map((entry) => ({
15743
+ id: entry.id,
15744
+ purpose: entry.data.purpose,
15745
+ status: entry.data.response,
15746
+ digest: entry.data.digest,
15747
+ choice: compactDecisionChoice(entry) || `task.inspect taskId=${source.taskId} view=full; decision=${entry.id}`,
15748
+ references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference),
15749
+ origin: source.origin ?? undefined
15750
+ })) : []).slice(0, COMPACT_MAX_ITEMS);
15751
+ function compactTaskContext(view, inherited = null) {
15752
+ const decisions = compactDecisions([
15753
+ view && { origin: null, taskId: view.task.id, decisions: view.task.decisions },
15754
+ inherited
15755
+ ]);
15756
+ const methods = view?.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
15618
15757
  id: method.id,
15619
15758
  assurance: method.assurance,
15620
15759
  reason: compactText(method.reason, COMPACT_TEXT_BYTES) ?? ""
15621
15760
  })) : [];
15761
+ const stale = view?.evidence.filter((entry) => entry.status === "stale").length;
15622
15762
  const gaps = Array.from(new Set([
15623
- ...view.evidence.filter((entry) => entry.status === "stale").map((entry) => `stale evidence: ${entry.evidenceId}`),
15624
- ...view.requirements.filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
15625
- ...view.task.progress.blockers.map((entry) => entry.reason)
15763
+ ...stale ? [`stale evidence: ${stale}; workit task inspect --task ${view.task.id} --view full`] : [],
15764
+ ...(view?.requirements ?? []).filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
15765
+ ...(view?.task.progress.blockers ?? []).map((entry) => entry.reason)
15626
15766
  ])).toSorted().slice(0, COMPACT_MAX_ITEMS).map((gap) => compactText(gap, COMPACT_TEXT_BYTES));
15627
15767
  const context = {
15628
- objective: compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "",
15629
- status: view.task.status,
15768
+ objective: view ? compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "" : "no task on this branch yet",
15769
+ status: view?.task.status ?? null,
15630
15770
  decisions,
15631
15771
  methods,
15632
15772
  gaps,
15633
- nextAction: compactText(view.task.progress.nextAction, COMPACT_TEXT_BYTES)
15773
+ nextAction: compactText(view?.task.progress.nextAction ?? null, COMPACT_TEXT_BYTES)
15634
15774
  };
15635
15775
  let encoded = JSON.stringify(context);
15636
15776
  while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.methods.length || context.gaps.length)) {
@@ -15819,6 +15959,13 @@ var TASK_SCOPED_ACTIONS = new Set([
15819
15959
  "worker.cancel",
15820
15960
  "state.export"
15821
15961
  ]);
15962
+ var WORKER_ADDRESSED_ACTIONS = new Set(["worker.cancel", "worker.report"]);
15963
+ var workerCommand = (taskId, request) => {
15964
+ const { action, workerId, reason, report } = request;
15965
+ const rest = JSON.stringify({ reason, report });
15966
+ const payload = rest === "{}" ? "" : ` --payload '${rest.replace(/'/gu, "'\\''")}'`;
15967
+ return `workit worker ${String(action)} ${String(workerId)} --task ${taskId}${payload}`;
15968
+ };
15822
15969
  var CREATING_ACTIONS = new Set([
15823
15970
  "task.revise",
15824
15971
  "task.progress",
@@ -16069,6 +16216,17 @@ class WorkitCore {
16069
16216
  const root = this.contextRootError();
16070
16217
  if (!root.ok)
16071
16218
  return root;
16219
+ const addressed = WORKER_ADDRESSED_ACTIONS.has(action);
16220
+ const workerId = addressed ? value.workerId : this.context.workerId ?? null;
16221
+ if (workerId !== null) {
16222
+ const owner = this.store.taskForWorker(workerId);
16223
+ if (!owner.ok)
16224
+ return owner;
16225
+ if (owner.data)
16226
+ return success(null, null, { ...request, taskId: owner.data });
16227
+ if (addressed)
16228
+ return failure2("not_found", `worker ${workerId} is on no open task; find its task with \`workit task status --all\`, then run \`${workerCommand("<task-id>", request)}\``);
16229
+ }
16072
16230
  const create = CREATING_ACTIONS.has(action) && (this.context.workerId ?? null) === null;
16073
16231
  const found = this.store.implicitTask({
16074
16232
  provenance: provenance(this.context),
@@ -16775,7 +16933,9 @@ class WorkitCore {
16775
16933
  if (!resolved.ok)
16776
16934
  return resolved;
16777
16935
  const value = resolved.data;
16778
- return this.retryOmittedRevisions(value, () => this.workerOnce(value));
16936
+ const result = this.retryOmittedRevisions(value, () => this.workerOnce(value));
16937
+ const { action, taskId } = value ?? {};
16938
+ return result.ok || request?.taskId !== undefined || typeof taskId !== "string" || !WORKER_ADDRESSED_ACTIONS.has(`worker.${String(action)}`) ? result : { ...result, error: `${result.error}; run \`${workerCommand(taskId, value)}\`` };
16779
16939
  }
16780
16940
  workerOnce(request) {
16781
16941
  const root = this.contextRootError();
@@ -16980,10 +17140,18 @@ class WorkitCore {
16980
17140
  requirements
16981
17141
  });
16982
17142
  }
16983
- compactContext(taskId, freshness) {
17143
+ compactContext(taskId, freshness, origin = null) {
16984
17144
  const root = this.contextRootError();
16985
17145
  if (!root.ok)
16986
17146
  return root;
17147
+ const base = origin && this.store.readStoreTask(origin.taskId);
17148
+ const inherited = base?.ok && base.data ? {
17149
+ origin: origin.origin,
17150
+ taskId: base.data.id,
17151
+ decisions: base.data.decisions.filter((entry) => entry.data.revoked === null)
17152
+ } : null;
17153
+ if (taskId === null)
17154
+ return success(null, null, inherited?.decisions.length ? compactTaskContext(null, inherited) : "");
16987
17155
  const task = this.store.readTask(taskId);
16988
17156
  if (!task.ok)
16989
17157
  return task;
@@ -16993,7 +17161,7 @@ class WorkitCore {
16993
17161
  const view = this.view(task.data, false, freshness ?? signalFreshness(this.store.root));
16994
17162
  if (!view.ok)
16995
17163
  return view;
16996
- return success(view.revision, view.workspaceRevision, compactTaskContext(view.data));
17164
+ return success(view.revision, view.workspaceRevision, compactTaskContext(view.data, inherited));
16997
17165
  }
16998
17166
  view(task, capture = true, freshness = treeFreshness(this.store.root)) {
16999
17167
  const workspace = this.store.readWorkspace();
@@ -17288,8 +17456,9 @@ var currentTaskEntry = (entries, session, selection) => {
17288
17456
  const active = entries.filter((entry) => entry.status === "active");
17289
17457
  return active.length === 1 ? active[0] : null;
17290
17458
  };
17459
+ var otherConversation = (entry, session) => entry.sessions.some((item) => item.host !== "workit_cli" && !(item.host === session.host && item.handle === session.handle));
17291
17460
  var implicitTaskEntry = (store, entries, session) => {
17292
- const open = entries.filter((entry) => entry.key !== null && entry.status !== "closed" && !entry.sessions.some((item) => item.host !== "workit_cli" && !(item.host === session.host && item.handle === session.handle)));
17461
+ const open = entries.filter((entry) => entry.key !== null && entry.status !== "closed" && !otherConversation(entry, session));
17293
17462
  if (open.length === 0)
17294
17463
  return null;
17295
17464
  const key = store.currentKey();
@@ -17330,18 +17499,23 @@ function sessionCompactContext(store, session, context, selection = "session-bou
17330
17499
  if (!listed.ok)
17331
17500
  return migrationPending(listed) ? MIGRATION_PENDING_NOTE : null;
17332
17501
  const entry = currentTaskEntry(listed.data, session, selection) ?? implicitTaskEntry(store, listed.data, session);
17333
- return entry ? entryCompactContext(store, entry, session, context) : null;
17502
+ return entryCompactContext(store, entry, session, context);
17334
17503
  }
17335
17504
  function entryCompactContext(store, entry, session, context) {
17505
+ const found = store.originTaskEntry();
17506
+ const origin = found.ok && found.data && found.data.entry.id !== entry?.id && !otherConversation(found.data.entry, session) ? found.data : null;
17507
+ if (!entry && !origin)
17508
+ return null;
17336
17509
  const workspace = store.readWorkspace();
17337
- if (!workspace.ok || !workspace.data)
17510
+ if (!workspace.ok || entry && !workspace.data)
17338
17511
  return null;
17339
17512
  const slot = `${store.root}\x00${session.host}\x00${session.handle}`;
17340
17513
  const key = canonicalJson({
17341
- task: entry.id,
17342
- revision: entry.revision,
17343
- file: entry.file,
17344
- workspace: workspace.data.revision,
17514
+ task: entry?.id ?? null,
17515
+ revision: entry?.revision ?? null,
17516
+ file: entry?.file ?? null,
17517
+ origin: origin && origin.entry.file,
17518
+ workspace: workspace.data?.revision ?? null,
17345
17519
  caller: context.caller,
17346
17520
  workerId: context.workerId ?? null,
17347
17521
  capabilities: context.capabilities
@@ -17349,15 +17523,15 @@ function entryCompactContext(store, entry, session, context) {
17349
17523
  const hit = cache.get(slot);
17350
17524
  if (hit && hit.key === key && hit.filesKey !== null && hit.filesKey === filesKey(hit.files) && (hit.signal === null || hit.signal === recentSignal(store.root)))
17351
17525
  return hit.value;
17352
- const task = store.readTask(entry.id);
17353
- if (!task.ok)
17526
+ const task = entry ? store.readTask(entry.id) : null;
17527
+ if (task && !task.ok)
17354
17528
  return null;
17355
17529
  const freshness = { mode: "signal", current: () => recentSignal(store.root) };
17356
- const observed = task.data.evidence.some(isObservedCheck);
17357
- const files = task.data.decisions.flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path16.resolve(store.root, ref.path)] : []));
17530
+ const observed = task?.data.evidence.some(isObservedCheck) ?? false;
17531
+ const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path17.resolve(store.root, ref.path)] : []));
17358
17532
  const observedFiles = filesKey(files);
17359
- const compact = new WorkitCore(store, context).compactContext(entry.id, freshness);
17360
- if (!compact.ok)
17533
+ const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
17534
+ if (!compact.ok || !compact.data)
17361
17535
  return null;
17362
17536
  cache.delete(slot);
17363
17537
  cache.set(slot, {
@@ -17396,7 +17570,7 @@ ${options.addendum}` : ""}
17396
17570
  if (!listed.ok)
17397
17571
  throw new Error(listed.error);
17398
17572
  const entry = currentTaskEntry(listed.data, session, descriptor.context.task) ?? implicitTaskEntry(store, listed.data, session);
17399
- const text = entry ? entryCompactContext(store, entry, session, hookOperationContext(input, descriptor)) : null;
17573
+ const text = entryCompactContext(store, entry, session, hookOperationContext(input, descriptor));
17400
17574
  if (text)
17401
17575
  compact = `
17402
17576
  <workit-task-context>${text}</workit-task-context>`;
@@ -17423,7 +17597,7 @@ var turnContextText = (input, descriptor) => {
17423
17597
  }
17424
17598
  };
17425
17599
  var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
17426
- var digestOf = (text) => createHash10("sha256").update(text).digest("hex");
17600
+ var digestOf = (text) => createHash11("sha256").update(text).digest("hex");
17427
17601
  var turnMarker = (input) => {
17428
17602
  if (!input.session.id)
17429
17603
  return null;
@@ -17432,32 +17606,32 @@ var turnMarker = (input) => {
17432
17606
  if (location instanceof Error)
17433
17607
  return null;
17434
17608
  const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
17435
- return path16.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
17609
+ return path17.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
17436
17610
  } catch {
17437
17611
  return null;
17438
17612
  }
17439
17613
  };
17440
17614
  var writeTurnDigest = (file, digest) => {
17441
17615
  try {
17442
- fs13.mkdirSync(path16.dirname(file), { recursive: true });
17443
- fs13.writeFileSync(file, `${JSON.stringify({ digest })}
17616
+ fs14.mkdirSync(path17.dirname(file), { recursive: true });
17617
+ fs14.writeFileSync(file, `${JSON.stringify({ digest })}
17444
17618
  `);
17445
17619
  } catch {}
17446
17620
  };
17447
17621
  var clearTurnDigest = (file) => {
17448
17622
  try {
17449
- fs13.rmSync(file, { force: true });
17623
+ fs14.rmSync(file, { force: true });
17450
17624
  } catch {}
17451
17625
  };
17452
17626
  var pruneTurnDigests = (dir, now) => {
17453
17627
  try {
17454
- for (const name of fs13.readdirSync(dir)) {
17628
+ for (const name of fs14.readdirSync(dir)) {
17455
17629
  if (!name.startsWith("turn-"))
17456
17630
  continue;
17457
- const file = path16.join(dir, name);
17631
+ const file = path17.join(dir, name);
17458
17632
  try {
17459
- if (now - fs13.statSync(file).mtimeMs > TURN_TTL_MS)
17460
- fs13.rmSync(file, { force: true });
17633
+ if (now - fs14.statSync(file).mtimeMs > TURN_TTL_MS)
17634
+ fs14.rmSync(file, { force: true });
17461
17635
  } catch {}
17462
17636
  }
17463
17637
  } catch {}
@@ -17473,7 +17647,7 @@ var changedTurnContext = (input, text) => {
17473
17647
  return text;
17474
17648
  const digest = digestOf(text);
17475
17649
  try {
17476
- const previous = JSON.parse(fs13.readFileSync(file, "utf8"));
17650
+ const previous = JSON.parse(fs14.readFileSync(file, "utf8"));
17477
17651
  if (previous.digest === digest)
17478
17652
  return null;
17479
17653
  } catch {}
@@ -17484,14 +17658,14 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
17484
17658
  const file = turnMarker(input);
17485
17659
  if (!file)
17486
17660
  return;
17487
- pruneTurnDigests(path16.dirname(file), Date.now());
17661
+ pruneTurnDigests(path17.dirname(file), Date.now());
17488
17662
  if (text)
17489
17663
  writeTurnDigest(file, digestOf(text));
17490
17664
  else
17491
17665
  clearTurnDigest(file);
17492
17666
  };
17493
17667
  // packages/workit-core/src/core/branch.ts
17494
- import { createHash as createHash11 } from "node:crypto";
17668
+ import { createHash as createHash12 } from "node:crypto";
17495
17669
  var withReleaseTracks = (workspaceRoot, policy) => {
17496
17670
  const read = workspaceReleaseTracks(workspaceRoot);
17497
17671
  if (read.error)
@@ -17559,7 +17733,7 @@ var branchPolicySnapshotFor = (workspaceRoot) => {
17559
17733
  const source = resolved.provenance.branchPolicy;
17560
17734
  const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
17561
17735
  const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
17562
- const fingerprint = createHash11("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
17736
+ const fingerprint = createHash12("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
17563
17737
  return {
17564
17738
  branchPolicy,
17565
17739
  namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
@@ -17608,7 +17782,7 @@ var shellPolicy = (cwd, command) => {
17608
17782
  };
17609
17783
  // packages/workit-core/src/hooks/write-gate.ts
17610
17784
  import { realpathSync as realpathSync5 } from "node:fs";
17611
- import path17 from "node:path";
17785
+ import path18 from "node:path";
17612
17786
 
17613
17787
  // packages/workit-core/src/hooks/shell-words.ts
17614
17788
  var closingQuote = (command, start, dialect) => {
@@ -17738,22 +17912,22 @@ var NONE2 = { kind: "none" };
17738
17912
  var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
17739
17913
  var canonical2 = (file) => {
17740
17914
  let rest = "";
17741
- for (let dir = path17.resolve(file);; dir = path17.dirname(dir)) {
17915
+ for (let dir = path18.resolve(file);; dir = path18.dirname(dir)) {
17742
17916
  try {
17743
- return path17.join(realpathSync5(dir), rest);
17917
+ return path18.join(realpathSync5(dir), rest);
17744
17918
  } catch {
17745
- if (path17.dirname(dir) === dir)
17746
- return path17.resolve(file);
17747
- rest = rest ? path17.join(path17.basename(dir), rest) : path17.basename(dir);
17919
+ if (path18.dirname(dir) === dir)
17920
+ return path18.resolve(file);
17921
+ rest = rest ? path18.join(path18.basename(dir), rest) : path18.basename(dir);
17748
17922
  }
17749
17923
  }
17750
17924
  };
17751
17925
  var exempt = (cwd, root, file, plans) => {
17752
17926
  const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
17753
- const relative = path17.relative(fold(canonical2(root)), fold(canonical2(path17.resolve(cwd, file))));
17754
- if (relative.startsWith("..") || path17.isAbsolute(relative))
17927
+ const relative = path18.relative(fold(canonical2(root)), fold(canonical2(path18.resolve(cwd, file))));
17928
+ if (relative.startsWith("..") || path18.isAbsolute(relative))
17755
17929
  return true;
17756
- const posix = relative.split(path17.sep).join("/");
17930
+ const posix = relative.split(path18.sep).join("/");
17757
17931
  const segments = posix.split("/");
17758
17932
  return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
17759
17933
  };
@@ -17851,7 +18025,7 @@ var shellWrites = (command) => {
17851
18025
  return { writes: true, targets: unknown ? null : targets };
17852
18026
  };
17853
18027
  var cache2 = new Map;
17854
- var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path17.resolve(root, file)) ?? "-").join("\x00");
18028
+ var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path18.resolve(root, file)) ?? "-").join("\x00");
17855
18029
  var gateFor = (cwd) => {
17856
18030
  const store = new TaskStore(cwd);
17857
18031
  const listed = store.listTaskIndex();
@@ -17911,15 +18085,15 @@ import { spawnSync as spawnSync12 } from "node:child_process";
17911
18085
 
17912
18086
  // packages/workit-core/src/hooks/raw-git.ts
17913
18087
  import { spawnSync as spawnSync11 } from "node:child_process";
17914
- import { createHash as createHash13 } from "node:crypto";
17915
- import fs15 from "node:fs";
18088
+ import { createHash as createHash14 } from "node:crypto";
18089
+ import fs16 from "node:fs";
17916
18090
  import os4 from "node:os";
17917
- import path19 from "node:path";
18091
+ import path20 from "node:path";
17918
18092
 
17919
18093
  // packages/workit-core/src/hooks/session-marker.ts
17920
- import { createHash as createHash12 } from "node:crypto";
17921
- import fs14 from "node:fs";
17922
- import path18 from "node:path";
18094
+ import { createHash as createHash13 } from "node:crypto";
18095
+ import fs15 from "node:fs";
18096
+ import path19 from "node:path";
17923
18097
  var sessionMarkerFile = (input, session, store) => {
17924
18098
  let dir = store;
17925
18099
  if (dir === undefined) {
@@ -17928,13 +18102,13 @@ var sessionMarkerFile = (input, session, store) => {
17928
18102
  return null;
17929
18103
  dir = location.dir;
17930
18104
  }
17931
- const name = createHash12("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
17932
- return path18.join(dir, "hooks", `skills-${name}.json`);
18105
+ const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
18106
+ return path19.join(dir, "hooks", `skills-${name}.json`);
17933
18107
  };
17934
18108
  var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
17935
18109
  var readSessionMarker = (file) => {
17936
18110
  try {
17937
- const value = JSON.parse(fs14.readFileSync(file, "utf8"));
18111
+ const value = JSON.parse(fs15.readFileSync(file, "utf8"));
17938
18112
  return { nudged: list2(value.nudged), loaded: list2(value.loaded), raw: list2(value.raw) };
17939
18113
  } catch {
17940
18114
  return { nudged: [], loaded: [], raw: [] };
@@ -17942,8 +18116,8 @@ var readSessionMarker = (file) => {
17942
18116
  };
17943
18117
  var writeSessionMarker = (file, marker) => {
17944
18118
  try {
17945
- fs14.mkdirSync(path18.dirname(file), { recursive: true });
17946
- fs14.writeFileSync(file, JSON.stringify(marker));
18119
+ fs15.mkdirSync(path19.dirname(file), { recursive: true });
18120
+ fs15.writeFileSync(file, JSON.stringify(marker));
17947
18121
  } catch {}
17948
18122
  };
17949
18123
 
@@ -17964,12 +18138,12 @@ var GIT_VALUE_OPTIONS = new Set([
17964
18138
  "--config-env",
17965
18139
  "--super-prefix"
17966
18140
  ]);
17967
- var isAbsolute = (value) => path19.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
18141
+ var isAbsolute = (value) => path20.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
17968
18142
  var joinDir = (base, next) => {
17969
18143
  if (base === undefined || /[$`*?]/.test(next) || next === "-")
17970
18144
  return;
17971
- const expanded = next === "~" || next.startsWith("~/") ? path19.join(os4.homedir(), next.slice(1)) : next;
17972
- return base === null || isAbsolute(expanded) ? expanded : path19.join(base, expanded);
18145
+ const expanded = next === "~" || next.startsWith("~/") ? path20.join(os4.homedir(), next.slice(1)) : next;
18146
+ return base === null || isAbsolute(expanded) ? expanded : path20.join(base, expanded);
17973
18147
  };
17974
18148
  var cdTarget = (words) => {
17975
18149
  const args = words.slice(1);
@@ -18222,7 +18396,7 @@ var repoAt = (dir) => {
18222
18396
  return { location, dir, branch: resolveTaskKey(dir, location).branch };
18223
18397
  };
18224
18398
  var isWorkitWorkspace = (repo) => {
18225
- if (fs15.existsSync(repo.location.dir))
18399
+ if (fs16.existsSync(repo.location.dir))
18226
18400
  return true;
18227
18401
  try {
18228
18402
  return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
@@ -18253,17 +18427,17 @@ var headSha2 = (repo) => {
18253
18427
  if (!git || git.reftable)
18254
18428
  return null;
18255
18429
  try {
18256
- const head = fs15.readFileSync(path19.join(git.gitDir, "HEAD"), "utf8").trim();
18430
+ const head = fs16.readFileSync(path20.join(git.gitDir, "HEAD"), "utf8").trim();
18257
18431
  if (/^[0-9a-f]{40,64}$/.test(head))
18258
18432
  return head;
18259
18433
  const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
18260
18434
  if (!ref)
18261
18435
  return null;
18262
- const common = path19.dirname(repo.location.dir);
18436
+ const common = path20.dirname(repo.location.dir);
18263
18437
  try {
18264
- return fs15.readFileSync(path19.join(common, ref), "utf8").trim() || null;
18438
+ return fs16.readFileSync(path20.join(common, ref), "utf8").trim() || null;
18265
18439
  } catch {}
18266
- const packed = fs15.readFileSync(path19.join(common, "packed-refs"), "utf8");
18440
+ const packed = fs16.readFileSync(path20.join(common, "packed-refs"), "utf8");
18267
18441
  return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
18268
18442
  } catch {
18269
18443
  return null;
@@ -18300,7 +18474,7 @@ var actionsIn = (cwd, command, dialect) => {
18300
18474
  const action = rawAction(invocation);
18301
18475
  if (!action)
18302
18476
  continue;
18303
- const dir = path19.resolve(cwd, invocation.dir ?? ".");
18477
+ const dir = path20.resolve(cwd, invocation.dir ?? ".");
18304
18478
  if (!repos.has(dir)) {
18305
18479
  const repo = repoAt(dir);
18306
18480
  repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
@@ -18369,8 +18543,8 @@ function rawGitPre(input, command, options = {}) {
18369
18543
  var deny = (reason) => ({ kind: "deny", reason, unblock: null });
18370
18544
  var NEXT_COMMAND = "next";
18371
18545
  var MARKER_TTL_SECONDS = 3600;
18372
- var markerFile = (repo, session, key) => path19.join(repo.location.dir, "hooks", `commit-${createHash13("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
18373
- var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash13("sha256").update(command).digest("hex")}`;
18546
+ var markerFile = (repo, session, key) => path20.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
18547
+ var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash14("sha256").update(command).digest("hex")}`;
18374
18548
  function noteRawCommit(input, command, key) {
18375
18549
  try {
18376
18550
  if (!input.session.id || !/\bcommit\b/.test(command))
@@ -18380,8 +18554,8 @@ function noteRawCommit(input, command, key) {
18380
18554
  if (action.kind !== "commit")
18381
18555
  continue;
18382
18556
  const file = markerFile(repo, input.session.id, key);
18383
- fs15.mkdirSync(path19.dirname(file), { recursive: true });
18384
- fs15.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
18557
+ fs16.mkdirSync(path20.dirname(file), { recursive: true });
18558
+ fs16.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
18385
18559
  `);
18386
18560
  }
18387
18561
  } catch {}
@@ -18404,11 +18578,11 @@ var headCommit = (dir) => {
18404
18578
  var settle2 = (input, repo, file) => {
18405
18579
  let marker;
18406
18580
  try {
18407
- marker = JSON.parse(fs15.readFileSync(file, "utf8"));
18581
+ marker = JSON.parse(fs16.readFileSync(file, "utf8"));
18408
18582
  } catch {
18409
18583
  return;
18410
18584
  }
18411
- fs15.rmSync(file, { force: true });
18585
+ fs16.rmSync(file, { force: true });
18412
18586
  const session = input.session.id;
18413
18587
  const now = Date.now() / 1000;
18414
18588
  if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
@@ -18457,7 +18631,7 @@ function settlePendingCommit(input) {
18457
18631
  if (!repo)
18458
18632
  return;
18459
18633
  const file = markerFile(repo, input.session.id, NEXT_COMMAND);
18460
- if (fs15.existsSync(file))
18634
+ if (fs16.existsSync(file))
18461
18635
  settle2(input, repo, file);
18462
18636
  } catch {}
18463
18637
  }
@@ -18847,12 +19021,12 @@ ${line}` };
18847
19021
  };
18848
19022
  // packages/workit-core/src/hooks/hosts/fields.ts
18849
19023
  import { existsSync as existsSync6, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
18850
- import path20 from "node:path";
19024
+ import path21 from "node:path";
18851
19025
  var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
18852
19026
  var nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "";
18853
19027
  var optionalText = (value) => typeof value === "string" ? value : null;
18854
19028
  var existingDirectory = (value) => {
18855
- if (!nonEmpty2(value) || !path20.isAbsolute(value) || !existsSync6(value))
19029
+ if (!nonEmpty2(value) || !path21.isAbsolute(value) || !existsSync6(value))
18856
19030
  return null;
18857
19031
  try {
18858
19032
  return statSync2(value).isDirectory() ? realpathSync6(value) : null;
@@ -18952,6 +19126,8 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
18952
19126
  if (role !== "judge" || !event.agentId)
18953
19127
  return readOnly;
18954
19128
  const own = subagentSession(session, event.agentId);
19129
+ if (session)
19130
+ recordIssuedSession(input.cwd || process.cwd(), session, own);
18955
19131
  return `${readOnly} Its own Workit session is ${own}: record verdicts with \`workit ledger verdict <result> --session ${own} ...\` so the ledger tells it apart from the author.`;
18956
19132
  };
18957
19133
  function handleHook(input, deps) {
@@ -19583,12 +19759,12 @@ var codexAdapter = {
19583
19759
  };
19584
19760
  },
19585
19761
  render: render2,
19586
- addendum: (input) => `<workit-codex-mutations>Codex MCP is read-only: unattested callers cannot mutate. Run workit verbs with the workit CLI on the shell (node_modules/.bin/workit, or npx -y @brainervirus/workit-cli): check, git branch|commit|push, pr, ci, stack, ledger, handoff; task-family mutations take --json${input.session.id ? ` --actor ${input.session.id}` : ""}. workit acts as this thread (CODEX_THREAD_ID${input.session.id ? `=${input.session.id}` : ""}) unless WORKIT_SESSION_ID is set. A verifier or reviewer records workit ledger verdict under its own session, never the author's: a workit-verifier or workit-reviewer agent uses the --session its SubagentStart context names; any other uses one the lead assigns (WORKIT_HOST=codex_cli WORKIT_SESSION_ID=<lead>-v<n>). Merge and release need a workspace grant (workit grant show); a question answer is not host permission.</workit-codex-mutations>`
19762
+ addendum: (input) => `<workit-codex-mutations>Codex MCP is read-only: unattested callers cannot mutate. Run workit verbs with the workit CLI on the shell (node_modules/.bin/workit, or npx -y @brainervirus/workit-cli): check, git branch|commit|push, pr, ci, stack, ledger, handoff; task-family mutations take --json${input.session.id ? ` --actor ${input.session.id}` : ""}. workit acts as this thread (CODEX_THREAD_ID${input.session.id ? `=${input.session.id}` : ""}) unless WORKIT_SESSION_ID is set. A verifier or reviewer records workit ledger verdict under its own session, never the author's: a workit-verifier or workit-reviewer agent uses the --session its SubagentStart context names; any other passes --as verifier (an id derived from its own thread). A hand-minted id such as <lead>-v1 is refused as forged_session. Merge and release need a workspace grant (workit grant show); a question answer is not host permission.</workit-codex-mutations>`
19587
19763
  };
19588
19764
 
19589
19765
  // packages/workit-core/src/hooks/hosts/cursor.ts
19590
- import fs16 from "node:fs";
19591
- import path21 from "node:path";
19766
+ import fs17 from "node:fs";
19767
+ import path22 from "node:path";
19592
19768
  var undocumented = { support: "undocumented", native: null };
19593
19769
  var none = { support: "none", native: null };
19594
19770
  var CURSOR_DESCRIPTOR = {
@@ -19785,17 +19961,17 @@ var protocolEvent2 = (input) => {
19785
19961
  };
19786
19962
  var TRANSCRIPT_TAIL_BYTES = 256 * 1024;
19787
19963
  var lastAssistantText = (file) => {
19788
- if (!file || !path21.isAbsolute(file))
19964
+ if (!file || !path22.isAbsolute(file))
19789
19965
  return null;
19790
19966
  try {
19791
- const size = fs16.statSync(file).size;
19967
+ const size = fs17.statSync(file).size;
19792
19968
  const start = Math.max(0, size - TRANSCRIPT_TAIL_BYTES);
19793
19969
  const buffer = Buffer.alloc(size - start);
19794
- const fd = fs16.openSync(file, "r");
19970
+ const fd = fs17.openSync(file, "r");
19795
19971
  try {
19796
- fs16.readSync(fd, buffer, 0, buffer.length, start);
19972
+ fs17.readSync(fd, buffer, 0, buffer.length, start);
19797
19973
  } finally {
19798
- fs16.closeSync(fd);
19974
+ fs17.closeSync(fd);
19799
19975
  }
19800
19976
  const lines = buffer.toString("utf8").split(`
19801
19977
  `);
@@ -19822,7 +19998,7 @@ var lastAssistantText = (file) => {
19822
19998
  return null;
19823
19999
  }
19824
20000
  };
19825
- var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path21.sep) ? root : `${root}${path21.sep}`);
20001
+ var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path22.sep) ? root : `${root}${path22.sep}`);
19826
20002
  var hookCwd = (input) => {
19827
20003
  const cwd = existingDirectory(input.cwd);
19828
20004
  if (cwd && input.hook_event_name === "beforeShellExecution")