@brainervirus/workit-cursor 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.
@@ -8377,7 +8377,7 @@ import { realpathSync as realpathSync4 } from "node:fs";
8377
8377
 
8378
8378
  // packages/workit-core/src/core/policy/derive.ts
8379
8379
  import { existsSync as existsSync2 } from "node:fs";
8380
- import path7 from "node:path";
8380
+ import path8 from "node:path";
8381
8381
 
8382
8382
  // packages/workit-core/src/git/rev.ts
8383
8383
  import { spawnSync } from "node:child_process";
@@ -8562,9 +8562,9 @@ function pushRemoteName(cwd, branch) {
8562
8562
 
8563
8563
  // packages/workit-core/src/ledger.ts
8564
8564
  import { spawnSync as spawnSync7 } from "node:child_process";
8565
- import { createHash as createHash6, randomBytes } from "node:crypto";
8566
- import fs4 from "node:fs";
8567
- import path6 from "node:path";
8565
+ import { createHash as createHash7, randomBytes } from "node:crypto";
8566
+ import fs5 from "node:fs";
8567
+ import path7 from "node:path";
8568
8568
 
8569
8569
  // packages/workit-core/src/core/vcs-config.ts
8570
8570
  import fs2 from "node:fs";
@@ -9799,33 +9799,9 @@ function vcsConfig(mode, cwd, options = {}) {
9799
9799
  }
9800
9800
 
9801
9801
  // packages/workit-core/src/host-session.ts
9802
- var HOST_SESSION_VARS = [
9803
- ["OPENCODE_SESSION_ID", () => "opencode"],
9804
- ["PI_SESSION_ID", () => "pi"],
9805
- [
9806
- "CODEX_THREAD_ID",
9807
- (env) => env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || env.CODEX_ELECTRON_RESOURCES_PATH ? "codex_desktop" : "codex_cli"
9808
- ]
9809
- ];
9810
- var family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null;
9811
- function hostSessionFromEnv(env) {
9812
- const value = (key) => env[key]?.trim() || null;
9813
- let inner = null;
9814
- for (const [key, host] of HOST_SESSION_VARS) {
9815
- const session = value(key);
9816
- if (session) {
9817
- inner = { host: host(env), session };
9818
- break;
9819
- }
9820
- }
9821
- const declared = value("WORKIT_HOST");
9822
- if (env.WORKIT_SESSION_ID !== undefined) {
9823
- const inherited = inner !== null && declared !== null && family(declared) !== family(inner.host);
9824
- if (!inherited)
9825
- return { host: declared, session: value("WORKIT_SESSION_ID") };
9826
- }
9827
- return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
9828
- }
9802
+ import { createHash as createHash6 } from "node:crypto";
9803
+ import fs4 from "node:fs";
9804
+ import path6 from "node:path";
9829
9805
 
9830
9806
  // packages/workit-core/src/store/paths.ts
9831
9807
  import { spawnSync as spawnSync6 } from "node:child_process";
@@ -10107,6 +10083,63 @@ var checkoutSlug = (root) => {
10107
10083
  return `${base}-${shortHash(canonical)}`;
10108
10084
  };
10109
10085
 
10086
+ // packages/workit-core/src/host-session.ts
10087
+ var HOST_SESSION_VARS = [
10088
+ ["OPENCODE_SESSION_ID", () => "opencode"],
10089
+ ["PI_SESSION_ID", () => "pi"],
10090
+ [
10091
+ "CODEX_THREAD_ID",
10092
+ (env) => env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || env.CODEX_ELECTRON_RESOURCES_PATH ? "codex_desktop" : "codex_cli"
10093
+ ]
10094
+ ];
10095
+ var family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null;
10096
+ function hostSessionFromEnv(env) {
10097
+ const value = (key) => env[key]?.trim() || null;
10098
+ let inner = null;
10099
+ for (const [key, host] of HOST_SESSION_VARS) {
10100
+ const session = value(key);
10101
+ if (session) {
10102
+ inner = { host: host(env), session };
10103
+ break;
10104
+ }
10105
+ }
10106
+ const declared = value("WORKIT_HOST");
10107
+ if (env.WORKIT_SESSION_ID !== undefined) {
10108
+ const inherited = inner !== null && declared !== null && family(declared) !== family(inner.host);
10109
+ if (!inherited)
10110
+ return { host: declared, session: value("WORKIT_SESSION_ID") };
10111
+ }
10112
+ return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
10113
+ }
10114
+ var ISSUED_PER_LEAD = 64;
10115
+ var ISSUED_SESSIONS_MARKER = "workit-issued-sessions/1";
10116
+ var hash = (value) => createHash6("sha256").update(value).digest("hex").slice(0, 32);
10117
+ var issuedRoot = (cwd) => {
10118
+ const location = resolveStore(cwd);
10119
+ return location instanceof Error ? null : path6.join(location.dir, "hooks", "issued");
10120
+ };
10121
+ var issuedDir = (cwd, lead) => {
10122
+ const root = issuedRoot(cwd);
10123
+ return root === null ? null : path6.join(root, hash(lead));
10124
+ };
10125
+ function recordIssuedSession(cwd, lead, issued) {
10126
+ try {
10127
+ const dir = issuedDir(cwd, lead);
10128
+ if (!dir)
10129
+ return;
10130
+ fs4.mkdirSync(dir, { recursive: true });
10131
+ const own = hash(issued);
10132
+ fs4.writeFileSync(path6.join(dir, own), ISSUED_SESSIONS_MARKER);
10133
+ const entries = fs4.readdirSync(dir);
10134
+ if (entries.length <= ISSUED_PER_LEAD)
10135
+ return;
10136
+ const byAge = entries.filter((name) => name !== own).map((name) => ({ name, at: fs4.statSync(path6.join(dir, name)).mtimeMs })).toSorted((a, b) => a.at - b.at);
10137
+ for (const { name } of byAge.slice(0, entries.length - ISSUED_PER_LEAD))
10138
+ fs4.rmSync(path6.join(dir, name), { force: true });
10139
+ } catch {}
10140
+ }
10141
+ var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
10142
+
10110
10143
  // packages/workit-core/src/ledger.ts
10111
10144
  var LEDGER_VERSION = 1;
10112
10145
  var MAX_LINE_BYTES = 4096;
@@ -10212,7 +10245,7 @@ function diffHash(cwd, base, head) {
10212
10245
  ], GIT_TIMEOUTS.worktree);
10213
10246
  if (!diff.ok || !diff.stdout)
10214
10247
  return null;
10215
- const hash = createHash6("sha256");
10248
+ const hash = createHash7("sha256");
10216
10249
  for (const line of diff.stdout.split(`
10217
10250
  `)) {
10218
10251
  if (line.startsWith("index "))
@@ -10224,14 +10257,14 @@ function diffHash(cwd, base, head) {
10224
10257
  return `sha256:${hash.digest("hex")}`;
10225
10258
  }
10226
10259
  function storeRoot(cwd) {
10227
- const location = resolveStore(path6.resolve(cwd));
10260
+ const location = resolveStore(path7.resolve(cwd));
10228
10261
  if (location instanceof Error)
10229
10262
  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");
10230
10263
  return { ok: true, value: { root: location.dir, shared: location.shared } };
10231
10264
  }
10232
10265
  function ledgerPath(cwd) {
10233
10266
  const root = storeRoot(cwd);
10234
- return root.ok ? { ok: true, value: path6.join(root.value.root, "ledger", "ledger.jsonl") } : root;
10267
+ return root.ok ? { ok: true, value: path7.join(root.value.root, "ledger", "ledger.jsonl") } : root;
10235
10268
  }
10236
10269
  var newId2 = () => `${Date.now().toString(36)}-${randomBytes(6).toString("hex")}`;
10237
10270
  var NETWORK_FS_TYPES = new Set([
@@ -10251,7 +10284,7 @@ var onNetworkFs = (dir) => {
10251
10284
  if (process.platform !== "linux")
10252
10285
  return false;
10253
10286
  try {
10254
- return isNetworkFsType(fs4.statfsSync(dir).type);
10287
+ return isNetworkFsType(fs5.statfsSync(dir).type);
10255
10288
  } catch {
10256
10289
  return false;
10257
10290
  }
@@ -10261,15 +10294,15 @@ var LOCK_STALE_MS = 30000;
10261
10294
  var LOCK_OWNER = "owner";
10262
10295
  var lockToken = (lock) => {
10263
10296
  try {
10264
- return fs4.readFileSync(path6.join(lock, LOCK_OWNER), "utf8");
10297
+ return fs5.readFileSync(path7.join(lock, LOCK_OWNER), "utf8");
10265
10298
  } catch {
10266
10299
  return null;
10267
10300
  }
10268
10301
  };
10269
10302
  var lockAgeMs = (lock) => {
10270
- for (const target of [path6.join(lock, LOCK_OWNER), lock]) {
10303
+ for (const target of [path7.join(lock, LOCK_OWNER), lock]) {
10271
10304
  try {
10272
- return Date.now() - fs4.statSync(target).mtimeMs;
10305
+ return Date.now() - fs5.statSync(target).mtimeMs;
10273
10306
  } catch {}
10274
10307
  }
10275
10308
  return null;
@@ -10277,14 +10310,14 @@ var lockAgeMs = (lock) => {
10277
10310
  var ledgerLock = {
10278
10311
  acquire(lock) {
10279
10312
  try {
10280
- fs4.mkdirSync(lock);
10313
+ fs5.mkdirSync(lock);
10281
10314
  } catch (error) {
10282
10315
  if (error.code === "EEXIST")
10283
10316
  return null;
10284
10317
  throw error;
10285
10318
  }
10286
10319
  const token = `${process.pid}-${randomBytes(8).toString("hex")}`;
10287
- fs4.writeFileSync(path6.join(lock, LOCK_OWNER), token);
10320
+ fs5.writeFileSync(path7.join(lock, LOCK_OWNER), token);
10288
10321
  return token;
10289
10322
  },
10290
10323
  release(lock, token) {
@@ -10292,35 +10325,35 @@ var ledgerLock = {
10292
10325
  return false;
10293
10326
  const tomb = `${lock}.release-${randomBytes(6).toString("hex")}`;
10294
10327
  try {
10295
- fs4.renameSync(lock, tomb);
10328
+ fs5.renameSync(lock, tomb);
10296
10329
  } catch {
10297
10330
  return false;
10298
10331
  }
10299
10332
  if (lockToken(tomb) !== token) {
10300
10333
  try {
10301
- fs4.renameSync(tomb, lock);
10334
+ fs5.renameSync(tomb, lock);
10302
10335
  } catch {}
10303
10336
  return false;
10304
10337
  }
10305
- fs4.rmSync(tomb, { recursive: true, force: true });
10338
+ fs5.rmSync(tomb, { recursive: true, force: true });
10306
10339
  return true;
10307
10340
  },
10308
10341
  token: lockToken,
10309
10342
  reap(lock, observed) {
10310
10343
  const tomb = `${lock}.reap-${randomBytes(6).toString("hex")}`;
10311
10344
  try {
10312
- fs4.renameSync(lock, tomb);
10345
+ fs5.renameSync(lock, tomb);
10313
10346
  } catch {
10314
10347
  return false;
10315
10348
  }
10316
10349
  if (lockToken(tomb) === observed) {
10317
- fs4.rmSync(tomb, { recursive: true, force: true });
10350
+ fs5.rmSync(tomb, { recursive: true, force: true });
10318
10351
  return true;
10319
10352
  }
10320
10353
  try {
10321
- fs4.renameSync(tomb, lock);
10354
+ fs5.renameSync(tomb, lock);
10322
10355
  } catch {
10323
- fs4.rmSync(tomb, { recursive: true, force: true });
10356
+ fs5.rmSync(tomb, { recursive: true, force: true });
10324
10357
  }
10325
10358
  return false;
10326
10359
  }
@@ -10347,14 +10380,14 @@ function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
10347
10380
  ledgerLock.release(lock, token);
10348
10381
  }
10349
10382
  }
10350
- var sha2562 = (text) => createHash6("sha256").update(text).digest("hex");
10383
+ var sha2562 = (text) => createHash7("sha256").update(text).digest("hex");
10351
10384
  var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
10352
10385
  ${body}`);
10353
10386
  var TAIL_BYTES = 64 * 1024;
10354
10387
  var lastLine = (fd, size) => {
10355
10388
  for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
10356
10389
  const buffer = Buffer.alloc(span);
10357
- fs4.readSync(fd, buffer, 0, span, size - span);
10390
+ fs5.readSync(fd, buffer, 0, span, size - span);
10358
10391
  const end = buffer.lastIndexOf(10);
10359
10392
  if (end < 0) {
10360
10393
  if (span === size)
@@ -10385,13 +10418,13 @@ var lastLine = (fd, size) => {
10385
10418
  };
10386
10419
  function appendLine(file, build, options) {
10387
10420
  const write = () => {
10388
- const fd = fs4.openSync(file, "a+");
10421
+ const fd = fs5.openSync(file, "a+");
10389
10422
  try {
10390
- const size = fs4.fstatSync(fd).size;
10423
+ const size = fs5.fstatSync(fd).size;
10391
10424
  let fence = "";
10392
10425
  if (size > 0) {
10393
10426
  const last = Buffer.alloc(1);
10394
- fs4.readSync(fd, last, 0, 1, size - 1);
10427
+ fs5.readSync(fd, last, 0, 1, size - 1);
10395
10428
  if (last[0] !== 10)
10396
10429
  fence = `
10397
10430
  `;
@@ -10400,17 +10433,17 @@ function appendLine(file, build, options) {
10400
10433
  if (!line.ok)
10401
10434
  return line;
10402
10435
  const bytes = Buffer.from(fence + line.value);
10403
- const written = fs4.writeSync(fd, bytes);
10436
+ const written = fs5.writeSync(fd, bytes);
10404
10437
  if (written !== bytes.length)
10405
10438
  return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
10406
10439
  return { ok: true, value: undefined };
10407
10440
  } finally {
10408
- fs4.closeSync(fd);
10441
+ fs5.closeSync(fd);
10409
10442
  }
10410
10443
  };
10411
10444
  try {
10412
- fs4.mkdirSync(path6.dirname(file), { recursive: true });
10413
- if (!options.forceLock && !onNetworkFs(path6.dirname(file)))
10445
+ fs5.mkdirSync(path7.dirname(file), { recursive: true });
10446
+ if (!options.forceLock && !onNetworkFs(path7.dirname(file)))
10414
10447
  return write();
10415
10448
  const locked = withLedgerLock(file, write);
10416
10449
  return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
@@ -10482,7 +10515,7 @@ function readLedger(cwd, options = {}) {
10482
10515
  return file;
10483
10516
  let text = "";
10484
10517
  try {
10485
- text = fs4.readFileSync(file.value, "utf8");
10518
+ text = fs5.readFileSync(file.value, "utf8");
10486
10519
  } catch (error) {
10487
10520
  if (error.code === "ENOENT")
10488
10521
  return {
@@ -10676,11 +10709,20 @@ function authorSessions(cwd, rows, branch, range = { base: null, head: null }, s
10676
10709
  sessions.add(session);
10677
10710
  return sessions;
10678
10711
  }
10712
+ var derivesFrom = (derived, bare) => !bare.includes(":") && derived.endsWith(`:${bare}`);
10713
+ var authoredBy = (authors, session) => {
10714
+ if (authors.has(session))
10715
+ return true;
10716
+ for (const author of authors)
10717
+ if (derivesFrom(author, session) || derivesFrom(session, author))
10718
+ return true;
10719
+ return false;
10720
+ };
10679
10721
  var independenceReasons = (row, authors) => {
10680
10722
  const reasons = [];
10681
10723
  if (!row.actor.session)
10682
10724
  reasons.push("no_session");
10683
- else if (authors.has(row.actor.session))
10725
+ else if (authoredBy(authors, row.actor.session))
10684
10726
  reasons.push("author_session");
10685
10727
  if (row.self === true && !reasons.includes("no_session"))
10686
10728
  reasons.push("self");
@@ -10964,7 +11006,7 @@ var productDecision = (task, ledger) => {
10964
11006
  };
10965
11007
  };
10966
11008
  var planRecorded = (task, root) => {
10967
- const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync2(path7.resolve(root, ref.path)));
11009
+ const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync2(path8.resolve(root, ref.path)));
10968
11010
  if (cited)
10969
11011
  return {
10970
11012
  met: true,
@@ -11580,7 +11622,7 @@ var judgeInputSummary = (raw) => {
11580
11622
 
11581
11623
  // packages/workit-core/src/autonomy.ts
11582
11624
  import os3 from "node:os";
11583
- import path8 from "node:path";
11625
+ import path9 from "node:path";
11584
11626
  var accountHome = () => {
11585
11627
  try {
11586
11628
  return os3.userInfo().homedir;
@@ -11589,10 +11631,10 @@ var accountHome = () => {
11589
11631
  }
11590
11632
  };
11591
11633
  var grantsHome = { resolve: accountHome };
11592
- var grantsDir = () => path8.join(grantsHome.resolve(), ".config", "workit");
11634
+ var grantsDir = () => path9.join(grantsHome.resolve(), ".config", "workit");
11593
11635
  var grantsOverride = () => {
11594
- const configured = path8.resolve(resolveConfigDir());
11595
- return configured === path8.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 ${path8.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
11636
+ const configured = path9.resolve(resolveConfigDir());
11637
+ return configured === path9.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 ${path9.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
11596
11638
  };
11597
11639
  var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
11598
11640
  var DEFAULT_GRANTS = Object.freeze({
@@ -11716,9 +11758,9 @@ var suggested = (kind) => kind === "merge" ? "verified" : "true";
11716
11758
  var grantHint = (workspace, kind) => `ask the user to run, in their own terminal: workit grant set ${workspace ?? "<workspace>"} ${kind}=${suggested(kind)}`;
11717
11759
 
11718
11760
  // packages/workit-core/src/core/task-store.ts
11719
- import { createHash as createHash8, randomUUID as randomUUID3 } from "node:crypto";
11720
- import * as fs10 from "node:fs";
11721
- import path13 from "node:path";
11761
+ import { createHash as createHash9, randomUUID as randomUUID3 } from "node:crypto";
11762
+ import * as fs11 from "node:fs";
11763
+ import path14 from "node:path";
11722
11764
 
11723
11765
  // node_modules/@openclaw/fs-safe/dist/errors.js
11724
11766
  var OPERATIONAL_CODES = new Set([
@@ -11769,10 +11811,10 @@ function sameFileIdentity(left, right, platform = process.platform) {
11769
11811
  // node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js
11770
11812
  import { randomBytes as randomBytes2 } from "node:crypto";
11771
11813
  import fsSync from "node:fs";
11772
- import path9 from "node:path";
11814
+ import path10 from "node:path";
11773
11815
 
11774
11816
  // node_modules/@openclaw/fs-safe/dist/bounded-read.js
11775
- import fs5 from "node:fs";
11817
+ import fs6 from "node:fs";
11776
11818
 
11777
11819
  // node_modules/@openclaw/fs-safe/dist/byte-budget.js
11778
11820
  function normalizeMaxBytes(value, options = {}) {
@@ -11809,7 +11851,7 @@ function readFileDescriptorBoundedSync(fd, maxBytes) {
11809
11851
  let total = 0;
11810
11852
  while (true) {
11811
11853
  const length = nextReadLength(total, maxBytes, scratch.length);
11812
- const bytesRead = fs5.readSync(fd, scratch, 0, length, null);
11854
+ const bytesRead = fs6.readSync(fd, scratch, 0, length, null);
11813
11855
  if (bytesRead === 0) {
11814
11856
  return Buffer.concat(chunks, total);
11815
11857
  }
@@ -11818,9 +11860,9 @@ function readFileDescriptorBoundedSync(fd, maxBytes) {
11818
11860
  }
11819
11861
 
11820
11862
  // node_modules/@openclaw/fs-safe/dist/read-open-flags.js
11821
- import fs6 from "node:fs";
11863
+ import fs7 from "node:fs";
11822
11864
  function resolveReadOpenFlags(options) {
11823
- const constants = options?.constants ?? fs6.constants;
11865
+ const constants = options?.constants ?? fs7.constants;
11824
11866
  const noFollow = process.platform !== "win32" && options?.followSymlinks !== true && typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
11825
11867
  const nonBlocking = process.platform !== "win32" && typeof constants.O_NONBLOCK === "number" ? constants.O_NONBLOCK : 0;
11826
11868
  return constants.O_RDONLY | noFollow | nonBlocking;
@@ -11859,13 +11901,13 @@ ${ownershipToken}
11859
11901
  return { raw, ownershipToken };
11860
11902
  }
11861
11903
  function relativeSidecarLockPath(lockRoot, lockPath) {
11862
- const resolved = path9.resolve(lockPath);
11863
- const lexicalRelative = path9.relative(lockRoot.rootDir, resolved);
11864
- const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${path9.sep}`) && !path9.isAbsolute(lexicalRelative) ? lexicalRelative : path9.relative(lockRoot.rootReal, resolved);
11865
- if (!relative || relative === ".." || relative.startsWith(`..${path9.sep}`) || path9.isAbsolute(relative)) {
11904
+ const resolved = path10.resolve(lockPath);
11905
+ const lexicalRelative = path10.relative(lockRoot.rootDir, resolved);
11906
+ const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${path10.sep}`) && !path10.isAbsolute(lexicalRelative) ? lexicalRelative : path10.relative(lockRoot.rootReal, resolved);
11907
+ if (!relative || relative === ".." || relative.startsWith(`..${path10.sep}`) || path10.isAbsolute(relative)) {
11866
11908
  throw new FsSafeError("outside-workspace", "sidecar lock path is outside lockRoot");
11867
11909
  }
11868
- return relative.split(path9.sep).join(path9.posix.sep);
11910
+ return relative.split(path10.sep).join(path10.posix.sep);
11869
11911
  }
11870
11912
  function parseSidecarLockPayload(raw, parser) {
11871
11913
  if (parser) {
@@ -12011,8 +12053,8 @@ function getFsSafeLockConfig() {
12011
12053
  }
12012
12054
 
12013
12055
  // node_modules/@openclaw/fs-safe/dist/file-lock-sync.js
12014
- import fs7 from "node:fs";
12015
- import path10 from "node:path";
12056
+ import fs8 from "node:fs";
12057
+ import path11 from "node:path";
12016
12058
 
12017
12059
  // node_modules/@openclaw/fs-safe/dist/timing.js
12018
12060
  function sleepSync(ms) {
@@ -12042,7 +12084,7 @@ function releaseAllSyncHeldLocks() {
12042
12084
  }
12043
12085
  try {
12044
12086
  if (held.fd !== undefined)
12045
- fs7.closeSync(held.fd);
12087
+ fs8.closeSync(held.fd);
12046
12088
  } catch {}
12047
12089
  try {
12048
12090
  removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
@@ -12077,7 +12119,7 @@ function releaseSyncHeldLock(held) {
12077
12119
  if (held.fd !== undefined) {
12078
12120
  const fd = held.fd;
12079
12121
  held.fd = undefined;
12080
- fs7.closeSync(fd);
12122
+ fs8.closeSync(fd);
12081
12123
  }
12082
12124
  removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
12083
12125
  heldLocks.delete(held.normalizedTargetPath);
@@ -12100,29 +12142,29 @@ function createSyncHeldLockHandle(held) {
12100
12142
  };
12101
12143
  }
12102
12144
  function canonicalLockParentSync(parent) {
12103
- return process.platform === "win32" ? fs7.realpathSync.native(parent) : fs7.realpathSync(parent);
12145
+ return process.platform === "win32" ? fs8.realpathSync.native(parent) : fs8.realpathSync(parent);
12104
12146
  }
12105
12147
  function normalizeTargetPath(targetPath) {
12106
- const resolved = path10.resolve(targetPath);
12107
- fs7.mkdirSync(path10.dirname(resolved), { recursive: true });
12148
+ const resolved = path11.resolve(targetPath);
12149
+ fs8.mkdirSync(path11.dirname(resolved), { recursive: true });
12108
12150
  try {
12109
- return path10.join(canonicalLockParentSync(path10.dirname(resolved)), path10.basename(resolved));
12151
+ return path11.join(canonicalLockParentSync(path11.dirname(resolved)), path11.basename(resolved));
12110
12152
  } catch {
12111
12153
  return resolved;
12112
12154
  }
12113
12155
  }
12114
12156
  function boundedLockPath(lockPath, lockRoot) {
12115
- const resolved = path10.resolve(lockPath);
12157
+ const resolved = path11.resolve(lockPath);
12116
12158
  if (!lockRoot)
12117
12159
  return resolved;
12118
12160
  relativeSidecarLockPath(lockRoot, resolved);
12119
- const parent = path10.dirname(resolved);
12161
+ const parent = path11.dirname(resolved);
12120
12162
  const parentReal = canonicalLockParentSync(parent);
12121
- const parentRelative = path10.relative(lockRoot.rootReal, parentReal);
12122
- if (parentRelative === ".." || parentRelative.startsWith(`..${path10.sep}`) || path10.isAbsolute(parentRelative)) {
12163
+ const parentRelative = path11.relative(lockRoot.rootReal, parentReal);
12164
+ if (parentRelative === ".." || parentRelative.startsWith(`..${path11.sep}`) || path11.isAbsolute(parentRelative)) {
12123
12165
  throw new FsSafeError("outside-workspace", "sidecar lock parent is outside lockRoot");
12124
12166
  }
12125
- return path10.join(parentReal, path10.basename(resolved));
12167
+ return path11.join(parentReal, path11.basename(resolved));
12126
12168
  }
12127
12169
  function defaultShouldReclaim(snapshot, staleMs, nowMs) {
12128
12170
  const createdAtMs = sidecarLockPayloadCreatedAtMs(snapshot.payload);
@@ -12132,7 +12174,7 @@ function defaultShouldReclaim(snapshot, staleMs, nowMs) {
12132
12174
  }
12133
12175
  function reclaimGuardExists(reclaimGuardPath) {
12134
12176
  try {
12135
- fs7.lstatSync(reclaimGuardPath);
12177
+ fs8.lstatSync(reclaimGuardPath);
12136
12178
  return true;
12137
12179
  } catch (error) {
12138
12180
  if (error.code === "ENOENT")
@@ -12196,19 +12238,19 @@ function acquireFileLockSync(targetPath, options) {
12196
12238
  const { raw, ownershipToken } = serializeSidecarLockPayload(payload);
12197
12239
  let lockFileCreateDenied = false;
12198
12240
  try {
12199
- const noFollow = process.platform !== "win32" && typeof fs7.constants.O_NOFOLLOW === "number" ? fs7.constants.O_NOFOLLOW : 0;
12241
+ const noFollow = process.platform !== "win32" && typeof fs8.constants.O_NOFOLLOW === "number" ? fs8.constants.O_NOFOLLOW : 0;
12200
12242
  try {
12201
- fd = fs7.openSync(lockPath, fs7.constants.O_WRONLY | fs7.constants.O_CREAT | fs7.constants.O_EXCL | noFollow, 384);
12243
+ fd = fs8.openSync(lockPath, fs8.constants.O_WRONLY | fs8.constants.O_CREAT | fs8.constants.O_EXCL | noFollow, 384);
12202
12244
  } catch (error) {
12203
12245
  lockFileCreateDenied = isTransientLockFileDenial(error, lockPath);
12204
12246
  throw error;
12205
12247
  }
12206
- fs7.writeFileSync(fd, raw, "utf8");
12207
- fs7.fsyncSync(fd);
12248
+ fs8.writeFileSync(fd, raw, "utf8");
12249
+ fs8.fsyncSync(fd);
12208
12250
  const snapshot = {
12209
12251
  raw,
12210
12252
  payload,
12211
- stat: fs7.fstatSync(fd),
12253
+ stat: fs8.fstatSync(fd),
12212
12254
  ownershipToken
12213
12255
  };
12214
12256
  const createdHeld = {
@@ -12243,8 +12285,8 @@ function acquireFileLockSync(targetPath, options) {
12243
12285
  return returnedHandle;
12244
12286
  } catch (error) {
12245
12287
  if (fd !== undefined) {
12246
- const failed = { payload: null, stat: fs7.fstatSync(fd) };
12247
- fs7.closeSync(fd);
12288
+ const failed = { payload: null, stat: fs8.fstatSync(fd) };
12289
+ fs8.closeSync(fd);
12248
12290
  fd = undefined;
12249
12291
  removeSidecarLockIfUnchangedSync(lockPath, failed);
12250
12292
  }
@@ -12293,7 +12335,7 @@ function acquireFileLockSync(targetPath, options) {
12293
12335
  })) {
12294
12336
  let ownsReclaimGuard = false;
12295
12337
  try {
12296
- fs7.mkdirSync(reclaimGuardPath);
12338
+ fs8.mkdirSync(reclaimGuardPath);
12297
12339
  ownsReclaimGuard = true;
12298
12340
  if (removeSidecarLockIfUnchangedSync(lockPath, snapshot))
12299
12341
  continue;
@@ -12306,7 +12348,7 @@ function acquireFileLockSync(targetPath, options) {
12306
12348
  } finally {
12307
12349
  if (ownsReclaimGuard) {
12308
12350
  try {
12309
- fs7.rmdirSync(reclaimGuardPath);
12351
+ fs8.rmdirSync(reclaimGuardPath);
12310
12352
  } catch {}
12311
12353
  }
12312
12354
  }
@@ -12323,13 +12365,13 @@ function acquireFileLockSync(targetPath, options) {
12323
12365
  }
12324
12366
  // packages/workit-core/src/core/package-root.ts
12325
12367
  import { existsSync as existsSync3 } from "node:fs";
12326
- import path11 from "node:path";
12368
+ import path12 from "node:path";
12327
12369
  import { fileURLToPath } from "node:url";
12328
12370
  var packageRoot = () => {
12329
- let dir = path11.dirname(fileURLToPath(import.meta.url));
12371
+ let dir = path12.dirname(fileURLToPath(import.meta.url));
12330
12372
  while (true) {
12331
- const parent = path11.dirname(dir);
12332
- if (existsSync3(path11.join(dir, "package.json")) || parent === dir)
12373
+ const parent = path12.dirname(dir);
12374
+ if (existsSync3(path12.join(dir, "package.json")) || parent === dir)
12333
12375
  return dir;
12334
12376
  dir = parent;
12335
12377
  }
@@ -12337,7 +12379,7 @@ var packageRoot = () => {
12337
12379
 
12338
12380
  // packages/workit-core/src/core/store-lock.ts
12339
12381
  import { spawnSync as spawnSync8 } from "node:child_process";
12340
- import fs8 from "node:fs";
12382
+ import fs9 from "node:fs";
12341
12383
  import { hostname } from "node:os";
12342
12384
  var metadataLockSchema = object({
12343
12385
  pid: number2().int().nonnegative().safe(),
@@ -12379,7 +12421,7 @@ var parseProcStatStart = (stat) => {
12379
12421
  var processStartOf = (pid) => {
12380
12422
  if (process.platform === "linux") {
12381
12423
  try {
12382
- return parseProcStatStart(fs8.readFileSync(`/proc/${pid}/stat`, "utf8"));
12424
+ return parseProcStatStart(fs9.readFileSync(`/proc/${pid}/stat`, "utf8"));
12383
12425
  } catch {
12384
12426
  return null;
12385
12427
  }
@@ -12400,7 +12442,7 @@ var processStartOf = (pid) => {
12400
12442
  };
12401
12443
  var readTrimmed = (file) => {
12402
12444
  try {
12403
- return fs8.readFileSync(file, "utf8").trim() || null;
12445
+ return fs9.readFileSync(file, "utf8").trim() || null;
12404
12446
  } catch {
12405
12447
  return null;
12406
12448
  }
@@ -12411,7 +12453,7 @@ var localLockHost = () => {
12411
12453
  return cachedLockHost;
12412
12454
  let pidns = null;
12413
12455
  try {
12414
- pidns = /\[(\d+)\]/.exec(fs8.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
12456
+ pidns = /\[(\d+)\]/.exec(fs9.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
12415
12457
  } catch {}
12416
12458
  const boot = readTrimmed("/proc/sys/kernel/random/boot_id");
12417
12459
  cachedLockHost = pidns || boot ? `${hostname()}#${pidns ?? "?"}:${boot ?? "?"}` : hostname();
@@ -12457,7 +12499,7 @@ var classifyLockOwner = (payload, ageMs, localHost = localLockHost(), options =
12457
12499
  };
12458
12500
  var ageOf = (file, nowMs) => {
12459
12501
  try {
12460
- return nowMs - fs8.lstatSync(file).mtimeMs;
12502
+ return nowMs - fs9.lstatSync(file).mtimeMs;
12461
12503
  } catch {
12462
12504
  return null;
12463
12505
  }
@@ -12468,7 +12510,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
12468
12510
  if (age === null || age <= RECLAIM_GUARD_TTL_MS)
12469
12511
  return false;
12470
12512
  try {
12471
- fs8.rmdirSync(guard);
12513
+ fs9.rmdirSync(guard);
12472
12514
  return true;
12473
12515
  } catch {
12474
12516
  return false;
@@ -12477,8 +12519,8 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
12477
12519
 
12478
12520
  // packages/workit-core/src/store/event-log.ts
12479
12521
  import { randomUUID as randomUUID2 } from "node:crypto";
12480
- import fs9 from "node:fs";
12481
- import path12 from "node:path";
12522
+ import fs10 from "node:fs";
12523
+ import path13 from "node:path";
12482
12524
  var EVENT_VERSION = 1;
12483
12525
 
12484
12526
  class LogDamage extends Error {
@@ -12507,7 +12549,7 @@ var parseEvent = (line, file, offset) => {
12507
12549
  function readLog(file, from = 0, expectSeq = null) {
12508
12550
  let fd;
12509
12551
  try {
12510
- fd = fs9.openSync(file, "r");
12552
+ fd = fs10.openSync(file, "r");
12511
12553
  } catch (error) {
12512
12554
  if (error.code === "ENOENT")
12513
12555
  return null;
@@ -12516,13 +12558,13 @@ function readLog(file, from = 0, expectSeq = null) {
12516
12558
  let bytes;
12517
12559
  let size;
12518
12560
  try {
12519
- size = fs9.fstatSync(fd).size;
12561
+ size = fs10.fstatSync(fd).size;
12520
12562
  if (from > size)
12521
12563
  throw new LogDamage(`${file}: shorter than its snapshot`);
12522
12564
  bytes = Buffer.alloc(size - from);
12523
12565
  let read = 0;
12524
12566
  while (read < bytes.length) {
12525
- const got = fs9.readSync(fd, bytes, read, bytes.length - read, from + read);
12567
+ const got = fs10.readSync(fd, bytes, read, bytes.length - read, from + read);
12526
12568
  if (got === 0)
12527
12569
  break;
12528
12570
  read += got;
@@ -12530,7 +12572,7 @@ function readLog(file, from = 0, expectSeq = null) {
12530
12572
  bytes = bytes.subarray(0, read);
12531
12573
  size = from + read;
12532
12574
  } finally {
12533
- fs9.closeSync(fd);
12575
+ fs10.closeSync(fd);
12534
12576
  }
12535
12577
  const events = [];
12536
12578
  let start = 0;
@@ -12555,11 +12597,11 @@ function readLog(file, from = 0, expectSeq = null) {
12555
12597
  }
12556
12598
  var fsyncDirectory = (dir) => {
12557
12599
  try {
12558
- const fd = fs9.openSync(dir, "r");
12600
+ const fd = fs10.openSync(dir, "r");
12559
12601
  try {
12560
- fs9.fsyncSync(fd);
12602
+ fs10.fsyncSync(fd);
12561
12603
  } finally {
12562
- fs9.closeSync(fd);
12604
+ fs10.closeSync(fd);
12563
12605
  }
12564
12606
  } catch (error) {
12565
12607
  if (process.platform !== "win32")
@@ -12569,46 +12611,46 @@ var fsyncDirectory = (dir) => {
12569
12611
  function appendEvent(file, event, validEnd) {
12570
12612
  const line = Buffer.from(`${JSON.stringify(event)}
12571
12613
  `, "utf8");
12572
- const created = !fs9.existsSync(file);
12573
- if (!created && fs9.statSync(file).size !== validEnd) {
12574
- const cut = fs9.openSync(file, "r+");
12614
+ const created = !fs10.existsSync(file);
12615
+ if (!created && fs10.statSync(file).size !== validEnd) {
12616
+ const cut = fs10.openSync(file, "r+");
12575
12617
  try {
12576
- fs9.ftruncateSync(cut, validEnd);
12577
- fs9.fsyncSync(cut);
12618
+ fs10.ftruncateSync(cut, validEnd);
12619
+ fs10.fsyncSync(cut);
12578
12620
  } finally {
12579
- fs9.closeSync(cut);
12621
+ fs10.closeSync(cut);
12580
12622
  }
12581
12623
  }
12582
- const fd = fs9.openSync(file, "a", 384);
12624
+ const fd = fs10.openSync(file, "a", 384);
12583
12625
  try {
12584
12626
  let written = 0;
12585
12627
  while (written < line.length)
12586
- written += fs9.writeSync(fd, line, written, line.length - written);
12587
- fs9.fsyncSync(fd);
12628
+ written += fs10.writeSync(fd, line, written, line.length - written);
12629
+ fs10.fsyncSync(fd);
12588
12630
  } finally {
12589
- fs9.closeSync(fd);
12631
+ fs10.closeSync(fd);
12590
12632
  }
12591
12633
  if (created)
12592
- fsyncDirectory(path12.dirname(file));
12634
+ fsyncDirectory(path13.dirname(file));
12593
12635
  return validEnd;
12594
12636
  }
12595
12637
  function replaceFile(file, bytes, durable) {
12596
12638
  const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
12597
12639
  try {
12598
- const fd = fs9.openSync(temporary, "wx", 384);
12640
+ const fd = fs10.openSync(temporary, "wx", 384);
12599
12641
  try {
12600
- fs9.writeSync(fd, bytes);
12642
+ fs10.writeSync(fd, bytes);
12601
12643
  if (durable)
12602
- fs9.fsyncSync(fd);
12644
+ fs10.fsyncSync(fd);
12603
12645
  } finally {
12604
- fs9.closeSync(fd);
12646
+ fs10.closeSync(fd);
12605
12647
  }
12606
12648
  renameWithRetry(temporary, file);
12607
12649
  if (durable)
12608
- fsyncDirectory(path12.dirname(file));
12650
+ fsyncDirectory(path13.dirname(file));
12609
12651
  } catch (error) {
12610
12652
  try {
12611
- fs9.unlinkSync(temporary);
12653
+ fs10.unlinkSync(temporary);
12612
12654
  } catch {}
12613
12655
  throw error;
12614
12656
  }
@@ -12633,7 +12675,7 @@ var retryTransient = (run) => {
12633
12675
  }
12634
12676
  }
12635
12677
  };
12636
- var renameWithRetry = (from, to) => retryTransient(() => fs9.renameSync(from, to));
12678
+ var renameWithRetry = (from, to) => retryTransient(() => fs10.renameSync(from, to));
12637
12679
 
12638
12680
  // packages/workit-core/src/store/patch.ts
12639
12681
  var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -12746,7 +12788,7 @@ var isPatch = (value) => Array.isArray(value) && value.every((op) => {
12746
12788
  });
12747
12789
 
12748
12790
  // packages/workit-core/src/store/reduce.ts
12749
- import { createHash as createHash7 } from "node:crypto";
12791
+ import { createHash as createHash8 } from "node:crypto";
12750
12792
  var OPENING_TYPES = new Set([
12751
12793
  "task.opened",
12752
12794
  "task.imported",
@@ -12775,7 +12817,7 @@ var isObject5 = (value) => typeof value === "object" && value !== null && !Array
12775
12817
  var isKey = (value) => isObject5(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string");
12776
12818
  var BLOB_REF = "$blob";
12777
12819
  var blobRef = (value) => isObject5(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null;
12778
- var blobDigest = (value) => createHash7("sha256").update(JSON.stringify(value)).digest("hex");
12820
+ var blobDigest = (value) => createHash8("sha256").update(JSON.stringify(value)).digest("hex");
12779
12821
  var toBlob = (value, blobs) => {
12780
12822
  if (!isObject5(value))
12781
12823
  return value;
@@ -12930,7 +12972,7 @@ var indexEntry = (task, key, legacy, file) => {
12930
12972
  };
12931
12973
  var fileSignature = (file) => {
12932
12974
  try {
12933
- const stat = fs10.statSync(file, { bigint: true });
12975
+ const stat = fs11.statSync(file, { bigint: true });
12934
12976
  return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
12935
12977
  } catch {
12936
12978
  return null;
@@ -12948,7 +12990,7 @@ var cachedRuntimeVersion = null;
12948
12990
  var runtimeVersion = () => {
12949
12991
  if (cachedRuntimeVersion === null) {
12950
12992
  try {
12951
- const pkg = JSON.parse(fs10.readFileSync(path13.join(packageRoot(), "package.json"), "utf8"));
12993
+ const pkg = JSON.parse(fs11.readFileSync(path14.join(packageRoot(), "package.json"), "utf8"));
12952
12994
  cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
12953
12995
  } catch {
12954
12996
  cachedRuntimeVersion = "0.0.0";
@@ -12972,20 +13014,52 @@ var isNewerVersion = (candidate, current) => {
12972
13014
  return false;
12973
13015
  };
12974
13016
  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);
13017
+ var readText = (file) => {
13018
+ try {
13019
+ return fs11.readFileSync(file, "utf8");
13020
+ } catch {
13021
+ return "";
13022
+ }
13023
+ };
13024
+ var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
13025
+ var branchStart = (location, branch, aliases) => {
13026
+ const first = readText(path14.join(path14.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
13027
+ `, 1)[0];
13028
+ const created = REFLOG_LINE.exec(first);
13029
+ const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
13030
+ if (!created || !start)
13031
+ return null;
13032
+ if (start !== "HEAD")
13033
+ return start;
13034
+ if (!location.git)
13035
+ return null;
13036
+ for (const line of readText(path14.join(location.git.gitDir, "logs", "HEAD")).split(`
13037
+ `)) {
13038
+ const entry = REFLOG_LINE.exec(line);
13039
+ const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
13040
+ const seconds = entry ? Number(entry[2]) - Number(created[2]) : -1;
13041
+ if (moved && entry[1] === created[1] && seconds >= 0 && seconds <= 1 && aliases.includes(moved[2]))
13042
+ return moved[1];
13043
+ }
13044
+ return null;
13045
+ };
13046
+ var refExists = (common, ref) => fs11.existsSync(path14.join(common, ref)) || readText(path14.join(common, "packed-refs")).includes(` ${ref}
13047
+ `);
13048
+ var origins = new Map;
12975
13049
  var sameDirectoryIdentity = (left, right) => {
12976
- if (!path13.isAbsolute(left) || !path13.isAbsolute(right))
13050
+ if (!path14.isAbsolute(left) || !path14.isAbsolute(right))
12977
13051
  return false;
12978
- const normalizedLeft = path13.resolve(left);
12979
- const normalizedRight = path13.resolve(right);
13052
+ const normalizedLeft = path14.resolve(left);
13053
+ const normalizedRight = path14.resolve(right);
12980
13054
  try {
12981
- const a = fs10.statSync(normalizedLeft, { bigint: true });
12982
- const b = fs10.statSync(normalizedRight, { bigint: true });
13055
+ const a = fs11.statSync(normalizedLeft, { bigint: true });
13056
+ const b = fs11.statSync(normalizedRight, { bigint: true });
12983
13057
  if (!a.isDirectory() || !b.isDirectory())
12984
13058
  return false;
12985
13059
  if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
12986
13060
  return true;
12987
- const canonicalLeft = fs10.realpathSync(normalizedLeft);
12988
- const canonicalRight = fs10.realpathSync(normalizedRight);
13061
+ const canonicalLeft = fs11.realpathSync(normalizedLeft);
13062
+ const canonicalRight = fs11.realpathSync(normalizedRight);
12989
13063
  if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
12990
13064
  return true;
12991
13065
  return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
@@ -13022,8 +13096,8 @@ class TaskStore {
13022
13096
  migrationChecked = false;
13023
13097
  compactDue = new Set;
13024
13098
  constructor(root, options = {}) {
13025
- const resolved = path13.resolve(root);
13026
- this.origin = fs10.existsSync(resolved) ? fs10.realpathSync(resolved) : resolved;
13099
+ const resolved = path14.resolve(root);
13100
+ this.origin = fs11.existsSync(resolved) ? fs11.realpathSync(resolved) : resolved;
13027
13101
  this.located = resolveStore(this.origin);
13028
13102
  this.root = checkoutRootOf(this.origin, this.located);
13029
13103
  this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
@@ -13031,7 +13105,7 @@ class TaskStore {
13031
13105
  this.migrateOnRead = options.migrateOnRead;
13032
13106
  }
13033
13107
  location() {
13034
- if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs10.existsSync(path13.join(this.root, ".git"))) {
13108
+ if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs11.existsSync(path14.join(this.root, ".git"))) {
13035
13109
  this.located = undefined;
13036
13110
  this.migrationChecked = false;
13037
13111
  }
@@ -13095,7 +13169,7 @@ class TaskStore {
13095
13169
  const tasksDir = this.paths().tasks;
13096
13170
  let names;
13097
13171
  try {
13098
- names = fs10.existsSync(tasksDir) ? fs10.readdirSync(tasksDir).filter((name) => validId(name)) : [];
13172
+ names = fs11.existsSync(tasksDir) ? fs11.readdirSync(tasksDir).filter((name) => validId(name)) : [];
13099
13173
  } catch (error) {
13100
13174
  return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
13101
13175
  path: tasksDir
@@ -13136,7 +13210,7 @@ class TaskStore {
13136
13210
  const file = this.paths().workspace;
13137
13211
  let bytes;
13138
13212
  try {
13139
- bytes = retryTransient(() => fs10.readFileSync(file, "utf8"));
13213
+ bytes = retryTransient(() => fs11.readFileSync(file, "utf8"));
13140
13214
  } catch (error) {
13141
13215
  if (error.code === "ENOENT")
13142
13216
  return success(null, null, null);
@@ -13187,7 +13261,7 @@ class TaskStore {
13187
13261
  const moved = this.bindLocked(again.data.id, key, input.now);
13188
13262
  return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
13189
13263
  }
13190
- const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path13.basename(this.root) || this.root;
13264
+ const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path14.basename(this.root) || this.root;
13191
13265
  const intent = {
13192
13266
  objective: input.objective?.trim() || `Work on ${label}`,
13193
13267
  scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
@@ -13224,6 +13298,66 @@ class TaskStore {
13224
13298
  return bound;
13225
13299
  return success(null, null, { key: key.data, bound: bound.data });
13226
13300
  }
13301
+ taskForWorker(workerId) {
13302
+ if (typeof workerId !== "string" || !validId(workerId))
13303
+ return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
13304
+ const listed = this.listTaskIndex();
13305
+ if (!listed.ok)
13306
+ return listed;
13307
+ for (const entry of listed.data) {
13308
+ if (entry.status === "closed")
13309
+ continue;
13310
+ const loaded = this.load(entry.id);
13311
+ if (!loaded.ok)
13312
+ return loaded;
13313
+ if (loaded.data?.record.workers.some((worker) => worker.id === workerId))
13314
+ return success(null, null, entry.id);
13315
+ }
13316
+ return success(null, null, null);
13317
+ }
13318
+ originTaskEntry() {
13319
+ const key = this.currentKey();
13320
+ const location = this.location();
13321
+ const branch = key.ok ? key.data.branch : null;
13322
+ if (!branch || !location.ok)
13323
+ return success(null, null, null);
13324
+ const common = path14.dirname(location.data.dir);
13325
+ const heads = path14.join(common, "logs", "refs", "heads");
13326
+ const headLog = location.data.git ? path14.join(location.data.git.gitDir, "logs", "HEAD") : "";
13327
+ const signatures = [
13328
+ path14.join(heads, branch),
13329
+ headLog,
13330
+ heads,
13331
+ path14.join(common, "packed-refs")
13332
+ ].map((file) => fileSignature(file) ?? "-");
13333
+ const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
13334
+ let resolved = origins.get(slot);
13335
+ if (resolved?.signature !== signatures.join("|")) {
13336
+ const renames = branchRenames(location.data);
13337
+ const aliases = [branch];
13338
+ for (const rename of renames.toReversed())
13339
+ if (rename.to === aliases.at(-1))
13340
+ aliases.push(rename.from);
13341
+ const start = branchStart(location.data, branch, aliases);
13342
+ const slash = start?.indexOf("/") ?? -1;
13343
+ const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path14.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
13344
+ const name = start && (remote ? start.slice(slash + 1) : start);
13345
+ resolved = {
13346
+ signature: signatures.join("|"),
13347
+ name: name && !aliases.includes(name) ? name : null,
13348
+ renames
13349
+ };
13350
+ origins.set(slot, resolved);
13351
+ }
13352
+ const entry = resolved.name ? this.openTasksForKey(resolved.name, resolved.renames) : null;
13353
+ if (entry && !entry.ok)
13354
+ return entry;
13355
+ return success(null, null, entry?.data[0] ? { origin: `branch ${resolved.name}`, entry: entry.data[0] } : null);
13356
+ }
13357
+ readStoreTask(taskId) {
13358
+ const loaded = this.load(taskId);
13359
+ return loaded.ok ? success(null, null, loaded.data?.record ?? null) : loaded;
13360
+ }
13227
13361
  create(input, provenance, expectedWorkspaceRevision) {
13228
13362
  const value = "intent" in input ? input : {
13229
13363
  intent: input,
@@ -13444,13 +13578,13 @@ class TaskStore {
13444
13578
  if (!ready.ok)
13445
13579
  return ready;
13446
13580
  const dirs = this.paths();
13447
- const recovery = path13.join(this.root, ".workit", "recovery");
13448
- if (fs10.existsSync(recovery)) {
13581
+ const recovery = path14.join(this.root, ".workit", "recovery");
13582
+ if (fs11.existsSync(recovery)) {
13449
13583
  let files = 0;
13450
13584
  let bytes = 0;
13451
13585
  try {
13452
- for (const name of fs10.readdirSync(recovery)) {
13453
- const stat = fs10.lstatSync(path13.join(recovery, name));
13586
+ for (const name of fs11.readdirSync(recovery)) {
13587
+ const stat = fs11.lstatSync(path14.join(recovery, name));
13454
13588
  if (!stat.isFile())
13455
13589
  continue;
13456
13590
  files += 1;
@@ -13459,17 +13593,17 @@ class TaskStore {
13459
13593
  } catch {}
13460
13594
  const remove = options.pruneRecovery === true && !dryRun;
13461
13595
  if (remove)
13462
- fs10.rmSync(recovery, { recursive: true, force: true });
13596
+ fs11.rmSync(recovery, { recursive: true, force: true });
13463
13597
  report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
13464
13598
  }
13465
- if (!fs10.existsSync(dirs.tasks))
13599
+ if (!fs11.existsSync(dirs.tasks))
13466
13600
  return success(null, null, report);
13467
- const names = fs10.readdirSync(dirs.tasks).filter((name) => validId(name));
13601
+ const names = fs11.readdirSync(dirs.tasks).filter((name) => validId(name));
13468
13602
  for (const name of names) {
13469
13603
  const file = this.eventsPath(name);
13470
13604
  let size = 0;
13471
13605
  try {
13472
- size = fs10.statSync(file).size;
13606
+ size = fs11.statSync(file).size;
13473
13607
  } catch {
13474
13608
  continue;
13475
13609
  }
@@ -13497,16 +13631,16 @@ class TaskStore {
13497
13631
  const references = new Set;
13498
13632
  for (const name of names)
13499
13633
  try {
13500
- for (const match of fs10.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
13634
+ for (const match of fs11.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
13501
13635
  references.add(match[1]);
13502
13636
  } catch {}
13503
- if (fs10.existsSync(dirs.blobs))
13504
- for (const name of fs10.readdirSync(dirs.blobs)) {
13637
+ if (fs11.existsSync(dirs.blobs))
13638
+ for (const name of fs11.readdirSync(dirs.blobs)) {
13505
13639
  const digest = name.replace(/\.json$/, "");
13506
- const file = path13.join(dirs.blobs, name);
13640
+ const file = path14.join(dirs.blobs, name);
13507
13641
  let stat;
13508
13642
  try {
13509
- stat = fs10.lstatSync(file);
13643
+ stat = fs11.lstatSync(file);
13510
13644
  } catch {
13511
13645
  continue;
13512
13646
  }
@@ -13517,11 +13651,11 @@ class TaskStore {
13517
13651
  report.blobs.removed += 1;
13518
13652
  report.blobs.removedBytes += stat.size;
13519
13653
  if (!dryRun)
13520
- fs10.rmSync(file, { force: true });
13654
+ fs11.rmSync(file, { force: true });
13521
13655
  }
13522
13656
  return success(null, null, null);
13523
13657
  };
13524
- const swept = dryRun ? sweep() : this.withLock(path13.join(dirs.dir, "gc.lock"), sweep);
13658
+ const swept = dryRun ? sweep() : this.withLock(path14.join(dirs.dir, "gc.lock"), sweep);
13525
13659
  if (!swept.ok)
13526
13660
  return swept;
13527
13661
  const temporaryDirs = [
@@ -13529,17 +13663,17 @@ class TaskStore {
13529
13663
  dirs.tasks,
13530
13664
  dirs.blobs,
13531
13665
  dirs.checkout,
13532
- ...names.map((name) => path13.join(dirs.tasks, name))
13666
+ ...names.map((name) => path14.join(dirs.tasks, name))
13533
13667
  ];
13534
13668
  for (const directory of temporaryDirs) {
13535
- if (!fs10.existsSync(directory))
13669
+ if (!fs11.existsSync(directory))
13536
13670
  continue;
13537
- for (const name of fs10.readdirSync(directory)) {
13671
+ for (const name of fs11.readdirSync(directory)) {
13538
13672
  if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
13539
13673
  continue;
13540
- const file = path13.join(directory, name);
13674
+ const file = path14.join(directory, name);
13541
13675
  try {
13542
- const stat = fs10.lstatSync(file);
13676
+ const stat = fs11.lstatSync(file);
13543
13677
  if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
13544
13678
  continue;
13545
13679
  } catch {
@@ -13547,37 +13681,37 @@ class TaskStore {
13547
13681
  }
13548
13682
  report.temporary.removed += 1;
13549
13683
  if (!dryRun)
13550
- fs10.rmSync(file, { force: true });
13684
+ fs11.rmSync(file, { force: true });
13551
13685
  }
13552
13686
  }
13553
13687
  return success(null, null, report);
13554
13688
  }
13555
13689
  paths() {
13556
13690
  const location = this.location();
13557
- const dir = location.ok ? location.data.dir : path13.join(this.root, ".workit");
13558
- const checkout = path13.join(dir, "checkouts", checkoutSlug(this.root));
13691
+ const dir = location.ok ? location.data.dir : path14.join(this.root, ".workit");
13692
+ const checkout = path14.join(dir, "checkouts", checkoutSlug(this.root));
13559
13693
  return {
13560
13694
  dir,
13561
13695
  shared: location.ok ? location.data.shared : false,
13562
- marker: path13.join(dir, "store.json"),
13696
+ marker: path14.join(dir, "store.json"),
13563
13697
  checkout,
13564
- workspace: path13.join(checkout, "workspace.json"),
13565
- checkoutLock: path13.join(checkout, "metadata.lock"),
13566
- tasks: path13.join(dir, "tasks"),
13567
- index: path13.join(dir, "task-index.json"),
13568
- blobs: path13.join(dir, "blobs", "candidates"),
13569
- legacy: path13.join(dir, "legacy", checkoutSlug(this.root), "v2"),
13570
- v2: path13.join(this.root, ".workit")
13698
+ workspace: path14.join(checkout, "workspace.json"),
13699
+ checkoutLock: path14.join(checkout, "metadata.lock"),
13700
+ tasks: path14.join(dir, "tasks"),
13701
+ index: path14.join(dir, "task-index.json"),
13702
+ blobs: path14.join(dir, "blobs", "candidates"),
13703
+ legacy: path14.join(dir, "legacy", checkoutSlug(this.root), "v2"),
13704
+ v2: path14.join(this.root, ".workit")
13571
13705
  };
13572
13706
  }
13573
13707
  eventsPath(taskId) {
13574
- return path13.join(this.paths().tasks, taskId, "events.jsonl");
13708
+ return path14.join(this.paths().tasks, taskId, "events.jsonl");
13575
13709
  }
13576
13710
  snapshotPath(taskId) {
13577
- return path13.join(this.paths().tasks, taskId, "snapshot.json");
13711
+ return path14.join(this.paths().tasks, taskId, "snapshot.json");
13578
13712
  }
13579
13713
  taskLockPath(taskId) {
13580
- return path13.join(this.paths().tasks, taskId, "lock");
13714
+ return path14.join(this.paths().tasks, taskId, "lock");
13581
13715
  }
13582
13716
  ready(write = false) {
13583
13717
  const location = this.location();
@@ -13587,7 +13721,7 @@ class TaskStore {
13587
13721
  return success(null, null, null);
13588
13722
  const dirs = this.paths();
13589
13723
  try {
13590
- const marker = JSON.parse(fs10.readFileSync(dirs.marker, "utf8"));
13724
+ const marker = JSON.parse(fs11.readFileSync(dirs.marker, "utf8"));
13591
13725
  if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
13592
13726
  return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
13593
13727
  } catch {}
@@ -13616,21 +13750,21 @@ class TaskStore {
13616
13750
  return {
13617
13751
  read: (digest) => {
13618
13752
  try {
13619
- return JSON.parse(fs10.readFileSync(path13.join(dir, `${digest}.json`), "utf8"));
13753
+ return JSON.parse(fs11.readFileSync(path14.join(dir, `${digest}.json`), "utf8"));
13620
13754
  } catch (error) {
13621
13755
  throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
13622
13756
  }
13623
13757
  },
13624
13758
  write: (digest, value) => {
13625
- const file = path13.join(dir, `${digest}.json`);
13626
- if (fs10.existsSync(file)) {
13759
+ const file = path14.join(dir, `${digest}.json`);
13760
+ if (fs11.existsSync(file)) {
13627
13761
  const stamp = new Date;
13628
13762
  try {
13629
- fs10.utimesSync(file, stamp, stamp);
13763
+ fs11.utimesSync(file, stamp, stamp);
13630
13764
  return;
13631
13765
  } catch {}
13632
13766
  }
13633
- fs10.mkdirSync(dir, { recursive: true });
13767
+ fs11.mkdirSync(dir, { recursive: true });
13634
13768
  replaceFile(file, JSON.stringify(value), true);
13635
13769
  }
13636
13770
  };
@@ -13712,7 +13846,7 @@ class TaskStore {
13712
13846
  }
13713
13847
  readSnapshot(taskId) {
13714
13848
  try {
13715
- const value = JSON.parse(fs10.readFileSync(this.snapshotPath(taskId), "utf8"));
13849
+ const value = JSON.parse(fs11.readFileSync(this.snapshotPath(taskId), "utf8"));
13716
13850
  if (!isObject6(value) || value.v !== 1 || value.task !== taskId || typeof value.seq !== "number" || typeof value.lastId !== "string" || typeof value.lastStart !== "number" || typeof value.end !== "number" || !isObject6(value.record))
13717
13851
  return null;
13718
13852
  return value;
@@ -13814,8 +13948,8 @@ class TaskStore {
13814
13948
  }
13815
13949
  }
13816
13950
  openTask(record, type, key, legacy = null) {
13817
- const dir = path13.join(this.paths().tasks, record.id);
13818
- fs10.mkdirSync(dir, { recursive: true });
13951
+ const dir = path14.join(this.paths().tasks, record.id);
13952
+ fs11.mkdirSync(dir, { recursive: true });
13819
13953
  const blobs = this.blobStore();
13820
13954
  const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
13821
13955
  const event = this.event(record.id, 1, type, {
@@ -13867,11 +14001,11 @@ class TaskStore {
13867
14001
  } catch {}
13868
14002
  if (!latest || latest.events[0]?.id !== last.id)
13869
14003
  return failure2("busy", "the task log changed during compaction; retry", { taskId });
13870
- const appended = fs10.readFileSync(file).subarray(log.end, latest.end);
14004
+ const appended = fs11.readFileSync(file).subarray(log.end, latest.end);
13871
14005
  const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
13872
14006
  replaceFile(file, bytes.toString("utf8"), true);
13873
14007
  try {
13874
- fs10.rmSync(this.snapshotPath(taskId), { force: true });
14008
+ fs11.rmSync(this.snapshotPath(taskId), { force: true });
13875
14009
  } catch {}
13876
14010
  const reloaded = this.load(taskId);
13877
14011
  if (reloaded.ok && reloaded.data)
@@ -13884,7 +14018,7 @@ class TaskStore {
13884
14018
  }
13885
14019
  countEvents(file) {
13886
14020
  try {
13887
- const bytes = fs10.readFileSync(file);
14021
+ const bytes = fs11.readFileSync(file);
13888
14022
  let count = 0;
13889
14023
  for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
13890
14024
  count += 1;
@@ -13893,12 +14027,12 @@ class TaskStore {
13893
14027
  return 0;
13894
14028
  }
13895
14029
  }
13896
- openTasksForKey(key) {
14030
+ openTasksForKey(key, known) {
13897
14031
  const all = this.listStoreIndex();
13898
14032
  if (!all.ok)
13899
14033
  return all;
13900
- const location = this.location();
13901
- const renames = location.ok ? branchRenames(location.data) : [];
14034
+ const location = known ? null : this.location();
14035
+ const renames = known ?? (location?.ok ? branchRenames(location.data) : []);
13902
14036
  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));
13903
14037
  }
13904
14038
  openTaskForKey(key) {
@@ -13906,8 +14040,8 @@ class TaskStore {
13906
14040
  return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
13907
14041
  }
13908
14042
  withKeyLock(key, operation) {
13909
- const digest = createHash8("sha256").update(key).digest("hex").slice(0, 32);
13910
- return this.withLock(path13.join(this.paths().dir, "keys", `${digest}.lock`), operation);
14043
+ const digest = createHash9("sha256").update(key).digest("hex").slice(0, 32);
14044
+ return this.withLock(path14.join(this.paths().dir, "keys", `${digest}.lock`), operation);
13911
14045
  }
13912
14046
  bindLocked(taskId, key, timestamp) {
13913
14047
  const current = this.readWorkspace();
@@ -14048,7 +14182,7 @@ class TaskStore {
14048
14182
  writeWorkspace(record) {
14049
14183
  const file = this.paths().workspace;
14050
14184
  try {
14051
- fs10.mkdirSync(path13.dirname(file), { recursive: true });
14185
+ fs11.mkdirSync(path14.dirname(file), { recursive: true });
14052
14186
  replaceFile(file, `${canonicalJson(record)}
14053
14187
  `, true);
14054
14188
  return success(null, null, null);
@@ -14058,7 +14192,7 @@ class TaskStore {
14058
14192
  }
14059
14193
  readIndex() {
14060
14194
  try {
14061
- const value = JSON.parse(fs10.readFileSync(this.paths().index, "utf8"));
14195
+ const value = JSON.parse(fs11.readFileSync(this.paths().index, "utf8"));
14062
14196
  if (!isObject6(value) || value.version !== INDEX_VERSION || !isObject6(value.tasks))
14063
14197
  return {};
14064
14198
  const tasks = {};
@@ -14072,7 +14206,7 @@ class TaskStore {
14072
14206
  }
14073
14207
  writeIndex(entries) {
14074
14208
  try {
14075
- fs10.mkdirSync(this.paths().tasks, { recursive: true });
14209
+ fs11.mkdirSync(this.paths().tasks, { recursive: true });
14076
14210
  replaceFile(this.paths().index, JSON.stringify({
14077
14211
  version: INDEX_VERSION,
14078
14212
  tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
@@ -14126,23 +14260,23 @@ class TaskStore {
14126
14260
  return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
14127
14261
  }
14128
14262
  v2Dirs() {
14129
- return [...new Set([this.root, this.origin])].map((dir) => path13.join(dir, ".workit"));
14263
+ return [...new Set([this.root, this.origin])].map((dir) => path14.join(dir, ".workit"));
14130
14264
  }
14131
14265
  pendingMigrations() {
14132
14266
  return this.v2Dirs().filter((dir) => {
14133
- const raw = this.readV2Workspace(path13.join(dir, "workspace.json"));
14267
+ const raw = this.readV2Workspace(path14.join(dir, "workspace.json"));
14134
14268
  return raw !== null && raw !== TOMBSTONE;
14135
14269
  });
14136
14270
  }
14137
14271
  migrateV2(v2) {
14138
14272
  const dirs = this.paths();
14139
- const v2Workspace = path13.join(v2, "workspace.json");
14140
- const v2Tasks = path13.join(v2, "tasks");
14141
- const legacy = path13.join(dirs.dir, "legacy", checkoutSlug(path13.dirname(v2)), "v2");
14273
+ const v2Workspace = path14.join(v2, "workspace.json");
14274
+ const v2Tasks = path14.join(v2, "tasks");
14275
+ const legacy = path14.join(dirs.dir, "legacy", checkoutSlug(path14.dirname(v2)), "v2");
14142
14276
  const raw = this.readV2Workspace(v2Workspace);
14143
14277
  if (raw === null || raw === TOMBSTONE)
14144
14278
  return success(null, null, null);
14145
- return this.withLock(dirs.checkoutLock, () => this.withLock(path13.join(v2, "metadata.lock"), () => {
14279
+ return this.withLock(dirs.checkoutLock, () => this.withLock(path14.join(v2, "metadata.lock"), () => {
14146
14280
  const workspace = this.readV2Workspace(v2Workspace);
14147
14281
  if (workspace === null || workspace === TOMBSTONE)
14148
14282
  return success(null, null, null);
@@ -14151,7 +14285,7 @@ class TaskStore {
14151
14285
  return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
14152
14286
  let files = [];
14153
14287
  try {
14154
- files = fs10.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path13.join(v2Tasks, name)));
14288
+ files = fs11.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path14.join(v2Tasks, name)));
14155
14289
  } catch {}
14156
14290
  const current = this.readWorkspace();
14157
14291
  if (!current.ok)
@@ -14169,22 +14303,22 @@ class TaskStore {
14169
14303
  let skipped = 0;
14170
14304
  const done = new Map;
14171
14305
  try {
14172
- fs10.mkdirSync(path13.join(legacy, "tasks"), { recursive: true });
14306
+ fs11.mkdirSync(path14.join(legacy, "tasks"), { recursive: true });
14173
14307
  for (const name of ["workspace.json", "index.json"])
14174
- if (fs10.existsSync(path13.join(v2, name)))
14175
- fs10.copyFileSync(path13.join(v2, name), path13.join(legacy, name));
14308
+ if (fs11.existsSync(path14.join(v2, name)))
14309
+ fs11.copyFileSync(path14.join(v2, name), path14.join(legacy, name));
14176
14310
  for (const name of files) {
14177
14311
  const id = name.slice(0, -5);
14178
- const file = path13.join(v2Tasks, name);
14179
- const bytes = fs10.readFileSync(file, "utf8");
14312
+ const file = path14.join(v2Tasks, name);
14313
+ const bytes = fs11.readFileSync(file, "utf8");
14180
14314
  const digest = sha256(bytes);
14181
- fs10.writeFileSync(path13.join(legacy, "tasks", name), bytes);
14315
+ fs11.writeFileSync(path14.join(legacy, "tasks", name), bytes);
14182
14316
  const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
14183
14317
  if (!parsed.ok || parsed.data.id !== id)
14184
14318
  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 });
14185
14319
  const record = { ...parsed.data, workspaceId: target.id };
14186
- const origin = { path: path13.join(legacy, "tasks", name), digest };
14187
- if (!fs10.existsSync(this.eventsPath(id))) {
14320
+ const origin = { path: path14.join(legacy, "tasks", name), digest };
14321
+ if (!fs11.existsSync(this.eventsPath(id))) {
14188
14322
  this.openTask(record, "migrated.from_v2", null, origin);
14189
14323
  migrated += 1;
14190
14324
  } else {
@@ -14219,8 +14353,8 @@ class TaskStore {
14219
14353
  try {
14220
14354
  let complete = true;
14221
14355
  for (const [name, digest] of done) {
14222
- const file = path13.join(v2Tasks, name);
14223
- if (sha256(fs10.readFileSync(file, "utf8")) !== digest) {
14356
+ const file = path14.join(v2Tasks, name);
14357
+ if (sha256(fs11.readFileSync(file, "utf8")) !== digest) {
14224
14358
  complete = false;
14225
14359
  continue;
14226
14360
  }
@@ -14230,7 +14364,7 @@ class TaskStore {
14230
14364
  return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
14231
14365
  path: v2
14232
14366
  });
14233
- fs10.rmSync(path13.join(v2, "index.json"), { force: true });
14367
+ fs11.rmSync(path14.join(v2, "index.json"), { force: true });
14234
14368
  this.writeTombstone(v2, target.id);
14235
14369
  } catch (error) {
14236
14370
  return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
@@ -14250,45 +14384,45 @@ class TaskStore {
14250
14384
  }
14251
14385
  adoptLocalStore() {
14252
14386
  const dirs = this.paths();
14253
- const marker = path13.join(dirs.v2, "store.json");
14254
- if (!dirs.shared || !fs10.existsSync(marker))
14387
+ const marker = path14.join(dirs.v2, "store.json");
14388
+ if (!dirs.shared || !fs11.existsSync(marker))
14255
14389
  return success(null, null, null);
14256
14390
  return this.withLock(dirs.checkoutLock, () => {
14257
- if (!fs10.existsSync(marker))
14391
+ if (!fs11.existsSync(marker))
14258
14392
  return success(null, null, null);
14259
14393
  let tasks = 0;
14260
14394
  try {
14261
14395
  const merge = (from, to) => {
14262
- if (!fs10.existsSync(to)) {
14263
- fs10.mkdirSync(path13.dirname(to), { recursive: true });
14396
+ if (!fs11.existsSync(to)) {
14397
+ fs11.mkdirSync(path14.dirname(to), { recursive: true });
14264
14398
  try {
14265
- fs10.renameSync(from, to);
14399
+ fs11.renameSync(from, to);
14266
14400
  } catch {
14267
- fs10.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
14268
- fs10.rmSync(from, { recursive: true, force: true });
14401
+ fs11.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
14402
+ fs11.rmSync(from, { recursive: true, force: true });
14269
14403
  }
14270
14404
  return;
14271
14405
  }
14272
- if (fs10.lstatSync(from).isDirectory() && fs10.lstatSync(to).isDirectory())
14273
- for (const name of fs10.readdirSync(from))
14274
- merge(path13.join(from, name), path13.join(to, name));
14406
+ if (fs11.lstatSync(from).isDirectory() && fs11.lstatSync(to).isDirectory())
14407
+ for (const name of fs11.readdirSync(from))
14408
+ merge(path14.join(from, name), path14.join(to, name));
14275
14409
  };
14276
14410
  for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
14277
- const from = path13.join(dirs.v2, sub);
14278
- if (!fs10.existsSync(from))
14411
+ const from = path14.join(dirs.v2, sub);
14412
+ if (!fs11.existsSync(from))
14279
14413
  continue;
14280
14414
  if (sub === "tasks") {
14281
- for (const name of fs10.readdirSync(from))
14282
- if (validId(name) && !fs10.existsSync(path13.join(dirs.dir, sub, name)))
14415
+ for (const name of fs11.readdirSync(from))
14416
+ if (validId(name) && !fs11.existsSync(path14.join(dirs.dir, sub, name)))
14283
14417
  tasks += 1;
14284
14418
  }
14285
- merge(from, path13.join(dirs.dir, sub));
14419
+ merge(from, path14.join(dirs.dir, sub));
14286
14420
  }
14287
- const ledger = path13.join(dirs.v2, "ledger");
14288
- if (fs10.existsSync(ledger) && !fs10.existsSync(path13.join(dirs.dir, "ledger")))
14289
- merge(ledger, path13.join(dirs.dir, "ledger"));
14290
- fs10.rmSync(path13.join(dirs.v2, "task-index.json"), { force: true });
14291
- fs10.renameSync(marker, path13.join(dirs.v2, "store.moved.json"));
14421
+ const ledger = path14.join(dirs.v2, "ledger");
14422
+ if (fs11.existsSync(ledger) && !fs11.existsSync(path14.join(dirs.dir, "ledger")))
14423
+ merge(ledger, path14.join(dirs.dir, "ledger"));
14424
+ fs11.rmSync(path14.join(dirs.v2, "task-index.json"), { force: true });
14425
+ fs11.renameSync(marker, path14.join(dirs.v2, "store.moved.json"));
14292
14426
  } catch (error) {
14293
14427
  return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
14294
14428
  path: dirs.v2
@@ -14308,7 +14442,7 @@ class TaskStore {
14308
14442
  readV2Workspace(file) {
14309
14443
  let bytes;
14310
14444
  try {
14311
- bytes = fs10.readFileSync(file, "utf8");
14445
+ bytes = fs11.readFileSync(file, "utf8");
14312
14446
  } catch {
14313
14447
  return null;
14314
14448
  }
@@ -14326,7 +14460,7 @@ class TaskStore {
14326
14460
  schemaVersion: SCHEMA_VERSION,
14327
14461
  id: workspaceId ?? newId(),
14328
14462
  revision: newRevision(),
14329
- root: path13.dirname(v2),
14463
+ root: path14.dirname(v2),
14330
14464
  runtime: { createdWith: version, updatedWith: version },
14331
14465
  writer: null,
14332
14466
  store: {
@@ -14337,12 +14471,12 @@ class TaskStore {
14337
14471
  },
14338
14472
  critical: ["store"]
14339
14473
  };
14340
- fs10.mkdirSync(v2, { recursive: true });
14341
- const ignore = path13.join(v2, ".gitignore");
14342
- if (!fs10.existsSync(ignore))
14343
- fs10.writeFileSync(ignore, `*
14474
+ fs11.mkdirSync(v2, { recursive: true });
14475
+ const ignore = path14.join(v2, ".gitignore");
14476
+ if (!fs11.existsSync(ignore))
14477
+ fs11.writeFileSync(ignore, `*
14344
14478
  `);
14345
- replaceFile(path13.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
14479
+ replaceFile(path14.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
14346
14480
  `, true);
14347
14481
  }
14348
14482
  stubFor(taskId) {
@@ -14358,7 +14492,7 @@ class TaskStore {
14358
14492
  }
14359
14493
  isStub(file) {
14360
14494
  try {
14361
- const value = JSON.parse(fs10.readFileSync(file, "utf8"));
14495
+ const value = JSON.parse(fs11.readFileSync(file, "utf8"));
14362
14496
  return isObject6(value) && isObject6(value.store) && value.store.format === "workit-store";
14363
14497
  } catch {
14364
14498
  return false;
@@ -14366,32 +14500,32 @@ class TaskStore {
14366
14500
  }
14367
14501
  writeTombstoneIfMissing() {
14368
14502
  try {
14369
- const v2 = path13.join(this.root, ".workit");
14370
- if (fs10.existsSync(path13.join(v2, "workspace.json")))
14503
+ const v2 = path14.join(this.root, ".workit");
14504
+ if (fs11.existsSync(path14.join(v2, "workspace.json")))
14371
14505
  return;
14372
14506
  let id = null;
14373
14507
  try {
14374
- id = JSON.parse(fs10.readFileSync(this.paths().workspace, "utf8")).id ?? null;
14508
+ id = JSON.parse(fs11.readFileSync(this.paths().workspace, "utf8")).id ?? null;
14375
14509
  } catch {}
14376
14510
  this.writeTombstone(v2, id);
14377
14511
  } catch {}
14378
14512
  }
14379
14513
  initializeStorage() {
14380
14514
  const dirs = this.paths();
14381
- retryTransient(() => fs10.mkdirSync(dirs.checkout, { recursive: true }));
14382
- retryTransient(() => fs10.mkdirSync(dirs.tasks, { recursive: true }));
14383
- if (!fs10.existsSync(dirs.marker))
14515
+ retryTransient(() => fs11.mkdirSync(dirs.checkout, { recursive: true }));
14516
+ retryTransient(() => fs11.mkdirSync(dirs.tasks, { recursive: true }));
14517
+ if (!fs11.existsSync(dirs.marker))
14384
14518
  replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
14385
14519
  `, false);
14386
14520
  if (!dirs.shared) {
14387
- const ignore = path13.join(dirs.dir, ".gitignore");
14521
+ const ignore = path14.join(dirs.dir, ".gitignore");
14388
14522
  let current = null;
14389
14523
  try {
14390
- current = fs10.readFileSync(ignore, "utf8");
14524
+ current = fs11.readFileSync(ignore, "utf8");
14391
14525
  } catch {}
14392
14526
  if (current !== `*
14393
14527
  `)
14394
- retryTransient(() => fs10.writeFileSync(ignore, `*
14528
+ retryTransient(() => fs11.writeFileSync(ignore, `*
14395
14529
  `));
14396
14530
  }
14397
14531
  this.writeTombstoneIfMissing();
@@ -14407,7 +14541,7 @@ class TaskStore {
14407
14541
  shouldReclaim: ({ payload, nowMs }) => {
14408
14542
  let ageMs = null;
14409
14543
  try {
14410
- ageMs = nowMs - fs10.lstatSync(lockPath).mtimeMs;
14544
+ ageMs = nowMs - fs11.lstatSync(lockPath).mtimeMs;
14411
14545
  } catch {}
14412
14546
  return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
14413
14547
  },
@@ -14444,7 +14578,7 @@ class TaskStore {
14444
14578
  withLock(lockPath, operation) {
14445
14579
  try {
14446
14580
  this.initializeStorage();
14447
- fs10.mkdirSync(path13.dirname(lockPath), { recursive: true });
14581
+ fs11.mkdirSync(path14.dirname(lockPath), { recursive: true });
14448
14582
  } catch (error) {
14449
14583
  return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
14450
14584
  path: this.paths().dir
@@ -14484,18 +14618,18 @@ class TaskStore {
14484
14618
  lockDirWritable(lockPath) {
14485
14619
  const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
14486
14620
  try {
14487
- fs10.closeSync(fs10.openSync(probe, "wx", 384));
14621
+ fs11.closeSync(fs11.openSync(probe, "wx", 384));
14488
14622
  } catch {
14489
14623
  return false;
14490
14624
  }
14491
14625
  try {
14492
- fs10.rmSync(probe, { force: true });
14626
+ fs11.rmSync(probe, { force: true });
14493
14627
  } catch {}
14494
14628
  return true;
14495
14629
  }
14496
14630
  lockHolderPresent(lockPath) {
14497
14631
  try {
14498
- fs10.lstatSync(lockPath);
14632
+ fs11.lstatSync(lockPath);
14499
14633
  return true;
14500
14634
  } catch (error) {
14501
14635
  return error?.code !== "ENOENT";
@@ -14507,12 +14641,12 @@ class TaskStore {
14507
14641
  if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
14508
14642
  return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
14509
14643
  path: lockPath,
14510
- guidance: `Check permissions and the read-only attribute on ${path13.dirname(lockPath)}.`
14644
+ guidance: `Check permissions and the read-only attribute on ${path14.dirname(lockPath)}.`
14511
14645
  });
14512
14646
  if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
14513
14647
  let lock = null;
14514
14648
  try {
14515
- lock = parseMetadataLockOrNull(fs10.readFileSync(lockPath, "utf8"));
14649
+ lock = parseMetadataLockOrNull(fs11.readFileSync(lockPath, "utf8"));
14516
14650
  } catch {}
14517
14651
  return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
14518
14652
  outcome: "not_started",
@@ -14531,15 +14665,15 @@ var isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state);
14531
14665
  var workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state);
14532
14666
 
14533
14667
  // packages/workit-core/src/core/task-evaluation.ts
14534
- import { createHash as createHash9 } from "node:crypto";
14535
- import * as fs12 from "node:fs";
14668
+ import { createHash as createHash10 } from "node:crypto";
14669
+ import * as fs13 from "node:fs";
14536
14670
  import { spawnSync as spawnSync10 } from "node:child_process";
14537
- import path15 from "node:path";
14671
+ import path16 from "node:path";
14538
14672
 
14539
14673
  // packages/workit-core/src/check-config.ts
14540
14674
  import { spawnSync as spawnSync9 } from "node:child_process";
14541
- import fs11 from "node:fs";
14542
- import path14 from "node:path";
14675
+ import fs12 from "node:fs";
14676
+ import path15 from "node:path";
14543
14677
  var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
14544
14678
  var CHECKS_FILE = "workit.checks.json";
14545
14679
  var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -14592,10 +14726,10 @@ var git4 = (cwd, args) => {
14592
14726
  return value || null;
14593
14727
  };
14594
14728
  function checkRoot(cwd) {
14595
- return path14.resolve(git4(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
14729
+ return path15.resolve(git4(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
14596
14730
  }
14597
14731
  var packageManager = (root) => {
14598
- const has = (file) => fs11.existsSync(path14.join(root, file));
14732
+ const has = (file) => fs12.existsSync(path15.join(root, file));
14599
14733
  if (has("bun.lock") || has("bun.lockb"))
14600
14734
  return "bun";
14601
14735
  if (has("pnpm-lock.yaml"))
@@ -14615,7 +14749,7 @@ var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
14615
14749
  function detectedChecks(root) {
14616
14750
  const read = (file) => {
14617
14751
  try {
14618
- return fs11.readFileSync(path14.join(root, file), "utf8");
14752
+ return fs12.readFileSync(path15.join(root, file), "utf8");
14619
14753
  } catch {
14620
14754
  return null;
14621
14755
  }
@@ -14654,7 +14788,7 @@ function detectedChecks(root) {
14654
14788
  var GATES = ["testing", "verification"];
14655
14789
  function loadCheckConfig(cwd) {
14656
14790
  const root = checkRoot(cwd);
14657
- const file = path14.join(root, CHECKS_FILE);
14791
+ const file = path15.join(root, CHECKS_FILE);
14658
14792
  const none = (error = null) => ({
14659
14793
  source: error ? CHECKS_FILE : "none",
14660
14794
  root,
@@ -14664,7 +14798,7 @@ function loadCheckConfig(cwd) {
14664
14798
  });
14665
14799
  let text = null;
14666
14800
  try {
14667
- text = fs11.readFileSync(file, "utf8");
14801
+ text = fs12.readFileSync(file, "utf8");
14668
14802
  } catch (error) {
14669
14803
  if (error.code !== "ENOENT")
14670
14804
  return none(`cannot read ${CHECKS_FILE}: ${error.message}`);
@@ -14727,10 +14861,10 @@ function workitAvailable(env = process.env) {
14727
14861
  return workitOnPath;
14728
14862
  const windows = process.platform === "win32";
14729
14863
  const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
14730
- const dirs = (env.PATH ?? env.Path ?? "").split(path14.delimiter).filter(Boolean);
14864
+ const dirs = (env.PATH ?? env.Path ?? "").split(path15.delimiter).filter(Boolean);
14731
14865
  workitOnPath = dirs.some((dir) => exts.some((ext) => {
14732
14866
  try {
14733
- return fs11.statSync(path14.join(dir, `workit${ext}`)).isFile();
14867
+ return fs12.statSync(path15.join(dir, `workit${ext}`)).isFile();
14734
14868
  } catch {
14735
14869
  return false;
14736
14870
  }
@@ -14742,15 +14876,15 @@ function checkCommand(args, version, onPath = workitAvailable()) {
14742
14876
  }
14743
14877
 
14744
14878
  // packages/workit-core/src/core/task-evaluation.ts
14745
- var digestBytes = (value) => createHash9("sha256").update(value).digest("hex");
14746
- var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path15.sep}`);
14747
- var relative = (root, candidate) => path15.relative(root, candidate).split(path15.sep).join("/") || ".";
14879
+ var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
14880
+ var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
14881
+ var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
14748
14882
  var canonicalPath = (value) => {
14749
14883
  if (typeof value !== "string" || !value)
14750
14884
  return null;
14751
14885
  if (value.includes("\\") || value.split("/").includes(".."))
14752
14886
  return null;
14753
- const normalized = path15.posix.normalize(value);
14887
+ const normalized = path16.posix.normalize(value);
14754
14888
  if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
14755
14889
  return null;
14756
14890
  return normalized === "." ? "." : normalized.replace(/\/$/, "");
@@ -14798,21 +14932,21 @@ var gitPaths = (root) => {
14798
14932
  git: !/not a git repository/i.test(stderr)
14799
14933
  };
14800
14934
  }
14801
- const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")) : [];
14935
+ const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
14802
14936
  const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
14803
14937
  if (stagedDeleted.status !== 0) {
14804
14938
  const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
14805
14939
  if (!/not a git repository/i.test(stderr))
14806
14940
  return { paths, uncertain: true, git: true };
14807
14941
  } else if (stagedDeleted.stdout) {
14808
- paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")));
14942
+ paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
14809
14943
  }
14810
14944
  return { paths: [...new Set(paths)], uncertain: false, git: true };
14811
14945
  };
14812
14946
  var walk = (root, directory, output) => {
14813
14947
  let names;
14814
14948
  try {
14815
- names = fs12.readdirSync(directory);
14949
+ names = fs13.readdirSync(directory);
14816
14950
  } catch {
14817
14951
  return true;
14818
14952
  }
@@ -14820,10 +14954,10 @@ var walk = (root, directory, output) => {
14820
14954
  for (const name of names) {
14821
14955
  if (name === ".git" || name === ".workit")
14822
14956
  continue;
14823
- const target = path15.join(directory, name);
14957
+ const target = path16.join(directory, name);
14824
14958
  let stat;
14825
14959
  try {
14826
- stat = fs12.lstatSync(target);
14960
+ stat = fs13.lstatSync(target);
14827
14961
  } catch {
14828
14962
  uncertain = true;
14829
14963
  continue;
@@ -14838,14 +14972,14 @@ var walk = (root, directory, output) => {
14838
14972
  var scopeRoots = (root, scope) => {
14839
14973
  const roots = [];
14840
14974
  for (const item of scope.paths.length ? scope.paths : ["."]) {
14841
- const target = path15.resolve(root, item);
14975
+ const target = path16.resolve(root, item);
14842
14976
  if (!inside(root, target))
14843
14977
  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` }] });
14844
14978
  let ancestor = target;
14845
- while (!fs12.existsSync(ancestor) && ancestor !== root)
14846
- ancestor = path15.dirname(ancestor);
14979
+ while (!fs13.existsSync(ancestor) && ancestor !== root)
14980
+ ancestor = path16.dirname(ancestor);
14847
14981
  try {
14848
- if (!inside(root, fs12.realpathSync(ancestor)))
14982
+ if (!inside(root, fs13.realpathSync(ancestor)))
14849
14983
  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` }] });
14850
14984
  } catch {
14851
14985
  return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
@@ -14857,7 +14991,7 @@ var scopeRoots = (root, scope) => {
14857
14991
  function captureCandidate(root, scope, environment = []) {
14858
14992
  let checkout;
14859
14993
  try {
14860
- checkout = fs12.realpathSync(root);
14994
+ checkout = fs13.realpathSync(root);
14861
14995
  } catch {
14862
14996
  return failure2("invalid_input", "candidate root does not exist");
14863
14997
  }
@@ -14875,11 +15009,11 @@ function captureCandidate(root, scope, environment = []) {
14875
15009
  if (item === ".git" || item === ".workit")
14876
15010
  continue;
14877
15011
  names.add(item);
14878
- if (!fs12.existsSync(target))
15012
+ if (!fs13.existsSync(target))
14879
15013
  continue;
14880
15014
  let stat;
14881
15015
  try {
14882
- stat = fs12.lstatSync(target);
15016
+ stat = fs13.lstatSync(target);
14883
15017
  } catch {
14884
15018
  uncertain = true;
14885
15019
  continue;
@@ -14895,17 +15029,17 @@ function captureCandidate(root, scope, environment = []) {
14895
15029
  for (const item of [...names].toSorted()) {
14896
15030
  if (!scopeMatches(item, normalizedScope))
14897
15031
  continue;
14898
- const target = path15.join(checkout, item);
15032
+ const target = path16.join(checkout, item);
14899
15033
  try {
14900
- const stat = fs12.lstatSync(target);
15034
+ const stat = fs13.lstatSync(target);
14901
15035
  if (stat.isSymbolicLink()) {
14902
- const link = fs12.readlinkSync(target);
15036
+ const link = fs13.readlinkSync(target);
14903
15037
  files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
14904
15038
  } else if (stat.isFile()) {
14905
15039
  files.push({
14906
15040
  path: item,
14907
15041
  kind: "file",
14908
- digest: digestBytes(fs12.readFileSync(target)),
15042
+ digest: digestBytes(fs13.readFileSync(target)),
14909
15043
  executable: (stat.mode & 73) !== 0
14910
15044
  });
14911
15045
  } else if (!stat.isDirectory()) {
@@ -15070,7 +15204,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
15070
15204
  var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
15071
15205
  let root;
15072
15206
  try {
15073
- root = fs12.realpathSync(checkoutRoot);
15207
+ root = fs13.realpathSync(checkoutRoot);
15074
15208
  } catch {
15075
15209
  return failure2("permission_denied", "checkout root is unavailable");
15076
15210
  }
@@ -15079,23 +15213,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
15079
15213
  continue;
15080
15214
  if (!reference.digest)
15081
15215
  return failure2("invalid_input", "document references require a byte digest");
15082
- const target = path15.resolve(root, reference.path);
15083
- if (target !== root && !target.startsWith(`${root}${path15.sep}`))
15216
+ const target = path16.resolve(root, reference.path);
15217
+ if (target !== root && !target.startsWith(`${root}${path16.sep}`))
15084
15218
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
15085
15219
  fields: [
15086
15220
  { path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
15087
15221
  ]
15088
15222
  });
15089
15223
  try {
15090
- const below = path15.relative(root, target);
15224
+ const below = path16.relative(root, target);
15091
15225
  let current = root;
15092
- for (const segment of below.split(path15.sep)) {
15226
+ for (const segment of below.split(path16.sep)) {
15093
15227
  if (!segment)
15094
15228
  continue;
15095
- current = path15.join(current, segment);
15096
- const stat = fs12.lstatSync(current);
15097
- const real = fs12.realpathSync(current);
15098
- if (real !== root && !real.startsWith(`${root}${path15.sep}`))
15229
+ current = path16.join(current, segment);
15230
+ const stat = fs13.lstatSync(current);
15231
+ const real = fs13.realpathSync(current);
15232
+ if (real !== root && !real.startsWith(`${root}${path16.sep}`))
15099
15233
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
15100
15234
  fields: [
15101
15235
  {
@@ -15111,7 +15245,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
15111
15245
  if (current !== target && !stat.isDirectory())
15112
15246
  return failure2("invalid_input", "document reference ancestor is not a directory");
15113
15247
  }
15114
- if (digestBytes(fs12.readFileSync(target)) !== reference.digest)
15248
+ if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
15115
15249
  return failure2("permission_denied", "decision document bytes have changed");
15116
15250
  } catch {
15117
15251
  return failure2("invalid_input", "decision document is unavailable");
@@ -15480,7 +15614,8 @@ Autonomy contract:
15480
15614
  satisfies a gate; an ad-hoc \`workit check -- <cmd>\` never does.
15481
15615
  - Author is not verifier: your own verdict is \`--self\`, shown as
15482
15616
  self-reviewed, never verified. High risk, \`verification: independent\` and
15483
- merge need a verifier with its own session (\`WORKIT_SESSION_ID=<lead>-v<n>\`).
15617
+ merge need a verifier with its own host-derived session (a subagent's
15618
+ \`<lead>:<child>\`, set by the host); never hand-mint one such as \`<lead>-v1\`.
15484
15619
  - A local-commit endpoint does not imply PR readiness, and a local commit alone
15485
15620
  is not evidence of a requested remote push. Before reporting delivery,
15486
15621
  reconcile every requested item and observe it (\`workit verify-delivery\`).
@@ -15573,38 +15708,45 @@ var compactReference = (ref) => {
15573
15708
  };
15574
15709
  return { kind: ref.kind };
15575
15710
  };
15576
- function compactTaskContext(view) {
15577
- const decisions = view.task.decisions.slice().toSorted((left, right) => {
15578
- const leftAt = compactTimestamp(left.recordedAt);
15579
- const rightAt = compactTimestamp(right.recordedAt);
15580
- if (leftAt !== rightAt)
15581
- return leftAt > rightAt ? -1 : 1;
15582
- return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
15583
- }).slice(0, COMPACT_MAX_ITEMS).map((entry) => ({
15584
- id: entry.id,
15585
- purpose: entry.data.purpose,
15586
- status: entry.data.response,
15587
- digest: entry.data.digest,
15588
- choice: compactDecisionChoice(entry) || `task.inspect taskId=${view.task.id} view=full; decision=${entry.id}`,
15589
- references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
15590
- }));
15591
- const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
15711
+ var newestDecisionFirst = (left, right) => {
15712
+ const leftAt = compactTimestamp(left.recordedAt);
15713
+ const rightAt = compactTimestamp(right.recordedAt);
15714
+ if (leftAt !== rightAt)
15715
+ return leftAt > rightAt ? -1 : 1;
15716
+ return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
15717
+ };
15718
+ var compactDecisions = (sources) => sources.flatMap((source) => source ? source.decisions.toSorted(newestDecisionFirst).map((entry) => ({
15719
+ id: entry.id,
15720
+ purpose: entry.data.purpose,
15721
+ status: entry.data.response,
15722
+ digest: entry.data.digest,
15723
+ choice: compactDecisionChoice(entry) || `task.inspect taskId=${source.taskId} view=full; decision=${entry.id}`,
15724
+ references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference),
15725
+ origin: source.origin ?? undefined
15726
+ })) : []).slice(0, COMPACT_MAX_ITEMS);
15727
+ function compactTaskContext(view, inherited = null) {
15728
+ const decisions = compactDecisions([
15729
+ view && { origin: null, taskId: view.task.id, decisions: view.task.decisions },
15730
+ inherited
15731
+ ]);
15732
+ const methods = view?.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
15592
15733
  id: method.id,
15593
15734
  assurance: method.assurance,
15594
15735
  reason: compactText(method.reason, COMPACT_TEXT_BYTES) ?? ""
15595
15736
  })) : [];
15737
+ const stale = view?.evidence.filter((entry) => entry.status === "stale").length;
15596
15738
  const gaps = Array.from(new Set([
15597
- ...view.evidence.filter((entry) => entry.status === "stale").map((entry) => `stale evidence: ${entry.evidenceId}`),
15598
- ...view.requirements.filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
15599
- ...view.task.progress.blockers.map((entry) => entry.reason)
15739
+ ...stale ? [`stale evidence: ${stale}; workit task inspect --task ${view.task.id} --view full`] : [],
15740
+ ...(view?.requirements ?? []).filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
15741
+ ...(view?.task.progress.blockers ?? []).map((entry) => entry.reason)
15600
15742
  ])).toSorted().slice(0, COMPACT_MAX_ITEMS).map((gap) => compactText(gap, COMPACT_TEXT_BYTES));
15601
15743
  const context = {
15602
- objective: compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "",
15603
- status: view.task.status,
15744
+ objective: view ? compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "" : "no task on this branch yet",
15745
+ status: view?.task.status ?? null,
15604
15746
  decisions,
15605
15747
  methods,
15606
15748
  gaps,
15607
- nextAction: compactText(view.task.progress.nextAction, COMPACT_TEXT_BYTES)
15749
+ nextAction: compactText(view?.task.progress.nextAction ?? null, COMPACT_TEXT_BYTES)
15608
15750
  };
15609
15751
  let encoded = JSON.stringify(context);
15610
15752
  while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.methods.length || context.gaps.length)) {
@@ -15793,6 +15935,13 @@ var TASK_SCOPED_ACTIONS = new Set([
15793
15935
  "worker.cancel",
15794
15936
  "state.export"
15795
15937
  ]);
15938
+ var WORKER_ADDRESSED_ACTIONS = new Set(["worker.cancel", "worker.report"]);
15939
+ var workerCommand = (taskId, request) => {
15940
+ const { action, workerId, reason, report } = request;
15941
+ const rest = JSON.stringify({ reason, report });
15942
+ const payload = rest === "{}" ? "" : ` --payload '${rest.replace(/'/gu, "'\\''")}'`;
15943
+ return `workit worker ${String(action)} ${String(workerId)} --task ${taskId}${payload}`;
15944
+ };
15796
15945
  var CREATING_ACTIONS = new Set([
15797
15946
  "task.revise",
15798
15947
  "task.progress",
@@ -16043,6 +16192,17 @@ class WorkitCore {
16043
16192
  const root = this.contextRootError();
16044
16193
  if (!root.ok)
16045
16194
  return root;
16195
+ const addressed = WORKER_ADDRESSED_ACTIONS.has(action);
16196
+ const workerId = addressed ? value.workerId : this.context.workerId ?? null;
16197
+ if (workerId !== null) {
16198
+ const owner = this.store.taskForWorker(workerId);
16199
+ if (!owner.ok)
16200
+ return owner;
16201
+ if (owner.data)
16202
+ return success(null, null, { ...request, taskId: owner.data });
16203
+ if (addressed)
16204
+ 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)}\``);
16205
+ }
16046
16206
  const create = CREATING_ACTIONS.has(action) && (this.context.workerId ?? null) === null;
16047
16207
  const found = this.store.implicitTask({
16048
16208
  provenance: provenance(this.context),
@@ -16749,7 +16909,9 @@ class WorkitCore {
16749
16909
  if (!resolved.ok)
16750
16910
  return resolved;
16751
16911
  const value = resolved.data;
16752
- return this.retryOmittedRevisions(value, () => this.workerOnce(value));
16912
+ const result = this.retryOmittedRevisions(value, () => this.workerOnce(value));
16913
+ const { action, taskId } = value ?? {};
16914
+ 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)}\`` };
16753
16915
  }
16754
16916
  workerOnce(request) {
16755
16917
  const root = this.contextRootError();
@@ -16954,10 +17116,18 @@ class WorkitCore {
16954
17116
  requirements
16955
17117
  });
16956
17118
  }
16957
- compactContext(taskId, freshness) {
17119
+ compactContext(taskId, freshness, origin = null) {
16958
17120
  const root = this.contextRootError();
16959
17121
  if (!root.ok)
16960
17122
  return root;
17123
+ const base = origin && this.store.readStoreTask(origin.taskId);
17124
+ const inherited = base?.ok && base.data ? {
17125
+ origin: origin.origin,
17126
+ taskId: base.data.id,
17127
+ decisions: base.data.decisions.filter((entry) => entry.data.revoked === null)
17128
+ } : null;
17129
+ if (taskId === null)
17130
+ return success(null, null, inherited?.decisions.length ? compactTaskContext(null, inherited) : "");
16961
17131
  const task = this.store.readTask(taskId);
16962
17132
  if (!task.ok)
16963
17133
  return task;
@@ -16967,7 +17137,7 @@ class WorkitCore {
16967
17137
  const view = this.view(task.data, false, freshness ?? signalFreshness(this.store.root));
16968
17138
  if (!view.ok)
16969
17139
  return view;
16970
- return success(view.revision, view.workspaceRevision, compactTaskContext(view.data));
17140
+ return success(view.revision, view.workspaceRevision, compactTaskContext(view.data, inherited));
16971
17141
  }
16972
17142
  view(task, capture = true, freshness = treeFreshness(this.store.root)) {
16973
17143
  const workspace = this.store.readWorkspace();
@@ -17273,9 +17443,9 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
17273
17443
  };
17274
17444
  });
17275
17445
  // packages/workit-core/src/hooks/context.ts
17276
- import { createHash as createHash10 } from "node:crypto";
17277
- import fs13 from "node:fs";
17278
- import path16 from "node:path";
17446
+ import { createHash as createHash11 } from "node:crypto";
17447
+ import fs14 from "node:fs";
17448
+ import path17 from "node:path";
17279
17449
  var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
17280
17450
  var migrationPending = (result) => !result.ok && result.code === "needs_input" && (result.error ?? "").startsWith(MIGRATION_PENDING);
17281
17451
  var boundTo = (entry, session) => entry.sessions.some((item) => item.host === session.host && item.handle === session.handle);
@@ -17288,8 +17458,9 @@ var currentTaskEntry = (entries, session, selection) => {
17288
17458
  const active = entries.filter((entry) => entry.status === "active");
17289
17459
  return active.length === 1 ? active[0] : null;
17290
17460
  };
17461
+ var otherConversation = (entry, session) => entry.sessions.some((item) => item.host !== "workit_cli" && !(item.host === session.host && item.handle === session.handle));
17291
17462
  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)));
17463
+ const open = entries.filter((entry) => entry.key !== null && entry.status !== "closed" && !otherConversation(entry, session));
17293
17464
  if (open.length === 0)
17294
17465
  return null;
17295
17466
  const key = store.currentKey();
@@ -17330,18 +17501,23 @@ function sessionCompactContext(store, session, context, selection = "session-bou
17330
17501
  if (!listed.ok)
17331
17502
  return migrationPending(listed) ? MIGRATION_PENDING_NOTE : null;
17332
17503
  const entry = currentTaskEntry(listed.data, session, selection) ?? implicitTaskEntry(store, listed.data, session);
17333
- return entry ? entryCompactContext(store, entry, session, context) : null;
17504
+ return entryCompactContext(store, entry, session, context);
17334
17505
  }
17335
17506
  function entryCompactContext(store, entry, session, context) {
17507
+ const found = store.originTaskEntry();
17508
+ const origin = found.ok && found.data && found.data.entry.id !== entry?.id && !otherConversation(found.data.entry, session) ? found.data : null;
17509
+ if (!entry && !origin)
17510
+ return null;
17336
17511
  const workspace = store.readWorkspace();
17337
- if (!workspace.ok || !workspace.data)
17512
+ if (!workspace.ok || entry && !workspace.data)
17338
17513
  return null;
17339
17514
  const slot = `${store.root}\x00${session.host}\x00${session.handle}`;
17340
17515
  const key = canonicalJson({
17341
- task: entry.id,
17342
- revision: entry.revision,
17343
- file: entry.file,
17344
- workspace: workspace.data.revision,
17516
+ task: entry?.id ?? null,
17517
+ revision: entry?.revision ?? null,
17518
+ file: entry?.file ?? null,
17519
+ origin: origin && origin.entry.file,
17520
+ workspace: workspace.data?.revision ?? null,
17345
17521
  caller: context.caller,
17346
17522
  workerId: context.workerId ?? null,
17347
17523
  capabilities: context.capabilities
@@ -17349,15 +17525,15 @@ function entryCompactContext(store, entry, session, context) {
17349
17525
  const hit = cache.get(slot);
17350
17526
  if (hit && hit.key === key && hit.filesKey !== null && hit.filesKey === filesKey(hit.files) && (hit.signal === null || hit.signal === recentSignal(store.root)))
17351
17527
  return hit.value;
17352
- const task = store.readTask(entry.id);
17353
- if (!task.ok)
17528
+ const task = entry ? store.readTask(entry.id) : null;
17529
+ if (task && !task.ok)
17354
17530
  return null;
17355
17531
  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)] : []));
17532
+ const observed = task?.data.evidence.some(isObservedCheck) ?? false;
17533
+ const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path17.resolve(store.root, ref.path)] : []));
17358
17534
  const observedFiles = filesKey(files);
17359
- const compact = new WorkitCore(store, context).compactContext(entry.id, freshness);
17360
- if (!compact.ok)
17535
+ const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
17536
+ if (!compact.ok || !compact.data)
17361
17537
  return null;
17362
17538
  cache.delete(slot);
17363
17539
  cache.set(slot, {
@@ -17396,7 +17572,7 @@ ${options.addendum}` : ""}
17396
17572
  if (!listed.ok)
17397
17573
  throw new Error(listed.error);
17398
17574
  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;
17575
+ const text = entryCompactContext(store, entry, session, hookOperationContext(input, descriptor));
17400
17576
  if (text)
17401
17577
  compact = `
17402
17578
  <workit-task-context>${text}</workit-task-context>`;
@@ -17423,7 +17599,7 @@ var turnContextText = (input, descriptor) => {
17423
17599
  }
17424
17600
  };
17425
17601
  var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
17426
- var digestOf = (text) => createHash10("sha256").update(text).digest("hex");
17602
+ var digestOf = (text) => createHash11("sha256").update(text).digest("hex");
17427
17603
  var turnMarker = (input) => {
17428
17604
  if (!input.session.id)
17429
17605
  return null;
@@ -17432,32 +17608,32 @@ var turnMarker = (input) => {
17432
17608
  if (location instanceof Error)
17433
17609
  return null;
17434
17610
  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`);
17611
+ return path17.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
17436
17612
  } catch {
17437
17613
  return null;
17438
17614
  }
17439
17615
  };
17440
17616
  var writeTurnDigest = (file, digest) => {
17441
17617
  try {
17442
- fs13.mkdirSync(path16.dirname(file), { recursive: true });
17443
- fs13.writeFileSync(file, `${JSON.stringify({ digest })}
17618
+ fs14.mkdirSync(path17.dirname(file), { recursive: true });
17619
+ fs14.writeFileSync(file, `${JSON.stringify({ digest })}
17444
17620
  `);
17445
17621
  } catch {}
17446
17622
  };
17447
17623
  var clearTurnDigest = (file) => {
17448
17624
  try {
17449
- fs13.rmSync(file, { force: true });
17625
+ fs14.rmSync(file, { force: true });
17450
17626
  } catch {}
17451
17627
  };
17452
17628
  var pruneTurnDigests = (dir, now) => {
17453
17629
  try {
17454
- for (const name of fs13.readdirSync(dir)) {
17630
+ for (const name of fs14.readdirSync(dir)) {
17455
17631
  if (!name.startsWith("turn-"))
17456
17632
  continue;
17457
- const file = path16.join(dir, name);
17633
+ const file = path17.join(dir, name);
17458
17634
  try {
17459
- if (now - fs13.statSync(file).mtimeMs > TURN_TTL_MS)
17460
- fs13.rmSync(file, { force: true });
17635
+ if (now - fs14.statSync(file).mtimeMs > TURN_TTL_MS)
17636
+ fs14.rmSync(file, { force: true });
17461
17637
  } catch {}
17462
17638
  }
17463
17639
  } catch {}
@@ -17473,7 +17649,7 @@ var changedTurnContext = (input, text) => {
17473
17649
  return text;
17474
17650
  const digest = digestOf(text);
17475
17651
  try {
17476
- const previous = JSON.parse(fs13.readFileSync(file, "utf8"));
17652
+ const previous = JSON.parse(fs14.readFileSync(file, "utf8"));
17477
17653
  if (previous.digest === digest)
17478
17654
  return null;
17479
17655
  } catch {}
@@ -17484,14 +17660,14 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
17484
17660
  const file = turnMarker(input);
17485
17661
  if (!file)
17486
17662
  return;
17487
- pruneTurnDigests(path16.dirname(file), Date.now());
17663
+ pruneTurnDigests(path17.dirname(file), Date.now());
17488
17664
  if (text)
17489
17665
  writeTurnDigest(file, digestOf(text));
17490
17666
  else
17491
17667
  clearTurnDigest(file);
17492
17668
  };
17493
17669
  // packages/workit-core/src/core/branch.ts
17494
- import { createHash as createHash11 } from "node:crypto";
17670
+ import { createHash as createHash12 } from "node:crypto";
17495
17671
  var withReleaseTracks = (workspaceRoot, policy) => {
17496
17672
  const read = workspaceReleaseTracks(workspaceRoot);
17497
17673
  if (read.error)
@@ -17559,7 +17735,7 @@ var branchPolicySnapshotFor = (workspaceRoot) => {
17559
17735
  const source = resolved.provenance.branchPolicy;
17560
17736
  const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
17561
17737
  const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
17562
- const fingerprint = createHash11("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
17738
+ const fingerprint = createHash12("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
17563
17739
  return {
17564
17740
  branchPolicy,
17565
17741
  namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
@@ -17608,7 +17784,7 @@ var shellPolicy = (cwd, command) => {
17608
17784
  };
17609
17785
  // packages/workit-core/src/hooks/write-gate.ts
17610
17786
  import { realpathSync as realpathSync5 } from "node:fs";
17611
- import path17 from "node:path";
17787
+ import path18 from "node:path";
17612
17788
 
17613
17789
  // packages/workit-core/src/hooks/shell-words.ts
17614
17790
  var closingQuote = (command, start, dialect) => {
@@ -17738,22 +17914,22 @@ var NONE2 = { kind: "none" };
17738
17914
  var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
17739
17915
  var canonical2 = (file) => {
17740
17916
  let rest = "";
17741
- for (let dir = path17.resolve(file);; dir = path17.dirname(dir)) {
17917
+ for (let dir = path18.resolve(file);; dir = path18.dirname(dir)) {
17742
17918
  try {
17743
- return path17.join(realpathSync5(dir), rest);
17919
+ return path18.join(realpathSync5(dir), rest);
17744
17920
  } catch {
17745
- if (path17.dirname(dir) === dir)
17746
- return path17.resolve(file);
17747
- rest = rest ? path17.join(path17.basename(dir), rest) : path17.basename(dir);
17921
+ if (path18.dirname(dir) === dir)
17922
+ return path18.resolve(file);
17923
+ rest = rest ? path18.join(path18.basename(dir), rest) : path18.basename(dir);
17748
17924
  }
17749
17925
  }
17750
17926
  };
17751
17927
  var exempt = (cwd, root, file, plans) => {
17752
17928
  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))
17929
+ const relative = path18.relative(fold(canonical2(root)), fold(canonical2(path18.resolve(cwd, file))));
17930
+ if (relative.startsWith("..") || path18.isAbsolute(relative))
17755
17931
  return true;
17756
- const posix = relative.split(path17.sep).join("/");
17932
+ const posix = relative.split(path18.sep).join("/");
17757
17933
  const segments = posix.split("/");
17758
17934
  return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
17759
17935
  };
@@ -17851,7 +18027,7 @@ var shellWrites = (command) => {
17851
18027
  return { writes: true, targets: unknown ? null : targets };
17852
18028
  };
17853
18029
  var cache2 = new Map;
17854
- var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path17.resolve(root, file)) ?? "-").join("\x00");
18030
+ var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path18.resolve(root, file)) ?? "-").join("\x00");
17855
18031
  var gateFor = (cwd) => {
17856
18032
  const store = new TaskStore(cwd);
17857
18033
  const listed = store.listTaskIndex();
@@ -17911,15 +18087,15 @@ import { spawnSync as spawnSync12 } from "node:child_process";
17911
18087
 
17912
18088
  // packages/workit-core/src/hooks/raw-git.ts
17913
18089
  import { spawnSync as spawnSync11 } from "node:child_process";
17914
- import { createHash as createHash13 } from "node:crypto";
17915
- import fs15 from "node:fs";
18090
+ import { createHash as createHash14 } from "node:crypto";
18091
+ import fs16 from "node:fs";
17916
18092
  import os4 from "node:os";
17917
- import path19 from "node:path";
18093
+ import path20 from "node:path";
17918
18094
 
17919
18095
  // 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";
18096
+ import { createHash as createHash13 } from "node:crypto";
18097
+ import fs15 from "node:fs";
18098
+ import path19 from "node:path";
17923
18099
  var sessionMarkerFile = (input, session, store) => {
17924
18100
  let dir = store;
17925
18101
  if (dir === undefined) {
@@ -17928,13 +18104,13 @@ var sessionMarkerFile = (input, session, store) => {
17928
18104
  return null;
17929
18105
  dir = location.dir;
17930
18106
  }
17931
- const name = createHash12("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
17932
- return path18.join(dir, "hooks", `skills-${name}.json`);
18107
+ const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
18108
+ return path19.join(dir, "hooks", `skills-${name}.json`);
17933
18109
  };
17934
18110
  var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
17935
18111
  var readSessionMarker = (file) => {
17936
18112
  try {
17937
- const value = JSON.parse(fs14.readFileSync(file, "utf8"));
18113
+ const value = JSON.parse(fs15.readFileSync(file, "utf8"));
17938
18114
  return { nudged: list2(value.nudged), loaded: list2(value.loaded), raw: list2(value.raw) };
17939
18115
  } catch {
17940
18116
  return { nudged: [], loaded: [], raw: [] };
@@ -17942,8 +18118,8 @@ var readSessionMarker = (file) => {
17942
18118
  };
17943
18119
  var writeSessionMarker = (file, marker) => {
17944
18120
  try {
17945
- fs14.mkdirSync(path18.dirname(file), { recursive: true });
17946
- fs14.writeFileSync(file, JSON.stringify(marker));
18121
+ fs15.mkdirSync(path19.dirname(file), { recursive: true });
18122
+ fs15.writeFileSync(file, JSON.stringify(marker));
17947
18123
  } catch {}
17948
18124
  };
17949
18125
 
@@ -17964,12 +18140,12 @@ var GIT_VALUE_OPTIONS = new Set([
17964
18140
  "--config-env",
17965
18141
  "--super-prefix"
17966
18142
  ]);
17967
- var isAbsolute = (value) => path19.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
18143
+ var isAbsolute = (value) => path20.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
17968
18144
  var joinDir = (base, next) => {
17969
18145
  if (base === undefined || /[$`*?]/.test(next) || next === "-")
17970
18146
  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);
18147
+ const expanded = next === "~" || next.startsWith("~/") ? path20.join(os4.homedir(), next.slice(1)) : next;
18148
+ return base === null || isAbsolute(expanded) ? expanded : path20.join(base, expanded);
17973
18149
  };
17974
18150
  var cdTarget = (words) => {
17975
18151
  const args = words.slice(1);
@@ -18222,7 +18398,7 @@ var repoAt = (dir) => {
18222
18398
  return { location, dir, branch: resolveTaskKey(dir, location).branch };
18223
18399
  };
18224
18400
  var isWorkitWorkspace = (repo) => {
18225
- if (fs15.existsSync(repo.location.dir))
18401
+ if (fs16.existsSync(repo.location.dir))
18226
18402
  return true;
18227
18403
  try {
18228
18404
  return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
@@ -18253,17 +18429,17 @@ var headSha2 = (repo) => {
18253
18429
  if (!git || git.reftable)
18254
18430
  return null;
18255
18431
  try {
18256
- const head = fs15.readFileSync(path19.join(git.gitDir, "HEAD"), "utf8").trim();
18432
+ const head = fs16.readFileSync(path20.join(git.gitDir, "HEAD"), "utf8").trim();
18257
18433
  if (/^[0-9a-f]{40,64}$/.test(head))
18258
18434
  return head;
18259
18435
  const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
18260
18436
  if (!ref)
18261
18437
  return null;
18262
- const common = path19.dirname(repo.location.dir);
18438
+ const common = path20.dirname(repo.location.dir);
18263
18439
  try {
18264
- return fs15.readFileSync(path19.join(common, ref), "utf8").trim() || null;
18440
+ return fs16.readFileSync(path20.join(common, ref), "utf8").trim() || null;
18265
18441
  } catch {}
18266
- const packed = fs15.readFileSync(path19.join(common, "packed-refs"), "utf8");
18442
+ const packed = fs16.readFileSync(path20.join(common, "packed-refs"), "utf8");
18267
18443
  return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
18268
18444
  } catch {
18269
18445
  return null;
@@ -18300,7 +18476,7 @@ var actionsIn = (cwd, command, dialect) => {
18300
18476
  const action = rawAction(invocation);
18301
18477
  if (!action)
18302
18478
  continue;
18303
- const dir = path19.resolve(cwd, invocation.dir ?? ".");
18479
+ const dir = path20.resolve(cwd, invocation.dir ?? ".");
18304
18480
  if (!repos.has(dir)) {
18305
18481
  const repo = repoAt(dir);
18306
18482
  repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
@@ -18369,8 +18545,8 @@ function rawGitPre(input, command, options = {}) {
18369
18545
  var deny = (reason) => ({ kind: "deny", reason, unblock: null });
18370
18546
  var NEXT_COMMAND = "next";
18371
18547
  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")}`;
18548
+ var markerFile = (repo, session, key) => path20.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
18549
+ var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash14("sha256").update(command).digest("hex")}`;
18374
18550
  function noteRawCommit(input, command, key) {
18375
18551
  try {
18376
18552
  if (!input.session.id || !/\bcommit\b/.test(command))
@@ -18380,8 +18556,8 @@ function noteRawCommit(input, command, key) {
18380
18556
  if (action.kind !== "commit")
18381
18557
  continue;
18382
18558
  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 })}
18559
+ fs16.mkdirSync(path20.dirname(file), { recursive: true });
18560
+ fs16.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
18385
18561
  `);
18386
18562
  }
18387
18563
  } catch {}
@@ -18404,11 +18580,11 @@ var headCommit = (dir) => {
18404
18580
  var settle2 = (input, repo, file) => {
18405
18581
  let marker;
18406
18582
  try {
18407
- marker = JSON.parse(fs15.readFileSync(file, "utf8"));
18583
+ marker = JSON.parse(fs16.readFileSync(file, "utf8"));
18408
18584
  } catch {
18409
18585
  return;
18410
18586
  }
18411
- fs15.rmSync(file, { force: true });
18587
+ fs16.rmSync(file, { force: true });
18412
18588
  const session = input.session.id;
18413
18589
  const now = Date.now() / 1000;
18414
18590
  if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
@@ -18457,7 +18633,7 @@ function settlePendingCommit(input) {
18457
18633
  if (!repo)
18458
18634
  return;
18459
18635
  const file = markerFile(repo, input.session.id, NEXT_COMMAND);
18460
- if (fs15.existsSync(file))
18636
+ if (fs16.existsSync(file))
18461
18637
  settle2(input, repo, file);
18462
18638
  } catch {}
18463
18639
  }
@@ -18847,12 +19023,12 @@ ${line}` };
18847
19023
  };
18848
19024
  // packages/workit-core/src/hooks/hosts/fields.ts
18849
19025
  import { existsSync as existsSync6, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
18850
- import path20 from "node:path";
19026
+ import path21 from "node:path";
18851
19027
  var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
18852
19028
  var nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "";
18853
19029
  var optionalText = (value) => typeof value === "string" ? value : null;
18854
19030
  var existingDirectory = (value) => {
18855
- if (!nonEmpty2(value) || !path20.isAbsolute(value) || !existsSync6(value))
19031
+ if (!nonEmpty2(value) || !path21.isAbsolute(value) || !existsSync6(value))
18856
19032
  return null;
18857
19033
  try {
18858
19034
  return statSync2(value).isDirectory() ? realpathSync6(value) : null;
@@ -18952,6 +19128,8 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
18952
19128
  if (role !== "judge" || !event.agentId)
18953
19129
  return readOnly;
18954
19130
  const own = subagentSession(session, event.agentId);
19131
+ if (session)
19132
+ recordIssuedSession(input.cwd || process.cwd(), session, own);
18955
19133
  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
19134
  };
18957
19135
  function handleHook(input, deps) {
@@ -19583,12 +19761,12 @@ var codexAdapter = {
19583
19761
  };
19584
19762
  },
19585
19763
  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>`
19764
+ 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
19765
  };
19588
19766
 
19589
19767
  // packages/workit-core/src/hooks/hosts/cursor.ts
19590
- import fs16 from "node:fs";
19591
- import path21 from "node:path";
19768
+ import fs17 from "node:fs";
19769
+ import path22 from "node:path";
19592
19770
  var undocumented = { support: "undocumented", native: null };
19593
19771
  var none = { support: "none", native: null };
19594
19772
  var CURSOR_DESCRIPTOR = {
@@ -19785,17 +19963,17 @@ var protocolEvent2 = (input) => {
19785
19963
  };
19786
19964
  var TRANSCRIPT_TAIL_BYTES = 256 * 1024;
19787
19965
  var lastAssistantText = (file) => {
19788
- if (!file || !path21.isAbsolute(file))
19966
+ if (!file || !path22.isAbsolute(file))
19789
19967
  return null;
19790
19968
  try {
19791
- const size = fs16.statSync(file).size;
19969
+ const size = fs17.statSync(file).size;
19792
19970
  const start = Math.max(0, size - TRANSCRIPT_TAIL_BYTES);
19793
19971
  const buffer = Buffer.alloc(size - start);
19794
- const fd = fs16.openSync(file, "r");
19972
+ const fd = fs17.openSync(file, "r");
19795
19973
  try {
19796
- fs16.readSync(fd, buffer, 0, buffer.length, start);
19974
+ fs17.readSync(fd, buffer, 0, buffer.length, start);
19797
19975
  } finally {
19798
- fs16.closeSync(fd);
19976
+ fs17.closeSync(fd);
19799
19977
  }
19800
19978
  const lines = buffer.toString("utf8").split(`
19801
19979
  `);
@@ -19822,7 +20000,7 @@ var lastAssistantText = (file) => {
19822
20000
  return null;
19823
20001
  }
19824
20002
  };
19825
- var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path21.sep) ? root : `${root}${path21.sep}`);
20003
+ var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path22.sep) ? root : `${root}${path22.sep}`);
19826
20004
  var hookCwd = (input) => {
19827
20005
  const cwd = existingDirectory(input.cwd);
19828
20006
  if (cwd && input.hook_event_name === "beforeShellExecution")