@brainervirus/workit-pi 8.20.0 → 8.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/worker.js +596 -7
  2. package/dist/workit.js +464 -245
  3. package/package.json +1 -1
package/dist/workit.js CHANGED
@@ -5,7 +5,7 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
5
5
  // packages/workit-core/src/core.ts
6
6
  import { spawnSync as spawnSync16 } from "node:child_process";
7
7
  import { existsSync as existsSync8, realpathSync as realpathSync5 } from "node:fs";
8
- import path24 from "node:path";
8
+ import path25 from "node:path";
9
9
 
10
10
  // packages/workit-core/src/core/task-contract.ts
11
11
  import { createHash, randomUUID } from "node:crypto";
@@ -14381,10 +14381,10 @@ var isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state);
14381
14381
  var workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state);
14382
14382
 
14383
14383
  // packages/workit-core/src/core/task-evaluation.ts
14384
- import { createHash as createHash11 } from "node:crypto";
14385
- import * as fs13 from "node:fs";
14384
+ import { createHash as createHash12 } from "node:crypto";
14385
+ import * as fs14 from "node:fs";
14386
14386
  import { spawnSync as spawnSync10 } from "node:child_process";
14387
- import path16 from "node:path";
14387
+ import path17 from "node:path";
14388
14388
 
14389
14389
  // packages/workit-core/src/check-config.ts
14390
14390
  import { spawnSync as spawnSync8 } from "node:child_process";
@@ -14615,13 +14615,70 @@ function checkCommand(args, version, onPath = workitAvailable()) {
14615
14615
 
14616
14616
  // packages/workit-core/src/core/policy/derive.ts
14617
14617
  import { existsSync as existsSync4 } from "node:fs";
14618
- import path15 from "node:path";
14618
+ import path16 from "node:path";
14619
14619
 
14620
14620
  // packages/workit-core/src/ledger.ts
14621
14621
  import { spawnSync as spawnSync9 } from "node:child_process";
14622
- import { createHash as createHash10, randomBytes as randomBytes3 } from "node:crypto";
14622
+ import { createHash as createHash11, randomBytes as randomBytes3 } from "node:crypto";
14623
+ import fs13 from "node:fs";
14624
+ import path15 from "node:path";
14625
+
14626
+ // packages/workit-core/src/hooks/standing-signal.ts
14627
+ import { createHash as createHash10 } from "node:crypto";
14623
14628
  import fs12 from "node:fs";
14624
14629
  import path14 from "node:path";
14630
+ var gitStoreDir = (cwd) => {
14631
+ try {
14632
+ for (let dir = path14.resolve(cwd);; dir = path14.dirname(dir)) {
14633
+ const dotGit = path14.join(dir, ".git");
14634
+ if (fs12.existsSync(dotGit)) {
14635
+ let gitDir = dotGit;
14636
+ if (fs12.statSync(dotGit).isFile()) {
14637
+ const target = /^gitdir:\s*(.+)$/mu.exec(fs12.readFileSync(dotGit, "utf8"))?.[1]?.trim();
14638
+ if (!target)
14639
+ return null;
14640
+ gitDir = path14.resolve(dir, target);
14641
+ const common = path14.join(gitDir, "commondir");
14642
+ if (fs12.existsSync(common))
14643
+ gitDir = path14.resolve(gitDir, fs12.readFileSync(common, "utf8").trim());
14644
+ }
14645
+ return path14.join(gitDir, "workit");
14646
+ }
14647
+ if (path14.dirname(dir) === dir)
14648
+ return null;
14649
+ }
14650
+ } catch {
14651
+ return null;
14652
+ }
14653
+ };
14654
+ var standingRevFile = (store) => path14.join(store, "standing", "rev");
14655
+ var standingSeenFile = (store, session, agentId) => path14.join(store, "standing", "seen", `${createHash10("sha256").update(`${session}\x00${agentId ?? ""}`).digest("hex").slice(0, 32)}.json`);
14656
+ var readStandingRev = (store) => {
14657
+ try {
14658
+ return fs12.readFileSync(standingRevFile(store), "utf8").trim() || null;
14659
+ } catch {
14660
+ return null;
14661
+ }
14662
+ };
14663
+ var readStandingSeen = (file) => {
14664
+ try {
14665
+ const value = JSON.parse(fs12.readFileSync(file, "utf8"));
14666
+ return {
14667
+ rev: typeof value.rev === "string" ? value.rev : null,
14668
+ ids: Array.isArray(value.ids) ? value.ids.filter((id) => typeof id === "string") : []
14669
+ };
14670
+ } catch {
14671
+ return { rev: null, ids: [] };
14672
+ }
14673
+ };
14674
+ var writeStandingSeen = (file, seen) => {
14675
+ try {
14676
+ fs12.mkdirSync(path14.dirname(file), { recursive: true });
14677
+ fs12.writeFileSync(file, JSON.stringify(seen));
14678
+ } catch {}
14679
+ };
14680
+
14681
+ // packages/workit-core/src/ledger.ts
14625
14682
  var LEDGER_VERSION = 1;
14626
14683
  var MAX_LINE_BYTES = 4096;
14627
14684
  var PASSING = new Set(["verified", "tests-verified", "type-check-only"]);
@@ -14731,7 +14788,7 @@ function diffHash(cwd, base, head) {
14731
14788
  ], GIT_TIMEOUTS.worktree);
14732
14789
  if (!diff.ok || !diff.stdout)
14733
14790
  return null;
14734
- const hash = createHash10("sha256");
14791
+ const hash = createHash11("sha256");
14735
14792
  for (const line of diff.stdout.split(`
14736
14793
  `)) {
14737
14794
  if (line.startsWith("index "))
@@ -14743,14 +14800,14 @@ function diffHash(cwd, base, head) {
14743
14800
  return `sha256:${hash.digest("hex")}`;
14744
14801
  }
14745
14802
  function storeRoot(cwd) {
14746
- const location = resolveStore(path14.resolve(cwd));
14803
+ const location = resolveStore(path15.resolve(cwd));
14747
14804
  if (location instanceof Error)
14748
14805
  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");
14749
14806
  return { ok: true, value: { root: location.dir, shared: location.shared } };
14750
14807
  }
14751
14808
  function ledgerPath(cwd) {
14752
14809
  const root = storeRoot(cwd);
14753
- return root.ok ? { ok: true, value: path14.join(root.value.root, "ledger", "ledger.jsonl") } : root;
14810
+ return root.ok ? { ok: true, value: path15.join(root.value.root, "ledger", "ledger.jsonl") } : root;
14754
14811
  }
14755
14812
  var newId2 = () => `${Date.now().toString(36)}-${randomBytes3(6).toString("hex")}`;
14756
14813
  var NETWORK_FS_TYPES = new Set([
@@ -14770,7 +14827,7 @@ var onNetworkFs = (dir) => {
14770
14827
  if (process.platform !== "linux")
14771
14828
  return false;
14772
14829
  try {
14773
- return isNetworkFsType(fs12.statfsSync(dir).type);
14830
+ return isNetworkFsType(fs13.statfsSync(dir).type);
14774
14831
  } catch {
14775
14832
  return false;
14776
14833
  }
@@ -14780,15 +14837,15 @@ var LOCK_STALE_MS = 30000;
14780
14837
  var LOCK_OWNER = "owner";
14781
14838
  var lockToken = (lock) => {
14782
14839
  try {
14783
- return fs12.readFileSync(path14.join(lock, LOCK_OWNER), "utf8");
14840
+ return fs13.readFileSync(path15.join(lock, LOCK_OWNER), "utf8");
14784
14841
  } catch {
14785
14842
  return null;
14786
14843
  }
14787
14844
  };
14788
14845
  var lockAgeMs = (lock) => {
14789
- for (const target of [path14.join(lock, LOCK_OWNER), lock]) {
14846
+ for (const target of [path15.join(lock, LOCK_OWNER), lock]) {
14790
14847
  try {
14791
- return Date.now() - fs12.statSync(target).mtimeMs;
14848
+ return Date.now() - fs13.statSync(target).mtimeMs;
14792
14849
  } catch {}
14793
14850
  }
14794
14851
  return null;
@@ -14796,14 +14853,14 @@ var lockAgeMs = (lock) => {
14796
14853
  var ledgerLock = {
14797
14854
  acquire(lock) {
14798
14855
  try {
14799
- fs12.mkdirSync(lock);
14856
+ fs13.mkdirSync(lock);
14800
14857
  } catch (error) {
14801
14858
  if (error.code === "EEXIST")
14802
14859
  return null;
14803
14860
  throw error;
14804
14861
  }
14805
14862
  const token = `${process.pid}-${randomBytes3(8).toString("hex")}`;
14806
- fs12.writeFileSync(path14.join(lock, LOCK_OWNER), token);
14863
+ fs13.writeFileSync(path15.join(lock, LOCK_OWNER), token);
14807
14864
  return token;
14808
14865
  },
14809
14866
  release(lock, token) {
@@ -14811,35 +14868,35 @@ var ledgerLock = {
14811
14868
  return false;
14812
14869
  const tomb = `${lock}.release-${randomBytes3(6).toString("hex")}`;
14813
14870
  try {
14814
- fs12.renameSync(lock, tomb);
14871
+ fs13.renameSync(lock, tomb);
14815
14872
  } catch {
14816
14873
  return false;
14817
14874
  }
14818
14875
  if (lockToken(tomb) !== token) {
14819
14876
  try {
14820
- fs12.renameSync(tomb, lock);
14877
+ fs13.renameSync(tomb, lock);
14821
14878
  } catch {}
14822
14879
  return false;
14823
14880
  }
14824
- fs12.rmSync(tomb, { recursive: true, force: true });
14881
+ fs13.rmSync(tomb, { recursive: true, force: true });
14825
14882
  return true;
14826
14883
  },
14827
14884
  token: lockToken,
14828
14885
  reap(lock, observed) {
14829
14886
  const tomb = `${lock}.reap-${randomBytes3(6).toString("hex")}`;
14830
14887
  try {
14831
- fs12.renameSync(lock, tomb);
14888
+ fs13.renameSync(lock, tomb);
14832
14889
  } catch {
14833
14890
  return false;
14834
14891
  }
14835
14892
  if (lockToken(tomb) === observed) {
14836
- fs12.rmSync(tomb, { recursive: true, force: true });
14893
+ fs13.rmSync(tomb, { recursive: true, force: true });
14837
14894
  return true;
14838
14895
  }
14839
14896
  try {
14840
- fs12.renameSync(tomb, lock);
14897
+ fs13.renameSync(tomb, lock);
14841
14898
  } catch {
14842
- fs12.rmSync(tomb, { recursive: true, force: true });
14899
+ fs13.rmSync(tomb, { recursive: true, force: true });
14843
14900
  }
14844
14901
  return false;
14845
14902
  }
@@ -14866,14 +14923,14 @@ function withLedgerLock(file, fn, waitMs = hostAwareLockTimeout(LOCK_WAIT_MS)) {
14866
14923
  ledgerLock.release(lock, token);
14867
14924
  }
14868
14925
  }
14869
- var sha2562 = (text) => createHash10("sha256").update(text).digest("hex");
14926
+ var sha2562 = (text) => createHash11("sha256").update(text).digest("hex");
14870
14927
  var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
14871
14928
  ${body}`);
14872
14929
  var TAIL_BYTES = 64 * 1024;
14873
14930
  var lastLine = (fd, size) => {
14874
14931
  for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
14875
14932
  const buffer = Buffer.alloc(span);
14876
- fs12.readSync(fd, buffer, 0, span, size - span);
14933
+ fs13.readSync(fd, buffer, 0, span, size - span);
14877
14934
  const end = buffer.lastIndexOf(10);
14878
14935
  if (end < 0) {
14879
14936
  if (span === size)
@@ -14904,21 +14961,21 @@ var lastLine = (fd, size) => {
14904
14961
  };
14905
14962
  var tighten = (fd) => {
14906
14963
  try {
14907
- if ((fs12.fstatSync(fd).mode & 63) !== 0)
14908
- fs12.fchmodSync(fd, 384);
14964
+ if ((fs13.fstatSync(fd).mode & 63) !== 0)
14965
+ fs13.fchmodSync(fd, 384);
14909
14966
  } catch {}
14910
14967
  };
14911
14968
  function appendLine(file, build, options) {
14912
14969
  const write = () => {
14913
- const fd = fs12.openSync(file, "a+", 384);
14970
+ const fd = fs13.openSync(file, "a+", 384);
14914
14971
  try {
14915
14972
  if (process.platform !== "win32")
14916
14973
  tighten(fd);
14917
- const size = fs12.fstatSync(fd).size;
14974
+ const size = fs13.fstatSync(fd).size;
14918
14975
  let fence = "";
14919
14976
  if (size > 0) {
14920
14977
  const last = Buffer.alloc(1);
14921
- fs12.readSync(fd, last, 0, 1, size - 1);
14978
+ fs13.readSync(fd, last, 0, 1, size - 1);
14922
14979
  if (last[0] !== 10)
14923
14980
  fence = `
14924
14981
  `;
@@ -14927,17 +14984,17 @@ function appendLine(file, build, options) {
14927
14984
  if (!line.ok)
14928
14985
  return line;
14929
14986
  const bytes = Buffer.from(fence + line.value);
14930
- const written = fs12.writeSync(fd, bytes);
14987
+ const written = fs13.writeSync(fd, bytes);
14931
14988
  if (written !== bytes.length)
14932
14989
  return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
14933
14990
  return { ok: true, value: undefined };
14934
14991
  } finally {
14935
- fs12.closeSync(fd);
14992
+ fs13.closeSync(fd);
14936
14993
  }
14937
14994
  };
14938
14995
  try {
14939
- fs12.mkdirSync(path14.dirname(file), { recursive: true });
14940
- if (!options.forceLock && !onNetworkFs(path14.dirname(file)))
14996
+ fs13.mkdirSync(path15.dirname(file), { recursive: true });
14997
+ if (!options.forceLock && !onNetworkFs(path15.dirname(file)))
14941
14998
  return write();
14942
14999
  const locked = withLedgerLock(file, write);
14943
15000
  return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
@@ -15010,8 +15067,8 @@ function readLedger(cwd, options = {}) {
15010
15067
  let text = "";
15011
15068
  let stat = null;
15012
15069
  try {
15013
- stat = fs12.statSync(file.value);
15014
- text = fs12.readFileSync(file.value, "utf8");
15070
+ stat = fs13.statSync(file.value);
15071
+ text = fs13.readFileSync(file.value, "utf8");
15015
15072
  } catch (error) {
15016
15073
  if (error.code === "ENOENT")
15017
15074
  return {
@@ -15146,7 +15203,7 @@ function ledgerTampering(cwd) {
15146
15203
  if (!file.ok)
15147
15204
  return [];
15148
15205
  try {
15149
- const stat = fs12.statSync(file.value);
15206
+ const stat = fs13.statSync(file.value);
15150
15207
  const cached = tamperCache.get(file.value);
15151
15208
  if (cached && cached.size === stat.size && cached.stamp === fileStamp(stat))
15152
15209
  return cached.breaks;
@@ -15477,6 +15534,28 @@ function checkVerdicts(cwd, branch, ledgerRows) {
15477
15534
  warnings
15478
15535
  };
15479
15536
  }
15537
+ var fromLead = (row, leads) => leads === null || row.actor.session !== null && leads.includes(row.actor.session);
15538
+ function activeStanding(rows, fanout, leads = null) {
15539
+ const active = [];
15540
+ for (const row of rows) {
15541
+ if (row.fanout !== fanout || !fromLead(row, leads))
15542
+ continue;
15543
+ if (row.type === "standing" && typeof row.what === "string" && row.what.trim()) {
15544
+ if (!row.superseded)
15545
+ active.push(row);
15546
+ } else if (row.type === "standing.cleared") {
15547
+ const target = str2(row.target);
15548
+ if (target === null)
15549
+ active.length = 0;
15550
+ else {
15551
+ const index = active.findIndex((order) => order.id === target);
15552
+ if (index >= 0)
15553
+ active.splice(index, 1);
15554
+ }
15555
+ }
15556
+ }
15557
+ return active;
15558
+ }
15480
15559
  var OBSERVED_ONLY = new Set([
15481
15560
  "check",
15482
15561
  "merge.unverified",
@@ -15625,7 +15704,7 @@ var productDecision = (task, ledger) => {
15625
15704
  };
15626
15705
  };
15627
15706
  var planRecorded = (task, root) => {
15628
- const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path15.resolve(root, ref.path)));
15707
+ const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path16.resolve(root, ref.path)));
15629
15708
  if (cited)
15630
15709
  return {
15631
15710
  met: true,
@@ -15684,15 +15763,15 @@ function writeBlockers(task, root) {
15684
15763
  }
15685
15764
 
15686
15765
  // packages/workit-core/src/core/task-evaluation.ts
15687
- var digestBytes = (value) => createHash11("sha256").update(value).digest("hex");
15688
- var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
15689
- var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
15766
+ var digestBytes = (value) => createHash12("sha256").update(value).digest("hex");
15767
+ var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path17.sep}`);
15768
+ var relative = (root, candidate) => path17.relative(root, candidate).split(path17.sep).join("/") || ".";
15690
15769
  var canonicalPath = (value) => {
15691
15770
  if (typeof value !== "string" || !value)
15692
15771
  return null;
15693
15772
  if (value.includes("\\") || value.split("/").includes(".."))
15694
15773
  return null;
15695
- const normalized = path16.posix.normalize(value);
15774
+ const normalized = path17.posix.normalize(value);
15696
15775
  if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
15697
15776
  return null;
15698
15777
  return normalized === "." ? "." : normalized.replace(/\/$/, "");
@@ -15740,21 +15819,21 @@ var gitPaths = (root) => {
15740
15819
  git: !/not a git repository/i.test(stderr)
15741
15820
  };
15742
15821
  }
15743
- const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
15822
+ const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path17.sep).join("/")) : [];
15744
15823
  const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
15745
15824
  if (stagedDeleted.status !== 0) {
15746
15825
  const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
15747
15826
  if (!/not a git repository/i.test(stderr))
15748
15827
  return { paths, uncertain: true, git: true };
15749
15828
  } else if (stagedDeleted.stdout) {
15750
- paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
15829
+ paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path17.sep).join("/")));
15751
15830
  }
15752
15831
  return { paths: [...new Set(paths)], uncertain: false, git: true };
15753
15832
  };
15754
15833
  var walk = (root, directory, output) => {
15755
15834
  let names;
15756
15835
  try {
15757
- names = fs13.readdirSync(directory);
15836
+ names = fs14.readdirSync(directory);
15758
15837
  } catch {
15759
15838
  return true;
15760
15839
  }
@@ -15762,10 +15841,10 @@ var walk = (root, directory, output) => {
15762
15841
  for (const name of names) {
15763
15842
  if (name === ".git" || name === ".workit")
15764
15843
  continue;
15765
- const target = path16.join(directory, name);
15844
+ const target = path17.join(directory, name);
15766
15845
  let stat;
15767
15846
  try {
15768
- stat = fs13.lstatSync(target);
15847
+ stat = fs14.lstatSync(target);
15769
15848
  } catch {
15770
15849
  uncertain = true;
15771
15850
  continue;
@@ -15780,14 +15859,14 @@ var walk = (root, directory, output) => {
15780
15859
  var scopeRoots = (root, scope) => {
15781
15860
  const roots = [];
15782
15861
  for (const item of scope.paths.length ? scope.paths : ["."]) {
15783
- const target = path16.resolve(root, item);
15862
+ const target = path17.resolve(root, item);
15784
15863
  if (!inside(root, target))
15785
15864
  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` }] });
15786
15865
  let ancestor = target;
15787
- while (!fs13.existsSync(ancestor) && ancestor !== root)
15788
- ancestor = path16.dirname(ancestor);
15866
+ while (!fs14.existsSync(ancestor) && ancestor !== root)
15867
+ ancestor = path17.dirname(ancestor);
15789
15868
  try {
15790
- if (!inside(root, fs13.realpathSync(ancestor)))
15869
+ if (!inside(root, fs14.realpathSync(ancestor)))
15791
15870
  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` }] });
15792
15871
  } catch {
15793
15872
  return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
@@ -15799,7 +15878,7 @@ var scopeRoots = (root, scope) => {
15799
15878
  function captureCandidate(root, scope, environment = []) {
15800
15879
  let checkout;
15801
15880
  try {
15802
- checkout = fs13.realpathSync(root);
15881
+ checkout = fs14.realpathSync(root);
15803
15882
  } catch {
15804
15883
  return failure2("invalid_input", "candidate root does not exist");
15805
15884
  }
@@ -15817,11 +15896,11 @@ function captureCandidate(root, scope, environment = []) {
15817
15896
  if (item === ".git" || item === ".workit")
15818
15897
  continue;
15819
15898
  names.add(item);
15820
- if (!fs13.existsSync(target))
15899
+ if (!fs14.existsSync(target))
15821
15900
  continue;
15822
15901
  let stat;
15823
15902
  try {
15824
- stat = fs13.lstatSync(target);
15903
+ stat = fs14.lstatSync(target);
15825
15904
  } catch {
15826
15905
  uncertain = true;
15827
15906
  continue;
@@ -15837,17 +15916,17 @@ function captureCandidate(root, scope, environment = []) {
15837
15916
  for (const item of [...names].toSorted()) {
15838
15917
  if (!scopeMatches(item, normalizedScope))
15839
15918
  continue;
15840
- const target = path16.join(checkout, item);
15919
+ const target = path17.join(checkout, item);
15841
15920
  try {
15842
- const stat = fs13.lstatSync(target);
15921
+ const stat = fs14.lstatSync(target);
15843
15922
  if (stat.isSymbolicLink()) {
15844
- const link = fs13.readlinkSync(target);
15923
+ const link = fs14.readlinkSync(target);
15845
15924
  files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
15846
15925
  } else if (stat.isFile()) {
15847
15926
  files.push({
15848
15927
  path: item,
15849
15928
  kind: "file",
15850
- digest: digestBytes(fs13.readFileSync(target)),
15929
+ digest: digestBytes(fs14.readFileSync(target)),
15851
15930
  executable: (stat.mode & 73) !== 0
15852
15931
  });
15853
15932
  } else if (!stat.isDirectory()) {
@@ -16012,7 +16091,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
16012
16091
  var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
16013
16092
  let root;
16014
16093
  try {
16015
- root = fs13.realpathSync(checkoutRoot);
16094
+ root = fs14.realpathSync(checkoutRoot);
16016
16095
  } catch {
16017
16096
  return failure2("permission_denied", "checkout root is unavailable");
16018
16097
  }
@@ -16021,23 +16100,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
16021
16100
  continue;
16022
16101
  if (!reference.digest)
16023
16102
  return failure2("invalid_input", "document references require a byte digest");
16024
- const target = path16.resolve(root, reference.path);
16025
- if (target !== root && !target.startsWith(`${root}${path16.sep}`))
16103
+ const target = path17.resolve(root, reference.path);
16104
+ if (target !== root && !target.startsWith(`${root}${path17.sep}`))
16026
16105
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
16027
16106
  fields: [
16028
16107
  { path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
16029
16108
  ]
16030
16109
  });
16031
16110
  try {
16032
- const below = path16.relative(root, target);
16111
+ const below = path17.relative(root, target);
16033
16112
  let current = root;
16034
- for (const segment of below.split(path16.sep)) {
16113
+ for (const segment of below.split(path17.sep)) {
16035
16114
  if (!segment)
16036
16115
  continue;
16037
- current = path16.join(current, segment);
16038
- const stat = fs13.lstatSync(current);
16039
- const real = fs13.realpathSync(current);
16040
- if (real !== root && !real.startsWith(`${root}${path16.sep}`))
16116
+ current = path17.join(current, segment);
16117
+ const stat = fs14.lstatSync(current);
16118
+ const real = fs14.realpathSync(current);
16119
+ if (real !== root && !real.startsWith(`${root}${path17.sep}`))
16041
16120
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
16042
16121
  fields: [
16043
16122
  {
@@ -16053,7 +16132,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
16053
16132
  if (current !== target && !stat.isDirectory())
16054
16133
  return failure2("invalid_input", "document reference ancestor is not a directory");
16055
16134
  }
16056
- if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
16135
+ if (digestBytes(fs14.readFileSync(target)) !== reference.digest)
16057
16136
  return failure2("permission_denied", "decision document bytes have changed");
16058
16137
  } catch {
16059
16138
  return failure2("invalid_input", "decision document is unavailable");
@@ -16637,19 +16716,19 @@ var exportDigest = (bundle) => sha256({
16637
16716
  // packages/workit-core/src/core/route-intent.ts
16638
16717
  import { spawnSync as spawnSync12 } from "node:child_process";
16639
16718
  import { existsSync as existsSync6 } from "node:fs";
16640
- import path19 from "node:path";
16719
+ import path20 from "node:path";
16641
16720
 
16642
16721
  // packages/workit-core/src/hooks/raw-git.ts
16643
16722
  import { spawnSync as spawnSync11 } from "node:child_process";
16644
- import { createHash as createHash13 } from "node:crypto";
16645
- import fs15 from "node:fs";
16723
+ import { createHash as createHash14 } from "node:crypto";
16724
+ import fs16 from "node:fs";
16646
16725
  import os4 from "node:os";
16647
- import path18 from "node:path";
16726
+ import path19 from "node:path";
16648
16727
 
16649
16728
  // packages/workit-core/src/hooks/session-marker.ts
16650
- import { createHash as createHash12 } from "node:crypto";
16651
- import fs14 from "node:fs";
16652
- import path17 from "node:path";
16729
+ import { createHash as createHash13 } from "node:crypto";
16730
+ import fs15 from "node:fs";
16731
+ import path18 from "node:path";
16653
16732
  var sessionMarkerFile = (input, session, store) => {
16654
16733
  let dir = store;
16655
16734
  if (dir === undefined) {
@@ -16658,13 +16737,13 @@ var sessionMarkerFile = (input, session, store) => {
16658
16737
  return null;
16659
16738
  dir = location.dir;
16660
16739
  }
16661
- const name = createHash12("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
16662
- return path17.join(dir, "hooks", `skills-${name}.json`);
16740
+ const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
16741
+ return path18.join(dir, "hooks", `skills-${name}.json`);
16663
16742
  };
16664
16743
  var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
16665
16744
  var readSessionMarker = (file) => {
16666
16745
  try {
16667
- const value = JSON.parse(fs14.readFileSync(file, "utf8"));
16746
+ const value = JSON.parse(fs15.readFileSync(file, "utf8"));
16668
16747
  return { nudged: list2(value.nudged), loaded: list2(value.loaded), raw: list2(value.raw) };
16669
16748
  } catch {
16670
16749
  return { nudged: [], loaded: [], raw: [] };
@@ -16672,8 +16751,8 @@ var readSessionMarker = (file) => {
16672
16751
  };
16673
16752
  var writeSessionMarker = (file, marker) => {
16674
16753
  try {
16675
- fs14.mkdirSync(path17.dirname(file), { recursive: true });
16676
- fs14.writeFileSync(file, JSON.stringify(marker));
16754
+ fs15.mkdirSync(path18.dirname(file), { recursive: true });
16755
+ fs15.writeFileSync(file, JSON.stringify(marker));
16677
16756
  } catch {}
16678
16757
  };
16679
16758
 
@@ -17170,14 +17249,14 @@ var GIT_CONFIG_ENV = /^GIT_(?:CONFIG\w*|DIR|COMMON_DIR|WORK_TREE)$/;
17170
17249
  var ASSIGNMENT = /^([A-Za-z_]\w*)=([\s\S]*)$/;
17171
17250
  var MAX_DEPTH = 4;
17172
17251
  var MAX_EXPANSIONS = 16;
17173
- var isAbsolute = (value) => path18.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
17252
+ var isAbsolute = (value) => path19.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
17174
17253
  var HERE = /^(?:\$PWD|\$\{PWD\}|\$\(\s*pwd\s*\)|`pwd`|\$\(\s*git\s+rev-parse\s+--show-toplevel\s*\))(?=$|[\\/])/;
17175
17254
  var joinDir = (base, raw) => {
17176
17255
  const next = raw.replace(HERE, ".");
17177
17256
  if (base === undefined || /[$`*?]/.test(next) || next === "-")
17178
17257
  return;
17179
- const expanded = next === "~" || next.startsWith("~/") ? path18.join(os4.homedir(), next.slice(1)) : next;
17180
- return base === null || isAbsolute(expanded) ? expanded : path18.join(base, expanded);
17258
+ const expanded = next === "~" || next.startsWith("~/") ? path19.join(os4.homedir(), next.slice(1)) : next;
17259
+ return base === null || isAbsolute(expanded) ? expanded : path19.join(base, expanded);
17181
17260
  };
17182
17261
  var rebase = (base, inner) => inner === null ? base : inner === undefined ? undefined : joinDir(base, inner);
17183
17262
  var cdTarget = (words) => {
@@ -17989,7 +18068,7 @@ var repoAt = (dir) => {
17989
18068
  return { location, dir, branch: resolveTaskKey(dir, location).branch };
17990
18069
  };
17991
18070
  var isWorkitWorkspace = (repo) => {
17992
- if (fs15.existsSync(repo.location.dir))
18071
+ if (fs16.existsSync(repo.location.dir))
17993
18072
  return true;
17994
18073
  try {
17995
18074
  return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
@@ -18010,17 +18089,17 @@ var headSha2 = (repo) => {
18010
18089
  if (!git || git.reftable)
18011
18090
  return null;
18012
18091
  try {
18013
- const head = fs15.readFileSync(path18.join(git.gitDir, "HEAD"), "utf8").trim();
18092
+ const head = fs16.readFileSync(path19.join(git.gitDir, "HEAD"), "utf8").trim();
18014
18093
  if (/^[0-9a-f]{40,64}$/.test(head))
18015
18094
  return head;
18016
18095
  const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
18017
18096
  if (!ref)
18018
18097
  return null;
18019
- const common = path18.dirname(repo.location.dir);
18098
+ const common = path19.dirname(repo.location.dir);
18020
18099
  try {
18021
- return fs15.readFileSync(path18.join(common, ref), "utf8").trim() || null;
18100
+ return fs16.readFileSync(path19.join(common, ref), "utf8").trim() || null;
18022
18101
  } catch {}
18023
- const packed = fs15.readFileSync(path18.join(common, "packed-refs"), "utf8");
18102
+ const packed = fs16.readFileSync(path19.join(common, "packed-refs"), "utf8");
18024
18103
  return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
18025
18104
  } catch {
18026
18105
  return null;
@@ -18108,8 +18187,8 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
18108
18187
  const sub = invocation.args[0];
18109
18188
  if (invocation.tool !== "git" || invocation.dir === undefined || !sub || sub.startsWith("-") || GIT_COMMANDS.has(sub) || depth >= MAX_DEPTH)
18110
18189
  return [invocation];
18111
- const dir = path18.resolve(root, invocation.dir ?? ".");
18112
- if (!fs15.existsSync(dir))
18190
+ const dir = path19.resolve(root, invocation.dir ?? ".");
18191
+ if (!fs16.existsSync(dir))
18113
18192
  return [invocation];
18114
18193
  const config = gitConfig(dir, invocation, cache);
18115
18194
  const alias = configValue(config, `alias.${sub.toLowerCase()}`);
@@ -18131,11 +18210,11 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
18131
18210
  var normalizedUrl = (url, dir) => {
18132
18211
  const trimmed = url.trim();
18133
18212
  if (/^file:\/\//i.test(trimmed))
18134
- return path18.resolve(dir, trimmed.slice(7)).replace(/\/+$/, "").replace(/\.git$/, "");
18213
+ return path19.resolve(dir, trimmed.slice(7)).replace(/\/+$/, "").replace(/\.git$/, "");
18135
18214
  const scheme = /^[a-z][a-z0-9+.-]*:\/\//i.exec(trimmed);
18136
18215
  const scp = !scheme && /^(?:[^@/\\]+@)?[^/\\:]{2,}:/.test(trimmed);
18137
18216
  if (!scheme && !scp)
18138
- return path18.resolve(dir, trimmed).replace(/\/+$/, "").replace(/\.git$/, "");
18217
+ return path19.resolve(dir, trimmed).replace(/\/+$/, "").replace(/\.git$/, "");
18139
18218
  const value = scheme ? trimmed.slice(scheme[0].length).replace(/^[^@/]*@/, "").replace(/^([^/:]+):\d+(?=\/)/, "$1") : trimmed.replace(/^[^@/]*@/, "").replace(":", "/");
18140
18219
  return value.toLowerCase().replace(/\/{2,}/g, "/").replace(/^www\./, "").replace(/\/+$/, "").replace(/\.git$/, "");
18141
18220
  };
@@ -18359,7 +18438,7 @@ var actionsIn = (cwd, command, dialect, cache = new Map) => {
18359
18438
  const out = [];
18360
18439
  const repos = new Map;
18361
18440
  const repoFor = (relative) => {
18362
- const dir = path18.resolve(cwd, relative ?? ".");
18441
+ const dir = path19.resolve(cwd, relative ?? ".");
18363
18442
  if (!repos.has(dir)) {
18364
18443
  const repo = repoAt(dir);
18365
18444
  repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
@@ -18445,8 +18524,8 @@ var analysisDenial = (error) => ({
18445
18524
  });
18446
18525
  var NEXT_COMMAND = "next";
18447
18526
  var MARKER_TTL_SECONDS = 3600;
18448
- var markerFile = (repo, session, key) => path18.join(repo.location.dir, "hooks", `commit-${createHash13("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
18449
- var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash13("sha256").update(command).digest("hex")}`;
18527
+ var markerFile = (repo, session, key) => path19.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
18528
+ var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash14("sha256").update(command).digest("hex")}`;
18450
18529
  function noteRawCommit(input, command, key) {
18451
18530
  try {
18452
18531
  if (!input.session.id || !/\bcommit\b/.test(command))
@@ -18456,8 +18535,8 @@ function noteRawCommit(input, command, key) {
18456
18535
  if (action.kind !== "commit")
18457
18536
  continue;
18458
18537
  const file = markerFile(repo, input.session.id, key);
18459
- fs15.mkdirSync(path18.dirname(file), { recursive: true });
18460
- fs15.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
18538
+ fs16.mkdirSync(path19.dirname(file), { recursive: true });
18539
+ fs16.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
18461
18540
  `);
18462
18541
  }
18463
18542
  } catch {}
@@ -18480,11 +18559,11 @@ var headCommit = (dir) => {
18480
18559
  var settle2 = (input, repo, file) => {
18481
18560
  let marker;
18482
18561
  try {
18483
- marker = JSON.parse(fs15.readFileSync(file, "utf8"));
18562
+ marker = JSON.parse(fs16.readFileSync(file, "utf8"));
18484
18563
  } catch {
18485
18564
  return;
18486
18565
  }
18487
- fs15.rmSync(file, { force: true });
18566
+ fs16.rmSync(file, { force: true });
18488
18567
  const session = input.session.id;
18489
18568
  const now = Date.now() / 1000;
18490
18569
  if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
@@ -18533,7 +18612,7 @@ function settlePendingCommit(input) {
18533
18612
  if (!repo)
18534
18613
  return;
18535
18614
  const file = markerFile(repo, input.session.id, NEXT_COMMAND);
18536
- if (fs15.existsSync(file))
18615
+ if (fs16.existsSync(file))
18537
18616
  settle2(input, repo, file);
18538
18617
  } catch {}
18539
18618
  }
@@ -18687,7 +18766,7 @@ var judgedDir = (root, dir) => {
18687
18766
  return null;
18688
18767
  if (dir === null)
18689
18768
  return root;
18690
- const resolved = path19.resolve(root, dir);
18769
+ const resolved = path20.resolve(root, dir);
18691
18770
  return existsSync6(resolved) && inWorkitWorkspace(resolved) ? resolved : null;
18692
18771
  };
18693
18772
  var shellBranchPolicyViolation = (root, command, dialect = "posix") => {
@@ -18923,7 +19002,7 @@ var judgeInputSummary = (raw) => {
18923
19002
 
18924
19003
  // packages/workit-core/src/autonomy.ts
18925
19004
  import os5 from "node:os";
18926
- import path20 from "node:path";
19005
+ import path21 from "node:path";
18927
19006
  var accountHome = () => {
18928
19007
  try {
18929
19008
  return os5.userInfo().homedir;
@@ -18932,10 +19011,10 @@ var accountHome = () => {
18932
19011
  }
18933
19012
  };
18934
19013
  var grantsHome = { resolve: accountHome };
18935
- var grantsDir = () => path20.join(grantsHome.resolve(), ".config", "workit");
19014
+ var grantsDir = () => path21.join(grantsHome.resolve(), ".config", "workit");
18936
19015
  var grantsOverride = () => {
18937
- const configured = path20.resolve(resolveConfigDir());
18938
- return configured === path20.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 ${path20.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
19016
+ const configured = path21.resolve(resolveConfigDir());
19017
+ return configured === path21.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 ${path21.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
18939
19018
  };
18940
19019
  var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
18941
19020
  var DEFAULT_GRANTS = Object.freeze({
@@ -20738,7 +20817,7 @@ class WorkitCore {
20738
20817
  // packages/workit-core/src/core/repo-context.ts
20739
20818
  import { spawnSync as spawnSync13 } from "node:child_process";
20740
20819
  import { existsSync as existsSync7, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
20741
- import path21 from "node:path";
20820
+ import path22 from "node:path";
20742
20821
  var isSafeContextRange = (value) => value.length <= 4096 && (() => {
20743
20822
  try {
20744
20823
  gitRevisionParts(value);
@@ -20872,7 +20951,7 @@ var findPrTemplate = (cwd) => {
20872
20951
  ]) {
20873
20952
  const parts = rel.split("/");
20874
20953
  const base = parts[parts.length - 1];
20875
- const dir = parts.length > 1 ? path21.join(cwd, ...parts.slice(0, -1)) : cwd;
20954
+ const dir = parts.length > 1 ? path22.join(cwd, ...parts.slice(0, -1)) : cwd;
20876
20955
  const actual = probeCaseInsensitive(dir, base);
20877
20956
  if (actual)
20878
20957
  return [...parts.slice(0, -1), actual].join("/");
@@ -20903,7 +20982,7 @@ var diffStatForRange = (cwd, range) => {
20903
20982
  return runGit(cwd, ["diff", "--stat", "--"]).stdout;
20904
20983
  };
20905
20984
  var packageScripts = (cwd, keys) => {
20906
- const pkgPath = path21.join(cwd, "package.json");
20985
+ const pkgPath = path22.join(cwd, "package.json");
20907
20986
  if (!existsSync7(pkgPath))
20908
20987
  return [];
20909
20988
  try {
@@ -20929,9 +21008,9 @@ var documentationFiles = (cwd) => {
20929
21008
  if (entry.isDirectory()) {
20930
21009
  if (excluded.has(entry.name))
20931
21010
  continue;
20932
- walk(path21.join(dir, entry.name), depth + 1);
21011
+ walk(path22.join(dir, entry.name), depth + 1);
20933
21012
  } else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
20934
- matches.push("./" + path21.relative(cwd, path21.join(dir, entry.name)).replaceAll("\\", "/"));
21013
+ matches.push("./" + path22.relative(cwd, path22.join(dir, entry.name)).replaceAll("\\", "/"));
20935
21014
  }
20936
21015
  }
20937
21016
  };
@@ -20947,7 +21026,7 @@ var readTrimmed2 = (file, maxLines) => {
20947
21026
  `);
20948
21027
  };
20949
21028
  function prReadyContext(root, range) {
20950
- const cwd = path21.resolve(repoRoot(root));
21029
+ const cwd = path22.resolve(repoRoot(root));
20951
21030
  if (range !== undefined && !isResolvableContextRange(cwd, range))
20952
21031
  return invalidRange(cwd);
20953
21032
  let stdout = "";
@@ -21005,7 +21084,7 @@ ${status.stderr}` : "");
21005
21084
  stdout += `template_path: ${template}
21006
21085
 
21007
21086
  `;
21008
- stdout += readTrimmed2(path21.join(cwd, template), 220);
21087
+ stdout += readTrimmed2(path22.join(cwd, template), 220);
21009
21088
  } else {
21010
21089
  stdout += `template_path: none
21011
21090
 
@@ -21015,7 +21094,7 @@ ${status.stderr}` : "");
21015
21094
  stdout += `
21016
21095
  `;
21017
21096
  stdout += printSection("Recent Validation Signals");
21018
- if (existsSync7(path21.join(cwd, "package.json"))) {
21097
+ if (existsSync7(path22.join(cwd, "package.json"))) {
21019
21098
  stdout += `package.json detected. Common scripts:
21020
21099
  `;
21021
21100
  const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
@@ -21024,7 +21103,7 @@ ${status.stderr}` : "");
21024
21103
  `) + `
21025
21104
  `;
21026
21105
  }
21027
- if (existsSync7(path21.join(cwd, "Cargo.toml")) || existsSync7(path21.join(cwd, "src-tauri/Cargo.toml"))) {
21106
+ if (existsSync7(path22.join(cwd, "Cargo.toml")) || existsSync7(path22.join(cwd, "src-tauri/Cargo.toml"))) {
21028
21107
  stdout += `Rust project detected.
21029
21108
  `;
21030
21109
  }
@@ -21057,7 +21136,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
21057
21136
  - Apply with the host-native editor, preserving the repository changelog conventions.
21058
21137
  - If Unreleased already has duplicate category headings, normalize_only first.`;
21059
21138
  function changelogContext(root, range) {
21060
- const cwd = path21.resolve(repoRoot(root));
21139
+ const cwd = path22.resolve(repoRoot(root));
21061
21140
  if (range !== undefined && !isResolvableContextRange(cwd, range))
21062
21141
  return invalidRange(cwd);
21063
21142
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -21075,7 +21154,7 @@ function changelogContext(root, range) {
21075
21154
  stdout += CHANGELOG_RULES + `
21076
21155
  `;
21077
21156
  stdout += printSection("Existing CHANGELOG.md");
21078
- const changelogPath = path21.join(cwd, "CHANGELOG.md");
21157
+ const changelogPath = path22.join(cwd, "CHANGELOG.md");
21079
21158
  if (existsSync7(changelogPath)) {
21080
21159
  stdout += readTrimmed2(changelogPath, 260) + `
21081
21160
  `;
@@ -21095,7 +21174,7 @@ function changelogContext(root, range) {
21095
21174
  return { stdout, stderr: "", exitCode: 0, cwd };
21096
21175
  }
21097
21176
  function docsRefreshContext(root, range) {
21098
- const cwd = path21.resolve(repoRoot(root));
21177
+ const cwd = path22.resolve(repoRoot(root));
21099
21178
  if (range !== undefined && !isResolvableContextRange(cwd, range))
21100
21179
  return invalidRange(cwd);
21101
21180
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -21117,7 +21196,7 @@ function docsRefreshContext(root, range) {
21117
21196
  `) + `
21118
21197
  `;
21119
21198
  stdout += printSection("README Preview");
21120
- const readme = path21.join(cwd, "README.md");
21199
+ const readme = path22.join(cwd, "README.md");
21121
21200
  if (existsSync7(readme)) {
21122
21201
  stdout += readTrimmed2(readme, 220) + `
21123
21202
  `;
@@ -21126,7 +21205,7 @@ function docsRefreshContext(root, range) {
21126
21205
  `;
21127
21206
  }
21128
21207
  stdout += printSection("Package Scripts");
21129
- const pkgPath = path21.join(cwd, "package.json");
21208
+ const pkgPath = path22.join(cwd, "package.json");
21130
21209
  if (existsSync7(pkgPath)) {
21131
21210
  try {
21132
21211
  const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
@@ -21140,7 +21219,7 @@ function docsRefreshContext(root, range) {
21140
21219
  return { stdout, stderr: "", exitCode: 0, cwd };
21141
21220
  }
21142
21221
  function releaseNotesContext(root, rangeOrTag) {
21143
- const cwd = path21.resolve(repoRoot(root));
21222
+ const cwd = path22.resolve(repoRoot(root));
21144
21223
  if (!rangeOrTag) {
21145
21224
  return { stdout: "", stderr: `ERROR: release tag or range required
21146
21225
  `, exitCode: 1, cwd };
@@ -21178,7 +21257,7 @@ function releaseNotesContext(root, rangeOrTag) {
21178
21257
  `;
21179
21258
  stdout += printSection("Existing Release Files");
21180
21259
  for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
21181
- if (existsSync7(path21.join(cwd, rel)))
21260
+ if (existsSync7(path22.join(cwd, rel)))
21182
21261
  stdout += rel + `
21183
21262
  `;
21184
21263
  }
@@ -21209,8 +21288,8 @@ function releaseNotesContext(root, rangeOrTag) {
21209
21288
  import { spawnSync as spawnSync15 } from "node:child_process";
21210
21289
 
21211
21290
  // packages/workit-core/src/core/pr-create.ts
21212
- import fs16 from "node:fs";
21213
- import path22 from "node:path";
21291
+ import fs17 from "node:fs";
21292
+ import path23 from "node:path";
21214
21293
  import { spawnSync as spawnSync14 } from "node:child_process";
21215
21294
  // packages/workit-core/src/forge/pr-body.ts
21216
21295
  function parseGhIssue(value) {
@@ -21221,13 +21300,13 @@ function parseGhIssue(value) {
21221
21300
  // packages/workit-core/src/core/pr-create.ts
21222
21301
  function whichOnPath(tool) {
21223
21302
  const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
21224
- for (const dir of (process.env.PATH ?? "").split(path22.delimiter)) {
21303
+ for (const dir of (process.env.PATH ?? "").split(path23.delimiter)) {
21225
21304
  if (!dir)
21226
21305
  continue;
21227
21306
  for (const name of names) {
21228
- const candidate = path22.join(dir, name);
21307
+ const candidate = path23.join(dir, name);
21229
21308
  try {
21230
- fs16.accessSync(candidate, fs16.constants.X_OK);
21309
+ fs17.accessSync(candidate, fs17.constants.X_OK);
21231
21310
  return candidate;
21232
21311
  } catch {}
21233
21312
  }
@@ -21345,8 +21424,8 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
21345
21424
  };
21346
21425
 
21347
21426
  // packages/workit-core/src/core/youtrack.ts
21348
- import fs17 from "node:fs";
21349
- import path23 from "node:path";
21427
+ import fs18 from "node:fs";
21428
+ import path24 from "node:path";
21350
21429
 
21351
21430
  // packages/workit-core/src/core/templates.ts
21352
21431
  var repoRoot2 = assetRoot();
@@ -21359,22 +21438,22 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
21359
21438
  // packages/workit-core/src/core/youtrack.ts
21360
21439
  var ISSUE_RE = /^[A-Z]+-\d+$/;
21361
21440
  var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
21362
- var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path23.join(configDir(), "youtrack.json");
21363
- var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path23.join(resolveConfigDir(), "youtrack.json");
21441
+ var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path24.join(configDir(), "youtrack.json");
21442
+ var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path24.join(resolveConfigDir(), "youtrack.json");
21364
21443
  var youTrackTokenModeOk = (p) => {
21365
21444
  if (process.platform === "win32")
21366
21445
  return true;
21367
- const mode = fs17.statSync(p).mode & 511;
21446
+ const mode = fs18.statSync(p).mode & 511;
21368
21447
  return mode === 384;
21369
21448
  };
21370
21449
  function readYouTrackConfig(required) {
21371
21450
  const cfgPath = youTrackConfigPath();
21372
- if (!fs17.existsSync(cfgPath)) {
21451
+ if (!fs18.existsSync(cfgPath)) {
21373
21452
  return required ? { error: "ERROR: missing youtrack.json", path: cfgPath } : { config: {}, path: cfgPath };
21374
21453
  }
21375
21454
  let parsed;
21376
21455
  try {
21377
- parsed = JSON.parse(fs17.readFileSync(cfgPath, "utf8"));
21456
+ parsed = JSON.parse(fs18.readFileSync(cfgPath, "utf8"));
21378
21457
  } catch {
21379
21458
  return { error: `${cfgPath} is not valid JSON`, path: cfgPath };
21380
21459
  }
@@ -21385,11 +21464,11 @@ function readYouTrackConfig(required) {
21385
21464
  }
21386
21465
  var readYouTrackContextConfig = () => {
21387
21466
  const cfgPath = youTrackReadOnlyConfigPath();
21388
- if (!fs17.existsSync(cfgPath))
21467
+ if (!fs18.existsSync(cfgPath))
21389
21468
  return { data: {} };
21390
21469
  let parsed;
21391
21470
  try {
21392
- parsed = JSON.parse(fs17.readFileSync(cfgPath, "utf8"));
21471
+ parsed = JSON.parse(fs18.readFileSync(cfgPath, "utf8"));
21393
21472
  } catch {
21394
21473
  return { error: "YouTrack configuration is unavailable" };
21395
21474
  }
@@ -21428,12 +21507,12 @@ var youTrackToken = () => {
21428
21507
  if ("error" in loaded)
21429
21508
  return loaded;
21430
21509
  const tokenFile = String(loaded.config.tokenFile ?? "");
21431
- const tokenPath = tokenFile ? path23.isAbsolute(tokenFile) ? path23.resolve(tokenFile) : path23.resolve(process.cwd(), tokenFile) : "";
21432
- if (!tokenPath || !fs17.existsSync(tokenPath))
21510
+ const tokenPath = tokenFile ? path24.isAbsolute(tokenFile) ? path24.resolve(tokenFile) : path24.resolve(process.cwd(), tokenFile) : "";
21511
+ if (!tokenPath || !fs18.existsSync(tokenPath))
21433
21512
  return { error: "missing youtrack.token" };
21434
21513
  if (!youTrackTokenModeOk(tokenPath))
21435
21514
  return { error: "youtrack.token mode must be 0600" };
21436
- const token = fs17.readFileSync(tokenPath, "utf8").trim();
21515
+ const token = fs18.readFileSync(tokenPath, "utf8").trim();
21437
21516
  if (!token)
21438
21517
  return { error: "empty token file" };
21439
21518
  if (token === TOKEN_PLACEHOLDER || token.startsWith(TOKEN_PLACEHOLDER)) {
@@ -21498,9 +21577,9 @@ function resolveYouTrackFromPaths(spec_path, plan_path, workspace_root) {
21498
21577
  } catch {
21499
21578
  continue;
21500
21579
  }
21501
- if (!fs17.existsSync(full))
21580
+ if (!fs18.existsSync(full))
21502
21581
  continue;
21503
- const text = fs17.readFileSync(full, "utf8");
21582
+ const text = fs18.readFileSync(full, "utf8");
21504
21583
  const m = text.match(/^\*\*YouTrack:\*\*\s*`?([A-Z]+-\d+)`?/m);
21505
21584
  if (m)
21506
21585
  return m[1];
@@ -21785,15 +21864,15 @@ function resolveGitRevision(root, value) {
21785
21864
  }
21786
21865
  function resolveInside(root, candidate) {
21787
21866
  const base = realpathSync5(root);
21788
- const target = path24.resolve(base, candidate);
21789
- if (target !== base && !target.startsWith(base + path24.sep)) {
21867
+ const target = path25.resolve(base, candidate);
21868
+ if (target !== base && !target.startsWith(base + path25.sep)) {
21790
21869
  throw new Error("path must stay inside repository root");
21791
21870
  }
21792
21871
  let ancestor = target;
21793
21872
  while (!existsSync8(ancestor))
21794
- ancestor = path24.dirname(ancestor);
21873
+ ancestor = path25.dirname(ancestor);
21795
21874
  const canonicalAncestor = realpathSync5(ancestor);
21796
- if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path24.sep)) {
21875
+ if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path25.sep)) {
21797
21876
  throw new Error("path must stay inside repository root");
21798
21877
  }
21799
21878
  return target;
@@ -21837,9 +21916,9 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
21837
21916
  };
21838
21917
  });
21839
21918
  // packages/workit-core/src/hooks/context.ts
21840
- import { createHash as createHash14 } from "node:crypto";
21841
- import fs18 from "node:fs";
21842
- import path25 from "node:path";
21919
+ import { createHash as createHash15 } from "node:crypto";
21920
+ import fs19 from "node:fs";
21921
+ import path26 from "node:path";
21843
21922
  var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
21844
21923
  var migrationPending = (result) => !result.ok && result.code === "needs_input" && (result.error ?? "").startsWith(MIGRATION_PENDING);
21845
21924
  var boundTo = (entry, session) => entry.sessions.some((item) => item.host === session.host && item.handle === session.handle);
@@ -21924,7 +22003,7 @@ function entryCompactContext(store, entry, session, context) {
21924
22003
  return null;
21925
22004
  const freshness = { mode: "signal", current: () => recentSignal(store.root) };
21926
22005
  const observed = task?.data.evidence.some(isObservedCheck) ?? false;
21927
- const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path25.resolve(store.root, ref.path)] : []));
22006
+ const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path26.resolve(store.root, ref.path)] : []));
21928
22007
  const observedFiles = filesKey(files);
21929
22008
  const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
21930
22009
  if (!compact.ok || !compact.data)
@@ -21993,7 +22072,7 @@ var turnContextText = (input, descriptor) => {
21993
22072
  }
21994
22073
  };
21995
22074
  var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
21996
- var digestOf = (text) => createHash14("sha256").update(text).digest("hex");
22075
+ var digestOf = (text) => createHash15("sha256").update(text).digest("hex");
21997
22076
  var turnMarker = (input) => {
21998
22077
  if (!input.session.id)
21999
22078
  return null;
@@ -22002,32 +22081,32 @@ var turnMarker = (input) => {
22002
22081
  if (location instanceof Error)
22003
22082
  return null;
22004
22083
  const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
22005
- return path25.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
22084
+ return path26.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
22006
22085
  } catch {
22007
22086
  return null;
22008
22087
  }
22009
22088
  };
22010
22089
  var writeTurnDigest = (file, digest) => {
22011
22090
  try {
22012
- fs18.mkdirSync(path25.dirname(file), { recursive: true });
22013
- fs18.writeFileSync(file, `${JSON.stringify({ digest })}
22091
+ fs19.mkdirSync(path26.dirname(file), { recursive: true });
22092
+ fs19.writeFileSync(file, `${JSON.stringify({ digest })}
22014
22093
  `);
22015
22094
  } catch {}
22016
22095
  };
22017
22096
  var clearTurnDigest = (file) => {
22018
22097
  try {
22019
- fs18.rmSync(file, { force: true });
22098
+ fs19.rmSync(file, { force: true });
22020
22099
  } catch {}
22021
22100
  };
22022
22101
  var pruneTurnDigests = (dir, now) => {
22023
22102
  try {
22024
- for (const name of fs18.readdirSync(dir)) {
22103
+ for (const name of fs19.readdirSync(dir)) {
22025
22104
  if (!name.startsWith("turn-"))
22026
22105
  continue;
22027
- const file = path25.join(dir, name);
22106
+ const file = path26.join(dir, name);
22028
22107
  try {
22029
- if (now - fs18.statSync(file).mtimeMs > TURN_TTL_MS)
22030
- fs18.rmSync(file, { force: true });
22108
+ if (now - fs19.statSync(file).mtimeMs > TURN_TTL_MS)
22109
+ fs19.rmSync(file, { force: true });
22031
22110
  } catch {}
22032
22111
  }
22033
22112
  } catch {}
@@ -22043,7 +22122,7 @@ var changedTurnContext = (input, text) => {
22043
22122
  return text;
22044
22123
  const digest = digestOf(text);
22045
22124
  try {
22046
- const previous = JSON.parse(fs18.readFileSync(file, "utf8"));
22125
+ const previous = JSON.parse(fs19.readFileSync(file, "utf8"));
22047
22126
  if (previous.digest === digest)
22048
22127
  return null;
22049
22128
  } catch {}
@@ -22054,7 +22133,7 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
22054
22133
  const file = turnMarker(input);
22055
22134
  if (!file)
22056
22135
  return;
22057
- pruneTurnDigests(path25.dirname(file), Date.now());
22136
+ pruneTurnDigests(path26.dirname(file), Date.now());
22058
22137
  if (text)
22059
22138
  writeTurnDigest(file, digestOf(text));
22060
22139
  else
@@ -22073,13 +22152,13 @@ var shellPolicy = (cwd, command, dialect = "posix") => {
22073
22152
  return policy && !policy.ok ? { kind: "deny", reason: `branch_policy_denied: ${policy.error}`, unblock: null } : { kind: "none" };
22074
22153
  };
22075
22154
  // packages/workit-core/src/core/heavy-rules.ts
22076
- import fs19 from "node:fs";
22155
+ import fs20 from "node:fs";
22077
22156
  import os6 from "node:os";
22078
- import path26 from "node:path";
22157
+ import path27 from "node:path";
22079
22158
  var EMPTY = () => ({ deny: [], allow: [] });
22080
22159
  var readText2 = (file) => {
22081
22160
  try {
22082
- return fs19.readFileSync(file, "utf8");
22161
+ return fs20.readFileSync(file, "utf8");
22083
22162
  } catch (error) {
22084
22163
  if (error.code === "ENOENT")
22085
22164
  return null;
@@ -22116,19 +22195,19 @@ function parseJsonc(text) {
22116
22195
  return JSON.parse(out.replace(/,(\s*[}\]])/gu, "$1"));
22117
22196
  }
22118
22197
  function gitTop(cwd) {
22119
- for (let dir = path26.resolve(cwd);; dir = path26.dirname(dir)) {
22120
- if (fs19.existsSync(path26.join(dir, ".git")))
22198
+ for (let dir = path27.resolve(cwd);; dir = path27.dirname(dir)) {
22199
+ if (fs20.existsSync(path27.join(dir, ".git")))
22121
22200
  return dir;
22122
- if (path26.dirname(dir) === dir)
22201
+ if (path27.dirname(dir) === dir)
22123
22202
  return null;
22124
22203
  }
22125
22204
  }
22126
22205
  var projectDirs = (cwd) => {
22127
22206
  const top = gitTop(cwd);
22128
22207
  const dirs = [];
22129
- for (let dir = path26.resolve(cwd);; dir = path26.dirname(dir)) {
22208
+ for (let dir = path27.resolve(cwd);; dir = path27.dirname(dir)) {
22130
22209
  dirs.push(dir);
22131
- if (!top || dir === top || path26.dirname(dir) === dir)
22210
+ if (!top || dir === top || path27.dirname(dir) === dir)
22132
22211
  return dirs;
22133
22212
  }
22134
22213
  };
@@ -22140,12 +22219,12 @@ var CLAUDE_MANAGED = {
22140
22219
  };
22141
22220
  function claudeSettingsFiles(cwd, env, platform = process.platform) {
22142
22221
  const project = env.CLAUDE_PROJECT_DIR || gitTop(cwd) || cwd;
22143
- const user = env.CLAUDE_CONFIG_DIR || path26.join(homeOf(env), ".claude");
22222
+ const user = env.CLAUDE_CONFIG_DIR || path27.join(homeOf(env), ".claude");
22144
22223
  return [
22145
22224
  ...CLAUDE_MANAGED[platform] ? [CLAUDE_MANAGED[platform]] : [],
22146
- path26.join(user, "settings.json"),
22147
- path26.join(project, ".claude", "settings.json"),
22148
- path26.join(project, ".claude", "settings.local.json")
22225
+ path27.join(user, "settings.json"),
22226
+ path27.join(project, ".claude", "settings.json"),
22227
+ path27.join(project, ".claude", "settings.local.json")
22149
22228
  ];
22150
22229
  }
22151
22230
  var bashPattern = (entry) => {
@@ -22235,10 +22314,10 @@ var opencodeConfig = (value, rules) => {
22235
22314
  function opencodeRules(cwd, env = process.env) {
22236
22315
  const rules = EMPTY();
22237
22316
  try {
22238
- const config = env.XDG_CONFIG_HOME || path26.join(homeOf(env), ".config");
22317
+ const config = env.XDG_CONFIG_HOME || path27.join(homeOf(env), ".config");
22239
22318
  const files = [
22240
- ...OPENCODE_NAMES.map((name) => path26.join(config, "opencode", name)),
22241
- ...projectDirs(cwd).flatMap((dir) => OPENCODE_NAMES.flatMap((name) => [path26.join(dir, name), path26.join(dir, ".opencode", name)])),
22319
+ ...OPENCODE_NAMES.map((name) => path27.join(config, "opencode", name)),
22320
+ ...projectDirs(cwd).flatMap((dir) => OPENCODE_NAMES.flatMap((name) => [path27.join(dir, name), path27.join(dir, ".opencode", name)])),
22242
22321
  ...env.OPENCODE_CONFIG ? [env.OPENCODE_CONFIG] : []
22243
22322
  ];
22244
22323
  for (const file of files) {
@@ -22282,19 +22361,19 @@ var codexRule = (body) => {
22282
22361
  function codexRules(cwd, env = process.env) {
22283
22362
  const rules = EMPTY();
22284
22363
  try {
22285
- const home = env.CODEX_HOME || path26.join(homeOf(env), ".codex");
22364
+ const home = env.CODEX_HOME || path27.join(homeOf(env), ".codex");
22286
22365
  const top = gitTop(cwd) ?? cwd;
22287
- for (const dir of [path26.join(home, "rules"), path26.join(top, ".codex", "rules")]) {
22366
+ for (const dir of [path27.join(home, "rules"), path27.join(top, ".codex", "rules")]) {
22288
22367
  let files;
22289
22368
  try {
22290
- files = fs19.readdirSync(dir).filter((name) => name.endsWith(".rules"));
22369
+ files = fs20.readdirSync(dir).filter((name) => name.endsWith(".rules"));
22291
22370
  } catch (error) {
22292
22371
  if (error.code === "ENOENT")
22293
22372
  continue;
22294
22373
  return "unreadable";
22295
22374
  }
22296
22375
  for (const name of files) {
22297
- const text = readText2(path26.join(dir, name)) ?? "";
22376
+ const text = readText2(path27.join(dir, name)) ?? "";
22298
22377
  for (const part of text.split(/\bprefix_rule\s*\(/u).slice(1)) {
22299
22378
  const rule = codexRule(part);
22300
22379
  if (!rule)
@@ -22313,8 +22392,8 @@ function cursorRules(cwd, env = process.env) {
22313
22392
  try {
22314
22393
  const top = gitTop(cwd) ?? cwd;
22315
22394
  for (const file of [
22316
- path26.join(homeOf(env), ".cursor", "cli-config.json"),
22317
- path26.join(top, ".cursor", "cli.json")
22395
+ path27.join(homeOf(env), ".cursor", "cli-config.json"),
22396
+ path27.join(top, ".cursor", "cli.json")
22318
22397
  ]) {
22319
22398
  const text = readText2(file);
22320
22399
  if (text === null)
@@ -22388,23 +22467,23 @@ function wrapAllowed(read, words, command, options = {}) {
22388
22467
  }
22389
22468
 
22390
22469
  // packages/workit-core/src/core/heavy.ts
22391
- import fs20 from "node:fs";
22470
+ import fs21 from "node:fs";
22392
22471
  import os7 from "node:os";
22393
- import path27 from "node:path";
22472
+ import path28 from "node:path";
22394
22473
  function stateDir(env, platform = process.platform) {
22395
22474
  if (env.WORKFLOW_TOOLKIT_STATE)
22396
22475
  return env.WORKFLOW_TOOLKIT_STATE;
22397
22476
  if (env.XDG_STATE_HOME)
22398
- return path27.join(env.XDG_STATE_HOME, "workit");
22477
+ return path28.join(env.XDG_STATE_HOME, "workit");
22399
22478
  const home = env.HOME || os7.homedir();
22400
22479
  if (platform === "darwin")
22401
- return path27.join(home, "Library", "Application Support", "workit");
22480
+ return path28.join(home, "Library", "Application Support", "workit");
22402
22481
  if (platform === "win32")
22403
- return path27.join(env.LOCALAPPDATA ?? path27.join(home, "AppData", "Local"), "workit");
22404
- return path27.join(home, ".local", "state", "workit");
22482
+ return path28.join(env.LOCALAPPDATA ?? path28.join(home, "AppData", "Local"), "workit");
22483
+ return path28.join(home, ".local", "state", "workit");
22405
22484
  }
22406
22485
  var HEAVY_COMMANDS_FILE = "heavy-commands.json";
22407
- var heavyCommandsFile = (env) => path27.join(stateDir(env), HEAVY_COMMANDS_FILE);
22486
+ var heavyCommandsFile = (env) => path28.join(stateDir(env), HEAVY_COMMANDS_FILE);
22408
22487
  var HEAVY_SCRIPT = /^(?:test|tests|t|tst|unit|integration|e2e|coverage|cov|lint|eslint|typecheck|type-check|types|tsc|check|verify|validate|build|compile|bundle|ci|sonar|cypress|playwright|jest|vitest|mocha|bench|benchmark|all)(?:$|[:_.-])/iu;
22409
22488
  var INFO_FLAGS = new Set(["--version", "-v", "-V", "--help", "-h", "help", "version"]);
22410
22489
  var WATCH_FLAG = /^(?:--watch(?:All)?(?:=.*)?|-w|--serve)$/u;
@@ -22667,7 +22746,7 @@ function parsePattern(pattern) {
22667
22746
  var matches = (matchers, words) => matchers.length <= words.length && matchers.every((matcher, index) => index === 0 ? matcher.test(words[0]) || matcher.test(baseName2(words[0])) : matcher.test(words[index]));
22668
22747
  var readJson = (file) => {
22669
22748
  try {
22670
- return JSON.parse(fs20.readFileSync(file, "utf8"));
22749
+ return JSON.parse(fs21.readFileSync(file, "utf8"));
22671
22750
  } catch {
22672
22751
  return;
22673
22752
  }
@@ -22679,7 +22758,7 @@ function machinePatterns(env) {
22679
22758
  return isRecord5(value) ? stringList(value.patterns) : [];
22680
22759
  }
22681
22760
  function repoPatterns(cwd) {
22682
- return repoHeavyCommands(gitTop(cwd) ?? path27.resolve(cwd));
22761
+ return repoHeavyCommands(gitTop(cwd) ?? path28.resolve(cwd));
22683
22762
  }
22684
22763
  function heavyLines(lines, options) {
22685
22764
  const found = [];
@@ -22757,12 +22836,12 @@ function heavyPlan(command, options) {
22757
22836
  }
22758
22837
  function workitOnPath2(env = process.env) {
22759
22838
  const names = process.platform === "win32" ? ["workit.exe", "workit.cmd", "workit"] : ["workit"];
22760
- for (const dir of (env.PATH ?? "").split(path27.delimiter))
22839
+ for (const dir of (env.PATH ?? "").split(path28.delimiter))
22761
22840
  for (const name of names) {
22762
22841
  if (!dir)
22763
22842
  continue;
22764
22843
  try {
22765
- fs20.accessSync(path27.join(dir, name), fs20.constants.X_OK);
22844
+ fs21.accessSync(path28.join(dir, name), fs21.constants.X_OK);
22766
22845
  return true;
22767
22846
  } catch {}
22768
22847
  }
@@ -22779,41 +22858,41 @@ function leaseRewrite(command) {
22779
22858
  }
22780
22859
 
22781
22860
  // packages/workit-core/src/core/heavy-words.ts
22782
- import fs21 from "node:fs";
22861
+ import fs22 from "node:fs";
22783
22862
  import os8 from "node:os";
22784
- import path28 from "node:path";
22863
+ import path29 from "node:path";
22785
22864
  var HEAVY_WORDS = new Set(("npm npx pnpm pnpx yarn bun bunx deno corepack make gmake docker podman nerdctl " + "python python3 py uv poetry pdm pipenv hatch rye bundle rake nx " + "jest vitest mocha ava tap karma jasmine nyc c8 tsc vue-tsc svelte-check eslint stylelint " + "tslint webpack webpack-cli rollup parcel tsup vite next nuxt nuxi astro ng react-scripts " + "playwright cypress wdio testcafe turbo lerna sonar-scanner sonarless sonarless-mcp go " + "golangci-lint gotestsum staticcheck cargo mvn mvnw gradle gradlew ant sbt bazel bazelisk " + "buck2 dotnet msbuild pytest py.test tox nox mypy pyright pylint coverage maturin pip pip3 " + "rspec rails phpunit pest phpstan psalm composer mix swift xcodebuild flutter dart pod cmake " + "ninja meson ctest scons docker-compose buildah earthly").split(" "));
22786
22865
  var wordsOf = (command) => command.split(/[\s;&|()<>`'"]+/u).map((word) => (word.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat)$/u, "")).filter(Boolean);
22787
22866
  var stateDir2 = (env) => {
22788
22867
  if (env.WORKFLOW_TOOLKIT_STATE)
22789
22868
  return env.WORKFLOW_TOOLKIT_STATE;
22790
22869
  if (env.XDG_STATE_HOME)
22791
- return path28.join(env.XDG_STATE_HOME, "workit");
22870
+ return path29.join(env.XDG_STATE_HOME, "workit");
22792
22871
  const home = env.HOME || os8.homedir();
22793
22872
  if (process.platform === "darwin")
22794
- return path28.join(home, "Library", "Application Support", "workit");
22873
+ return path29.join(home, "Library", "Application Support", "workit");
22795
22874
  if (process.platform === "win32")
22796
- return path28.join(env.LOCALAPPDATA ?? path28.join(home, "AppData", "Local"), "workit");
22797
- return path28.join(home, ".local", "state", "workit");
22875
+ return path29.join(env.LOCALAPPDATA ?? path29.join(home, "AppData", "Local"), "workit");
22876
+ return path29.join(home, ".local", "state", "workit");
22798
22877
  };
22799
22878
  var readJson2 = (file) => {
22800
22879
  try {
22801
- return JSON.parse(fs21.readFileSync(file, "utf8"));
22880
+ return JSON.parse(fs22.readFileSync(file, "utf8"));
22802
22881
  } catch {
22803
22882
  return;
22804
22883
  }
22805
22884
  };
22806
22885
  var patternWords = (cwd, env) => {
22807
22886
  const patterns = [];
22808
- const machine = readJson2(path28.join(stateDir2(env), "heavy-commands.json"));
22887
+ const machine = readJson2(path29.join(stateDir2(env), "heavy-commands.json"));
22809
22888
  if (Array.isArray(machine?.patterns))
22810
22889
  patterns.push(...machine.patterns);
22811
- for (let dir = path28.resolve(cwd);; dir = path28.dirname(dir)) {
22812
- if (fs21.existsSync(path28.join(dir, ".git"))) {
22890
+ for (let dir = path29.resolve(cwd);; dir = path29.dirname(dir)) {
22891
+ if (fs22.existsSync(path29.join(dir, ".git"))) {
22813
22892
  patterns.push(...repoHeavyCommands(dir));
22814
22893
  break;
22815
22894
  }
22816
- if (path28.dirname(dir) === dir)
22895
+ if (path29.dirname(dir) === dir)
22817
22896
  break;
22818
22897
  }
22819
22898
  const words = new Set;
@@ -22885,14 +22964,14 @@ var splitDenial = (plan) => ({
22885
22964
  // packages/workit-core/src/hooks/write-gate.ts
22886
22965
  import { realpathSync as realpathSync6 } from "node:fs";
22887
22966
  import os10 from "node:os";
22888
- import path30 from "node:path";
22967
+ import path31 from "node:path";
22889
22968
 
22890
22969
  // packages/workit-core/src/core/live-session.ts
22891
22970
  import { spawnSync as spawnSync17 } from "node:child_process";
22892
- import { createHash as createHash15 } from "node:crypto";
22893
- import fs22 from "node:fs";
22971
+ import { createHash as createHash16 } from "node:crypto";
22972
+ import fs23 from "node:fs";
22894
22973
  import os9 from "node:os";
22895
- import path29 from "node:path";
22974
+ import path30 from "node:path";
22896
22975
  var LIVE_SESSION_TTL_MS = 15 * 60000;
22897
22976
  var HEARTBEAT_EVERY_MS = 30000;
22898
22977
  var liveProbe = {
@@ -22913,9 +22992,9 @@ var processAlive = (pid) => {
22913
22992
  var processInfo = (pid) => {
22914
22993
  try {
22915
22994
  if (liveProbe.platform === "linux") {
22916
- const stat = fs22.readFileSync(`/proc/${pid}/stat`, "utf8");
22995
+ const stat = fs23.readFileSync(`/proc/${pid}/stat`, "utf8");
22917
22996
  const ppid = Number(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[1]);
22918
- const command = fs22.readFileSync(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ");
22997
+ const command = fs23.readFileSync(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ");
22919
22998
  return Number.isInteger(ppid) ? { ppid, command: command.trim() } : null;
22920
22999
  }
22921
23000
  if (liveProbe.platform === "win32")
@@ -22966,35 +23045,35 @@ var liveOwner = (input, transport, env = process.env) => {
22966
23045
  };
22967
23046
  };
22968
23047
  var checkoutOf = (target) => {
22969
- let dir = path29.resolve(target);
22970
- while (!fs22.existsSync(dir) && path29.dirname(dir) !== dir)
22971
- dir = path29.dirname(dir);
22972
- if (fs22.existsSync(dir) && !fs22.statSync(dir).isDirectory())
22973
- dir = path29.dirname(dir);
22974
- const parts = dir.split(path29.sep);
23048
+ let dir = path30.resolve(target);
23049
+ while (!fs23.existsSync(dir) && path30.dirname(dir) !== dir)
23050
+ dir = path30.dirname(dir);
23051
+ if (fs23.existsSync(dir) && !fs23.statSync(dir).isDirectory())
23052
+ dir = path30.dirname(dir);
23053
+ const parts = dir.split(path30.sep);
22975
23054
  const dotGit = parts.lastIndexOf(".git");
22976
23055
  if (dotGit > 0)
22977
- dir = parts.slice(0, dotGit).join(path29.sep) || path29.sep;
23056
+ dir = parts.slice(0, dotGit).join(path30.sep) || path30.sep;
22978
23057
  const location = resolveStore(dir);
22979
23058
  if (location instanceof Error || !location.shared || !location.top)
22980
23059
  return null;
22981
23060
  let top = location.top;
22982
23061
  try {
22983
- top = fs22.realpathSync.native(top);
23062
+ top = fs23.realpathSync.native(top);
22984
23063
  } catch {}
22985
23064
  return top;
22986
23065
  };
22987
- var markerFile2 = (top) => path29.join(resolveStateDir(), "live-sessions", `${createHash15("sha256").update(checkoutKey(top)).digest("hex").slice(0, 32)}.json`);
23066
+ var markerFile2 = (top) => path30.join(resolveStateDir(), "live-sessions", `${createHash16("sha256").update(checkoutKey(top)).digest("hex").slice(0, 32)}.json`);
22988
23067
  var checkoutKey = (top, platform = process.platform) => {
22989
- let key = path29.resolve(top);
23068
+ let key = path30.resolve(top);
22990
23069
  try {
22991
- key = fs22.realpathSync.native(key);
23070
+ key = fs23.realpathSync.native(key);
22992
23071
  } catch {}
22993
23072
  return platform === "win32" ? key.replaceAll("/", "\\").toLowerCase() : key;
22994
23073
  };
22995
23074
  var readMarker = (file) => {
22996
23075
  try {
22997
- const value = JSON.parse(fs22.readFileSync(file, "utf8"));
23076
+ const value = JSON.parse(fs23.readFileSync(file, "utf8"));
22998
23077
  if (value?.version !== 1 || typeof value.session !== "string" || typeof value.host !== "string" || typeof value.heartbeatAt !== "string" || Number.isNaN(Date.parse(value.heartbeatAt)))
22999
23078
  return null;
23000
23079
  return {
@@ -23081,10 +23160,10 @@ var claimLiveSession = (target, owner, deps = {}) => {
23081
23160
  checkout,
23082
23161
  heartbeatAt: now.toISOString()
23083
23162
  };
23084
- fs22.mkdirSync(path29.dirname(file), { recursive: true });
23163
+ fs23.mkdirSync(path30.dirname(file), { recursive: true });
23085
23164
  const temp = `${file}.${process.pid}.tmp`;
23086
- fs22.writeFileSync(temp, JSON.stringify(marker));
23087
- fs22.renameSync(temp, file);
23165
+ fs23.writeFileSync(temp, JSON.stringify(marker));
23166
+ fs23.renameSync(temp, file);
23088
23167
  } catch {}
23089
23168
  };
23090
23169
 
@@ -23093,22 +23172,22 @@ var NONE3 = { kind: "none" };
23093
23172
  var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
23094
23173
  var canonical2 = (file) => {
23095
23174
  let rest = "";
23096
- for (let dir = path30.resolve(file);; dir = path30.dirname(dir)) {
23175
+ for (let dir = path31.resolve(file);; dir = path31.dirname(dir)) {
23097
23176
  try {
23098
- return path30.join(realpathSync6.native(dir), rest);
23177
+ return path31.join(realpathSync6.native(dir), rest);
23099
23178
  } catch {
23100
- if (path30.dirname(dir) === dir)
23101
- return path30.resolve(file);
23102
- rest = rest ? path30.join(path30.basename(dir), rest) : path30.basename(dir);
23179
+ if (path31.dirname(dir) === dir)
23180
+ return path31.resolve(file);
23181
+ rest = rest ? path31.join(path31.basename(dir), rest) : path31.basename(dir);
23103
23182
  }
23104
23183
  }
23105
23184
  };
23106
23185
  var exempt = (cwd, root, file, plans) => {
23107
23186
  const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
23108
- const relative = path30.relative(fold(canonical2(root)), fold(canonical2(path30.resolve(cwd, file))));
23109
- if (relative.startsWith("..") || path30.isAbsolute(relative))
23187
+ const relative = path31.relative(fold(canonical2(root)), fold(canonical2(path31.resolve(cwd, file))));
23188
+ if (relative.startsWith("..") || path31.isAbsolute(relative))
23110
23189
  return true;
23111
- const posix = relative.split(path30.sep).join("/");
23190
+ const posix = relative.split(path31.sep).join("/");
23112
23191
  const segments = posix.split("/");
23113
23192
  return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
23114
23193
  };
@@ -23229,7 +23308,7 @@ var shellWrites = (command, depth = 0) => {
23229
23308
  return { writes: true, targets: unknown ? null : targets };
23230
23309
  };
23231
23310
  var cache2 = new Map;
23232
- var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path30.resolve(root, file)) ?? "-").join("\x00");
23311
+ var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path31.resolve(root, file)) ?? "-").join("\x00");
23233
23312
  var gateFor = (cwd) => {
23234
23313
  const store = new TaskStore(cwd);
23235
23314
  const listed = store.listTaskIndex();
@@ -23308,7 +23387,7 @@ var gitMutationDirs = (cwd, command, dialect) => {
23308
23387
  return [];
23309
23388
  if (sub === "stash" && ["list", "show"].includes(rest[0] ?? ""))
23310
23389
  return [];
23311
- return [path30.resolve(cwd, invocation.dir ?? ".")];
23390
+ return [path31.resolve(cwd, invocation.dir ?? ".")];
23312
23391
  });
23313
23392
  };
23314
23393
  var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
@@ -23319,7 +23398,7 @@ var cdInto = (dir, words) => {
23319
23398
  const target = named === undefined ? undefined : homeExpanded(named);
23320
23399
  if (dir === undefined || target === "-" || target && /^~|[$`*?]/.test(target))
23321
23400
  return;
23322
- return target === undefined ? os10.homedir() : path30.resolve(dir, target);
23401
+ return target === undefined ? os10.homedir() : path31.resolve(dir, target);
23323
23402
  };
23324
23403
  var quoteWord2 = (word) => /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`;
23325
23404
  var homeExpanded = (file) => {
@@ -23333,7 +23412,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0) => {
23333
23412
  const groups = [];
23334
23413
  const at = (file) => {
23335
23414
  const home = homeExpanded(file);
23336
- return path30.isAbsolute(home) ? home : dir === undefined ? null : path30.resolve(dir, home);
23415
+ return path31.isAbsolute(home) ? home : dir === undefined ? null : path31.resolve(dir, home);
23337
23416
  };
23338
23417
  for (const segment of segmentsOf(command, dialect)) {
23339
23418
  if (segment.group === "open") {
@@ -23374,7 +23453,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0) => {
23374
23453
  const edits = editsOf(segment.words);
23375
23454
  if (edits === null) {
23376
23455
  if (dir !== undefined)
23377
- targets.push(path30.join(dir, DIR_TARGET));
23456
+ targets.push(path31.join(dir, DIR_TARGET));
23378
23457
  } else
23379
23458
  for (const file of edits) {
23380
23459
  const resolved = at(file);
@@ -23382,7 +23461,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0) => {
23382
23461
  targets.push(resolved);
23383
23462
  }
23384
23463
  if (dir !== undefined && workitInvocations(segment.words.map(quoteWord2).join(" "), "posix").some((args) => args[0] === "git" && MUTATING_WORKIT_GIT.has(args[1] ?? "") && !inert(args.slice(2), "")))
23385
- targets.push(path30.join(dir, DIR_TARGET));
23464
+ targets.push(path31.join(dir, DIR_TARGET));
23386
23465
  }
23387
23466
  return targets;
23388
23467
  };
@@ -23417,7 +23496,7 @@ var liveDeny = ({ marker, checkout, ageMs, file }) => {
23417
23496
  var guarded = (targets) => {
23418
23497
  const seen = new Set;
23419
23498
  return targets.filter((target) => {
23420
- const dir = path30.dirname(target);
23499
+ const dir = path31.dirname(target);
23421
23500
  if (seen.has(dir))
23422
23501
  return false;
23423
23502
  seen.add(dir);
@@ -23438,7 +23517,7 @@ var claimAll = (owner, targets, deps) => {
23438
23517
  for (const target of guarded(targets))
23439
23518
  claimLiveSession(target, owner, deps);
23440
23519
  };
23441
- var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) => path30.resolve(cwd, file)) : [path30.join(cwd, DIR_TARGET)];
23520
+ var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) => path31.resolve(cwd, file)) : [path31.join(cwd, DIR_TARGET)];
23442
23521
  var issuedTarget = (cwd, targets) => {
23443
23522
  const state = resolveStateDir();
23444
23523
  const found = targets.find((target) => underIssued(state, cwd, homeExpanded(target), process.platform, canonical2));
@@ -23446,7 +23525,7 @@ var issuedTarget = (cwd, targets) => {
23446
23525
  };
23447
23526
  var underIssued = (state, cwd, target, platform = process.platform, real = (file) => file) => {
23448
23527
  const win = platform === "win32";
23449
- const p = win ? path30.win32 : path30.posix;
23528
+ const p = win ? path31.win32 : path31.posix;
23450
23529
  const fold = (value) => win || platform === "darwin" ? value.toLowerCase() : value;
23451
23530
  const named = win ? target.replace(/^\/([a-zA-Z])(?=\/|$)/, "$1:") : target;
23452
23531
  const relative = p.relative(fold(real(p.resolve(state))), fold(real(p.resolve(cwd, named))));
@@ -23495,7 +23574,7 @@ function shellGate(cwd, command, owner, dialect = "posix", deps) {
23495
23574
  try {
23496
23575
  targets = [
23497
23576
  ...segmentTargets(cwd, command, dialect),
23498
- ...gitMutationDirs(cwd, command, dialect).map((dir) => path30.join(dir, DIR_TARGET))
23577
+ ...gitMutationDirs(cwd, command, dialect).map((dir) => path31.join(dir, DIR_TARGET))
23499
23578
  ];
23500
23579
  } catch {
23501
23580
  targets = [];
@@ -23963,6 +24042,109 @@ var writePaths = (input) => {
23963
24042
  paths.push(match[1].trim());
23964
24043
  return [...new Set(paths)];
23965
24044
  };
24045
+ // packages/workit-core/src/hooks/standing.ts
24046
+ import fs24 from "node:fs";
24047
+ import path32 from "node:path";
24048
+ var readPlans = (store) => {
24049
+ const dir = path32.join(store, "fanouts");
24050
+ let names;
24051
+ try {
24052
+ names = fs24.readdirSync(dir).filter((name) => name.endsWith(".json"));
24053
+ } catch {
24054
+ return [];
24055
+ }
24056
+ const plans = [];
24057
+ for (const name of names) {
24058
+ try {
24059
+ const raw = JSON.parse(fs24.readFileSync(path32.join(dir, name), "utf8"));
24060
+ if (typeof raw.name !== "string" || !Array.isArray(raw.slices))
24061
+ continue;
24062
+ const texts = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string" && item !== "") : [];
24063
+ plans.push({
24064
+ name: raw.name,
24065
+ leads: texts([raw.leadSession, ...texts(raw.formerLeads)]),
24066
+ branches: texts(raw.slices.map((slice) => slice && typeof slice === "object" ? slice.branch : null))
24067
+ });
24068
+ } catch {}
24069
+ }
24070
+ return plans;
24071
+ };
24072
+ var leadOf2 = (input) => input.session.parentId ?? (input.session.agentId ? input.session.id : null) ?? (input.session.id.includes(":") ? input.session.id.split(":")[0] : null);
24073
+ var worksFor = (plan, input, branch) => {
24074
+ const session = input.session.id;
24075
+ if (plan.leads.includes(session) && !input.session.agentId)
24076
+ return false;
24077
+ const lead = leadOf2(input);
24078
+ if (lead && plan.leads.includes(lead))
24079
+ return true;
24080
+ if (plan.leads.some((each) => session.startsWith(`${each}-w-`)))
24081
+ return true;
24082
+ const current = branch();
24083
+ return current !== null && plan.branches.includes(current);
24084
+ };
24085
+ var standingFor = (input, store, rev) => {
24086
+ const orders = new Map;
24087
+ const ledger = readLedger(input.cwd);
24088
+ const rows = ledger.ok ? ledger.value.rows : [];
24089
+ let branch;
24090
+ const lazyBranch = () => branch === undefined ? branch = currentBranch(input.cwd) : branch;
24091
+ for (const plan of readPlans(store))
24092
+ if (worksFor(plan, input, lazyBranch))
24093
+ for (const row of activeStanding(rows, plan.name, plan.leads.length ? plan.leads : null))
24094
+ orders.set(row.id, row);
24095
+ return { rev, orders, rows };
24096
+ };
24097
+ var located = (input) => {
24098
+ const store = input.session.id ? gitStoreDir(input.cwd) : null;
24099
+ const rev = store ? readStandingRev(store) : null;
24100
+ if (!store || rev === null)
24101
+ return null;
24102
+ return { store, rev, file: standingSeenFile(store, input.session.id, input.session.agentId) };
24103
+ };
24104
+ var seedStanding = (input) => {
24105
+ try {
24106
+ const where = located(input);
24107
+ if (!where)
24108
+ return;
24109
+ const now = standingFor(input, where.store, where.rev);
24110
+ writeStandingSeen(where.file, { rev: where.rev, ids: [...now.orders.keys()] });
24111
+ } catch {}
24112
+ };
24113
+ var fanoutOf = (row) => typeof row.fanout === "string" ? row.fanout : "?";
24114
+ var changedSince = (now, ids) => {
24115
+ const known = new Set(ids);
24116
+ const added = [...now.orders.values()].filter((row) => !known.has(row.id));
24117
+ const byId = new Map(now.rows.map((row) => [row.id, row]));
24118
+ const dropped = ids.filter((id) => !now.orders.has(id)).map((id) => byId.get(id)).filter((row) => row !== undefined);
24119
+ if (!added.length && !dropped.length)
24120
+ return null;
24121
+ const fanouts = [...new Set([...added, ...dropped].map(fanoutOf))].join(", ");
24122
+ const lines = [
24123
+ `Workit: the lead changed the standing orders for fanout ${fanouts} while you run. They apply to you now and override your brief's STANDING list.`,
24124
+ ...added.map((row) => ` - new: ${String(row.what)}`),
24125
+ ...dropped.map((row) => ` - no longer in force: ${String(row.what)}${row.stop ? " (the stop is lifted: continue your brief)" : ""}`)
24126
+ ];
24127
+ if (added.some((row) => row.stop === true))
24128
+ lines.push("Stop now: make no further changes, close what you opened, and report to the lead with your branch, head SHA, what is done and what is not.");
24129
+ return lines.join(`
24130
+ `);
24131
+ };
24132
+ var standingDelta = (input) => {
24133
+ try {
24134
+ const where = located(input);
24135
+ if (!where)
24136
+ return null;
24137
+ const seen = readStandingSeen(where.file);
24138
+ if (seen.rev === where.rev)
24139
+ return null;
24140
+ const now = standingFor(input, where.store, where.rev);
24141
+ writeStandingSeen(where.file, { rev: where.rev, ids: [...now.orders.keys()] });
24142
+ return changedSince(now, seen.ids);
24143
+ } catch {
24144
+ return null;
24145
+ }
24146
+ };
24147
+ var sinceStart = new Map;
23966
24148
  // packages/workit-core/src/hooks/handle.ts
23967
24149
  var usable2 = (value) => value === "native" || value === "partial";
23968
24150
  var NONE5 = { kind: "none" };
@@ -24007,7 +24189,18 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
24007
24189
  const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
24008
24190
  return `${readOnly} Its own Workit session is ${own}, so the ledger tells its verdicts apart from the author's. Record the verdict with exactly this command (pick the result${pick}, name the candidate branch if it differs, say what you ran): \`${line}\`.${token ? " The token is this subagent's alone: never write it into a report, a file or a commit. --token needs a workit CLI at least as new as this plugin; if the CLI answers that --token is an unknown option, update the workit CLI (workit upgrade --cli) and record again." : ""}`;
24009
24191
  };
24192
+ var PRE_TOOL = new Set(["shell.pre", "write.pre", "tool.pre"]);
24010
24193
  function handleHook(input, deps) {
24194
+ const decision = decide(input, deps);
24195
+ if (deps.descriptor.transport !== "hook-process" || !PRE_TOOL.has(input.event.kind) || decision.kind === "deny")
24196
+ return decision;
24197
+ const delta = standingDelta(input);
24198
+ if (!delta)
24199
+ return decision;
24200
+ return decision.kind === "rewrite" ? { ...decision, text: [decision.text, delta].filter(Boolean).join(`
24201
+ `) } : withContextLine(decision, delta);
24202
+ }
24203
+ function decide(input, deps) {
24011
24204
  const { descriptor } = deps;
24012
24205
  const event = input.event;
24013
24206
  switch (event.kind) {
@@ -24084,6 +24277,7 @@ function handleHook(input, deps) {
24084
24277
  case "write.pre":
24085
24278
  return usable2(descriptor.events["write.pre"].support) ? writeGate(input.cwd, event.paths, liveOwner(input, descriptor.transport)) : NONE5;
24086
24279
  case "subagent.start":
24280
+ seedStanding({ ...input, session: { ...input.session, agentId: event.agentId } });
24087
24281
  return {
24088
24282
  kind: "context",
24089
24283
  text: subagentStartText(input, descriptor, event)
@@ -24243,6 +24437,13 @@ var turnInput = (ctx) => ({
24243
24437
  transcriptPath: null,
24244
24438
  event: { kind: "context.turn" }
24245
24439
  });
24440
+ var standingNotice = (ctx) => {
24441
+ if (!ctx.isProjectTrusted())
24442
+ return null;
24443
+ const worker = process.env.WORKIT_PI_WORKER_SESSION && process.env.WORKIT_SESSION_ID?.trim();
24444
+ const input = turnInput(ctx);
24445
+ return standingDelta(worker ? { ...input, session: { ...input.session, id: worker } } : input);
24446
+ };
24246
24447
  var workitContext = (ctx, taskContext = turnContext(ctx)) => {
24247
24448
  const session = ctx.sessionManager.getSessionId();
24248
24449
  if (!ctx.isProjectTrusted())
@@ -24403,12 +24604,12 @@ var skillPromptNudge = (prompt, ctx) => process.env.WORKIT_PI_WORKER_SESSION ? n
24403
24604
  // packages/workit-pi/src/launches.ts
24404
24605
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync6, readdirSync as readdirSync5, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
24405
24606
  import os11 from "node:os";
24406
- import path31 from "node:path";
24607
+ import path33 from "node:path";
24407
24608
  var launchDir = (root) => {
24408
24609
  const location = resolveStore(root);
24409
- return location instanceof Error ? null : path31.join(location.dir, "pi-launches");
24610
+ return location instanceof Error ? null : path33.join(location.dir, "pi-launches");
24410
24611
  };
24411
- var fileFor = (dir, workerId) => path31.join(dir, `${workerId.replace(/[^A-Za-z0-9-]/g, "_")}.json`);
24612
+ var fileFor = (dir, workerId) => path33.join(dir, `${workerId.replace(/[^A-Za-z0-9-]/g, "_")}.json`);
24412
24613
  var recordLaunch = (root, attempt) => {
24413
24614
  const dir = launchDir(root);
24414
24615
  if (!dir)
@@ -24454,7 +24655,7 @@ var abandonedLaunches = (root) => {
24454
24655
  const found = [];
24455
24656
  for (const name of names) {
24456
24657
  try {
24457
- const attempt = JSON.parse(readFileSync6(path31.join(dir, name), "utf8"));
24658
+ const attempt = JSON.parse(readFileSync6(path33.join(dir, name), "utf8"));
24458
24659
  if (typeof attempt.workerId === "string" && typeof attempt.session === "string") {
24459
24660
  if (!alive(attempt))
24460
24661
  found.push(attempt);
@@ -24632,6 +24833,14 @@ function launchWorker(assignment, options) {
24632
24833
  WORKIT_PI_WORKER_ROLE: assignment.role,
24633
24834
  WORKIT_PI_WORKER_SCOPE: JSON.stringify(assignment.scope)
24634
24835
  };
24836
+ seedStanding({
24837
+ host: "pi",
24838
+ cwd: spec.cwd,
24839
+ session: { id: env.WORKIT_SESSION_ID, agentId: null, agentType: null, parentId: null },
24840
+ permissionMode: null,
24841
+ transcriptPath: null,
24842
+ event: { kind: "session.start", source: "startup" }
24843
+ });
24635
24844
  try {
24636
24845
  const spawn = options.spawn ?? ((command, args, spawnOptions) => nodeSpawn(command, args, spawnOptions));
24637
24846
  handle.spec = { ...spec, env };
@@ -25361,6 +25570,16 @@ ${nudge}` : content) };
25361
25570
  });
25362
25571
  pi.on("tool_call", (event, ctx) => enforceToolPolicy(event, ctx));
25363
25572
  pi.on("tool_result", (event, ctx) => {
25573
+ const observed = observeResult(event, ctx);
25574
+ let standing = null;
25575
+ try {
25576
+ standing = standingNotice(ctx);
25577
+ } catch {}
25578
+ if (!standing)
25579
+ return observed;
25580
+ return { content: [...observed?.content ?? event.content, { type: "text", text: standing }] };
25581
+ });
25582
+ const observeResult = (event, ctx) => {
25364
25583
  if (childWorker && event.toolName === "workit_worker") {
25365
25584
  const details = event.details;
25366
25585
  const report = typeof details === "object" && details !== null && "data" in details && typeof details.data === "object" && details.data.data?.report;
@@ -25382,7 +25601,7 @@ ${nudge}` : content) };
25382
25601
  isError: event.isError
25383
25602
  });
25384
25603
  return observeToolResult(event, ctx);
25385
- });
25604
+ };
25386
25605
  pi.on("session_shutdown", (_event, ctx) => {
25387
25606
  sessions.delete(ctx.sessionManager.getSessionId());
25388
25607
  });