@brainervirus/workit-codex 8.16.0 → 8.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ CHECKS_FILE,
4
+ repoHeavyCommands,
5
+ loadCheckConfig,
6
+ matchesNamedCheck,
7
+ gateCheckNames,
8
+ checkCommand,
9
+ maybeHeavy
10
+ } from "./workit-hook-rbb0m9zp.js";
2
11
  // packages/workit-core/src/hooks/descriptor.ts
3
12
  var support = (descriptor, axis) => {
4
13
  if (axis.startsWith("event:"))
@@ -25,8 +34,8 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
25
34
  });
26
35
  // packages/workit-core/src/hooks/context.ts
27
36
  import { createHash as createHash11 } from "node:crypto";
28
- import fs14 from "node:fs";
29
- import path18 from "node:path";
37
+ import fs13 from "node:fs";
38
+ import path17 from "node:path";
30
39
 
31
40
  // packages/workit-core/src/core/methods.ts
32
41
  var METHODS = {
@@ -8804,225 +8813,20 @@ function requirementId(input) {
8804
8813
 
8805
8814
  // packages/workit-core/src/core/task-evaluation.ts
8806
8815
  import { createHash as createHash10 } from "node:crypto";
8807
- import * as fs13 from "node:fs";
8808
- import { spawnSync as spawnSync10 } from "node:child_process";
8809
- import path16 from "node:path";
8810
-
8811
- // packages/workit-core/src/check-config.ts
8812
- import { spawnSync as spawnSync2 } from "node:child_process";
8813
- import fs2 from "node:fs";
8814
- import path2 from "node:path";
8815
- var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
8816
- var CHECKS_FILE = "workit.checks.json";
8817
- var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8818
- var SHELL_META = /[|&;<>()$`\\*?[\]{}~!#]/u;
8819
- function splitCommand(command) {
8820
- const argv = [];
8821
- let current = "";
8822
- let quote = null;
8823
- let started = false;
8824
- for (const char of command) {
8825
- if (quote) {
8826
- if (char === quote)
8827
- quote = null;
8828
- else
8829
- current += char;
8830
- continue;
8831
- }
8832
- if (char === '"' || char === "'") {
8833
- quote = char;
8834
- started = true;
8835
- continue;
8836
- }
8837
- if (/\s/u.test(char)) {
8838
- if (started)
8839
- argv.push(current);
8840
- current = "";
8841
- started = false;
8842
- continue;
8843
- }
8844
- if (SHELL_META.test(char))
8845
- return new Error(`"${command}" uses shell syntax (${char}); configure an argv array instead`);
8846
- current += char;
8847
- started = true;
8848
- }
8849
- if (quote)
8850
- return new Error(`"${command}" has an unterminated quote`);
8851
- if (started)
8852
- argv.push(current);
8853
- return argv.length ? argv : new Error("empty command");
8854
- }
8855
- var git = (cwd, args) => {
8856
- const run = spawnSync2("git", args, {
8857
- cwd,
8858
- encoding: "utf8",
8859
- timeout: 20000,
8860
- killSignal: "SIGKILL",
8861
- windowsHide: true
8862
- });
8863
- const value = run.status === 0 ? (run.stdout ?? "").trim() : "";
8864
- return value || null;
8865
- };
8866
- function checkRoot(cwd) {
8867
- return path2.resolve(git(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
8868
- }
8869
- var packageManager = (root) => {
8870
- const has = (file) => fs2.existsSync(path2.join(root, file));
8871
- if (has("bun.lock") || has("bun.lockb"))
8872
- return "bun";
8873
- if (has("pnpm-lock.yaml"))
8874
- return "pnpm";
8875
- if (has("yarn.lock"))
8876
- return "yarn";
8877
- return "npm";
8878
- };
8879
- var scriptCheck = (pm, name) => {
8880
- const argv = [pm, "run", name];
8881
- const accepts = [argv];
8882
- if (pm === "pnpm" || pm === "yarn" || pm === "npm" && name === "test")
8883
- accepts.push([pm, name]);
8884
- return { name, argv, accepts };
8885
- };
8886
- var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
8887
- function detectedChecks(root) {
8888
- const read = (file) => {
8889
- try {
8890
- return fs2.readFileSync(path2.join(root, file), "utf8");
8891
- } catch {
8892
- return null;
8893
- }
8894
- };
8895
- const checks = [];
8896
- const add = (check) => {
8897
- if (!checks.some((item) => item.name === check.name))
8898
- checks.push(check);
8899
- };
8900
- const manifestText = read("package.json");
8901
- if (manifestText !== null) {
8902
- let manifest = null;
8903
- try {
8904
- manifest = JSON.parse(manifestText);
8905
- } catch {}
8906
- const scripts = isRecord(manifest) && isRecord(manifest.scripts) ? manifest.scripts : {};
8907
- const pm = packageManager(root);
8908
- for (const name of SCRIPT_CHECKS) {
8909
- const script = scripts[name];
8910
- if (typeof script === "string" && script.trim() !== "")
8911
- add(scriptCheck(pm, name));
8912
- }
8913
- }
8914
- const plain = (name, argv) => ({ name, argv, accepts: [argv] });
8915
- if (read("go.mod") !== null)
8916
- add(plain("test", ["go", "test", "./..."]));
8917
- if (read("Cargo.toml") !== null)
8918
- add(plain("test", ["cargo", "test"]));
8919
- if (read("pytest.ini") !== null || /\bpytest\b/u.test(read("pyproject.toml") ?? ""))
8920
- add(plain("test", ["pytest"]));
8921
- const makefile = read("Makefile") ?? read("makefile") ?? read("GNUmakefile");
8922
- if (makefile !== null && /^test\s*:(?!=)/mu.test(makefile))
8923
- add(plain("test", ["make", "test"]));
8924
- return checks;
8925
- }
8926
- var GATES = ["testing", "verification"];
8927
- function loadCheckConfig(cwd) {
8928
- const root = checkRoot(cwd);
8929
- const file = path2.join(root, CHECKS_FILE);
8930
- const none = (error = null) => ({
8931
- source: error ? CHECKS_FILE : "none",
8932
- root,
8933
- checks: [],
8934
- gates: {},
8935
- error
8936
- });
8937
- let text = null;
8938
- try {
8939
- text = fs2.readFileSync(file, "utf8");
8940
- } catch (error) {
8941
- if (error.code !== "ENOENT")
8942
- return none(`cannot read ${CHECKS_FILE}: ${error.message}`);
8943
- }
8944
- if (text === null) {
8945
- const checks = detectedChecks(root);
8946
- return checks.length ? { source: "defaults", root, checks, gates: {}, error: null } : none();
8947
- }
8948
- let parsed;
8949
- try {
8950
- parsed = JSON.parse(text);
8951
- } catch {
8952
- return none(`${CHECKS_FILE} is not valid JSON`);
8953
- }
8954
- if (!isRecord(parsed) || !isRecord(parsed.checks))
8955
- return none(`${CHECKS_FILE} must be {"checks":{"<name>":"<command>"|["argv",…]}}`);
8956
- const checks = [];
8957
- for (const [name, value] of Object.entries(parsed.checks)) {
8958
- if (!CHECK_NAME.test(name))
8959
- return none(`${CHECKS_FILE}: check name "${name}" must match ${CHECK_NAME.source}`);
8960
- const argv = typeof value === "string" ? splitCommand(value) : Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === "string" && item.length > 0) ? value : new Error("expected a command string or a non-empty argv array");
8961
- if (argv instanceof Error)
8962
- return none(`${CHECKS_FILE}: check "${name}": ${argv.message}`);
8963
- checks.push({ name, argv, accepts: [argv] });
8964
- }
8965
- const gates = {};
8966
- if (parsed.gates !== undefined) {
8967
- if (!isRecord(parsed.gates))
8968
- return none(`${CHECKS_FILE}: gates must be {"testing":"<name>"|["<name>",…]}`);
8969
- for (const [gate, value] of Object.entries(parsed.gates)) {
8970
- if (!GATES.includes(gate))
8971
- return none(`${CHECKS_FILE}: unknown gate "${gate}" (use ${GATES.join(" or ")})`);
8972
- const names = typeof value === "string" ? [value] : value;
8973
- if (!Array.isArray(names) || names.length === 0 || !names.every((name) => typeof name === "string" && checks.some((c) => c.name === name)))
8974
- return none(`${CHECKS_FILE}: gates.${gate} must name configured checks`);
8975
- gates[gate] = names;
8976
- }
8977
- }
8978
- return { source: CHECKS_FILE, root, checks, gates, error: null, resources: parsed.resources };
8979
- }
8980
- var sameArgv = (left, right) => left.length === right.length && left.every((item, index) => item === right[index]);
8981
- function matchesNamedCheck(config, name, argv, cwd) {
8982
- if (config.error || name === null || cwd !== ".")
8983
- return false;
8984
- const check = config.checks.find((item) => item.name === name);
8985
- return Boolean(check?.accepts.some((accepted) => sameArgv(accepted, argv)));
8986
- }
8987
- function gateCheckNames(config, dimension) {
8988
- const explicit = config.gates[dimension];
8989
- if (explicit)
8990
- return explicit;
8991
- const names = config.checks.map((check) => check.name);
8992
- if (dimension === "testing")
8993
- return names.includes("test") ? ["test"] : [];
8994
- return names;
8995
- }
8996
- var workitOnPath;
8997
- function workitAvailable(env = process.env) {
8998
- if (workitOnPath !== undefined)
8999
- return workitOnPath;
9000
- const windows = process.platform === "win32";
9001
- const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
9002
- const dirs = (env.PATH ?? env.Path ?? "").split(path2.delimiter).filter(Boolean);
9003
- workitOnPath = dirs.some((dir) => exts.some((ext) => {
9004
- try {
9005
- return fs2.statSync(path2.join(dir, `workit${ext}`)).isFile();
9006
- } catch {
9007
- return false;
9008
- }
9009
- }));
9010
- return workitOnPath;
9011
- }
9012
- function checkCommand(args, version, onPath = workitAvailable()) {
9013
- return onPath ? `workit check ${args}` : `npx -y @brainervirus/workit-cli@${version} check ${args}`;
9014
- }
8816
+ import * as fs12 from "node:fs";
8817
+ import { spawnSync as spawnSync9 } from "node:child_process";
8818
+ import path15 from "node:path";
9015
8819
 
9016
8820
  // packages/workit-core/src/git/rev.ts
9017
- import { spawnSync as spawnSync3 } from "node:child_process";
8821
+ import { spawnSync as spawnSync2 } from "node:child_process";
9018
8822
  import { createHash as createHash3 } from "node:crypto";
9019
- import fs3 from "node:fs";
8823
+ import fs2 from "node:fs";
9020
8824
  import os from "node:os";
9021
- import path3 from "node:path";
8825
+ import path2 from "node:path";
9022
8826
  var MAX_BUFFER = 256 * 1024 * 1024;
9023
8827
  var GIT_TIMEOUTS = { local: 20000, worktree: 120000, network: 15000 };
9024
- var git2 = (cwd, args, options = {}) => {
9025
- const result = spawnSync3("git", args, {
8828
+ var git = (cwd, args, options = {}) => {
8829
+ const result = spawnSync2("git", args, {
9026
8830
  cwd,
9027
8831
  encoding: "utf8",
9028
8832
  env: options.env ?? process.env,
@@ -9048,30 +8852,30 @@ var line = (run) => {
9048
8852
  };
9049
8853
  var safeArg = (value) => value.length > 0 && !value.startsWith("-");
9050
8854
  function headSha(cwd) {
9051
- return line(git2(cwd, ["rev-parse", "--verify", "-q", "HEAD^{commit}"]));
8855
+ return line(git(cwd, ["rev-parse", "--verify", "-q", "HEAD^{commit}"]));
9052
8856
  }
9053
- var emptyTree = (cwd) => line(git2(cwd, ["mktree"], { input: "" }));
8857
+ var emptyTree = (cwd) => line(git(cwd, ["mktree"], { input: "" }));
9054
8858
  var MAX_UNTRACKED_BYTES = 5 * 1024 * 1024;
9055
8859
  var seedIndex = (from, to) => {
9056
- fs3.copyFileSync(from, to);
9057
- const { atimeNs, mtimeNs } = fs3.statSync(from, { bigint: true });
8860
+ fs2.copyFileSync(from, to);
8861
+ const { atimeNs, mtimeNs } = fs2.statSync(from, { bigint: true });
9058
8862
  const seconds = (ns) => (Number(ns / 1000n) - 1) / 1e6;
9059
- fs3.utimesSync(to, seconds(atimeNs), seconds(mtimeNs));
8863
+ fs2.utimesSync(to, seconds(atimeNs), seconds(mtimeNs));
9060
8864
  };
9061
8865
  function worktreeTree(cwd, options = {}) {
9062
- const top = line(git2(cwd, ["rev-parse", "--show-toplevel"]));
9063
- const indexPath = line(git2(cwd, ["rev-parse", "--path-format=absolute", "--git-path", "index"]));
8866
+ const top = line(git(cwd, ["rev-parse", "--show-toplevel"]));
8867
+ const indexPath = line(git(cwd, ["rev-parse", "--path-format=absolute", "--git-path", "index"]));
9064
8868
  if (!top || !indexPath)
9065
8869
  return null;
9066
8870
  const cap = options.maxUntrackedBytes ?? MAX_UNTRACKED_BYTES;
9067
8871
  const timeoutMs = options.timeoutMs ?? GIT_TIMEOUTS.worktree;
9068
- const scratch = fs3.mkdtempSync(path3.join(os.tmpdir(), "workit-tree-"));
8872
+ const scratch = fs2.mkdtempSync(path2.join(os.tmpdir(), "workit-tree-"));
9069
8873
  try {
9070
- const tempIndex = path3.join(scratch, "index");
9071
- if (fs3.existsSync(indexPath))
8874
+ const tempIndex = path2.join(scratch, "index");
8875
+ if (fs2.existsSync(indexPath))
9072
8876
  seedIndex(indexPath, tempIndex);
9073
8877
  const env = { ...process.env, GIT_INDEX_FILE: tempIndex };
9074
- const untracked = git2(top, ["ls-files", "--others", "--exclude-standard", "-z"], {
8878
+ const untracked = git(top, ["ls-files", "--others", "--exclude-standard", "-z"], {
9075
8879
  env,
9076
8880
  timeoutMs
9077
8881
  });
@@ -9080,34 +8884,34 @@ function worktreeTree(cwd, options = {}) {
9080
8884
  const skipped = [];
9081
8885
  for (const file of untracked.stdout.split("\x00").filter(Boolean)) {
9082
8886
  try {
9083
- const stat = fs3.statSync(path3.join(top, file));
8887
+ const stat = fs2.statSync(path2.join(top, file));
9084
8888
  if (stat.isFile() && stat.size > cap)
9085
8889
  skipped.push({ path: file, size: stat.size, mtimeMs: Math.trunc(stat.mtimeMs) });
9086
8890
  } catch {}
9087
8891
  }
9088
8892
  skipped.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
9089
- const added = skipped.length ? git2(top, ["add", "-A", "--pathspec-from-file=-", "--pathspec-file-nul"], {
8893
+ const added = skipped.length ? git(top, ["add", "-A", "--pathspec-from-file=-", "--pathspec-file-nul"], {
9090
8894
  env,
9091
8895
  timeoutMs,
9092
8896
  input: [".", ...skipped.map((file) => `:(exclude,literal)${file.path}`)].join("\x00")
9093
- }) : git2(top, ["add", "-A"], { env, timeoutMs });
8897
+ }) : git(top, ["add", "-A"], { env, timeoutMs });
9094
8898
  if (!added.ok)
9095
8899
  return null;
9096
- const tree = line(git2(top, ["write-tree"], { env, timeoutMs }));
8900
+ const tree = line(git(top, ["write-tree"], { env, timeoutMs }));
9097
8901
  if (!tree)
9098
8902
  return null;
9099
- const base = line(git2(top, ["rev-parse", "--verify", "-q", "HEAD^{tree}"])) ?? emptyTree(top);
8903
+ const base = line(git(top, ["rev-parse", "--verify", "-q", "HEAD^{tree}"])) ?? emptyTree(top);
9100
8904
  const key = skipped.length ? `sha256:${createHash3("sha256").update(JSON.stringify({ tree, skipped })).digest("hex")}` : tree;
9101
8905
  return { tree, key, dirty: tree !== base || skipped.length > 0, skipped };
9102
8906
  } finally {
9103
- fs3.rmSync(scratch, { recursive: true, force: true });
8907
+ fs2.rmSync(scratch, { recursive: true, force: true });
9104
8908
  }
9105
8909
  }
9106
8910
  function worktreeSignal(cwd, options = {}) {
9107
- const top = line(git2(cwd, ["rev-parse", "--show-toplevel"]));
8911
+ const top = line(git(cwd, ["rev-parse", "--show-toplevel"]));
9108
8912
  if (!top)
9109
8913
  return null;
9110
- const status = git2(top, [
8914
+ const status = git(top, [
9111
8915
  "status",
9112
8916
  "--porcelain=v1",
9113
8917
  "-z",
@@ -9126,10 +8930,10 @@ function worktreeSignal(cwd, options = {}) {
9126
8930
  if (entry.length < 4)
9127
8931
  continue;
9128
8932
  const file = entry.slice(3);
9129
- const absolute = path3.join(top, file);
8933
+ const absolute = path2.join(top, file);
9130
8934
  let stat = "-";
9131
8935
  try {
9132
- const info = fs3.lstatSync(absolute, { bigint: true });
8936
+ const info = fs2.lstatSync(absolute, { bigint: true });
9133
8937
  stat = `${info.mode.toString(8)}:${info.size}:${info.mtimeNs}`;
9134
8938
  if (info.isDirectory())
9135
8939
  stat += `:${headSha(absolute) ?? "-"}`;
@@ -9141,12 +8945,12 @@ function worktreeSignal(cwd, options = {}) {
9141
8945
  function mergeBase(cwd, a, b) {
9142
8946
  if (!safeArg(a) || !safeArg(b))
9143
8947
  return null;
9144
- return line(git2(cwd, ["merge-base", a, b]));
8948
+ return line(git(cwd, ["merge-base", a, b]));
9145
8949
  }
9146
8950
  function patchId(cwd, base, head) {
9147
8951
  if (!safeArg(base) || !safeArg(head))
9148
8952
  return null;
9149
- const diff = git2(cwd, [
8953
+ const diff = git(cwd, [
9150
8954
  "diff",
9151
8955
  "-U3",
9152
8956
  "--diff-algorithm=myers",
@@ -9163,20 +8967,20 @@ function patchId(cwd, base, head) {
9163
8967
  ]);
9164
8968
  if (!diff.ok || !diff.stdout.trim())
9165
8969
  return null;
9166
- const id = git2(cwd, ["patch-id", "--stable"], { input: diff.stdout });
8970
+ const id = git(cwd, ["patch-id", "--stable"], { input: diff.stdout });
9167
8971
  return line(id)?.split(/\s+/u)[0] ?? null;
9168
8972
  }
9169
8973
  function remoteNames(cwd) {
9170
- return (git2(cwd, ["remote"]).stdout ?? "").split(/\r?\n/u).map((value) => value.trim()).filter(Boolean);
8974
+ return (git(cwd, ["remote"]).stdout ?? "").split(/\r?\n/u).map((value) => value.trim()).filter(Boolean);
9171
8975
  }
9172
8976
  function resolveRef(cwd, ref) {
9173
8977
  if (!safeArg(ref))
9174
8978
  return null;
9175
- return line(git2(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]));
8979
+ return line(git(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]));
9176
8980
  }
9177
- var config2 = (cwd, key) => line(git2(cwd, ["config", "--get", key]));
8981
+ var config2 = (cwd, key) => line(git(cwd, ["config", "--get", key]));
9178
8982
  function currentBranch(cwd) {
9179
- return line(git2(cwd, ["symbolic-ref", "--short", "-q", "HEAD"]));
8983
+ return line(git(cwd, ["symbolic-ref", "--short", "-q", "HEAD"]));
9180
8984
  }
9181
8985
  function pushRemoteName(cwd, branch) {
9182
8986
  const name = branch ?? currentBranch(cwd);
@@ -9196,8 +9000,8 @@ function pushRemoteName(cwd, branch) {
9196
9000
 
9197
9001
  // packages/workit-core/src/core/task-store.ts
9198
9002
  import { createHash as createHash6, randomUUID as randomUUID3 } from "node:crypto";
9199
- import * as fs10 from "node:fs";
9200
- import path10 from "node:path";
9003
+ import * as fs9 from "node:fs";
9004
+ import path9 from "node:path";
9201
9005
 
9202
9006
  // node_modules/@openclaw/fs-safe/dist/errors.js
9203
9007
  var OPERATIONAL_CODES = new Set([
@@ -9248,10 +9052,10 @@ function sameFileIdentity(left, right, platform = process.platform) {
9248
9052
  // node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js
9249
9053
  import { randomBytes } from "node:crypto";
9250
9054
  import fsSync from "node:fs";
9251
- import path4 from "node:path";
9055
+ import path3 from "node:path";
9252
9056
 
9253
9057
  // node_modules/@openclaw/fs-safe/dist/bounded-read.js
9254
- import fs4 from "node:fs";
9058
+ import fs3 from "node:fs";
9255
9059
 
9256
9060
  // node_modules/@openclaw/fs-safe/dist/byte-budget.js
9257
9061
  function normalizeMaxBytes(value, options = {}) {
@@ -9288,7 +9092,7 @@ function readFileDescriptorBoundedSync(fd, maxBytes) {
9288
9092
  let total = 0;
9289
9093
  while (true) {
9290
9094
  const length = nextReadLength(total, maxBytes, scratch.length);
9291
- const bytesRead = fs4.readSync(fd, scratch, 0, length, null);
9095
+ const bytesRead = fs3.readSync(fd, scratch, 0, length, null);
9292
9096
  if (bytesRead === 0) {
9293
9097
  return Buffer.concat(chunks, total);
9294
9098
  }
@@ -9297,9 +9101,9 @@ function readFileDescriptorBoundedSync(fd, maxBytes) {
9297
9101
  }
9298
9102
 
9299
9103
  // node_modules/@openclaw/fs-safe/dist/read-open-flags.js
9300
- import fs5 from "node:fs";
9104
+ import fs4 from "node:fs";
9301
9105
  function resolveReadOpenFlags(options) {
9302
- const constants = options?.constants ?? fs5.constants;
9106
+ const constants = options?.constants ?? fs4.constants;
9303
9107
  const noFollow = process.platform !== "win32" && options?.followSymlinks !== true && typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
9304
9108
  const nonBlocking = process.platform !== "win32" && typeof constants.O_NONBLOCK === "number" ? constants.O_NONBLOCK : 0;
9305
9109
  return constants.O_RDONLY | noFollow | nonBlocking;
@@ -9338,13 +9142,13 @@ ${ownershipToken}
9338
9142
  return { raw, ownershipToken };
9339
9143
  }
9340
9144
  function relativeSidecarLockPath(lockRoot, lockPath) {
9341
- const resolved = path4.resolve(lockPath);
9342
- const lexicalRelative = path4.relative(lockRoot.rootDir, resolved);
9343
- const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${path4.sep}`) && !path4.isAbsolute(lexicalRelative) ? lexicalRelative : path4.relative(lockRoot.rootReal, resolved);
9344
- if (!relative || relative === ".." || relative.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative)) {
9145
+ const resolved = path3.resolve(lockPath);
9146
+ const lexicalRelative = path3.relative(lockRoot.rootDir, resolved);
9147
+ const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${path3.sep}`) && !path3.isAbsolute(lexicalRelative) ? lexicalRelative : path3.relative(lockRoot.rootReal, resolved);
9148
+ if (!relative || relative === ".." || relative.startsWith(`..${path3.sep}`) || path3.isAbsolute(relative)) {
9345
9149
  throw new FsSafeError("outside-workspace", "sidecar lock path is outside lockRoot");
9346
9150
  }
9347
- return relative.split(path4.sep).join(path4.posix.sep);
9151
+ return relative.split(path3.sep).join(path3.posix.sep);
9348
9152
  }
9349
9153
  function parseSidecarLockPayload(raw, parser) {
9350
9154
  if (parser) {
@@ -9490,8 +9294,8 @@ function getFsSafeLockConfig() {
9490
9294
  }
9491
9295
 
9492
9296
  // node_modules/@openclaw/fs-safe/dist/file-lock-sync.js
9493
- import fs6 from "node:fs";
9494
- import path5 from "node:path";
9297
+ import fs5 from "node:fs";
9298
+ import path4 from "node:path";
9495
9299
 
9496
9300
  // node_modules/@openclaw/fs-safe/dist/timing.js
9497
9301
  function sleepSync(ms) {
@@ -9521,7 +9325,7 @@ function releaseAllSyncHeldLocks() {
9521
9325
  }
9522
9326
  try {
9523
9327
  if (held.fd !== undefined)
9524
- fs6.closeSync(held.fd);
9328
+ fs5.closeSync(held.fd);
9525
9329
  } catch {}
9526
9330
  try {
9527
9331
  removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
@@ -9556,7 +9360,7 @@ function releaseSyncHeldLock(held) {
9556
9360
  if (held.fd !== undefined) {
9557
9361
  const fd = held.fd;
9558
9362
  held.fd = undefined;
9559
- fs6.closeSync(fd);
9363
+ fs5.closeSync(fd);
9560
9364
  }
9561
9365
  removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
9562
9366
  heldLocks.delete(held.normalizedTargetPath);
@@ -9579,29 +9383,29 @@ function createSyncHeldLockHandle(held) {
9579
9383
  };
9580
9384
  }
9581
9385
  function canonicalLockParentSync(parent) {
9582
- return process.platform === "win32" ? fs6.realpathSync.native(parent) : fs6.realpathSync(parent);
9386
+ return process.platform === "win32" ? fs5.realpathSync.native(parent) : fs5.realpathSync(parent);
9583
9387
  }
9584
9388
  function normalizeTargetPath(targetPath) {
9585
- const resolved = path5.resolve(targetPath);
9586
- fs6.mkdirSync(path5.dirname(resolved), { recursive: true });
9389
+ const resolved = path4.resolve(targetPath);
9390
+ fs5.mkdirSync(path4.dirname(resolved), { recursive: true });
9587
9391
  try {
9588
- return path5.join(canonicalLockParentSync(path5.dirname(resolved)), path5.basename(resolved));
9392
+ return path4.join(canonicalLockParentSync(path4.dirname(resolved)), path4.basename(resolved));
9589
9393
  } catch {
9590
9394
  return resolved;
9591
9395
  }
9592
9396
  }
9593
9397
  function boundedLockPath(lockPath, lockRoot) {
9594
- const resolved = path5.resolve(lockPath);
9398
+ const resolved = path4.resolve(lockPath);
9595
9399
  if (!lockRoot)
9596
9400
  return resolved;
9597
9401
  relativeSidecarLockPath(lockRoot, resolved);
9598
- const parent = path5.dirname(resolved);
9402
+ const parent = path4.dirname(resolved);
9599
9403
  const parentReal = canonicalLockParentSync(parent);
9600
- const parentRelative = path5.relative(lockRoot.rootReal, parentReal);
9601
- if (parentRelative === ".." || parentRelative.startsWith(`..${path5.sep}`) || path5.isAbsolute(parentRelative)) {
9404
+ const parentRelative = path4.relative(lockRoot.rootReal, parentReal);
9405
+ if (parentRelative === ".." || parentRelative.startsWith(`..${path4.sep}`) || path4.isAbsolute(parentRelative)) {
9602
9406
  throw new FsSafeError("outside-workspace", "sidecar lock parent is outside lockRoot");
9603
9407
  }
9604
- return path5.join(parentReal, path5.basename(resolved));
9408
+ return path4.join(parentReal, path4.basename(resolved));
9605
9409
  }
9606
9410
  function defaultShouldReclaim(snapshot, staleMs, nowMs) {
9607
9411
  const createdAtMs = sidecarLockPayloadCreatedAtMs(snapshot.payload);
@@ -9611,7 +9415,7 @@ function defaultShouldReclaim(snapshot, staleMs, nowMs) {
9611
9415
  }
9612
9416
  function reclaimGuardExists(reclaimGuardPath) {
9613
9417
  try {
9614
- fs6.lstatSync(reclaimGuardPath);
9418
+ fs5.lstatSync(reclaimGuardPath);
9615
9419
  return true;
9616
9420
  } catch (error) {
9617
9421
  if (error.code === "ENOENT")
@@ -9675,19 +9479,19 @@ function acquireFileLockSync(targetPath, options) {
9675
9479
  const { raw, ownershipToken } = serializeSidecarLockPayload(payload);
9676
9480
  let lockFileCreateDenied = false;
9677
9481
  try {
9678
- const noFollow = process.platform !== "win32" && typeof fs6.constants.O_NOFOLLOW === "number" ? fs6.constants.O_NOFOLLOW : 0;
9482
+ const noFollow = process.platform !== "win32" && typeof fs5.constants.O_NOFOLLOW === "number" ? fs5.constants.O_NOFOLLOW : 0;
9679
9483
  try {
9680
- fd = fs6.openSync(lockPath, fs6.constants.O_WRONLY | fs6.constants.O_CREAT | fs6.constants.O_EXCL | noFollow, 384);
9484
+ fd = fs5.openSync(lockPath, fs5.constants.O_WRONLY | fs5.constants.O_CREAT | fs5.constants.O_EXCL | noFollow, 384);
9681
9485
  } catch (error) {
9682
9486
  lockFileCreateDenied = isTransientLockFileDenial(error, lockPath);
9683
9487
  throw error;
9684
9488
  }
9685
- fs6.writeFileSync(fd, raw, "utf8");
9686
- fs6.fsyncSync(fd);
9489
+ fs5.writeFileSync(fd, raw, "utf8");
9490
+ fs5.fsyncSync(fd);
9687
9491
  const snapshot = {
9688
9492
  raw,
9689
9493
  payload,
9690
- stat: fs6.fstatSync(fd),
9494
+ stat: fs5.fstatSync(fd),
9691
9495
  ownershipToken
9692
9496
  };
9693
9497
  const createdHeld = {
@@ -9722,8 +9526,8 @@ function acquireFileLockSync(targetPath, options) {
9722
9526
  return returnedHandle;
9723
9527
  } catch (error) {
9724
9528
  if (fd !== undefined) {
9725
- const failed = { payload: null, stat: fs6.fstatSync(fd) };
9726
- fs6.closeSync(fd);
9529
+ const failed = { payload: null, stat: fs5.fstatSync(fd) };
9530
+ fs5.closeSync(fd);
9727
9531
  fd = undefined;
9728
9532
  removeSidecarLockIfUnchangedSync(lockPath, failed);
9729
9533
  }
@@ -9772,7 +9576,7 @@ function acquireFileLockSync(targetPath, options) {
9772
9576
  })) {
9773
9577
  let ownsReclaimGuard = false;
9774
9578
  try {
9775
- fs6.mkdirSync(reclaimGuardPath);
9579
+ fs5.mkdirSync(reclaimGuardPath);
9776
9580
  ownsReclaimGuard = true;
9777
9581
  if (removeSidecarLockIfUnchangedSync(lockPath, snapshot))
9778
9582
  continue;
@@ -9785,7 +9589,7 @@ function acquireFileLockSync(targetPath, options) {
9785
9589
  } finally {
9786
9590
  if (ownsReclaimGuard) {
9787
9591
  try {
9788
- fs6.rmdirSync(reclaimGuardPath);
9592
+ fs5.rmdirSync(reclaimGuardPath);
9789
9593
  } catch {}
9790
9594
  }
9791
9595
  }
@@ -9802,12 +9606,12 @@ function acquireFileLockSync(targetPath, options) {
9802
9606
  }
9803
9607
  // packages/workit-core/src/host-session.ts
9804
9608
  import { createHash as createHash4, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
9805
- import fs7 from "node:fs";
9806
- import path7 from "node:path";
9609
+ import fs6 from "node:fs";
9610
+ import path6 from "node:path";
9807
9611
 
9808
9612
  // packages/workit-core/src/core/logger.ts
9809
9613
  import os2 from "node:os";
9810
- import path6 from "node:path";
9614
+ import path5 from "node:path";
9811
9615
  var SENSITIVE_WORDS = new Set([
9812
9616
  "token",
9813
9617
  "secret",
@@ -9852,14 +9656,14 @@ var resolveStateDir = () => {
9852
9656
  return override;
9853
9657
  const home = os2.homedir();
9854
9658
  if (process.env.XDG_STATE_HOME)
9855
- return path6.join(process.env.XDG_STATE_HOME, "workit");
9659
+ return path5.join(process.env.XDG_STATE_HOME, "workit");
9856
9660
  switch (os2.platform()) {
9857
9661
  case "darwin":
9858
- return path6.join(home, "Library", "Application Support", "workit");
9662
+ return path5.join(home, "Library", "Application Support", "workit");
9859
9663
  case "win32":
9860
- return path6.join(process.env.LOCALAPPDATA ?? path6.join(home, "AppData", "Local"), "workit");
9664
+ return path5.join(process.env.LOCALAPPDATA ?? path5.join(home, "AppData", "Local"), "workit");
9861
9665
  default:
9862
- return path6.join(process.env.HOME ?? home, ".local", "state", "workit");
9666
+ return path5.join(process.env.HOME ?? home, ".local", "state", "workit");
9863
9667
  }
9864
9668
  };
9865
9669
  var homePattern = new RegExp(`${escapeRegExp(os2.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
@@ -9895,8 +9699,8 @@ function hostSessionFromEnv(env) {
9895
9699
  var ISSUED_PER_LEAD = 64;
9896
9700
  var ISSUED_SESSIONS_MARKER = "workit-issued-sessions/3";
9897
9701
  var hash = (value) => createHash4("sha256").update(value).digest("hex").slice(0, 32);
9898
- var userIssuedRoot = () => path7.join(resolveStateDir(), "issued");
9899
- var userTokenRoot = () => path7.join(resolveStateDir(), "issued-tokens");
9702
+ var userIssuedRoot = () => path6.join(resolveStateDir(), "issued");
9703
+ var userTokenRoot = () => path6.join(resolveStateDir(), "issued-tokens");
9900
9704
  function migrateRepoIssued(cwd) {
9901
9705
  if (cwd === undefined)
9902
9706
  return;
@@ -9905,27 +9709,27 @@ function migrateRepoIssued(cwd) {
9905
9709
  const location = resolveStore(cwd);
9906
9710
  if (location instanceof Error)
9907
9711
  return;
9908
- old = path7.join(location.dir, "hooks", "issued");
9909
- if (!fs7.existsSync(old))
9712
+ old = path6.join(location.dir, "hooks", "issued");
9713
+ if (!fs6.existsSync(old))
9910
9714
  return;
9911
9715
  } catch {
9912
9716
  return;
9913
9717
  }
9914
9718
  for (const lead of safeList(old)) {
9915
9719
  try {
9916
- const from = path7.join(old, lead);
9917
- if (!fs7.statSync(from).isDirectory())
9720
+ const from = path6.join(old, lead);
9721
+ if (!fs6.statSync(from).isDirectory())
9918
9722
  continue;
9919
- const to = path7.join(userIssuedRoot(), lead);
9920
- fs7.mkdirSync(to, { recursive: true, mode: 448 });
9921
- for (const id of fs7.readdirSync(from)) {
9723
+ const to = path6.join(userIssuedRoot(), lead);
9724
+ fs6.mkdirSync(to, { recursive: true, mode: 448 });
9725
+ for (const id of fs6.readdirSync(from)) {
9922
9726
  try {
9923
- fs7.copyFileSync(path7.join(from, id), path7.join(to, id), fs7.constants.COPYFILE_EXCL);
9727
+ fs6.copyFileSync(path6.join(from, id), path6.join(to, id), fs6.constants.COPYFILE_EXCL);
9924
9728
  } catch (error) {
9925
9729
  if (error.code !== "EEXIST")
9926
9730
  throw error;
9927
9731
  }
9928
- fs7.rmSync(path7.join(from, id), { force: true });
9732
+ fs6.rmSync(path6.join(from, id), { force: true });
9929
9733
  }
9930
9734
  removeIfEmpty(from);
9931
9735
  } catch {}
@@ -9934,14 +9738,14 @@ function migrateRepoIssued(cwd) {
9934
9738
  }
9935
9739
  var safeList = (dir) => {
9936
9740
  try {
9937
- return fs7.readdirSync(dir);
9741
+ return fs6.readdirSync(dir);
9938
9742
  } catch {
9939
9743
  return [];
9940
9744
  }
9941
9745
  };
9942
9746
  var removeIfEmpty = (dir) => {
9943
9747
  try {
9944
- fs7.rmdirSync(dir);
9748
+ fs6.rmdirSync(dir);
9945
9749
  } catch {}
9946
9750
  };
9947
9751
  var tokenHash = (token) => createHash4("sha256").update(token).digest("hex");
@@ -9950,13 +9754,13 @@ function recordIssuedSession(cwd, lead, issued) {
9950
9754
  try {
9951
9755
  migrateRepoIssued(cwd);
9952
9756
  const own = hash(issued);
9953
- const tokens = path7.join(userTokenRoot(), hash(lead));
9954
- fs7.mkdirSync(tokens, { recursive: true, mode: 448 });
9955
- fs7.writeFileSync(path7.join(tokens, own), `${tokenHash(token)}
9757
+ const tokens = path6.join(userTokenRoot(), hash(lead));
9758
+ fs6.mkdirSync(tokens, { recursive: true, mode: 448 });
9759
+ fs6.writeFileSync(path6.join(tokens, own), `${tokenHash(token)}
9956
9760
  `, { mode: 384, flag: "wx" });
9957
- const dir = path7.join(userIssuedRoot(), hash(lead));
9958
- fs7.mkdirSync(dir, { recursive: true, mode: 448 });
9959
- fs7.writeFileSync(path7.join(dir, own), `${ISSUED_SESSIONS_MARKER}
9761
+ const dir = path6.join(userIssuedRoot(), hash(lead));
9762
+ fs6.mkdirSync(dir, { recursive: true, mode: 448 });
9763
+ fs6.writeFileSync(path6.join(dir, own), `${ISSUED_SESSIONS_MARKER}
9960
9764
  `, { mode: 384 });
9961
9765
  pruneIssued(dir, own, tokens);
9962
9766
  return token;
@@ -9966,13 +9770,13 @@ function recordIssuedSession(cwd, lead, issued) {
9966
9770
  }
9967
9771
  function pruneIssued(dir, own, tokens) {
9968
9772
  try {
9969
- const entries = fs7.readdirSync(dir);
9773
+ const entries = fs6.readdirSync(dir);
9970
9774
  if (entries.length <= ISSUED_PER_LEAD)
9971
9775
  return;
9972
- const byAge = entries.filter((name) => name !== own).map((name) => ({ name, at: fs7.statSync(path7.join(dir, name)).mtimeMs })).toSorted((a, b) => a.at - b.at);
9776
+ const byAge = entries.filter((name) => name !== own).map((name) => ({ name, at: fs6.statSync(path6.join(dir, name)).mtimeMs })).toSorted((a, b) => a.at - b.at);
9973
9777
  for (const { name } of byAge.slice(0, entries.length - ISSUED_PER_LEAD)) {
9974
- fs7.rmSync(path7.join(dir, name), { force: true });
9975
- fs7.rmSync(path7.join(tokens, name), { force: true });
9778
+ fs6.rmSync(path6.join(dir, name), { force: true });
9779
+ fs6.rmSync(path6.join(tokens, name), { force: true });
9976
9780
  }
9977
9781
  } catch {}
9978
9782
  }
@@ -9982,7 +9786,7 @@ var issuedRecord = (cwd, claimed) => {
9982
9786
  return null;
9983
9787
  migrateRepoIssued(cwd);
9984
9788
  try {
9985
- return fs7.readFileSync(path7.join(userIssuedRoot(), hash(claimed.slice(0, cut)), hash(claimed)), "utf8");
9789
+ return fs6.readFileSync(path6.join(userIssuedRoot(), hash(claimed.slice(0, cut)), hash(claimed)), "utf8");
9986
9790
  } catch {
9987
9791
  return null;
9988
9792
  }
@@ -9992,9 +9796,9 @@ var issuedToken = (claimed) => {
9992
9796
  const cut = claimed.lastIndexOf(":");
9993
9797
  if (cut <= 0)
9994
9798
  return { stored: null, leadBound: false };
9995
- const dir = path7.join(userTokenRoot(), hash(claimed.slice(0, cut)));
9799
+ const dir = path6.join(userTokenRoot(), hash(claimed.slice(0, cut)));
9996
9800
  try {
9997
- const text = fs7.readFileSync(path7.join(dir, hash(claimed)), "utf8");
9801
+ const text = fs6.readFileSync(path6.join(dir, hash(claimed)), "utf8");
9998
9802
  return { stored: TOKEN_HASH.exec(text)?.[1] ?? null, leadBound: true };
9999
9803
  } catch {
10000
9804
  return { stored: null, leadBound: safeList(dir).length > 0 };
@@ -10013,21 +9817,21 @@ var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
10013
9817
 
10014
9818
  // packages/workit-core/src/core/package-root.ts
10015
9819
  import { existsSync } from "node:fs";
10016
- import path8 from "node:path";
9820
+ import path7 from "node:path";
10017
9821
  import { fileURLToPath } from "node:url";
10018
9822
  var packageRoot = () => {
10019
- let dir = path8.dirname(fileURLToPath(import.meta.url));
9823
+ let dir = path7.dirname(fileURLToPath(import.meta.url));
10020
9824
  while (true) {
10021
- const parent = path8.dirname(dir);
10022
- if (existsSync(path8.join(dir, "package.json")) || parent === dir)
9825
+ const parent = path7.dirname(dir);
9826
+ if (existsSync(path7.join(dir, "package.json")) || parent === dir)
10023
9827
  return dir;
10024
9828
  dir = parent;
10025
9829
  }
10026
9830
  };
10027
9831
 
10028
9832
  // packages/workit-core/src/core/store-lock.ts
10029
- import { spawnSync as spawnSync4 } from "node:child_process";
10030
- import fs8 from "node:fs";
9833
+ import { spawnSync as spawnSync3 } from "node:child_process";
9834
+ import fs7 from "node:fs";
10031
9835
  import { hostname } from "node:os";
10032
9836
  var metadataLockSchema = object({
10033
9837
  pid: number2().int().nonnegative().safe(),
@@ -10071,14 +9875,14 @@ var parseProcStatStart = (stat) => {
10071
9875
  var processStartOf = (pid) => {
10072
9876
  if (process.platform === "linux") {
10073
9877
  try {
10074
- return parseProcStatStart(fs8.readFileSync(`/proc/${pid}/stat`, "utf8"));
9878
+ return parseProcStatStart(fs7.readFileSync(`/proc/${pid}/stat`, "utf8"));
10075
9879
  } catch {
10076
9880
  return null;
10077
9881
  }
10078
9882
  }
10079
9883
  if (process.platform === "darwin" || process.platform === "freebsd") {
10080
9884
  try {
10081
- const run = spawnSync4("ps", ["-o", "lstart=", "-p", String(pid)], {
9885
+ const run = spawnSync3("ps", ["-o", "lstart=", "-p", String(pid)], {
10082
9886
  encoding: "utf8",
10083
9887
  timeout: 1000
10084
9888
  });
@@ -10092,7 +9896,7 @@ var processStartOf = (pid) => {
10092
9896
  };
10093
9897
  var readTrimmed = (file) => {
10094
9898
  try {
10095
- return fs8.readFileSync(file, "utf8").trim() || null;
9899
+ return fs7.readFileSync(file, "utf8").trim() || null;
10096
9900
  } catch {
10097
9901
  return null;
10098
9902
  }
@@ -10103,7 +9907,7 @@ var localLockHost = () => {
10103
9907
  return cachedLockHost;
10104
9908
  let pidns = null;
10105
9909
  try {
10106
- pidns = /\[(\d+)\]/.exec(fs8.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
9910
+ pidns = /\[(\d+)\]/.exec(fs7.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
10107
9911
  } catch {}
10108
9912
  const boot = readTrimmed("/proc/sys/kernel/random/boot_id");
10109
9913
  cachedLockHost = pidns || boot ? `${hostname()}#${pidns ?? "?"}:${boot ?? "?"}` : hostname();
@@ -10149,7 +9953,7 @@ var classifyLockOwner = (payload, ageMs, localHost = localLockHost(), options =
10149
9953
  };
10150
9954
  var ageOf = (file, nowMs) => {
10151
9955
  try {
10152
- return nowMs - fs8.lstatSync(file).mtimeMs;
9956
+ return nowMs - fs7.lstatSync(file).mtimeMs;
10153
9957
  } catch {
10154
9958
  return null;
10155
9959
  }
@@ -10160,7 +9964,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
10160
9964
  if (age === null || age <= RECLAIM_GUARD_TTL_MS)
10161
9965
  return false;
10162
9966
  try {
10163
- fs8.rmdirSync(guard);
9967
+ fs7.rmdirSync(guard);
10164
9968
  return true;
10165
9969
  } catch {
10166
9970
  return false;
@@ -10169,8 +9973,8 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
10169
9973
 
10170
9974
  // packages/workit-core/src/store/event-log.ts
10171
9975
  import { randomUUID as randomUUID2 } from "node:crypto";
10172
- import fs9 from "node:fs";
10173
- import path9 from "node:path";
9976
+ import fs8 from "node:fs";
9977
+ import path8 from "node:path";
10174
9978
  var EVENT_VERSION = 1;
10175
9979
 
10176
9980
  class LogDamage extends Error {
@@ -10199,7 +10003,7 @@ var parseEvent = (line, file, offset) => {
10199
10003
  function readLog(file, from = 0, expectSeq = null) {
10200
10004
  let fd;
10201
10005
  try {
10202
- fd = fs9.openSync(file, "r");
10006
+ fd = fs8.openSync(file, "r");
10203
10007
  } catch (error) {
10204
10008
  if (error.code === "ENOENT")
10205
10009
  return null;
@@ -10208,13 +10012,13 @@ function readLog(file, from = 0, expectSeq = null) {
10208
10012
  let bytes;
10209
10013
  let size;
10210
10014
  try {
10211
- size = fs9.fstatSync(fd).size;
10015
+ size = fs8.fstatSync(fd).size;
10212
10016
  if (from > size)
10213
10017
  throw new LogDamage(`${file}: shorter than its snapshot`);
10214
10018
  bytes = Buffer.alloc(size - from);
10215
10019
  let read = 0;
10216
10020
  while (read < bytes.length) {
10217
- const got = fs9.readSync(fd, bytes, read, bytes.length - read, from + read);
10021
+ const got = fs8.readSync(fd, bytes, read, bytes.length - read, from + read);
10218
10022
  if (got === 0)
10219
10023
  break;
10220
10024
  read += got;
@@ -10222,7 +10026,7 @@ function readLog(file, from = 0, expectSeq = null) {
10222
10026
  bytes = bytes.subarray(0, read);
10223
10027
  size = from + read;
10224
10028
  } finally {
10225
- fs9.closeSync(fd);
10029
+ fs8.closeSync(fd);
10226
10030
  }
10227
10031
  const events = [];
10228
10032
  let start = 0;
@@ -10247,11 +10051,11 @@ function readLog(file, from = 0, expectSeq = null) {
10247
10051
  }
10248
10052
  var fsyncDirectory = (dir) => {
10249
10053
  try {
10250
- const fd = fs9.openSync(dir, "r");
10054
+ const fd = fs8.openSync(dir, "r");
10251
10055
  try {
10252
- fs9.fsyncSync(fd);
10056
+ fs8.fsyncSync(fd);
10253
10057
  } finally {
10254
- fs9.closeSync(fd);
10058
+ fs8.closeSync(fd);
10255
10059
  }
10256
10060
  } catch (error) {
10257
10061
  if (process.platform !== "win32")
@@ -10261,46 +10065,46 @@ var fsyncDirectory = (dir) => {
10261
10065
  function appendEvent(file, event, validEnd) {
10262
10066
  const line = Buffer.from(`${JSON.stringify(event)}
10263
10067
  `, "utf8");
10264
- const created = !fs9.existsSync(file);
10265
- if (!created && fs9.statSync(file).size !== validEnd) {
10266
- const cut = fs9.openSync(file, "r+");
10068
+ const created = !fs8.existsSync(file);
10069
+ if (!created && fs8.statSync(file).size !== validEnd) {
10070
+ const cut = fs8.openSync(file, "r+");
10267
10071
  try {
10268
- fs9.ftruncateSync(cut, validEnd);
10269
- fs9.fsyncSync(cut);
10072
+ fs8.ftruncateSync(cut, validEnd);
10073
+ fs8.fsyncSync(cut);
10270
10074
  } finally {
10271
- fs9.closeSync(cut);
10075
+ fs8.closeSync(cut);
10272
10076
  }
10273
10077
  }
10274
- const fd = fs9.openSync(file, "a", 384);
10078
+ const fd = fs8.openSync(file, "a", 384);
10275
10079
  try {
10276
10080
  let written = 0;
10277
10081
  while (written < line.length)
10278
- written += fs9.writeSync(fd, line, written, line.length - written);
10279
- fs9.fsyncSync(fd);
10082
+ written += fs8.writeSync(fd, line, written, line.length - written);
10083
+ fs8.fsyncSync(fd);
10280
10084
  } finally {
10281
- fs9.closeSync(fd);
10085
+ fs8.closeSync(fd);
10282
10086
  }
10283
10087
  if (created)
10284
- fsyncDirectory(path9.dirname(file));
10088
+ fsyncDirectory(path8.dirname(file));
10285
10089
  return validEnd;
10286
10090
  }
10287
10091
  function replaceFile(file, bytes, durable) {
10288
10092
  const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
10289
10093
  try {
10290
- const fd = fs9.openSync(temporary, "wx", 384);
10094
+ const fd = fs8.openSync(temporary, "wx", 384);
10291
10095
  try {
10292
- fs9.writeSync(fd, bytes);
10096
+ fs8.writeSync(fd, bytes);
10293
10097
  if (durable)
10294
- fs9.fsyncSync(fd);
10098
+ fs8.fsyncSync(fd);
10295
10099
  } finally {
10296
- fs9.closeSync(fd);
10100
+ fs8.closeSync(fd);
10297
10101
  }
10298
10102
  renameWithRetry(temporary, file);
10299
10103
  if (durable)
10300
- fsyncDirectory(path9.dirname(file));
10104
+ fsyncDirectory(path8.dirname(file));
10301
10105
  } catch (error) {
10302
10106
  try {
10303
- fs9.unlinkSync(temporary);
10107
+ fs8.unlinkSync(temporary);
10304
10108
  } catch {}
10305
10109
  throw error;
10306
10110
  }
@@ -10325,7 +10129,7 @@ var retryTransient = (run) => {
10325
10129
  }
10326
10130
  }
10327
10131
  };
10328
- var renameWithRetry = (from, to) => retryTransient(() => fs9.renameSync(from, to));
10132
+ var renameWithRetry = (from, to) => retryTransient(() => fs8.renameSync(from, to));
10329
10133
 
10330
10134
  // packages/workit-core/src/store/patch.ts
10331
10135
  var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -10622,7 +10426,7 @@ var indexEntry = (task, key, legacy, file) => {
10622
10426
  };
10623
10427
  var fileSignature = (file) => {
10624
10428
  try {
10625
- const stat = fs10.statSync(file, { bigint: true });
10429
+ const stat = fs9.statSync(file, { bigint: true });
10626
10430
  return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
10627
10431
  } catch {
10628
10432
  return null;
@@ -10640,7 +10444,7 @@ var cachedRuntimeVersion = null;
10640
10444
  var runtimeVersion = () => {
10641
10445
  if (cachedRuntimeVersion === null) {
10642
10446
  try {
10643
- const pkg = JSON.parse(fs10.readFileSync(path10.join(packageRoot(), "package.json"), "utf8"));
10447
+ const pkg = JSON.parse(fs9.readFileSync(path9.join(packageRoot(), "package.json"), "utf8"));
10644
10448
  cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
10645
10449
  } catch {
10646
10450
  cachedRuntimeVersion = "0.0.0";
@@ -10666,14 +10470,14 @@ var isNewerVersion = (candidate, current) => {
10666
10470
  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);
10667
10471
  var readText = (file) => {
10668
10472
  try {
10669
- return fs10.readFileSync(file, "utf8");
10473
+ return fs9.readFileSync(file, "utf8");
10670
10474
  } catch {
10671
10475
  return "";
10672
10476
  }
10673
10477
  };
10674
10478
  var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
10675
10479
  var branchStart = (location, branch, aliases) => {
10676
- const first = readText(path10.join(path10.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
10480
+ const first = readText(path9.join(path9.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
10677
10481
  `, 1)[0];
10678
10482
  const created = REFLOG_LINE.exec(first);
10679
10483
  const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
@@ -10683,7 +10487,7 @@ var branchStart = (location, branch, aliases) => {
10683
10487
  return start;
10684
10488
  if (!location.git)
10685
10489
  return null;
10686
- for (const line of readText(path10.join(location.git.gitDir, "logs", "HEAD")).split(`
10490
+ for (const line of readText(path9.join(location.git.gitDir, "logs", "HEAD")).split(`
10687
10491
  `)) {
10688
10492
  const entry = REFLOG_LINE.exec(line);
10689
10493
  const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
@@ -10693,23 +10497,23 @@ var branchStart = (location, branch, aliases) => {
10693
10497
  }
10694
10498
  return null;
10695
10499
  };
10696
- var refExists = (common, ref) => fs10.existsSync(path10.join(common, ref)) || readText(path10.join(common, "packed-refs")).includes(` ${ref}
10500
+ var refExists = (common, ref) => fs9.existsSync(path9.join(common, ref)) || readText(path9.join(common, "packed-refs")).includes(` ${ref}
10697
10501
  `);
10698
10502
  var origins = new Map;
10699
10503
  var sameDirectoryIdentity = (left, right) => {
10700
- if (!path10.isAbsolute(left) || !path10.isAbsolute(right))
10504
+ if (!path9.isAbsolute(left) || !path9.isAbsolute(right))
10701
10505
  return false;
10702
- const normalizedLeft = path10.resolve(left);
10703
- const normalizedRight = path10.resolve(right);
10506
+ const normalizedLeft = path9.resolve(left);
10507
+ const normalizedRight = path9.resolve(right);
10704
10508
  try {
10705
- const a = fs10.statSync(normalizedLeft, { bigint: true });
10706
- const b = fs10.statSync(normalizedRight, { bigint: true });
10509
+ const a = fs9.statSync(normalizedLeft, { bigint: true });
10510
+ const b = fs9.statSync(normalizedRight, { bigint: true });
10707
10511
  if (!a.isDirectory() || !b.isDirectory())
10708
10512
  return false;
10709
10513
  if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
10710
10514
  return true;
10711
- const canonicalLeft = fs10.realpathSync(normalizedLeft);
10712
- const canonicalRight = fs10.realpathSync(normalizedRight);
10515
+ const canonicalLeft = fs9.realpathSync(normalizedLeft);
10516
+ const canonicalRight = fs9.realpathSync(normalizedRight);
10713
10517
  if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
10714
10518
  return true;
10715
10519
  return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
@@ -10746,8 +10550,8 @@ class TaskStore {
10746
10550
  migrationChecked = false;
10747
10551
  compactDue = new Set;
10748
10552
  constructor(root, options = {}) {
10749
- const resolved = path10.resolve(root);
10750
- this.origin = fs10.existsSync(resolved) ? fs10.realpathSync(resolved) : resolved;
10553
+ const resolved = path9.resolve(root);
10554
+ this.origin = fs9.existsSync(resolved) ? fs9.realpathSync(resolved) : resolved;
10751
10555
  this.located = resolveStore(this.origin);
10752
10556
  this.root = checkoutRootOf(this.origin, this.located);
10753
10557
  this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
@@ -10755,7 +10559,7 @@ class TaskStore {
10755
10559
  this.migrateOnRead = options.migrateOnRead;
10756
10560
  }
10757
10561
  location() {
10758
- if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs10.existsSync(path10.join(this.root, ".git"))) {
10562
+ if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs9.existsSync(path9.join(this.root, ".git"))) {
10759
10563
  this.located = undefined;
10760
10564
  this.migrationChecked = false;
10761
10565
  }
@@ -10819,7 +10623,7 @@ class TaskStore {
10819
10623
  const tasksDir = this.paths().tasks;
10820
10624
  let names;
10821
10625
  try {
10822
- names = fs10.existsSync(tasksDir) ? fs10.readdirSync(tasksDir).filter((name) => validId(name)) : [];
10626
+ names = fs9.existsSync(tasksDir) ? fs9.readdirSync(tasksDir).filter((name) => validId(name)) : [];
10823
10627
  } catch (error) {
10824
10628
  return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
10825
10629
  path: tasksDir
@@ -10860,7 +10664,7 @@ class TaskStore {
10860
10664
  const file = this.paths().workspace;
10861
10665
  let bytes;
10862
10666
  try {
10863
- bytes = retryTransient(() => fs10.readFileSync(file, "utf8"));
10667
+ bytes = retryTransient(() => fs9.readFileSync(file, "utf8"));
10864
10668
  } catch (error) {
10865
10669
  if (error.code === "ENOENT")
10866
10670
  return success(null, null, null);
@@ -10911,7 +10715,7 @@ class TaskStore {
10911
10715
  const moved = this.bindLocked(again.data.id, key, input.now);
10912
10716
  return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
10913
10717
  }
10914
- const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path10.basename(this.root) || this.root;
10718
+ const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path9.basename(this.root) || this.root;
10915
10719
  const intent = {
10916
10720
  objective: input.objective?.trim() || `Work on ${label}`,
10917
10721
  scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
@@ -10977,14 +10781,14 @@ class TaskStore {
10977
10781
  const branch = key.ok ? key.data.branch : null;
10978
10782
  if (!branch || !location.ok)
10979
10783
  return success(null, null, null);
10980
- const common = path10.dirname(location.data.dir);
10981
- const heads = path10.join(common, "logs", "refs", "heads");
10982
- const headLog = location.data.git ? path10.join(location.data.git.gitDir, "logs", "HEAD") : "";
10784
+ const common = path9.dirname(location.data.dir);
10785
+ const heads = path9.join(common, "logs", "refs", "heads");
10786
+ const headLog = location.data.git ? path9.join(location.data.git.gitDir, "logs", "HEAD") : "";
10983
10787
  const signatures = [
10984
- path10.join(heads, branch),
10788
+ path9.join(heads, branch),
10985
10789
  headLog,
10986
10790
  heads,
10987
- path10.join(common, "packed-refs")
10791
+ path9.join(common, "packed-refs")
10988
10792
  ].map((file) => fileSignature(file) ?? "-");
10989
10793
  const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
10990
10794
  let resolved = origins.get(slot);
@@ -10996,7 +10800,7 @@ class TaskStore {
10996
10800
  aliases.push(rename.from);
10997
10801
  const start = branchStart(location.data, branch, aliases);
10998
10802
  const slash = start?.indexOf("/") ?? -1;
10999
- const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path10.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
10803
+ const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path9.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
11000
10804
  const name = start && (remote ? start.slice(slash + 1) : start);
11001
10805
  resolved = {
11002
10806
  signature: signatures.join("|"),
@@ -11234,13 +11038,13 @@ class TaskStore {
11234
11038
  if (!ready.ok)
11235
11039
  return ready;
11236
11040
  const dirs = this.paths();
11237
- const recovery = path10.join(this.root, ".workit", "recovery");
11238
- if (fs10.existsSync(recovery)) {
11041
+ const recovery = path9.join(this.root, ".workit", "recovery");
11042
+ if (fs9.existsSync(recovery)) {
11239
11043
  let files = 0;
11240
11044
  let bytes = 0;
11241
11045
  try {
11242
- for (const name of fs10.readdirSync(recovery)) {
11243
- const stat = fs10.lstatSync(path10.join(recovery, name));
11046
+ for (const name of fs9.readdirSync(recovery)) {
11047
+ const stat = fs9.lstatSync(path9.join(recovery, name));
11244
11048
  if (!stat.isFile())
11245
11049
  continue;
11246
11050
  files += 1;
@@ -11249,17 +11053,17 @@ class TaskStore {
11249
11053
  } catch {}
11250
11054
  const remove = options.pruneRecovery === true && !dryRun;
11251
11055
  if (remove)
11252
- fs10.rmSync(recovery, { recursive: true, force: true });
11056
+ fs9.rmSync(recovery, { recursive: true, force: true });
11253
11057
  report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
11254
11058
  }
11255
- if (!fs10.existsSync(dirs.tasks))
11059
+ if (!fs9.existsSync(dirs.tasks))
11256
11060
  return success(null, null, report);
11257
- const names = fs10.readdirSync(dirs.tasks).filter((name) => validId(name));
11061
+ const names = fs9.readdirSync(dirs.tasks).filter((name) => validId(name));
11258
11062
  for (const name of names) {
11259
11063
  const file = this.eventsPath(name);
11260
11064
  let size = 0;
11261
11065
  try {
11262
- size = fs10.statSync(file).size;
11066
+ size = fs9.statSync(file).size;
11263
11067
  } catch {
11264
11068
  continue;
11265
11069
  }
@@ -11287,16 +11091,16 @@ class TaskStore {
11287
11091
  const references = new Set;
11288
11092
  for (const name of names)
11289
11093
  try {
11290
- for (const match of fs10.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
11094
+ for (const match of fs9.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
11291
11095
  references.add(match[1]);
11292
11096
  } catch {}
11293
- if (fs10.existsSync(dirs.blobs))
11294
- for (const name of fs10.readdirSync(dirs.blobs)) {
11097
+ if (fs9.existsSync(dirs.blobs))
11098
+ for (const name of fs9.readdirSync(dirs.blobs)) {
11295
11099
  const digest = name.replace(/\.json$/, "");
11296
- const file = path10.join(dirs.blobs, name);
11100
+ const file = path9.join(dirs.blobs, name);
11297
11101
  let stat;
11298
11102
  try {
11299
- stat = fs10.lstatSync(file);
11103
+ stat = fs9.lstatSync(file);
11300
11104
  } catch {
11301
11105
  continue;
11302
11106
  }
@@ -11307,11 +11111,11 @@ class TaskStore {
11307
11111
  report.blobs.removed += 1;
11308
11112
  report.blobs.removedBytes += stat.size;
11309
11113
  if (!dryRun)
11310
- fs10.rmSync(file, { force: true });
11114
+ fs9.rmSync(file, { force: true });
11311
11115
  }
11312
11116
  return success(null, null, null);
11313
11117
  };
11314
- const swept = dryRun ? sweep() : this.withLock(path10.join(dirs.dir, "gc.lock"), sweep);
11118
+ const swept = dryRun ? sweep() : this.withLock(path9.join(dirs.dir, "gc.lock"), sweep);
11315
11119
  if (!swept.ok)
11316
11120
  return swept;
11317
11121
  const temporaryDirs = [
@@ -11319,17 +11123,17 @@ class TaskStore {
11319
11123
  dirs.tasks,
11320
11124
  dirs.blobs,
11321
11125
  dirs.checkout,
11322
- ...names.map((name) => path10.join(dirs.tasks, name))
11126
+ ...names.map((name) => path9.join(dirs.tasks, name))
11323
11127
  ];
11324
11128
  for (const directory of temporaryDirs) {
11325
- if (!fs10.existsSync(directory))
11129
+ if (!fs9.existsSync(directory))
11326
11130
  continue;
11327
- for (const name of fs10.readdirSync(directory)) {
11131
+ for (const name of fs9.readdirSync(directory)) {
11328
11132
  if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
11329
11133
  continue;
11330
- const file = path10.join(directory, name);
11134
+ const file = path9.join(directory, name);
11331
11135
  try {
11332
- const stat = fs10.lstatSync(file);
11136
+ const stat = fs9.lstatSync(file);
11333
11137
  if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
11334
11138
  continue;
11335
11139
  } catch {
@@ -11337,37 +11141,37 @@ class TaskStore {
11337
11141
  }
11338
11142
  report.temporary.removed += 1;
11339
11143
  if (!dryRun)
11340
- fs10.rmSync(file, { force: true });
11144
+ fs9.rmSync(file, { force: true });
11341
11145
  }
11342
11146
  }
11343
11147
  return success(null, null, report);
11344
11148
  }
11345
11149
  paths() {
11346
11150
  const location = this.location();
11347
- const dir = location.ok ? location.data.dir : path10.join(this.root, ".workit");
11348
- const checkout = path10.join(dir, "checkouts", checkoutSlug(this.root));
11151
+ const dir = location.ok ? location.data.dir : path9.join(this.root, ".workit");
11152
+ const checkout = path9.join(dir, "checkouts", checkoutSlug(this.root));
11349
11153
  return {
11350
11154
  dir,
11351
11155
  shared: location.ok ? location.data.shared : false,
11352
- marker: path10.join(dir, "store.json"),
11156
+ marker: path9.join(dir, "store.json"),
11353
11157
  checkout,
11354
- workspace: path10.join(checkout, "workspace.json"),
11355
- checkoutLock: path10.join(checkout, "metadata.lock"),
11356
- tasks: path10.join(dir, "tasks"),
11357
- index: path10.join(dir, "task-index.json"),
11358
- blobs: path10.join(dir, "blobs", "candidates"),
11359
- legacy: path10.join(dir, "legacy", checkoutSlug(this.root), "v2"),
11360
- v2: path10.join(this.root, ".workit")
11158
+ workspace: path9.join(checkout, "workspace.json"),
11159
+ checkoutLock: path9.join(checkout, "metadata.lock"),
11160
+ tasks: path9.join(dir, "tasks"),
11161
+ index: path9.join(dir, "task-index.json"),
11162
+ blobs: path9.join(dir, "blobs", "candidates"),
11163
+ legacy: path9.join(dir, "legacy", checkoutSlug(this.root), "v2"),
11164
+ v2: path9.join(this.root, ".workit")
11361
11165
  };
11362
11166
  }
11363
11167
  eventsPath(taskId) {
11364
- return path10.join(this.paths().tasks, taskId, "events.jsonl");
11168
+ return path9.join(this.paths().tasks, taskId, "events.jsonl");
11365
11169
  }
11366
11170
  snapshotPath(taskId) {
11367
- return path10.join(this.paths().tasks, taskId, "snapshot.json");
11171
+ return path9.join(this.paths().tasks, taskId, "snapshot.json");
11368
11172
  }
11369
11173
  taskLockPath(taskId) {
11370
- return path10.join(this.paths().tasks, taskId, "lock");
11174
+ return path9.join(this.paths().tasks, taskId, "lock");
11371
11175
  }
11372
11176
  ready(write = false) {
11373
11177
  const location = this.location();
@@ -11377,7 +11181,7 @@ class TaskStore {
11377
11181
  return success(null, null, null);
11378
11182
  const dirs = this.paths();
11379
11183
  try {
11380
- const marker = JSON.parse(fs10.readFileSync(dirs.marker, "utf8"));
11184
+ const marker = JSON.parse(fs9.readFileSync(dirs.marker, "utf8"));
11381
11185
  if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
11382
11186
  return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
11383
11187
  } catch {}
@@ -11406,21 +11210,21 @@ class TaskStore {
11406
11210
  return {
11407
11211
  read: (digest) => {
11408
11212
  try {
11409
- return JSON.parse(fs10.readFileSync(path10.join(dir, `${digest}.json`), "utf8"));
11213
+ return JSON.parse(fs9.readFileSync(path9.join(dir, `${digest}.json`), "utf8"));
11410
11214
  } catch (error) {
11411
11215
  throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
11412
11216
  }
11413
11217
  },
11414
11218
  write: (digest, value) => {
11415
- const file = path10.join(dir, `${digest}.json`);
11416
- if (fs10.existsSync(file)) {
11219
+ const file = path9.join(dir, `${digest}.json`);
11220
+ if (fs9.existsSync(file)) {
11417
11221
  const stamp = new Date;
11418
11222
  try {
11419
- fs10.utimesSync(file, stamp, stamp);
11223
+ fs9.utimesSync(file, stamp, stamp);
11420
11224
  return;
11421
11225
  } catch {}
11422
11226
  }
11423
- fs10.mkdirSync(dir, { recursive: true });
11227
+ fs9.mkdirSync(dir, { recursive: true });
11424
11228
  replaceFile(file, JSON.stringify(value), true);
11425
11229
  }
11426
11230
  };
@@ -11502,7 +11306,7 @@ class TaskStore {
11502
11306
  }
11503
11307
  readSnapshot(taskId) {
11504
11308
  try {
11505
- const value = JSON.parse(fs10.readFileSync(this.snapshotPath(taskId), "utf8"));
11309
+ const value = JSON.parse(fs9.readFileSync(this.snapshotPath(taskId), "utf8"));
11506
11310
  if (!isObject4(value) || value.v !== 1 || value.task !== taskId || typeof value.seq !== "number" || typeof value.lastId !== "string" || typeof value.lastStart !== "number" || typeof value.end !== "number" || !isObject4(value.record))
11507
11311
  return null;
11508
11312
  return value;
@@ -11604,8 +11408,8 @@ class TaskStore {
11604
11408
  }
11605
11409
  }
11606
11410
  openTask(record, type, key, legacy = null) {
11607
- const dir = path10.join(this.paths().tasks, record.id);
11608
- fs10.mkdirSync(dir, { recursive: true });
11411
+ const dir = path9.join(this.paths().tasks, record.id);
11412
+ fs9.mkdirSync(dir, { recursive: true });
11609
11413
  const blobs = this.blobStore();
11610
11414
  const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
11611
11415
  const event = this.event(record.id, 1, type, {
@@ -11657,11 +11461,11 @@ class TaskStore {
11657
11461
  } catch {}
11658
11462
  if (!latest || latest.events[0]?.id !== last.id)
11659
11463
  return failure2("busy", "the task log changed during compaction; retry", { taskId });
11660
- const appended = fs10.readFileSync(file).subarray(log.end, latest.end);
11464
+ const appended = fs9.readFileSync(file).subarray(log.end, latest.end);
11661
11465
  const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
11662
11466
  replaceFile(file, bytes.toString("utf8"), true);
11663
11467
  try {
11664
- fs10.rmSync(this.snapshotPath(taskId), { force: true });
11468
+ fs9.rmSync(this.snapshotPath(taskId), { force: true });
11665
11469
  } catch {}
11666
11470
  const reloaded = this.load(taskId);
11667
11471
  if (reloaded.ok && reloaded.data)
@@ -11674,7 +11478,7 @@ class TaskStore {
11674
11478
  }
11675
11479
  countEvents(file) {
11676
11480
  try {
11677
- const bytes = fs10.readFileSync(file);
11481
+ const bytes = fs9.readFileSync(file);
11678
11482
  let count = 0;
11679
11483
  for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
11680
11484
  count += 1;
@@ -11697,7 +11501,7 @@ class TaskStore {
11697
11501
  }
11698
11502
  withKeyLock(key, operation) {
11699
11503
  const digest = createHash6("sha256").update(key).digest("hex").slice(0, 32);
11700
- return this.withLock(path10.join(this.paths().dir, "keys", `${digest}.lock`), operation);
11504
+ return this.withLock(path9.join(this.paths().dir, "keys", `${digest}.lock`), operation);
11701
11505
  }
11702
11506
  bindLocked(taskId, key, timestamp) {
11703
11507
  const current = this.readWorkspace();
@@ -11838,7 +11642,7 @@ class TaskStore {
11838
11642
  writeWorkspace(record) {
11839
11643
  const file = this.paths().workspace;
11840
11644
  try {
11841
- fs10.mkdirSync(path10.dirname(file), { recursive: true });
11645
+ fs9.mkdirSync(path9.dirname(file), { recursive: true });
11842
11646
  replaceFile(file, `${canonicalJson(record)}
11843
11647
  `, true);
11844
11648
  return success(null, null, null);
@@ -11848,7 +11652,7 @@ class TaskStore {
11848
11652
  }
11849
11653
  readIndex() {
11850
11654
  try {
11851
- const value = JSON.parse(fs10.readFileSync(this.paths().index, "utf8"));
11655
+ const value = JSON.parse(fs9.readFileSync(this.paths().index, "utf8"));
11852
11656
  if (!isObject4(value) || value.version !== INDEX_VERSION || !isObject4(value.tasks))
11853
11657
  return {};
11854
11658
  const tasks = {};
@@ -11862,7 +11666,7 @@ class TaskStore {
11862
11666
  }
11863
11667
  writeIndex(entries) {
11864
11668
  try {
11865
- fs10.mkdirSync(this.paths().tasks, { recursive: true });
11669
+ fs9.mkdirSync(this.paths().tasks, { recursive: true });
11866
11670
  replaceFile(this.paths().index, JSON.stringify({
11867
11671
  version: INDEX_VERSION,
11868
11672
  tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
@@ -11916,23 +11720,23 @@ class TaskStore {
11916
11720
  return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
11917
11721
  }
11918
11722
  v2Dirs() {
11919
- return [...new Set([this.root, this.origin])].map((dir) => path10.join(dir, ".workit"));
11723
+ return [...new Set([this.root, this.origin])].map((dir) => path9.join(dir, ".workit"));
11920
11724
  }
11921
11725
  pendingMigrations() {
11922
11726
  return this.v2Dirs().filter((dir) => {
11923
- const raw = this.readV2Workspace(path10.join(dir, "workspace.json"));
11727
+ const raw = this.readV2Workspace(path9.join(dir, "workspace.json"));
11924
11728
  return raw !== null && raw !== TOMBSTONE;
11925
11729
  });
11926
11730
  }
11927
11731
  migrateV2(v2) {
11928
11732
  const dirs = this.paths();
11929
- const v2Workspace = path10.join(v2, "workspace.json");
11930
- const v2Tasks = path10.join(v2, "tasks");
11931
- const legacy = path10.join(dirs.dir, "legacy", checkoutSlug(path10.dirname(v2)), "v2");
11733
+ const v2Workspace = path9.join(v2, "workspace.json");
11734
+ const v2Tasks = path9.join(v2, "tasks");
11735
+ const legacy = path9.join(dirs.dir, "legacy", checkoutSlug(path9.dirname(v2)), "v2");
11932
11736
  const raw = this.readV2Workspace(v2Workspace);
11933
11737
  if (raw === null || raw === TOMBSTONE)
11934
11738
  return success(null, null, null);
11935
- return this.withLock(dirs.checkoutLock, () => this.withLock(path10.join(v2, "metadata.lock"), () => {
11739
+ return this.withLock(dirs.checkoutLock, () => this.withLock(path9.join(v2, "metadata.lock"), () => {
11936
11740
  const workspace = this.readV2Workspace(v2Workspace);
11937
11741
  if (workspace === null || workspace === TOMBSTONE)
11938
11742
  return success(null, null, null);
@@ -11941,7 +11745,7 @@ class TaskStore {
11941
11745
  return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
11942
11746
  let files = [];
11943
11747
  try {
11944
- files = fs10.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path10.join(v2Tasks, name)));
11748
+ files = fs9.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path9.join(v2Tasks, name)));
11945
11749
  } catch {}
11946
11750
  const current = this.readWorkspace();
11947
11751
  if (!current.ok)
@@ -11959,22 +11763,22 @@ class TaskStore {
11959
11763
  let skipped = 0;
11960
11764
  const done = new Map;
11961
11765
  try {
11962
- fs10.mkdirSync(path10.join(legacy, "tasks"), { recursive: true });
11766
+ fs9.mkdirSync(path9.join(legacy, "tasks"), { recursive: true });
11963
11767
  for (const name of ["workspace.json", "index.json"])
11964
- if (fs10.existsSync(path10.join(v2, name)))
11965
- fs10.copyFileSync(path10.join(v2, name), path10.join(legacy, name));
11768
+ if (fs9.existsSync(path9.join(v2, name)))
11769
+ fs9.copyFileSync(path9.join(v2, name), path9.join(legacy, name));
11966
11770
  for (const name of files) {
11967
11771
  const id = name.slice(0, -5);
11968
- const file = path10.join(v2Tasks, name);
11969
- const bytes = fs10.readFileSync(file, "utf8");
11772
+ const file = path9.join(v2Tasks, name);
11773
+ const bytes = fs9.readFileSync(file, "utf8");
11970
11774
  const digest = sha256(bytes);
11971
- fs10.writeFileSync(path10.join(legacy, "tasks", name), bytes);
11775
+ fs9.writeFileSync(path9.join(legacy, "tasks", name), bytes);
11972
11776
  const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
11973
11777
  if (!parsed.ok || parsed.data.id !== id)
11974
11778
  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 });
11975
11779
  const record = { ...parsed.data, workspaceId: target.id };
11976
- const origin = { path: path10.join(legacy, "tasks", name), digest };
11977
- if (!fs10.existsSync(this.eventsPath(id))) {
11780
+ const origin = { path: path9.join(legacy, "tasks", name), digest };
11781
+ if (!fs9.existsSync(this.eventsPath(id))) {
11978
11782
  this.openTask(record, "migrated.from_v2", null, origin);
11979
11783
  migrated += 1;
11980
11784
  } else {
@@ -12009,8 +11813,8 @@ class TaskStore {
12009
11813
  try {
12010
11814
  let complete = true;
12011
11815
  for (const [name, digest] of done) {
12012
- const file = path10.join(v2Tasks, name);
12013
- if (sha256(fs10.readFileSync(file, "utf8")) !== digest) {
11816
+ const file = path9.join(v2Tasks, name);
11817
+ if (sha256(fs9.readFileSync(file, "utf8")) !== digest) {
12014
11818
  complete = false;
12015
11819
  continue;
12016
11820
  }
@@ -12020,7 +11824,7 @@ class TaskStore {
12020
11824
  return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
12021
11825
  path: v2
12022
11826
  });
12023
- fs10.rmSync(path10.join(v2, "index.json"), { force: true });
11827
+ fs9.rmSync(path9.join(v2, "index.json"), { force: true });
12024
11828
  this.writeTombstone(v2, target.id);
12025
11829
  } catch (error) {
12026
11830
  return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
@@ -12040,45 +11844,45 @@ class TaskStore {
12040
11844
  }
12041
11845
  adoptLocalStore() {
12042
11846
  const dirs = this.paths();
12043
- const marker = path10.join(dirs.v2, "store.json");
12044
- if (!dirs.shared || !fs10.existsSync(marker))
11847
+ const marker = path9.join(dirs.v2, "store.json");
11848
+ if (!dirs.shared || !fs9.existsSync(marker))
12045
11849
  return success(null, null, null);
12046
11850
  return this.withLock(dirs.checkoutLock, () => {
12047
- if (!fs10.existsSync(marker))
11851
+ if (!fs9.existsSync(marker))
12048
11852
  return success(null, null, null);
12049
11853
  let tasks = 0;
12050
11854
  try {
12051
11855
  const merge = (from, to) => {
12052
- if (!fs10.existsSync(to)) {
12053
- fs10.mkdirSync(path10.dirname(to), { recursive: true });
11856
+ if (!fs9.existsSync(to)) {
11857
+ fs9.mkdirSync(path9.dirname(to), { recursive: true });
12054
11858
  try {
12055
- fs10.renameSync(from, to);
11859
+ fs9.renameSync(from, to);
12056
11860
  } catch {
12057
- fs10.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
12058
- fs10.rmSync(from, { recursive: true, force: true });
11861
+ fs9.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
11862
+ fs9.rmSync(from, { recursive: true, force: true });
12059
11863
  }
12060
11864
  return;
12061
11865
  }
12062
- if (fs10.lstatSync(from).isDirectory() && fs10.lstatSync(to).isDirectory())
12063
- for (const name of fs10.readdirSync(from))
12064
- merge(path10.join(from, name), path10.join(to, name));
11866
+ if (fs9.lstatSync(from).isDirectory() && fs9.lstatSync(to).isDirectory())
11867
+ for (const name of fs9.readdirSync(from))
11868
+ merge(path9.join(from, name), path9.join(to, name));
12065
11869
  };
12066
11870
  for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
12067
- const from = path10.join(dirs.v2, sub);
12068
- if (!fs10.existsSync(from))
11871
+ const from = path9.join(dirs.v2, sub);
11872
+ if (!fs9.existsSync(from))
12069
11873
  continue;
12070
11874
  if (sub === "tasks") {
12071
- for (const name of fs10.readdirSync(from))
12072
- if (validId(name) && !fs10.existsSync(path10.join(dirs.dir, sub, name)))
11875
+ for (const name of fs9.readdirSync(from))
11876
+ if (validId(name) && !fs9.existsSync(path9.join(dirs.dir, sub, name)))
12073
11877
  tasks += 1;
12074
11878
  }
12075
- merge(from, path10.join(dirs.dir, sub));
11879
+ merge(from, path9.join(dirs.dir, sub));
12076
11880
  }
12077
- const ledger = path10.join(dirs.v2, "ledger");
12078
- if (fs10.existsSync(ledger) && !fs10.existsSync(path10.join(dirs.dir, "ledger")))
12079
- merge(ledger, path10.join(dirs.dir, "ledger"));
12080
- fs10.rmSync(path10.join(dirs.v2, "task-index.json"), { force: true });
12081
- fs10.renameSync(marker, path10.join(dirs.v2, "store.moved.json"));
11881
+ const ledger = path9.join(dirs.v2, "ledger");
11882
+ if (fs9.existsSync(ledger) && !fs9.existsSync(path9.join(dirs.dir, "ledger")))
11883
+ merge(ledger, path9.join(dirs.dir, "ledger"));
11884
+ fs9.rmSync(path9.join(dirs.v2, "task-index.json"), { force: true });
11885
+ fs9.renameSync(marker, path9.join(dirs.v2, "store.moved.json"));
12082
11886
  } catch (error) {
12083
11887
  return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
12084
11888
  path: dirs.v2
@@ -12098,7 +11902,7 @@ class TaskStore {
12098
11902
  readV2Workspace(file) {
12099
11903
  let bytes;
12100
11904
  try {
12101
- bytes = fs10.readFileSync(file, "utf8");
11905
+ bytes = fs9.readFileSync(file, "utf8");
12102
11906
  } catch {
12103
11907
  return null;
12104
11908
  }
@@ -12116,7 +11920,7 @@ class TaskStore {
12116
11920
  schemaVersion: SCHEMA_VERSION,
12117
11921
  id: workspaceId ?? newId(),
12118
11922
  revision: newRevision(),
12119
- root: path10.dirname(v2),
11923
+ root: path9.dirname(v2),
12120
11924
  runtime: { createdWith: version, updatedWith: version },
12121
11925
  writer: null,
12122
11926
  store: {
@@ -12127,12 +11931,12 @@ class TaskStore {
12127
11931
  },
12128
11932
  critical: ["store"]
12129
11933
  };
12130
- fs10.mkdirSync(v2, { recursive: true });
12131
- const ignore = path10.join(v2, ".gitignore");
12132
- if (!fs10.existsSync(ignore))
12133
- fs10.writeFileSync(ignore, `*
11934
+ fs9.mkdirSync(v2, { recursive: true });
11935
+ const ignore = path9.join(v2, ".gitignore");
11936
+ if (!fs9.existsSync(ignore))
11937
+ fs9.writeFileSync(ignore, `*
12134
11938
  `);
12135
- replaceFile(path10.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
11939
+ replaceFile(path9.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
12136
11940
  `, true);
12137
11941
  }
12138
11942
  stubFor(taskId) {
@@ -12148,7 +11952,7 @@ class TaskStore {
12148
11952
  }
12149
11953
  isStub(file) {
12150
11954
  try {
12151
- const value = JSON.parse(fs10.readFileSync(file, "utf8"));
11955
+ const value = JSON.parse(fs9.readFileSync(file, "utf8"));
12152
11956
  return isObject4(value) && isObject4(value.store) && value.store.format === "workit-store";
12153
11957
  } catch {
12154
11958
  return false;
@@ -12156,32 +11960,32 @@ class TaskStore {
12156
11960
  }
12157
11961
  writeTombstoneIfMissing() {
12158
11962
  try {
12159
- const v2 = path10.join(this.root, ".workit");
12160
- if (fs10.existsSync(path10.join(v2, "workspace.json")))
11963
+ const v2 = path9.join(this.root, ".workit");
11964
+ if (fs9.existsSync(path9.join(v2, "workspace.json")))
12161
11965
  return;
12162
11966
  let id = null;
12163
11967
  try {
12164
- id = JSON.parse(fs10.readFileSync(this.paths().workspace, "utf8")).id ?? null;
11968
+ id = JSON.parse(fs9.readFileSync(this.paths().workspace, "utf8")).id ?? null;
12165
11969
  } catch {}
12166
11970
  this.writeTombstone(v2, id);
12167
11971
  } catch {}
12168
11972
  }
12169
11973
  initializeStorage() {
12170
11974
  const dirs = this.paths();
12171
- retryTransient(() => fs10.mkdirSync(dirs.checkout, { recursive: true }));
12172
- retryTransient(() => fs10.mkdirSync(dirs.tasks, { recursive: true }));
12173
- if (!fs10.existsSync(dirs.marker))
11975
+ retryTransient(() => fs9.mkdirSync(dirs.checkout, { recursive: true }));
11976
+ retryTransient(() => fs9.mkdirSync(dirs.tasks, { recursive: true }));
11977
+ if (!fs9.existsSync(dirs.marker))
12174
11978
  replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
12175
11979
  `, false);
12176
11980
  if (!dirs.shared) {
12177
- const ignore = path10.join(dirs.dir, ".gitignore");
11981
+ const ignore = path9.join(dirs.dir, ".gitignore");
12178
11982
  let current = null;
12179
11983
  try {
12180
- current = fs10.readFileSync(ignore, "utf8");
11984
+ current = fs9.readFileSync(ignore, "utf8");
12181
11985
  } catch {}
12182
11986
  if (current !== `*
12183
11987
  `)
12184
- retryTransient(() => fs10.writeFileSync(ignore, `*
11988
+ retryTransient(() => fs9.writeFileSync(ignore, `*
12185
11989
  `));
12186
11990
  }
12187
11991
  this.writeTombstoneIfMissing();
@@ -12197,7 +12001,7 @@ class TaskStore {
12197
12001
  shouldReclaim: ({ payload, nowMs }) => {
12198
12002
  let ageMs = null;
12199
12003
  try {
12200
- ageMs = nowMs - fs10.lstatSync(lockPath).mtimeMs;
12004
+ ageMs = nowMs - fs9.lstatSync(lockPath).mtimeMs;
12201
12005
  } catch {}
12202
12006
  return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
12203
12007
  },
@@ -12234,7 +12038,7 @@ class TaskStore {
12234
12038
  withLock(lockPath, operation) {
12235
12039
  try {
12236
12040
  this.initializeStorage();
12237
- fs10.mkdirSync(path10.dirname(lockPath), { recursive: true });
12041
+ fs9.mkdirSync(path9.dirname(lockPath), { recursive: true });
12238
12042
  } catch (error) {
12239
12043
  return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
12240
12044
  path: this.paths().dir
@@ -12274,18 +12078,18 @@ class TaskStore {
12274
12078
  lockDirWritable(lockPath) {
12275
12079
  const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
12276
12080
  try {
12277
- fs10.closeSync(fs10.openSync(probe, "wx", 384));
12081
+ fs9.closeSync(fs9.openSync(probe, "wx", 384));
12278
12082
  } catch {
12279
12083
  return false;
12280
12084
  }
12281
12085
  try {
12282
- fs10.rmSync(probe, { force: true });
12086
+ fs9.rmSync(probe, { force: true });
12283
12087
  } catch {}
12284
12088
  return true;
12285
12089
  }
12286
12090
  lockHolderPresent(lockPath) {
12287
12091
  try {
12288
- fs10.lstatSync(lockPath);
12092
+ fs9.lstatSync(lockPath);
12289
12093
  return true;
12290
12094
  } catch (error) {
12291
12095
  return error?.code !== "ENOENT";
@@ -12297,12 +12101,12 @@ class TaskStore {
12297
12101
  if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
12298
12102
  return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
12299
12103
  path: lockPath,
12300
- guidance: `Check permissions and the read-only attribute on ${path10.dirname(lockPath)}.`
12104
+ guidance: `Check permissions and the read-only attribute on ${path9.dirname(lockPath)}.`
12301
12105
  });
12302
12106
  if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
12303
12107
  let lock = null;
12304
12108
  try {
12305
- lock = parseMetadataLockOrNull(fs10.readFileSync(lockPath, "utf8"));
12109
+ lock = parseMetadataLockOrNull(fs9.readFileSync(lockPath, "utf8"));
12306
12110
  } catch {}
12307
12111
  return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
12308
12112
  outcome: "not_started",
@@ -12317,18 +12121,18 @@ class TaskStore {
12317
12121
 
12318
12122
  // packages/workit-core/src/core/policy/derive.ts
12319
12123
  import { existsSync as existsSync4 } from "node:fs";
12320
- import path15 from "node:path";
12124
+ import path14 from "node:path";
12321
12125
 
12322
12126
  // packages/workit-core/src/ledger.ts
12323
- import { spawnSync as spawnSync9 } from "node:child_process";
12127
+ import { spawnSync as spawnSync8 } from "node:child_process";
12324
12128
  import { createHash as createHash9, randomBytes as randomBytes3 } from "node:crypto";
12325
- import fs12 from "node:fs";
12326
- import path14 from "node:path";
12327
-
12328
- // packages/workit-core/src/core/vcs-config.ts
12329
12129
  import fs11 from "node:fs";
12330
12130
  import path13 from "node:path";
12331
- import { spawnSync as spawnSync8 } from "node:child_process";
12131
+
12132
+ // packages/workit-core/src/core/vcs-config.ts
12133
+ import fs10 from "node:fs";
12134
+ import path12 from "node:path";
12135
+ import { spawnSync as spawnSync7 } from "node:child_process";
12332
12136
 
12333
12137
  // packages/workit-core/src/core/config.ts
12334
12138
  import {
@@ -12341,7 +12145,7 @@ import {
12341
12145
  writeFileSync as writeFileSync2
12342
12146
  } from "node:fs";
12343
12147
  import os3 from "node:os";
12344
- import path11 from "node:path";
12148
+ import path10 from "node:path";
12345
12149
 
12346
12150
  // packages/workit-core/src/core/boundary.ts
12347
12151
  var EVENT = {
@@ -12385,7 +12189,7 @@ var mergePreset = (preset, input = {}, current = {
12385
12189
  protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
12386
12190
  };
12387
12191
  };
12388
- var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path11.join(process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config"), "workit");
12192
+ var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path10.join(process.env.XDG_CONFIG_HOME || path10.join(os3.homedir(), ".config"), "workit");
12389
12193
  var migratedDir = null;
12390
12194
  var migrationFailed = false;
12391
12195
  var ensureConfigDir = (dir = resolveConfigDir()) => {
@@ -12395,7 +12199,7 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
12395
12199
  migratedDir = dir;
12396
12200
  return dir;
12397
12201
  }
12398
- const legacy = path11.join(process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config"), "workflow-toolkit");
12202
+ const legacy = path10.join(process.env.XDG_CONFIG_HOME || path10.join(os3.homedir(), ".config"), "workflow-toolkit");
12399
12203
  if (!existsSync3(legacy)) {
12400
12204
  migratedDir = dir;
12401
12205
  return dir;
@@ -12408,8 +12212,8 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
12408
12212
  mkdirSync2(dir, { recursive: true });
12409
12213
  diagnosticLogger?.info(EVENT.migration, { from: legacy, to: dir });
12410
12214
  for (const entry of readdirSync2(legacy, { withFileTypes: true })) {
12411
- const src = path11.join(legacy, entry.name);
12412
- const dest = path11.join(dir, entry.name);
12215
+ const src = path10.join(legacy, entry.name);
12216
+ const dest = path10.join(dir, entry.name);
12413
12217
  if (existsSync3(dest))
12414
12218
  continue;
12415
12219
  try {
@@ -12481,7 +12285,7 @@ var parseConfigResult = (raw, file) => {
12481
12285
  return { status: "valid", path: file, config };
12482
12286
  };
12483
12287
  var readConfigTyped = (dir) => {
12484
- const file = path11.join(dir ?? configDir(), "config.json");
12288
+ const file = path10.join(dir ?? configDir(), "config.json");
12485
12289
  return parseConfigResult(readSafe(file), file);
12486
12290
  };
12487
12291
  var readConfig = () => {
@@ -12490,7 +12294,7 @@ var readConfig = () => {
12490
12294
  throw new Error(result.error);
12491
12295
  return result.config ?? DEFAULTS;
12492
12296
  };
12493
- var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path11.join(configDir(), "vcs.json");
12297
+ var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path10.join(configDir(), "vcs.json");
12494
12298
  var branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i");
12495
12299
  var resolveBranchPolicy = (config, workspace, repoPreset) => {
12496
12300
  const wp = workspace?.branchPolicy ?? {};
@@ -12531,13 +12335,13 @@ var resolveCommitPolicy = (config, workspace) => {
12531
12335
  };
12532
12336
 
12533
12337
  // packages/workit-core/src/core/workspaces.ts
12534
- import { spawnSync as spawnSync6 } from "node:child_process";
12338
+ import { spawnSync as spawnSync5 } from "node:child_process";
12535
12339
  import { createHash as createHash7 } from "node:crypto";
12536
12340
  import { readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
12537
- import path12 from "node:path";
12341
+ import path11 from "node:path";
12538
12342
 
12539
12343
  // packages/workit-core/src/core/branch-policy.ts
12540
- import { spawnSync as spawnSync5 } from "node:child_process";
12344
+ import { spawnSync as spawnSync4 } from "node:child_process";
12541
12345
  var PREFIXES = {
12542
12346
  feature: "feature/*",
12543
12347
  bugfix: "bugfix/*",
@@ -12545,7 +12349,7 @@ var PREFIXES = {
12545
12349
  hotfix: "hotfix/*"
12546
12350
  };
12547
12351
  var branchNames = (workspaceRoot) => {
12548
- const r = spawnSync5("git", ["for-each-ref", "--format=%(refname)", "refs/heads", "refs/remotes/origin"], { cwd: workspaceRoot, encoding: "utf8" });
12352
+ const r = spawnSync4("git", ["for-each-ref", "--format=%(refname)", "refs/heads", "refs/remotes/origin"], { cwd: workspaceRoot, encoding: "utf8" });
12549
12353
  if (r.status !== 0)
12550
12354
  return new Set;
12551
12355
  return new Set((r.stdout ?? "").split(`
@@ -12604,7 +12408,7 @@ var repoBranchPreset = (workspaceRoot) => {
12604
12408
  var releaseTagPrefixOf = (workspaceRoot, policyPrefix) => {
12605
12409
  if (typeof policyPrefix === "string")
12606
12410
  return policyPrefix.trim();
12607
- const r = spawnSync5("git", ["config", "--get", "gitflow.prefix.versiontag"], {
12411
+ const r = spawnSync4("git", ["config", "--get", "gitflow.prefix.versiontag"], {
12608
12412
  cwd: workspaceRoot,
12609
12413
  encoding: "utf8"
12610
12414
  });
@@ -12669,7 +12473,7 @@ var releaseTrackSchema = object({
12669
12473
  context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
12670
12474
  }
12671
12475
  }
12672
- if (track.versionSource?.kind === "package-json" && (path12.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
12476
+ if (track.versionSource?.kind === "package-json" && (path11.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
12673
12477
  context.addIssue({
12674
12478
  code: "custom",
12675
12479
  path: ["versionSource", "path"],
@@ -12689,6 +12493,7 @@ var workspaceConfigSchema = object({
12689
12493
  autoApprove: union([boolean2(), array(nonBlank)]).optional(),
12690
12494
  defaultEndpoint: unknown().optional(),
12691
12495
  verification: _enum(["self", "independent"]).optional(),
12496
+ delegation: unknown().optional(),
12692
12497
  trailers: boolean2().optional(),
12693
12498
  liveSessionGuard: boolean2().optional(),
12694
12499
  fanout: object({ tierModels: unknown().optional() }).passthrough().optional(),
@@ -12769,7 +12574,7 @@ var validateWorkspacesDocument = (parsed, file) => {
12769
12574
  };
12770
12575
  };
12771
12576
  var readWorkspacesResult = (dir = configDir()) => {
12772
- const file = path12.join(dir, "workspaces.json");
12577
+ const file = path11.join(dir, "workspaces.json");
12773
12578
  let raw;
12774
12579
  try {
12775
12580
  raw = readFileSync3(file, "utf8");
@@ -12868,7 +12673,7 @@ var mainCheckoutOf = (cwd) => {
12868
12673
  for (const name of ["GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR", "GIT_INDEX_FILE"])
12869
12674
  delete env[name];
12870
12675
  const git = (args) => {
12871
- const run = spawnSync6("git", args, {
12676
+ const run = spawnSync5("git", args, {
12872
12677
  cwd,
12873
12678
  env,
12874
12679
  encoding: "utf8",
@@ -12880,9 +12685,9 @@ var mainCheckoutOf = (cwd) => {
12880
12685
  let main = null;
12881
12686
  const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
12882
12687
  const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
12883
- if (gitDir && common && path12.resolve(gitDir) !== path12.resolve(common)) {
12688
+ if (gitDir && common && path11.resolve(gitDir) !== path11.resolve(common)) {
12884
12689
  const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
12885
- main = listed?.trim() || (path12.basename(common) === ".git" ? path12.dirname(common) : common);
12690
+ main = listed?.trim() || (path11.basename(common) === ".git" ? path11.dirname(common) : common);
12886
12691
  }
12887
12692
  mainCheckouts.set(cwd, main);
12888
12693
  return main;
@@ -12973,7 +12778,7 @@ var runtimeWorkspaceIndexSchema = object({
12973
12778
  workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
12974
12779
  }).passthrough();
12975
12780
  var matchRuntimeWorkspace = (cwd, dir = configDir()) => {
12976
- const file = path12.join(dir, "workspaces.json");
12781
+ const file = path11.join(dir, "workspaces.json");
12977
12782
  let raw;
12978
12783
  try {
12979
12784
  raw = readFileSync3(file, "utf8");
@@ -13082,7 +12887,7 @@ function workspaceDefaultTarget(cwd, globalDefault) {
13082
12887
 
13083
12888
  // packages/workit-core/src/core/release-tracks.ts
13084
12889
  import { createHash as createHash8 } from "node:crypto";
13085
- import { spawnSync as spawnSync7 } from "node:child_process";
12890
+ import { spawnSync as spawnSync6 } from "node:child_process";
13086
12891
  class ReleaseTrackError extends Error {
13087
12892
  }
13088
12893
  var KNOWN_FIELDS = new Set([
@@ -13101,7 +12906,7 @@ var KNOWN_FIELDS = new Set([
13101
12906
  var BRANCH_FIELDS = ["productionBranch", "integrationBranch", "baseBranch", "pullRequestTarget"];
13102
12907
  var PLACEHOLDER = /\{[^}]*\}/gu;
13103
12908
  var HAS_PLACEHOLDER = /\{[^}]*\}/u;
13104
- var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
12909
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
13105
12910
  var branchName = (value) => typeof value === "string" && value.trim() && !value.trim().startsWith("-") ? value.trim() : null;
13106
12911
  var namedBranches = (entry) => [
13107
12912
  ...BRANCH_FIELDS.map((field) => branchName(entry[field])),
@@ -13112,7 +12917,7 @@ function readReleaseTracks(raw) {
13112
12917
  const out = { tracks: [], issues: [], error: null, protectedBranches: [] };
13113
12918
  if (raw === undefined || raw === null)
13114
12919
  return out;
13115
- if (!isRecord2(raw)) {
12920
+ if (!isRecord(raw)) {
13116
12921
  out.issues.push("releaseTracks is not an object; ignored");
13117
12922
  return out;
13118
12923
  }
@@ -13120,7 +12925,7 @@ function readReleaseTracks(raw) {
13120
12925
  const protectedNames = new Set;
13121
12926
  for (const [name, entry] of Object.entries(raw).toSorted(([a], [b]) => a < b ? -1 : 1)) {
13122
12927
  const label = `release track ${JSON.stringify(name)}`;
13123
- if (!isRecord2(entry)) {
12928
+ if (!isRecord(entry)) {
13124
12929
  out.issues.push(`${label} is not an object; ignored`);
13125
12930
  continue;
13126
12931
  }
@@ -13171,7 +12976,7 @@ function readReleaseTracks(raw) {
13171
12976
  }
13172
12977
  const naming = {};
13173
12978
  if (entry.naming !== undefined) {
13174
- if (!isRecord2(entry.naming))
12979
+ if (!isRecord(entry.naming))
13175
12980
  problem("naming", "not an object; ignored");
13176
12981
  else
13177
12982
  for (const kind of ["feature", "release", "hotfix"]) {
@@ -13366,8 +13171,8 @@ function resolveReleaseTrack(input) {
13366
13171
  const newest = forks.filter((fork) => !forks.some((other) => descends(fork.sha, other.sha)));
13367
13172
  return fallback(`${branch} has the same or unrelated fork points with ${[...new Set(newest.map((fork) => `${fork.ref} (${fork.track.name === IMPLICIT ? "workspace default" : fork.track.name})`))].join(" and ")}`);
13368
13173
  }
13369
- var git3 = (cwd, args) => {
13370
- const run = spawnSync7("git", args, {
13174
+ var git2 = (cwd, args) => {
13175
+ const run = spawnSync6("git", args, {
13371
13176
  cwd,
13372
13177
  encoding: "utf8",
13373
13178
  timeout: 20000,
@@ -13378,7 +13183,7 @@ var git3 = (cwd, args) => {
13378
13183
  };
13379
13184
  var recordedBaseKey = (branch) => `branch.${branch}.workitBase`;
13380
13185
  var escapeRegExp2 = (text) => text.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
13381
- var reflog = (cwd, ref) => (git3(cwd, ["log", "-g", "--date=unix", "--format=%H%x09%gd%x09%gs", ref, "--"]) ?? "").split(`
13186
+ var reflog = (cwd, ref) => (git2(cwd, ["log", "-g", "--date=unix", "--format=%H%x09%gd%x09%gs", ref, "--"]) ?? "").split(`
13382
13187
  `).map((line) => {
13383
13188
  const [sha = "", selector = "", ...subject] = line.split("\t");
13384
13189
  return {
@@ -13396,9 +13201,9 @@ function gitTrackProbe(cwd) {
13396
13201
  };
13397
13202
  return {
13398
13203
  remotes: () => remotes ??= remoteNames(cwd),
13399
- recordedBase: (branch) => git3(cwd, ["config", "--get", recordedBaseKey(branch)]) || null,
13204
+ recordedBase: (branch) => git2(cwd, ["config", "--get", recordedBaseKey(branch)]) || null,
13400
13205
  createdFrom: (branch) => {
13401
- const log = git3(cwd, ["reflog", "show", "--format=%gs", `refs/heads/${branch}`, "--"]);
13206
+ const log = git2(cwd, ["reflog", "show", "--format=%gs", `refs/heads/${branch}`, "--"]);
13402
13207
  const oldest = log?.split(`
13403
13208
  `).findLast(Boolean) ?? "";
13404
13209
  const match = /^branch: Created from (\S+)$/u.exec(oldest);
@@ -13417,7 +13222,7 @@ function gitTrackProbe(cwd) {
13417
13222
  const base = tip(trackBranch);
13418
13223
  return base && resolveRef(cwd, `refs/heads/${branch}`) ? mergeBase(cwd, base, `refs/heads/${branch}`) : null;
13419
13224
  },
13420
- isAncestor: (ancestor, descendant) => git3(cwd, ["merge-base", "--is-ancestor", ancestor, descendant]) !== null
13225
+ isAncestor: (ancestor, descendant) => git2(cwd, ["merge-base", "--is-ancestor", ancestor, descendant]) !== null
13421
13226
  };
13422
13227
  }
13423
13228
  function workspaceReleaseTracks(cwd) {
@@ -13444,15 +13249,15 @@ function resolveTrackFor(cwd, options) {
13444
13249
  };
13445
13250
  let key = null;
13446
13251
  if (!options.probe) {
13447
- const refs = git3(cwd, [
13252
+ const refs = git2(cwd, [
13448
13253
  "for-each-ref",
13449
13254
  "--format=%(refname) %(objectname)",
13450
13255
  "refs/heads",
13451
13256
  "refs/remotes"
13452
13257
  ]) ?? "";
13453
- const head = git3(cwd, ["reflog", "show", "-n", "1", "--format=%H %gs", "HEAD", "--"]) ?? "";
13258
+ const head = git2(cwd, ["reflog", "show", "-n", "1", "--format=%H %gs", "HEAD", "--"]) ?? "";
13454
13259
  const own = branch ? [
13455
- git3(cwd, [
13260
+ git2(cwd, [
13456
13261
  "log",
13457
13262
  "-g",
13458
13263
  "-n",
@@ -13462,7 +13267,7 @@ function resolveTrackFor(cwd, options) {
13462
13267
  `refs/heads/${branch}`,
13463
13268
  "--"
13464
13269
  ]) ?? "",
13465
- git3(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
13270
+ git2(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
13466
13271
  ] : [];
13467
13272
  key = createHash8("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
13468
13273
  const hit = memo2.get(key);
@@ -13479,10 +13284,10 @@ function resolveTrackFor(cwd, options) {
13479
13284
  }
13480
13285
 
13481
13286
  // packages/workit-core/src/core/vcs-config.ts
13482
- var workspacesPath = () => path13.join(configDir(), "workspaces.json");
13287
+ var workspacesPath = () => path12.join(configDir(), "workspaces.json");
13483
13288
  var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
13484
13289
  var remoteProvider = (cwd) => {
13485
- const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
13290
+ const r = spawnSync7("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
13486
13291
  if (r.status !== 0)
13487
13292
  return null;
13488
13293
  const url = (r.stdout ?? "").trim();
@@ -13496,7 +13301,7 @@ var readVcsConfig = () => {
13496
13301
  const file = vcsConfigPath();
13497
13302
  let raw;
13498
13303
  try {
13499
- raw = fs11.readFileSync(file, "utf8");
13304
+ raw = fs10.readFileSync(file, "utf8");
13500
13305
  } catch {
13501
13306
  return { status: "missing", path: file, config: {} };
13502
13307
  }
@@ -13621,7 +13426,7 @@ function vcsConfig(mode, cwd, options = {}) {
13621
13426
  const prov = cfg[provider] ?? {};
13622
13427
  const out = {
13623
13428
  ok: true,
13624
- configPath: path13.resolve(cfgPath),
13429
+ configPath: path12.resolve(cfgPath),
13625
13430
  provider,
13626
13431
  defaultTargetBranch: workspaceDefault,
13627
13432
  pr: cfg.pr ?? {},
@@ -13662,7 +13467,7 @@ var err = (code, error, unblock) => ({
13662
13467
  ...unblock ? { unblock } : {}
13663
13468
  });
13664
13469
  var gitRun2 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
13665
- const run = spawnSync9("git", args, {
13470
+ const run = spawnSync8("git", args, {
13666
13471
  cwd,
13667
13472
  encoding: "utf8",
13668
13473
  timeout: timeoutMs,
@@ -13683,7 +13488,7 @@ var gitRun2 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
13683
13488
  stderr: run.error ? String(run.error.message) : run.stderr ?? ""
13684
13489
  };
13685
13490
  };
13686
- var git4 = (cwd, args) => {
13491
+ var git3 = (cwd, args) => {
13687
13492
  const run = gitRun2(cwd, args);
13688
13493
  const value = run.ok ? run.stdout.trim() : "";
13689
13494
  return value ? value : null;
@@ -13692,7 +13497,7 @@ var safeRef = (value) => value.length > 0 && !value.startsWith("-");
13692
13497
  function resolveCommit(cwd, ref) {
13693
13498
  if (!safeRef(ref))
13694
13499
  return null;
13695
- return git4(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]);
13500
+ return git3(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]);
13696
13501
  }
13697
13502
  function branchHead(cwd, branch) {
13698
13503
  if (!safeRef(branch))
@@ -13717,7 +13522,7 @@ function defaultBase(cwd) {
13717
13522
  if (resolveCommit(cwd, candidate))
13718
13523
  return candidate;
13719
13524
  }
13720
- const originHead = git4(cwd, ["symbolic-ref", "-q", "--short", "refs/remotes/origin/HEAD"]);
13525
+ const originHead = git3(cwd, ["symbolic-ref", "-q", "--short", "refs/remotes/origin/HEAD"]);
13721
13526
  if (originHead && resolveCommit(cwd, originHead))
13722
13527
  return originHead;
13723
13528
  for (const candidate of [
@@ -13765,14 +13570,14 @@ function diffHash(cwd, base, head) {
13765
13570
  return `sha256:${hash.digest("hex")}`;
13766
13571
  }
13767
13572
  function storeRoot(cwd) {
13768
- const location = resolveStore(path14.resolve(cwd));
13573
+ const location = resolveStore(path13.resolve(cwd));
13769
13574
  if (location instanceof Error)
13770
13575
  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");
13771
13576
  return { ok: true, value: { root: location.dir, shared: location.shared } };
13772
13577
  }
13773
13578
  function ledgerPath(cwd) {
13774
13579
  const root = storeRoot(cwd);
13775
- return root.ok ? { ok: true, value: path14.join(root.value.root, "ledger", "ledger.jsonl") } : root;
13580
+ return root.ok ? { ok: true, value: path13.join(root.value.root, "ledger", "ledger.jsonl") } : root;
13776
13581
  }
13777
13582
  var newId2 = () => `${Date.now().toString(36)}-${randomBytes3(6).toString("hex")}`;
13778
13583
  var NETWORK_FS_TYPES = new Set([
@@ -13792,7 +13597,7 @@ var onNetworkFs = (dir) => {
13792
13597
  if (process.platform !== "linux")
13793
13598
  return false;
13794
13599
  try {
13795
- return isNetworkFsType(fs12.statfsSync(dir).type);
13600
+ return isNetworkFsType(fs11.statfsSync(dir).type);
13796
13601
  } catch {
13797
13602
  return false;
13798
13603
  }
@@ -13802,15 +13607,15 @@ var LOCK_STALE_MS = 30000;
13802
13607
  var LOCK_OWNER = "owner";
13803
13608
  var lockToken = (lock) => {
13804
13609
  try {
13805
- return fs12.readFileSync(path14.join(lock, LOCK_OWNER), "utf8");
13610
+ return fs11.readFileSync(path13.join(lock, LOCK_OWNER), "utf8");
13806
13611
  } catch {
13807
13612
  return null;
13808
13613
  }
13809
13614
  };
13810
13615
  var lockAgeMs = (lock) => {
13811
- for (const target of [path14.join(lock, LOCK_OWNER), lock]) {
13616
+ for (const target of [path13.join(lock, LOCK_OWNER), lock]) {
13812
13617
  try {
13813
- return Date.now() - fs12.statSync(target).mtimeMs;
13618
+ return Date.now() - fs11.statSync(target).mtimeMs;
13814
13619
  } catch {}
13815
13620
  }
13816
13621
  return null;
@@ -13818,14 +13623,14 @@ var lockAgeMs = (lock) => {
13818
13623
  var ledgerLock = {
13819
13624
  acquire(lock) {
13820
13625
  try {
13821
- fs12.mkdirSync(lock);
13626
+ fs11.mkdirSync(lock);
13822
13627
  } catch (error) {
13823
13628
  if (error.code === "EEXIST")
13824
13629
  return null;
13825
13630
  throw error;
13826
13631
  }
13827
13632
  const token = `${process.pid}-${randomBytes3(8).toString("hex")}`;
13828
- fs12.writeFileSync(path14.join(lock, LOCK_OWNER), token);
13633
+ fs11.writeFileSync(path13.join(lock, LOCK_OWNER), token);
13829
13634
  return token;
13830
13635
  },
13831
13636
  release(lock, token) {
@@ -13833,35 +13638,35 @@ var ledgerLock = {
13833
13638
  return false;
13834
13639
  const tomb = `${lock}.release-${randomBytes3(6).toString("hex")}`;
13835
13640
  try {
13836
- fs12.renameSync(lock, tomb);
13641
+ fs11.renameSync(lock, tomb);
13837
13642
  } catch {
13838
13643
  return false;
13839
13644
  }
13840
13645
  if (lockToken(tomb) !== token) {
13841
13646
  try {
13842
- fs12.renameSync(tomb, lock);
13647
+ fs11.renameSync(tomb, lock);
13843
13648
  } catch {}
13844
13649
  return false;
13845
13650
  }
13846
- fs12.rmSync(tomb, { recursive: true, force: true });
13651
+ fs11.rmSync(tomb, { recursive: true, force: true });
13847
13652
  return true;
13848
13653
  },
13849
13654
  token: lockToken,
13850
13655
  reap(lock, observed) {
13851
13656
  const tomb = `${lock}.reap-${randomBytes3(6).toString("hex")}`;
13852
13657
  try {
13853
- fs12.renameSync(lock, tomb);
13658
+ fs11.renameSync(lock, tomb);
13854
13659
  } catch {
13855
13660
  return false;
13856
13661
  }
13857
13662
  if (lockToken(tomb) === observed) {
13858
- fs12.rmSync(tomb, { recursive: true, force: true });
13663
+ fs11.rmSync(tomb, { recursive: true, force: true });
13859
13664
  return true;
13860
13665
  }
13861
13666
  try {
13862
- fs12.renameSync(tomb, lock);
13667
+ fs11.renameSync(tomb, lock);
13863
13668
  } catch {
13864
- fs12.rmSync(tomb, { recursive: true, force: true });
13669
+ fs11.rmSync(tomb, { recursive: true, force: true });
13865
13670
  }
13866
13671
  return false;
13867
13672
  }
@@ -13895,7 +13700,7 @@ var TAIL_BYTES = 64 * 1024;
13895
13700
  var lastLine = (fd, size) => {
13896
13701
  for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
13897
13702
  const buffer = Buffer.alloc(span);
13898
- fs12.readSync(fd, buffer, 0, span, size - span);
13703
+ fs11.readSync(fd, buffer, 0, span, size - span);
13899
13704
  const end = buffer.lastIndexOf(10);
13900
13705
  if (end < 0) {
13901
13706
  if (span === size)
@@ -13926,21 +13731,21 @@ var lastLine = (fd, size) => {
13926
13731
  };
13927
13732
  var tighten = (fd) => {
13928
13733
  try {
13929
- if ((fs12.fstatSync(fd).mode & 63) !== 0)
13930
- fs12.fchmodSync(fd, 384);
13734
+ if ((fs11.fstatSync(fd).mode & 63) !== 0)
13735
+ fs11.fchmodSync(fd, 384);
13931
13736
  } catch {}
13932
13737
  };
13933
13738
  function appendLine(file, build, options) {
13934
13739
  const write = () => {
13935
- const fd = fs12.openSync(file, "a+", 384);
13740
+ const fd = fs11.openSync(file, "a+", 384);
13936
13741
  try {
13937
13742
  if (process.platform !== "win32")
13938
13743
  tighten(fd);
13939
- const size = fs12.fstatSync(fd).size;
13744
+ const size = fs11.fstatSync(fd).size;
13940
13745
  let fence = "";
13941
13746
  if (size > 0) {
13942
13747
  const last = Buffer.alloc(1);
13943
- fs12.readSync(fd, last, 0, 1, size - 1);
13748
+ fs11.readSync(fd, last, 0, 1, size - 1);
13944
13749
  if (last[0] !== 10)
13945
13750
  fence = `
13946
13751
  `;
@@ -13949,17 +13754,17 @@ function appendLine(file, build, options) {
13949
13754
  if (!line.ok)
13950
13755
  return line;
13951
13756
  const bytes = Buffer.from(fence + line.value);
13952
- const written = fs12.writeSync(fd, bytes);
13757
+ const written = fs11.writeSync(fd, bytes);
13953
13758
  if (written !== bytes.length)
13954
13759
  return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
13955
13760
  return { ok: true, value: undefined };
13956
13761
  } finally {
13957
- fs12.closeSync(fd);
13762
+ fs11.closeSync(fd);
13958
13763
  }
13959
13764
  };
13960
13765
  try {
13961
- fs12.mkdirSync(path14.dirname(file), { recursive: true });
13962
- if (!options.forceLock && !onNetworkFs(path14.dirname(file)))
13766
+ fs11.mkdirSync(path13.dirname(file), { recursive: true });
13767
+ if (!options.forceLock && !onNetworkFs(path13.dirname(file)))
13963
13768
  return write();
13964
13769
  const locked = withLedgerLock(file, write);
13965
13770
  return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
@@ -14002,10 +13807,10 @@ function appendObserved(cwd, row, options = {}) {
14002
13807
  function appendHookObserved(cwd, row) {
14003
13808
  return appendRaw(cwd, { ...row, observer: "host_hook" }, {});
14004
13809
  }
14005
- var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
13810
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
14006
13811
  var str = (value) => typeof value === "string" ? value : null;
14007
13812
  var normalizeActor = (value) => {
14008
- const actor = isRecord3(value) ? value : {};
13813
+ const actor = isRecord2(value) ? value : {};
14009
13814
  return {
14010
13815
  host: str(actor.host) ?? "unknown",
14011
13816
  session: str(actor.session),
@@ -14032,8 +13837,8 @@ function readLedger(cwd, options = {}) {
14032
13837
  let text = "";
14033
13838
  let stat = null;
14034
13839
  try {
14035
- stat = fs12.statSync(file.value);
14036
- text = fs12.readFileSync(file.value, "utf8");
13840
+ stat = fs11.statSync(file.value);
13841
+ text = fs11.readFileSync(file.value, "utf8");
14037
13842
  } catch (error) {
14038
13843
  if (error.code === "ENOENT")
14039
13844
  return {
@@ -14068,7 +13873,7 @@ function readLedger(cwd, options = {}) {
14068
13873
  skipped += 1;
14069
13874
  continue;
14070
13875
  }
14071
- if (!isRecord3(parsed) || !str(parsed.id) || !str(parsed.type) || !str(parsed.at)) {
13876
+ if (!isRecord2(parsed) || !str(parsed.id) || !str(parsed.type) || !str(parsed.at)) {
14072
13877
  skipped += 1;
14073
13878
  continue;
14074
13879
  }
@@ -14168,7 +13973,7 @@ function ledgerTampering(cwd) {
14168
13973
  if (!file.ok)
14169
13974
  return [];
14170
13975
  try {
14171
- const stat = fs12.statSync(file.value);
13976
+ const stat = fs11.statSync(file.value);
14172
13977
  const cached = tamperCache.get(file.value);
14173
13978
  if (cached && cached.size === stat.size && cached.stamp === fileStamp(stat))
14174
13979
  return cached.breaks;
@@ -14195,7 +14000,7 @@ var isLiveVerdict = (row, retired) => row.type === "verdict" && typeof row.resul
14195
14000
  function trailerSessions(cwd, base, head) {
14196
14001
  if (!base || !head || !safeRef(base) || !safeRef(head))
14197
14002
  return [];
14198
- const out = git4(cwd, [
14003
+ const out = git3(cwd, [
14199
14004
  "log",
14200
14005
  "--format=%(trailers:key=Workit-Session,valueonly,separator=%x00)",
14201
14006
  `${base}..${head}`
@@ -14207,7 +14012,7 @@ function branchScope(cwd, branch) {
14207
14012
  const renamedAt = new Map;
14208
14013
  let since = Number.NEGATIVE_INFINITY;
14209
14014
  if (safeRef(branch)) {
14210
- const log = git4(cwd, [
14015
+ const log = git3(cwd, [
14211
14016
  "log",
14212
14017
  "-g",
14213
14018
  "--date=unix",
@@ -14647,7 +14452,7 @@ var productDecision = (task, ledger) => {
14647
14452
  };
14648
14453
  };
14649
14454
  var planRecorded = (task, root) => {
14650
- const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path15.resolve(root, ref.path)));
14455
+ const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path14.resolve(root, ref.path)));
14651
14456
  if (cited)
14652
14457
  return {
14653
14458
  met: true,
@@ -14707,14 +14512,14 @@ function writeBlockers(task, root) {
14707
14512
 
14708
14513
  // packages/workit-core/src/core/task-evaluation.ts
14709
14514
  var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
14710
- var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
14711
- var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
14515
+ var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path15.sep}`);
14516
+ var relative = (root, candidate) => path15.relative(root, candidate).split(path15.sep).join("/") || ".";
14712
14517
  var canonicalPath = (value) => {
14713
14518
  if (typeof value !== "string" || !value)
14714
14519
  return null;
14715
14520
  if (value.includes("\\") || value.split("/").includes(".."))
14716
14521
  return null;
14717
- const normalized = path16.posix.normalize(value);
14522
+ const normalized = path15.posix.normalize(value);
14718
14523
  if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
14719
14524
  return null;
14720
14525
  return normalized === "." ? "." : normalized.replace(/\/$/, "");
@@ -14750,7 +14555,7 @@ var compareCodeUnits2 = (left, right) => {
14750
14555
  return left.length - right.length;
14751
14556
  };
14752
14557
  var gitPaths = (root) => {
14753
- const result = spawnSync10("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
14558
+ const result = spawnSync9("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
14754
14559
  cwd: root,
14755
14560
  encoding: "buffer"
14756
14561
  });
@@ -14762,21 +14567,21 @@ var gitPaths = (root) => {
14762
14567
  git: !/not a git repository/i.test(stderr)
14763
14568
  };
14764
14569
  }
14765
- const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
14766
- const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
14570
+ const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")) : [];
14571
+ const stagedDeleted = spawnSync9("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
14767
14572
  if (stagedDeleted.status !== 0) {
14768
14573
  const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
14769
14574
  if (!/not a git repository/i.test(stderr))
14770
14575
  return { paths, uncertain: true, git: true };
14771
14576
  } else if (stagedDeleted.stdout) {
14772
- paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
14577
+ paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")));
14773
14578
  }
14774
14579
  return { paths: [...new Set(paths)], uncertain: false, git: true };
14775
14580
  };
14776
14581
  var walk = (root, directory, output) => {
14777
14582
  let names;
14778
14583
  try {
14779
- names = fs13.readdirSync(directory);
14584
+ names = fs12.readdirSync(directory);
14780
14585
  } catch {
14781
14586
  return true;
14782
14587
  }
@@ -14784,10 +14589,10 @@ var walk = (root, directory, output) => {
14784
14589
  for (const name of names) {
14785
14590
  if (name === ".git" || name === ".workit")
14786
14591
  continue;
14787
- const target = path16.join(directory, name);
14592
+ const target = path15.join(directory, name);
14788
14593
  let stat;
14789
14594
  try {
14790
- stat = fs13.lstatSync(target);
14595
+ stat = fs12.lstatSync(target);
14791
14596
  } catch {
14792
14597
  uncertain = true;
14793
14598
  continue;
@@ -14802,14 +14607,14 @@ var walk = (root, directory, output) => {
14802
14607
  var scopeRoots = (root, scope) => {
14803
14608
  const roots = [];
14804
14609
  for (const item of scope.paths.length ? scope.paths : ["."]) {
14805
- const target = path16.resolve(root, item);
14610
+ const target = path15.resolve(root, item);
14806
14611
  if (!inside(root, target))
14807
14612
  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` }] });
14808
14613
  let ancestor = target;
14809
- while (!fs13.existsSync(ancestor) && ancestor !== root)
14810
- ancestor = path16.dirname(ancestor);
14614
+ while (!fs12.existsSync(ancestor) && ancestor !== root)
14615
+ ancestor = path15.dirname(ancestor);
14811
14616
  try {
14812
- if (!inside(root, fs13.realpathSync(ancestor)))
14617
+ if (!inside(root, fs12.realpathSync(ancestor)))
14813
14618
  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` }] });
14814
14619
  } catch {
14815
14620
  return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
@@ -14821,7 +14626,7 @@ var scopeRoots = (root, scope) => {
14821
14626
  function captureCandidate(root, scope, environment = []) {
14822
14627
  let checkout;
14823
14628
  try {
14824
- checkout = fs13.realpathSync(root);
14629
+ checkout = fs12.realpathSync(root);
14825
14630
  } catch {
14826
14631
  return failure2("invalid_input", "candidate root does not exist");
14827
14632
  }
@@ -14839,11 +14644,11 @@ function captureCandidate(root, scope, environment = []) {
14839
14644
  if (item === ".git" || item === ".workit")
14840
14645
  continue;
14841
14646
  names.add(item);
14842
- if (!fs13.existsSync(target))
14647
+ if (!fs12.existsSync(target))
14843
14648
  continue;
14844
14649
  let stat;
14845
14650
  try {
14846
- stat = fs13.lstatSync(target);
14651
+ stat = fs12.lstatSync(target);
14847
14652
  } catch {
14848
14653
  uncertain = true;
14849
14654
  continue;
@@ -14859,17 +14664,17 @@ function captureCandidate(root, scope, environment = []) {
14859
14664
  for (const item of [...names].toSorted()) {
14860
14665
  if (!scopeMatches(item, normalizedScope))
14861
14666
  continue;
14862
- const target = path16.join(checkout, item);
14667
+ const target = path15.join(checkout, item);
14863
14668
  try {
14864
- const stat = fs13.lstatSync(target);
14669
+ const stat = fs12.lstatSync(target);
14865
14670
  if (stat.isSymbolicLink()) {
14866
- const link = fs13.readlinkSync(target);
14671
+ const link = fs12.readlinkSync(target);
14867
14672
  files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
14868
14673
  } else if (stat.isFile()) {
14869
14674
  files.push({
14870
14675
  path: item,
14871
14676
  kind: "file",
14872
- digest: digestBytes(fs13.readFileSync(target)),
14677
+ digest: digestBytes(fs12.readFileSync(target)),
14873
14678
  executable: (stat.mode & 73) !== 0
14874
14679
  });
14875
14680
  } else if (!stat.isDirectory()) {
@@ -14894,7 +14699,7 @@ function captureCandidate(root, scope, environment = []) {
14894
14699
  const values = supplied.toSorted((left, right) => compareCodeUnits2(left.name, right.name)).map(({ name, value }) => ({ name, value, refs: [] }));
14895
14700
  if (values.some(({ value }) => value === null))
14896
14701
  completeness = "uncertain";
14897
- const headResult = spawnSync10("git", ["rev-parse", "HEAD"], { cwd: checkout, encoding: "utf8" });
14702
+ const headResult = spawnSync9("git", ["rev-parse", "HEAD"], { cwd: checkout, encoding: "utf8" });
14898
14703
  if (headResult.status !== 0 && !/not a git repository/i.test(headResult.stderr ?? ""))
14899
14704
  completeness = "uncertain";
14900
14705
  const head = headResult.status === 0 ? headResult.stdout.trim() : null;
@@ -15034,7 +14839,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
15034
14839
  var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
15035
14840
  let root;
15036
14841
  try {
15037
- root = fs13.realpathSync(checkoutRoot);
14842
+ root = fs12.realpathSync(checkoutRoot);
15038
14843
  } catch {
15039
14844
  return failure2("permission_denied", "checkout root is unavailable");
15040
14845
  }
@@ -15043,23 +14848,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
15043
14848
  continue;
15044
14849
  if (!reference.digest)
15045
14850
  return failure2("invalid_input", "document references require a byte digest");
15046
- const target = path16.resolve(root, reference.path);
15047
- if (target !== root && !target.startsWith(`${root}${path16.sep}`))
14851
+ const target = path15.resolve(root, reference.path);
14852
+ if (target !== root && !target.startsWith(`${root}${path15.sep}`))
15048
14853
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
15049
14854
  fields: [
15050
14855
  { path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
15051
14856
  ]
15052
14857
  });
15053
14858
  try {
15054
- const below = path16.relative(root, target);
14859
+ const below = path15.relative(root, target);
15055
14860
  let current = root;
15056
- for (const segment of below.split(path16.sep)) {
14861
+ for (const segment of below.split(path15.sep)) {
15057
14862
  if (!segment)
15058
14863
  continue;
15059
- current = path16.join(current, segment);
15060
- const stat = fs13.lstatSync(current);
15061
- const real = fs13.realpathSync(current);
15062
- if (real !== root && !real.startsWith(`${root}${path16.sep}`))
14864
+ current = path15.join(current, segment);
14865
+ const stat = fs12.lstatSync(current);
14866
+ const real = fs12.realpathSync(current);
14867
+ if (real !== root && !real.startsWith(`${root}${path15.sep}`))
15063
14868
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
15064
14869
  fields: [
15065
14870
  {
@@ -15075,7 +14880,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
15075
14880
  if (current !== target && !stat.isDirectory())
15076
14881
  return failure2("invalid_input", "document reference ancestor is not a directory");
15077
14882
  }
15078
- if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
14883
+ if (digestBytes(fs12.readFileSync(target)) !== reference.digest)
15079
14884
  return failure2("permission_denied", "decision document bytes have changed");
15080
14885
  } catch {
15081
14886
  return failure2("invalid_input", "decision document is unavailable");
@@ -15980,7 +15785,7 @@ var judgeInputSummary = (raw) => {
15980
15785
 
15981
15786
  // packages/workit-core/src/autonomy.ts
15982
15787
  import os4 from "node:os";
15983
- import path17 from "node:path";
15788
+ import path16 from "node:path";
15984
15789
  var accountHome = () => {
15985
15790
  try {
15986
15791
  return os4.userInfo().homedir;
@@ -15989,10 +15794,10 @@ var accountHome = () => {
15989
15794
  }
15990
15795
  };
15991
15796
  var grantsHome = { resolve: accountHome };
15992
- var grantsDir = () => path17.join(grantsHome.resolve(), ".config", "workit");
15797
+ var grantsDir = () => path16.join(grantsHome.resolve(), ".config", "workit");
15993
15798
  var grantsOverride = () => {
15994
- const configured = path17.resolve(resolveConfigDir());
15995
- return configured === path17.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path17.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
15799
+ const configured = path16.resolve(resolveConfigDir());
15800
+ return configured === path16.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path16.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
15996
15801
  };
15997
15802
  var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
15998
15803
  var DEFAULT_GRANTS = Object.freeze({
@@ -18005,7 +17810,7 @@ function entryCompactContext(store, entry, session, context) {
18005
17810
  return null;
18006
17811
  const freshness = { mode: "signal", current: () => recentSignal(store.root) };
18007
17812
  const observed = task?.data.evidence.some(isObservedCheck) ?? false;
18008
- const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path18.resolve(store.root, ref.path)] : []));
17813
+ const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path17.resolve(store.root, ref.path)] : []));
18009
17814
  const observedFiles = filesKey(files);
18010
17815
  const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
18011
17816
  if (!compact.ok || !compact.data)
@@ -18083,32 +17888,32 @@ var turnMarker = (input) => {
18083
17888
  if (location instanceof Error)
18084
17889
  return null;
18085
17890
  const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
18086
- return path18.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
17891
+ return path17.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
18087
17892
  } catch {
18088
17893
  return null;
18089
17894
  }
18090
17895
  };
18091
17896
  var writeTurnDigest = (file, digest) => {
18092
17897
  try {
18093
- fs14.mkdirSync(path18.dirname(file), { recursive: true });
18094
- fs14.writeFileSync(file, `${JSON.stringify({ digest })}
17898
+ fs13.mkdirSync(path17.dirname(file), { recursive: true });
17899
+ fs13.writeFileSync(file, `${JSON.stringify({ digest })}
18095
17900
  `);
18096
17901
  } catch {}
18097
17902
  };
18098
17903
  var clearTurnDigest = (file) => {
18099
17904
  try {
18100
- fs14.rmSync(file, { force: true });
17905
+ fs13.rmSync(file, { force: true });
18101
17906
  } catch {}
18102
17907
  };
18103
17908
  var pruneTurnDigests = (dir, now) => {
18104
17909
  try {
18105
- for (const name of fs14.readdirSync(dir)) {
17910
+ for (const name of fs13.readdirSync(dir)) {
18106
17911
  if (!name.startsWith("turn-"))
18107
17912
  continue;
18108
- const file = path18.join(dir, name);
17913
+ const file = path17.join(dir, name);
18109
17914
  try {
18110
- if (now - fs14.statSync(file).mtimeMs > TURN_TTL_MS)
18111
- fs14.rmSync(file, { force: true });
17915
+ if (now - fs13.statSync(file).mtimeMs > TURN_TTL_MS)
17916
+ fs13.rmSync(file, { force: true });
18112
17917
  } catch {}
18113
17918
  }
18114
17919
  } catch {}
@@ -18124,7 +17929,7 @@ var changedTurnContext = (input, text) => {
18124
17929
  return text;
18125
17930
  const digest = digestOf(text);
18126
17931
  try {
18127
- const previous = JSON.parse(fs14.readFileSync(file, "utf8"));
17932
+ const previous = JSON.parse(fs13.readFileSync(file, "utf8"));
18128
17933
  if (previous.digest === digest)
18129
17934
  return null;
18130
17935
  } catch {}
@@ -18135,23 +17940,23 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
18135
17940
  const file = turnMarker(input);
18136
17941
  if (!file)
18137
17942
  return;
18138
- pruneTurnDigests(path18.dirname(file), Date.now());
17943
+ pruneTurnDigests(path17.dirname(file), Date.now());
18139
17944
  if (text)
18140
17945
  writeTurnDigest(file, digestOf(text));
18141
17946
  else
18142
17947
  clearTurnDigest(file);
18143
17948
  };
18144
17949
  // packages/workit-core/src/core/route-intent.ts
18145
- import { spawnSync as spawnSync12 } from "node:child_process";
17950
+ import { spawnSync as spawnSync11 } from "node:child_process";
18146
17951
  import { existsSync as existsSync6 } from "node:fs";
18147
- import path21 from "node:path";
17952
+ import path20 from "node:path";
18148
17953
 
18149
17954
  // packages/workit-core/src/hooks/raw-git.ts
18150
- import { spawnSync as spawnSync11 } from "node:child_process";
17955
+ import { spawnSync as spawnSync10 } from "node:child_process";
18151
17956
  import { createHash as createHash14 } from "node:crypto";
18152
- import fs16 from "node:fs";
17957
+ import fs15 from "node:fs";
18153
17958
  import os5 from "node:os";
18154
- import path20 from "node:path";
17959
+ import path19 from "node:path";
18155
17960
 
18156
17961
  // packages/workit-core/src/core/branch.ts
18157
17962
  import { createHash as createHash12 } from "node:crypto";
@@ -18363,8 +18168,8 @@ var globOf = (pattern) => pattern.source.replace(/^\^|\$$/gu, "").replaceAll(".*
18363
18168
 
18364
18169
  // packages/workit-core/src/hooks/session-marker.ts
18365
18170
  import { createHash as createHash13 } from "node:crypto";
18366
- import fs15 from "node:fs";
18367
- import path19 from "node:path";
18171
+ import fs14 from "node:fs";
18172
+ import path18 from "node:path";
18368
18173
  var sessionMarkerFile = (input, session, store) => {
18369
18174
  let dir = store;
18370
18175
  if (dir === undefined) {
@@ -18374,12 +18179,12 @@ var sessionMarkerFile = (input, session, store) => {
18374
18179
  dir = location.dir;
18375
18180
  }
18376
18181
  const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
18377
- return path19.join(dir, "hooks", `skills-${name}.json`);
18182
+ return path18.join(dir, "hooks", `skills-${name}.json`);
18378
18183
  };
18379
18184
  var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
18380
18185
  var readSessionMarker = (file) => {
18381
18186
  try {
18382
- const value = JSON.parse(fs15.readFileSync(file, "utf8"));
18187
+ const value = JSON.parse(fs14.readFileSync(file, "utf8"));
18383
18188
  return { nudged: list2(value.nudged), loaded: list2(value.loaded), raw: list2(value.raw) };
18384
18189
  } catch {
18385
18190
  return { nudged: [], loaded: [], raw: [] };
@@ -18387,8 +18192,8 @@ var readSessionMarker = (file) => {
18387
18192
  };
18388
18193
  var writeSessionMarker = (file, marker) => {
18389
18194
  try {
18390
- fs15.mkdirSync(path19.dirname(file), { recursive: true });
18391
- fs15.writeFileSync(file, JSON.stringify(marker));
18195
+ fs14.mkdirSync(path18.dirname(file), { recursive: true });
18196
+ fs14.writeFileSync(file, JSON.stringify(marker));
18392
18197
  } catch {}
18393
18198
  };
18394
18199
 
@@ -18885,14 +18690,14 @@ var GIT_CONFIG_ENV = /^GIT_(?:CONFIG\w*|DIR|COMMON_DIR|WORK_TREE)$/;
18885
18690
  var ASSIGNMENT = /^([A-Za-z_]\w*)=([\s\S]*)$/;
18886
18691
  var MAX_DEPTH = 4;
18887
18692
  var MAX_EXPANSIONS = 16;
18888
- var isAbsolute = (value) => path20.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
18693
+ var isAbsolute = (value) => path19.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
18889
18694
  var HERE = /^(?:\$PWD|\$\{PWD\}|\$\(\s*pwd\s*\)|`pwd`|\$\(\s*git\s+rev-parse\s+--show-toplevel\s*\))(?=$|[\\/])/;
18890
18695
  var joinDir = (base, raw) => {
18891
18696
  const next = raw.replace(HERE, ".");
18892
18697
  if (base === undefined || /[$`*?]/.test(next) || next === "-")
18893
18698
  return;
18894
- const expanded = next === "~" || next.startsWith("~/") ? path20.join(os5.homedir(), next.slice(1)) : next;
18895
- return base === null || isAbsolute(expanded) ? expanded : path20.join(base, expanded);
18699
+ const expanded = next === "~" || next.startsWith("~/") ? path19.join(os5.homedir(), next.slice(1)) : next;
18700
+ return base === null || isAbsolute(expanded) ? expanded : path19.join(base, expanded);
18896
18701
  };
18897
18702
  var rebase = (base, inner) => inner === null ? base : inner === undefined ? undefined : joinDir(base, inner);
18898
18703
  var cdTarget = (words) => {
@@ -19230,7 +19035,16 @@ function rawInvocations(command, dialect = "posix", depth = 0) {
19230
19035
  return found;
19231
19036
  }
19232
19037
  var RECENT = new Map;
19233
- function walk2(command, dialect, depth) {
19038
+ function commandLines(command, dialect = "posix") {
19039
+ const lines = [];
19040
+ try {
19041
+ walk2(command, dialect, 0, lines);
19042
+ } catch (error) {
19043
+ throw error instanceof ShellAnalysisError ? error : new ShellAnalysisError(error instanceof Error ? error.message : String(error));
19044
+ }
19045
+ return lines;
19046
+ }
19047
+ function walk2(command, dialect, depth, seen) {
19234
19048
  const found = [];
19235
19049
  let dir = null;
19236
19050
  const groups = [];
@@ -19241,7 +19055,8 @@ function walk2(command, dialect, depth) {
19241
19055
  const nested = (script, inner) => {
19242
19056
  if (!script || depth >= MAX_DEPTH)
19243
19057
  return;
19244
- for (const invocation of rawInvocations(script, inner, depth + 1))
19058
+ const inside = seen ? walk2(script, inner, depth + 1, seen) : rawInvocations(script, inner, depth + 1);
19059
+ for (const invocation of inside)
19245
19060
  found.push({ ...invocation, dir: rebase(dir, invocation.dir) });
19246
19061
  };
19247
19062
  const visit = (input, stdin, hops) => {
@@ -19253,11 +19068,17 @@ function walk2(command, dialect, depth) {
19253
19068
  const name = commandName(words[0]);
19254
19069
  if (!name)
19255
19070
  return;
19071
+ seen?.push(words);
19072
+ if (name === "-c" || name === "--command")
19073
+ return nested(words[1], "posix");
19256
19074
  const runs = (lines) => {
19257
19075
  if (hops < MAX_DEPTH)
19258
19076
  for (const next of lines)
19259
19077
  visit(next, undefined, hops + 1);
19260
19078
  };
19079
+ const wrapped = seen ? null : workitCheckTail(words);
19080
+ if (wrapped)
19081
+ return "script" in wrapped ? nested(wrapped.script, "posix") : runs([wrapped.argv]);
19261
19082
  if (CD.has(name)) {
19262
19083
  const target = cdTarget(words);
19263
19084
  dir = target === null ? os5.homedir() : joinDir(dir, target);
@@ -19348,6 +19169,51 @@ var LAUNCHERS = new Set([
19348
19169
  "command"
19349
19170
  ]);
19350
19171
  var WORKIT_BIN = /(?:^|[\\/])workit(?:\.exe)?$|^@brainervirus\/workit-cli$/;
19172
+ var WORKIT_PACKAGE = /^@brainervirus\/workit-cli(?:@\S*)?$/;
19173
+ var PACKAGE_RUNNERS = new Set(["npx", "bunx", "pnpx"]);
19174
+ function workitCheckTail(words) {
19175
+ let at = 0;
19176
+ if (PACKAGE_RUNNERS.has(commandName(words[0]))) {
19177
+ at = words.findIndex((word, index) => index > 0 && !word.startsWith("-"));
19178
+ if (at < 0 || !WORKIT_PACKAGE.test(words[at]))
19179
+ return null;
19180
+ } else if (!/^workit(?:\.exe|\.cmd)?$/.test(commandName(words[0])))
19181
+ return null;
19182
+ const args = words.slice(at + 1);
19183
+ if (args[0] !== "check" && !(args[0] === "lock" && args[1] === "run"))
19184
+ return null;
19185
+ const split = args.indexOf("--");
19186
+ const tail = split < 0 ? [] : args.slice(split + 1);
19187
+ if (!tail.length)
19188
+ return null;
19189
+ return args.slice(0, split).includes("--shell") ? { script: tail.join(" ") } : { argv: tail };
19190
+ }
19191
+ function simpleCommand(command, dialect = "posix", depth = 0) {
19192
+ let segments;
19193
+ try {
19194
+ segments = segmentsOf(command, dialect);
19195
+ } catch {
19196
+ return null;
19197
+ }
19198
+ if (segments.length !== 1)
19199
+ return null;
19200
+ const [segment] = segments;
19201
+ if (segment.group || segment.pipe || segment.unanalyzable || segment.redirects.length || segment.subs?.length || segment.stdin?.length)
19202
+ return null;
19203
+ const { words } = stripPrefixes(segment.words);
19204
+ const name = commandName(words[0]);
19205
+ if (!name || depth >= MAX_DEPTH)
19206
+ return null;
19207
+ if (SHELLS.has(name)) {
19208
+ const script = shellScript(words, undefined);
19209
+ return script ? simpleCommand(script, "posix", depth + 1) : null;
19210
+ }
19211
+ if (name === "-c" || name === "--command")
19212
+ return words[1] ? simpleCommand(words[1], "posix", depth + 1) : null;
19213
+ if (EVALS.has(name) || POWERSHELLS.has(name) || ["xargs", "find", "parallel", "script", "cmd", "source", "."].includes(name))
19214
+ return null;
19215
+ return words;
19216
+ }
19351
19217
  function workitInvocations(command, dialect = "posix", depth = 0) {
19352
19218
  const found = [];
19353
19219
  for (const { words } of segmentsOf(command, dialect)) {
@@ -19643,7 +19509,7 @@ var repoAt = (dir) => {
19643
19509
  return { location, dir, branch: resolveTaskKey(dir, location).branch };
19644
19510
  };
19645
19511
  var isWorkitWorkspace = (repo) => {
19646
- if (fs16.existsSync(repo.location.dir))
19512
+ if (fs15.existsSync(repo.location.dir))
19647
19513
  return true;
19648
19514
  try {
19649
19515
  return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
@@ -19664,17 +19530,17 @@ var headSha2 = (repo) => {
19664
19530
  if (!git || git.reftable)
19665
19531
  return null;
19666
19532
  try {
19667
- const head = fs16.readFileSync(path20.join(git.gitDir, "HEAD"), "utf8").trim();
19533
+ const head = fs15.readFileSync(path19.join(git.gitDir, "HEAD"), "utf8").trim();
19668
19534
  if (/^[0-9a-f]{40,64}$/.test(head))
19669
19535
  return head;
19670
19536
  const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
19671
19537
  if (!ref)
19672
19538
  return null;
19673
- const common = path20.dirname(repo.location.dir);
19539
+ const common = path19.dirname(repo.location.dir);
19674
19540
  try {
19675
- return fs16.readFileSync(path20.join(common, ref), "utf8").trim() || null;
19541
+ return fs15.readFileSync(path19.join(common, ref), "utf8").trim() || null;
19676
19542
  } catch {}
19677
- const packed = fs16.readFileSync(path20.join(common, "packed-refs"), "utf8");
19543
+ const packed = fs15.readFileSync(path19.join(common, "packed-refs"), "utf8");
19678
19544
  return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
19679
19545
  } catch {
19680
19546
  return null;
@@ -19686,7 +19552,7 @@ var gitConfig = (dir, invocation, cache) => {
19686
19552
  if (cached)
19687
19553
  return cached;
19688
19554
  const config = new Map;
19689
- const listed = spawnSync11("git", [...invocation.config ?? [], "config", "-z", "--list"], {
19555
+ const listed = spawnSync10("git", [...invocation.config ?? [], "config", "-z", "--list"], {
19690
19556
  cwd: dir,
19691
19557
  encoding: "utf8",
19692
19558
  timeout: 3000,
@@ -19762,8 +19628,8 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
19762
19628
  const sub = invocation.args[0];
19763
19629
  if (invocation.tool !== "git" || invocation.dir === undefined || !sub || sub.startsWith("-") || GIT_COMMANDS.has(sub) || depth >= MAX_DEPTH)
19764
19630
  return [invocation];
19765
- const dir = path20.resolve(root, invocation.dir ?? ".");
19766
- if (!fs16.existsSync(dir))
19631
+ const dir = path19.resolve(root, invocation.dir ?? ".");
19632
+ if (!fs15.existsSync(dir))
19767
19633
  return [invocation];
19768
19634
  const config = gitConfig(dir, invocation, cache);
19769
19635
  const alias = configValue(config, `alias.${sub.toLowerCase()}`);
@@ -19785,11 +19651,11 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
19785
19651
  var normalizedUrl = (url, dir) => {
19786
19652
  const trimmed = url.trim();
19787
19653
  if (/^file:\/\//i.test(trimmed))
19788
- return path20.resolve(dir, trimmed.slice(7)).replace(/\/+$/, "").replace(/\.git$/, "");
19654
+ return path19.resolve(dir, trimmed.slice(7)).replace(/\/+$/, "").replace(/\.git$/, "");
19789
19655
  const scheme = /^[a-z][a-z0-9+.-]*:\/\//i.exec(trimmed);
19790
19656
  const scp = !scheme && /^(?:[^@/\\]+@)?[^/\\:]{2,}:/.test(trimmed);
19791
19657
  if (!scheme && !scp)
19792
- return path20.resolve(dir, trimmed).replace(/\/+$/, "").replace(/\.git$/, "");
19658
+ return path19.resolve(dir, trimmed).replace(/\/+$/, "").replace(/\.git$/, "");
19793
19659
  const value = scheme ? trimmed.slice(scheme[0].length).replace(/^[^@/]*@/, "").replace(/^([^/:]+):\d+(?=\/)/, "$1") : trimmed.replace(/^[^@/]*@/, "").replace(":", "/");
19794
19660
  return value.toLowerCase().replace(/\/{2,}/g, "/").replace(/^www\./, "").replace(/\/+$/, "").replace(/\.git$/, "");
19795
19661
  };
@@ -19850,7 +19716,7 @@ var refusal = (action, branch, dir) => {
19850
19716
  };
19851
19717
  var refFacts = (repo, remote) => {
19852
19718
  const facts = { heads: new Set, tags: new Set, remoteHeads: new Set };
19853
- const listed = spawnSync11("git", ["for-each-ref", "--format=%(refname)", "refs/heads", "refs/tags", `refs/remotes/${remote}`], { cwd: repo.dir, encoding: "utf8", timeout: 5000 });
19719
+ const listed = spawnSync10("git", ["for-each-ref", "--format=%(refname)", "refs/heads", "refs/tags", `refs/remotes/${remote}`], { cwd: repo.dir, encoding: "utf8", timeout: 5000 });
19854
19720
  const remotePrefix = `refs/remotes/${remote}/`;
19855
19721
  for (const ref of (listed.stdout ?? "").split(`
19856
19722
  `)) {
@@ -19867,7 +19733,7 @@ var globBranches = (repo, glob) => {
19867
19733
  const source = glob.source.startsWith("refs/") ? glob.source : `refs/heads/${glob.source}`;
19868
19734
  const [sourcePrefix, sourceSuffix = ""] = source.split("*");
19869
19735
  const [destinationPrefix, destinationSuffix = ""] = glob.destination.split("*");
19870
- const listed = spawnSync11("git", [
19736
+ const listed = spawnSync10("git", [
19871
19737
  "for-each-ref",
19872
19738
  "--format=%(refname)",
19873
19739
  sourcePrefix.slice(0, sourcePrefix.lastIndexOf("/") + 1)
@@ -19944,7 +19810,7 @@ var tagRefusal = (action, facts, dir) => {
19944
19810
  return `workit: raw ${quote(`git push${action.allTags ? " --tags" : ""}`)} of ${tags.length ? `tag ${tags.join(", ")}` : "tags"} bypasses the release grant. Push a release tag with ${quote(`workit git push --release ${named}`)} (${shape} tags whose commit the production branch already has; a tag never moves), under the ${quote("release")} grant (if refused, ask the user to run ${quote("workit grant set <workspace> release=true")}).`;
19945
19811
  };
19946
19812
  var remoteHeads = (repo, remote) => {
19947
- const listed = spawnSync11("git", ["ls-remote", "--heads", remote], {
19813
+ const listed = spawnSync10("git", ["ls-remote", "--heads", remote], {
19948
19814
  cwd: repo.dir,
19949
19815
  encoding: "utf8",
19950
19816
  timeout: 3000,
@@ -20013,7 +19879,7 @@ var actionsIn = (cwd, command, dialect, cache = new Map) => {
20013
19879
  const out = [];
20014
19880
  const repos = new Map;
20015
19881
  const repoFor = (relative) => {
20016
- const dir = path20.resolve(cwd, relative ?? ".");
19882
+ const dir = path19.resolve(cwd, relative ?? ".");
20017
19883
  if (!repos.has(dir)) {
20018
19884
  const repo = repoAt(dir);
20019
19885
  repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
@@ -20099,7 +19965,7 @@ var analysisDenial = (error) => ({
20099
19965
  });
20100
19966
  var NEXT_COMMAND = "next";
20101
19967
  var MARKER_TTL_SECONDS = 3600;
20102
- var markerFile = (repo, session, key) => path20.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
19968
+ var markerFile = (repo, session, key) => path19.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
20103
19969
  var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash14("sha256").update(command).digest("hex")}`;
20104
19970
  function noteRawCommit(input, command, key) {
20105
19971
  try {
@@ -20110,14 +19976,14 @@ function noteRawCommit(input, command, key) {
20110
19976
  if (action.kind !== "commit")
20111
19977
  continue;
20112
19978
  const file = markerFile(repo, input.session.id, key);
20113
- fs16.mkdirSync(path20.dirname(file), { recursive: true });
20114
- fs16.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
19979
+ fs15.mkdirSync(path19.dirname(file), { recursive: true });
19980
+ fs15.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
20115
19981
  `);
20116
19982
  }
20117
19983
  } catch {}
20118
19984
  }
20119
19985
  var headCommit = (dir) => {
20120
- const run = spawnSync11("git", [
19986
+ const run = spawnSync10("git", [
20121
19987
  "log",
20122
19988
  "-1",
20123
19989
  "--format=%H%x1f%ct%x1f%s%x1f%(trailers:key=Workit-Session,valueonly,separator=%x2c)"
@@ -20134,11 +20000,11 @@ var headCommit = (dir) => {
20134
20000
  var settle2 = (input, repo, file) => {
20135
20001
  let marker;
20136
20002
  try {
20137
- marker = JSON.parse(fs16.readFileSync(file, "utf8"));
20003
+ marker = JSON.parse(fs15.readFileSync(file, "utf8"));
20138
20004
  } catch {
20139
20005
  return;
20140
20006
  }
20141
- fs16.rmSync(file, { force: true });
20007
+ fs15.rmSync(file, { force: true });
20142
20008
  const session = input.session.id;
20143
20009
  const now = Date.now() / 1000;
20144
20010
  if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
@@ -20187,7 +20053,7 @@ function settlePendingCommit(input) {
20187
20053
  if (!repo)
20188
20054
  return;
20189
20055
  const file = markerFile(repo, input.session.id, NEXT_COMMAND);
20190
- if (fs16.existsSync(file))
20056
+ if (fs15.existsSync(file))
20191
20057
  settle2(input, repo, file);
20192
20058
  } catch {}
20193
20059
  }
@@ -20331,7 +20197,7 @@ var targetsOf = (invocations) => invocations.flatMap((invocation) => invocation.
20331
20197
  branch,
20332
20198
  dir: invocation.dir
20333
20199
  })) : []);
20334
- var localBranchExists = (dir, branch) => spawnSync12("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`], {
20200
+ var localBranchExists = (dir, branch) => spawnSync11("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`], {
20335
20201
  cwd: dir,
20336
20202
  stdio: "ignore",
20337
20203
  timeout: 5000
@@ -20341,7 +20207,7 @@ var judgedDir = (root, dir) => {
20341
20207
  return null;
20342
20208
  if (dir === null)
20343
20209
  return root;
20344
- const resolved = path21.resolve(root, dir);
20210
+ const resolved = path20.resolve(root, dir);
20345
20211
  return existsSync6(resolved) && inWorkitWorkspace(resolved) ? resolved : null;
20346
20212
  };
20347
20213
  var shellBranchPolicyViolation = (root, command, dialect = "posix") => {
@@ -20375,22 +20241,771 @@ var shellPolicy = (cwd, command, dialect = "posix") => {
20375
20241
  }
20376
20242
  return policy && !policy.ok ? { kind: "deny", reason: `branch_policy_denied: ${policy.error}`, unblock: null } : { kind: "none" };
20377
20243
  };
20244
+ // packages/workit-core/src/core/heavy-rules.ts
20245
+ import fs16 from "node:fs";
20246
+ import os6 from "node:os";
20247
+ import path21 from "node:path";
20248
+ var EMPTY = () => ({ deny: [], allow: [] });
20249
+ var readText2 = (file) => {
20250
+ try {
20251
+ return fs16.readFileSync(file, "utf8");
20252
+ } catch (error) {
20253
+ if (error.code === "ENOENT")
20254
+ return null;
20255
+ throw error;
20256
+ }
20257
+ };
20258
+ var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
20259
+ function parseJsonc(text) {
20260
+ let out = "";
20261
+ for (let index = 0;index < text.length; index += 1) {
20262
+ const char = text[index];
20263
+ if (char === '"') {
20264
+ const end = /"(?:[^"\\]|\\.)*"/y;
20265
+ end.lastIndex = index;
20266
+ const match = end.exec(text);
20267
+ if (!match)
20268
+ throw new Error("unterminated string");
20269
+ out += match[0];
20270
+ index += match[0].length - 1;
20271
+ } else if (char === "/" && text[index + 1] === "/") {
20272
+ while (index < text.length && text[index] !== `
20273
+ `)
20274
+ index += 1;
20275
+ out += `
20276
+ `;
20277
+ } else if (char === "/" && text[index + 1] === "*") {
20278
+ const close = text.indexOf("*/", index + 2);
20279
+ if (close < 0)
20280
+ throw new Error("unterminated comment");
20281
+ index = close + 1;
20282
+ } else
20283
+ out += char;
20284
+ }
20285
+ return JSON.parse(out.replace(/,(\s*[}\]])/gu, "$1"));
20286
+ }
20287
+ function gitTop(cwd) {
20288
+ for (let dir = path21.resolve(cwd);; dir = path21.dirname(dir)) {
20289
+ if (fs16.existsSync(path21.join(dir, ".git")))
20290
+ return dir;
20291
+ if (path21.dirname(dir) === dir)
20292
+ return null;
20293
+ }
20294
+ }
20295
+ var projectDirs = (cwd) => {
20296
+ const top = gitTop(cwd);
20297
+ const dirs = [];
20298
+ for (let dir = path21.resolve(cwd);; dir = path21.dirname(dir)) {
20299
+ dirs.push(dir);
20300
+ if (!top || dir === top || path21.dirname(dir) === dir)
20301
+ return dirs;
20302
+ }
20303
+ };
20304
+ var homeOf = (env) => env.HOME || os6.homedir();
20305
+ var CLAUDE_MANAGED = {
20306
+ linux: "/etc/claude-code/managed-settings.json",
20307
+ darwin: "/Library/Application Support/ClaudeCode/managed-settings.json",
20308
+ win32: "C:\\Program Files\\ClaudeCode\\managed-settings.json"
20309
+ };
20310
+ function claudeSettingsFiles(cwd, env, platform = process.platform) {
20311
+ const project = env.CLAUDE_PROJECT_DIR || gitTop(cwd) || cwd;
20312
+ const user = env.CLAUDE_CONFIG_DIR || path21.join(homeOf(env), ".claude");
20313
+ return [
20314
+ ...CLAUDE_MANAGED[platform] ? [CLAUDE_MANAGED[platform]] : [],
20315
+ path21.join(user, "settings.json"),
20316
+ path21.join(project, ".claude", "settings.json"),
20317
+ path21.join(project, ".claude", "settings.local.json")
20318
+ ];
20319
+ }
20320
+ var bashPattern = (entry) => {
20321
+ const match = /^Bash(?:\((.*)\))?$/su.exec(entry.trim());
20322
+ return match ? match[1] ?? "" : null;
20323
+ };
20324
+ function claudeRules(cwd, env = process.env) {
20325
+ const rules = EMPTY();
20326
+ try {
20327
+ for (const file of claudeSettingsFiles(cwd, env)) {
20328
+ const text = readText2(file);
20329
+ if (text === null)
20330
+ continue;
20331
+ const value = JSON.parse(text);
20332
+ if (!isRecord3(value))
20333
+ return "unreadable";
20334
+ const permissions = value.permissions;
20335
+ if (permissions === undefined)
20336
+ continue;
20337
+ if (!isRecord3(permissions))
20338
+ return "unreadable";
20339
+ for (const [key, bucket] of [
20340
+ ["deny", rules.deny],
20341
+ ["ask", rules.deny],
20342
+ ["allow", rules.allow]
20343
+ ]) {
20344
+ const list = permissions[key];
20345
+ if (list === undefined)
20346
+ continue;
20347
+ if (!Array.isArray(list))
20348
+ return "unreadable";
20349
+ for (const entry of list) {
20350
+ if (typeof entry !== "string")
20351
+ return "unreadable";
20352
+ const pattern = bashPattern(entry);
20353
+ if (pattern !== null)
20354
+ bucket.push(pattern);
20355
+ }
20356
+ }
20357
+ }
20358
+ } catch {
20359
+ return "unreadable";
20360
+ }
20361
+ return rules;
20362
+ }
20363
+ var OPENCODE_NAMES = ["opencode.json", "opencode.jsonc"];
20364
+ var opencodePermission = (permission, rules) => {
20365
+ if (permission === undefined)
20366
+ return true;
20367
+ if (typeof permission === "string") {
20368
+ (permission === "allow" ? rules.allow : rules.deny).push("");
20369
+ return ["allow", "ask", "deny"].includes(permission);
20370
+ }
20371
+ if (!isRecord3(permission))
20372
+ return false;
20373
+ for (const key of ["bash", "shell"]) {
20374
+ const value = permission[key];
20375
+ if (value === undefined)
20376
+ continue;
20377
+ if (typeof value === "string") {
20378
+ if (!["allow", "ask", "deny"].includes(value))
20379
+ return false;
20380
+ (value === "allow" ? rules.allow : rules.deny).push("");
20381
+ continue;
20382
+ }
20383
+ if (!isRecord3(value))
20384
+ return false;
20385
+ for (const [pattern, action] of Object.entries(value)) {
20386
+ if (action !== "allow" && action !== "ask" && action !== "deny")
20387
+ return false;
20388
+ (action === "allow" ? rules.allow : rules.deny).push(pattern);
20389
+ }
20390
+ }
20391
+ return true;
20392
+ };
20393
+ var opencodeConfig = (value, rules) => {
20394
+ if (!isRecord3(value))
20395
+ return false;
20396
+ if (!opencodePermission(value.permission, rules))
20397
+ return false;
20398
+ if (value.agent === undefined)
20399
+ return true;
20400
+ if (!isRecord3(value.agent))
20401
+ return false;
20402
+ return Object.values(value.agent).every((agent) => isRecord3(agent) && opencodePermission(agent.permission, rules));
20403
+ };
20404
+ function opencodeRules(cwd, env = process.env) {
20405
+ const rules = EMPTY();
20406
+ try {
20407
+ const config = env.XDG_CONFIG_HOME || path21.join(homeOf(env), ".config");
20408
+ const files = [
20409
+ ...OPENCODE_NAMES.map((name) => path21.join(config, "opencode", name)),
20410
+ ...projectDirs(cwd).flatMap((dir) => OPENCODE_NAMES.flatMap((name) => [path21.join(dir, name), path21.join(dir, ".opencode", name)])),
20411
+ ...env.OPENCODE_CONFIG ? [env.OPENCODE_CONFIG] : []
20412
+ ];
20413
+ for (const file of files) {
20414
+ const text = readText2(file);
20415
+ if (text !== null && !opencodeConfig(parseJsonc(text), rules))
20416
+ return "unreadable";
20417
+ }
20418
+ if (env.OPENCODE_CONFIG_CONTENT && !opencodeConfig(parseJsonc(env.OPENCODE_CONFIG_CONTENT), rules))
20419
+ return "unreadable";
20420
+ } catch {
20421
+ return "unreadable";
20422
+ }
20423
+ return rules;
20424
+ }
20425
+ var codexRule = (body) => {
20426
+ const open = /\bpattern\s*=\s*\[/u.exec(body);
20427
+ if (!open)
20428
+ return null;
20429
+ const words = [];
20430
+ let index = open.index + open[0].length;
20431
+ for (;; ) {
20432
+ while (/[\s,]/u.test(body[index] ?? ""))
20433
+ index += 1;
20434
+ if (body[index] === "]")
20435
+ break;
20436
+ if (body[index] !== '"')
20437
+ return null;
20438
+ const literal = /"((?:[^"\\]|\\.)*)"/y;
20439
+ literal.lastIndex = index;
20440
+ const match = literal.exec(body);
20441
+ if (!match)
20442
+ return null;
20443
+ words.push(JSON.parse(`"${match[1]}"`));
20444
+ index = literal.lastIndex;
20445
+ }
20446
+ const decision = /\bdecision\s*=\s*"(\w+)"/u.exec(body)?.[1];
20447
+ if (!words.length || !decision || !["allow", "prompt", "forbidden"].includes(decision))
20448
+ return null;
20449
+ return { pattern: words.join(" "), decision };
20450
+ };
20451
+ function codexRules(cwd, env = process.env) {
20452
+ const rules = EMPTY();
20453
+ try {
20454
+ const home = env.CODEX_HOME || path21.join(homeOf(env), ".codex");
20455
+ const top = gitTop(cwd) ?? cwd;
20456
+ for (const dir of [path21.join(home, "rules"), path21.join(top, ".codex", "rules")]) {
20457
+ let files;
20458
+ try {
20459
+ files = fs16.readdirSync(dir).filter((name) => name.endsWith(".rules"));
20460
+ } catch (error) {
20461
+ if (error.code === "ENOENT")
20462
+ continue;
20463
+ return "unreadable";
20464
+ }
20465
+ for (const name of files) {
20466
+ const text = readText2(path21.join(dir, name)) ?? "";
20467
+ for (const part of text.split(/\bprefix_rule\s*\(/u).slice(1)) {
20468
+ const rule = codexRule(part);
20469
+ if (!rule)
20470
+ return "unreadable";
20471
+ (rule.decision === "allow" ? rules.allow : rules.deny).push(rule.pattern);
20472
+ }
20473
+ }
20474
+ }
20475
+ } catch {
20476
+ return "unreadable";
20477
+ }
20478
+ return rules;
20479
+ }
20480
+ function cursorRules(cwd, env = process.env) {
20481
+ const rules = EMPTY();
20482
+ try {
20483
+ const top = gitTop(cwd) ?? cwd;
20484
+ for (const file of [
20485
+ path21.join(homeOf(env), ".cursor", "cli-config.json"),
20486
+ path21.join(top, ".cursor", "cli.json")
20487
+ ]) {
20488
+ const text = readText2(file);
20489
+ if (text === null)
20490
+ continue;
20491
+ const value = JSON.parse(text);
20492
+ if (!isRecord3(value))
20493
+ return "unreadable";
20494
+ if (value.permissions === undefined)
20495
+ continue;
20496
+ if (!isRecord3(value.permissions))
20497
+ return "unreadable";
20498
+ for (const [key, bucket] of [
20499
+ ["deny", rules.deny],
20500
+ ["allow", rules.allow]
20501
+ ]) {
20502
+ const list = value.permissions[key];
20503
+ if (list === undefined)
20504
+ continue;
20505
+ if (!Array.isArray(list))
20506
+ return "unreadable";
20507
+ for (const entry of list) {
20508
+ if (typeof entry !== "string")
20509
+ return "unreadable";
20510
+ const match = /^Shell(?:\((.*)\))?$/su.exec(entry.trim());
20511
+ if (match)
20512
+ bucket.push(match[1] ?? "");
20513
+ }
20514
+ }
20515
+ }
20516
+ } catch {
20517
+ return "unreadable";
20518
+ }
20519
+ return rules;
20520
+ }
20521
+ var baseName = (word) => (word.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat)$/u, "");
20522
+ var firstToken = (pattern) => pattern.trim().split(/[:\s]/u)[0] ?? "";
20523
+ function names(pattern, words) {
20524
+ const token = firstToken(pattern);
20525
+ if (!token || token === "*" || token.includes("*"))
20526
+ return true;
20527
+ const wanted = baseName(token);
20528
+ return words.some((word) => baseName(word) === wanted);
20529
+ }
20530
+ var literalPrefix = (pattern) => pattern.trim().replace(/(?::\*| \*|\*)$/u, "");
20531
+ var coversWrapper = (pattern) => {
20532
+ const token = firstToken(pattern);
20533
+ if (!token || token.includes("*"))
20534
+ return true;
20535
+ const words = literalPrefix(pattern).split(/\s+/u);
20536
+ if (baseName(words[0]) !== "workit")
20537
+ return false;
20538
+ return ["check", "--heavy"].slice(0, words.length - 1).every((word, at) => {
20539
+ const given = words[at + 1];
20540
+ return given === word || word.startsWith(given);
20541
+ });
20542
+ };
20543
+ var coversCommand = (pattern, command) => {
20544
+ const prefix = literalPrefix(pattern);
20545
+ if (!prefix)
20546
+ return true;
20547
+ return !prefix.includes("*") && command.trim().startsWith(prefix);
20548
+ };
20549
+ function wrapAllowed(read, words, command, options = {}) {
20550
+ if (read === "unreadable")
20551
+ return { ok: false, why: "named" };
20552
+ if (read.deny.some((pattern) => names(pattern, words)))
20553
+ return { ok: false, why: "named" };
20554
+ if (!options.bypass && read.allow.some(coversWrapper) && !read.allow.some((pattern) => coversCommand(pattern, command)))
20555
+ return { ok: false, why: "allowlisted" };
20556
+ return { ok: true };
20557
+ }
20558
+
20559
+ // packages/workit-core/src/core/heavy.ts
20560
+ import fs17 from "node:fs";
20561
+ import os7 from "node:os";
20562
+ import path22 from "node:path";
20563
+ function stateDir(env, platform = process.platform) {
20564
+ if (env.WORKFLOW_TOOLKIT_STATE)
20565
+ return env.WORKFLOW_TOOLKIT_STATE;
20566
+ if (env.XDG_STATE_HOME)
20567
+ return path22.join(env.XDG_STATE_HOME, "workit");
20568
+ const home = env.HOME || os7.homedir();
20569
+ if (platform === "darwin")
20570
+ return path22.join(home, "Library", "Application Support", "workit");
20571
+ if (platform === "win32")
20572
+ return path22.join(env.LOCALAPPDATA ?? path22.join(home, "AppData", "Local"), "workit");
20573
+ return path22.join(home, ".local", "state", "workit");
20574
+ }
20575
+ var HEAVY_COMMANDS_FILE = "heavy-commands.json";
20576
+ var heavyCommandsFile = (env) => path22.join(stateDir(env), HEAVY_COMMANDS_FILE);
20577
+ 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;
20578
+ var INFO_FLAGS = new Set(["--version", "-v", "-V", "--help", "-h", "help", "version"]);
20579
+ var WATCH_FLAG = /^(?:--watch(?:All)?(?:=.*)?|-w|--serve)$/u;
20580
+ var WATCH_SCRIPT = /(?:^|[:_.-])(?:watch|dev|serve|start|storybook)(?:$|[:_.-])/iu;
20581
+ var sub = (...names) => new Set(names);
20582
+ var TOOLS = {
20583
+ jest: "any",
20584
+ vitest: "any",
20585
+ mocha: "any",
20586
+ ava: "any",
20587
+ tap: "any",
20588
+ karma: "any",
20589
+ jasmine: "any",
20590
+ nyc: "any",
20591
+ c8: "any",
20592
+ tsc: "any",
20593
+ "vue-tsc": "any",
20594
+ "svelte-check": "any",
20595
+ eslint: "any",
20596
+ stylelint: "any",
20597
+ tslint: "any",
20598
+ webpack: "any",
20599
+ "webpack-cli": "any",
20600
+ rollup: "any",
20601
+ parcel: "any",
20602
+ tsup: "any",
20603
+ vite: sub("build", "optimize"),
20604
+ next: sub("build", "lint"),
20605
+ nuxt: sub("build", "generate"),
20606
+ nuxi: sub("build", "generate"),
20607
+ astro: sub("build", "check"),
20608
+ ng: sub("build", "b", "test", "t", "e2e", "lint"),
20609
+ "react-scripts": sub("build", "test"),
20610
+ playwright: sub("test", "install"),
20611
+ cypress: sub("run"),
20612
+ wdio: "any",
20613
+ testcafe: "any",
20614
+ turbo: "any",
20615
+ lerna: sub("run", "exec", "bootstrap"),
20616
+ "sonar-scanner": "any",
20617
+ sonarless: sub("scan"),
20618
+ "sonarless-mcp": sub("scan"),
20619
+ go: sub("test", "build", "vet", "install", "generate"),
20620
+ "golangci-lint": sub("run"),
20621
+ gotestsum: "any",
20622
+ staticcheck: "any",
20623
+ cargo: sub("build", "b", "test", "t", "check", "c", "clippy", "bench", "nextest", "doc", "install", "tarpaulin", "llvm-cov"),
20624
+ mvn: "any",
20625
+ mvnw: "any",
20626
+ gradle: "any",
20627
+ gradlew: "any",
20628
+ ant: "any",
20629
+ sbt: "any",
20630
+ bazel: sub("build", "test", "run", "coverage"),
20631
+ bazelisk: sub("build", "test", "run", "coverage"),
20632
+ buck2: sub("build", "test", "run"),
20633
+ dotnet: sub("build", "test", "publish", "restore", "pack", "msbuild"),
20634
+ msbuild: "any",
20635
+ pytest: "any",
20636
+ "py.test": "any",
20637
+ tox: "any",
20638
+ nox: "any",
20639
+ mypy: "any",
20640
+ pyright: "any",
20641
+ pylint: "any",
20642
+ coverage: sub("run"),
20643
+ maturin: sub("build", "develop"),
20644
+ pip: sub("install", "wheel"),
20645
+ pip3: sub("install", "wheel"),
20646
+ rspec: "any",
20647
+ rails: sub("test", "assets:precompile"),
20648
+ phpunit: "any",
20649
+ pest: "any",
20650
+ phpstan: "any",
20651
+ psalm: "any",
20652
+ composer: sub("install", "update", "require", "test"),
20653
+ mix: sub("test", "compile", "deps.get", "dialyzer", "credo"),
20654
+ swift: sub("build", "test"),
20655
+ xcodebuild: "any",
20656
+ flutter: sub("build", "test"),
20657
+ dart: sub("test", "compile"),
20658
+ pod: sub("install"),
20659
+ cmake: sub("--build"),
20660
+ ninja: "any",
20661
+ meson: sub("compile", "test"),
20662
+ ctest: "any",
20663
+ scons: "any",
20664
+ "docker-compose": sub("build"),
20665
+ buildah: sub("bud", "build"),
20666
+ earthly: "any"
20667
+ };
20668
+ var PM_VALUES = new Set([
20669
+ "--prefix",
20670
+ "-w",
20671
+ "--workspace",
20672
+ "-C",
20673
+ "--dir",
20674
+ "--filter",
20675
+ "-F",
20676
+ "--cwd",
20677
+ "-p",
20678
+ "--package",
20679
+ "--cache",
20680
+ "--registry"
20681
+ ]);
20682
+ function positional2(words, from, values = PM_VALUES) {
20683
+ let index = from;
20684
+ while (index < words.length && words[index].startsWith("-")) {
20685
+ if (words[index] === "--")
20686
+ return index + 1;
20687
+ index += values.has(words[index]) ? 2 : 1;
20688
+ }
20689
+ return index;
20690
+ }
20691
+ var baseName2 = (word) => (word?.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat|ps1)$/u, "");
20692
+ var WORKIT = /^(?:workit|@brainervirus\/workit-cli(?:@.*)?)$/u;
20693
+ var PYTHONS = /^(?:python[\d.]*|py)$/u;
20694
+ var NPM_INSTALL = new Set([
20695
+ "ci",
20696
+ "clean-install",
20697
+ "cit",
20698
+ "install-test",
20699
+ "it",
20700
+ "install",
20701
+ "i",
20702
+ "in",
20703
+ "add",
20704
+ "rebuild",
20705
+ "update",
20706
+ "up"
20707
+ ]);
20708
+ var NPM_RUN = new Set(["run", "run-script", "rum", "urn"]);
20709
+ var NPM_TEST = new Set(["test", "t", "tst"]);
20710
+ var EXEC = new Set(["exec", "x", "dlx"]);
20711
+ function builtIn(words, depth = 0) {
20712
+ if (depth > 6 || !words.length)
20713
+ return null;
20714
+ const name = baseName2(words[0]);
20715
+ const label = () => words.slice(0, 3).join(" ");
20716
+ const inner = (from) => builtIn(words.slice(from), depth + 1);
20717
+ if (WORKIT.test(name))
20718
+ return null;
20719
+ if (INFO_FLAGS.has(words[1] ?? "") && words.length === 2)
20720
+ return null;
20721
+ if (words.some((word) => word === "--watch" || word.startsWith("--watch=") || word === "--watchAll"))
20722
+ return null;
20723
+ if (name === "npx" || name === "bunx" || name === "pnpx")
20724
+ return inner(positional2(words, 1));
20725
+ if (name === "corepack")
20726
+ return inner(1);
20727
+ if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun" || name === "deno") {
20728
+ const at = positional2(words, 1);
20729
+ const command = words[at];
20730
+ if (command === undefined)
20731
+ return name === "yarn" ? "yarn (install)" : null;
20732
+ if (name === "deno") {
20733
+ if (["test", "bench", "check", "compile", "lint"].includes(command))
20734
+ return label();
20735
+ if (command === "task" && HEAVY_SCRIPT.test(words[at + 1] ?? ""))
20736
+ return label();
20737
+ return null;
20738
+ }
20739
+ if (NPM_INSTALL.has(command) || NPM_TEST.has(command))
20740
+ return label();
20741
+ if (name === "bun" && command === "build")
20742
+ return label();
20743
+ if (EXEC.has(command))
20744
+ return inner(positional2(words, at + 1));
20745
+ if (name === "yarn" && command === "workspace")
20746
+ return inner(at + 2);
20747
+ if (name === "yarn" && command === "workspaces")
20748
+ return words.slice(at + 1).some((word) => HEAVY_SCRIPT.test(word)) ? label() : null;
20749
+ if (NPM_RUN.has(command)) {
20750
+ const script = words[positional2(words, at + 1)];
20751
+ if (script === undefined || WATCH_SCRIPT.test(script))
20752
+ return null;
20753
+ if (HEAVY_SCRIPT.test(script))
20754
+ return label();
20755
+ return name === "bun" ? inner(positional2(words, at + 1)) : null;
20756
+ }
20757
+ if (name === "npm")
20758
+ return null;
20759
+ if (WATCH_SCRIPT.test(command))
20760
+ return null;
20761
+ if (HEAVY_SCRIPT.test(command) && !/\.[cm]?[jt]sx?$/u.test(command))
20762
+ return label();
20763
+ return inner(at);
20764
+ }
20765
+ if (PYTHONS.test(name)) {
20766
+ const at = words.indexOf("-m");
20767
+ return at > 0 && words[at + 1] ? inner(at + 1) : null;
20768
+ }
20769
+ if (["uv", "poetry", "pdm", "pipenv", "hatch", "rye"].includes(name)) {
20770
+ const at = positional2(words, 1);
20771
+ const command = words[at];
20772
+ if (command === "run")
20773
+ return inner(positional2(words, at + 1));
20774
+ if (command === "pip")
20775
+ return inner(at);
20776
+ return ["sync", "install", "build", "test", "add"].includes(command ?? "") ? label() : null;
20777
+ }
20778
+ if (name === "bundle") {
20779
+ const command = words[positional2(words, 1)];
20780
+ if (command === "exec")
20781
+ return inner(positional2(words, 2));
20782
+ return command === "install" || command === undefined ? label() : null;
20783
+ }
20784
+ if (name === "make" || name === "gmake") {
20785
+ const targets = words.slice(1).filter((word) => !word.startsWith("-") && !word.includes("="));
20786
+ if (targets.some((target) => WATCH_SCRIPT.test(target)))
20787
+ return null;
20788
+ return !targets.length || targets.some((target) => HEAVY_SCRIPT.test(target)) ? label() : null;
20789
+ }
20790
+ if (name === "rake") {
20791
+ const targets = words.slice(1).filter((word) => !word.startsWith("-") && !word.includes("="));
20792
+ return targets.some((target) => HEAVY_SCRIPT.test(target) || /^spec(?:$|:)/u.test(target)) ? label() : null;
20793
+ }
20794
+ if (name === "nx") {
20795
+ const at = positional2(words, 1);
20796
+ const command = words[at] ?? "";
20797
+ if (["run-many", "affected"].includes(command))
20798
+ return words.some((word) => /^(?:-t|--targets?)(?:=|$)/u.test(word)) && !words.some((word) => WATCH_SCRIPT.test(word.replace(/^--?targets?=/u, ""))) ? label() : null;
20799
+ if (command === "run") {
20800
+ const target = (words[at + 1] ?? "").split(":")[1] ?? "";
20801
+ return HEAVY_SCRIPT.test(target) && !WATCH_SCRIPT.test(target) ? label() : null;
20802
+ }
20803
+ return HEAVY_SCRIPT.test(command) && !WATCH_SCRIPT.test(command) ? label() : null;
20804
+ }
20805
+ if (name === "docker" || name === "podman" || name === "nerdctl") {
20806
+ const at = positional2(words, 1, new Set(["-H", "--host", "--context", "-c", "--config"]));
20807
+ const command = words[at];
20808
+ if (command === "build")
20809
+ return label();
20810
+ if (command === "buildx" || command === "image" || command === "builder")
20811
+ return words[positional2(words, at + 1)] === "build" ? label() : null;
20812
+ if (command === "compose") {
20813
+ const at2 = positional2(words, at + 1, new Set(["-f", "--file", "-p"]));
20814
+ const action = words[at2];
20815
+ if (action === "build")
20816
+ return label();
20817
+ return action === "up" && words.slice(at2 + 1).includes("--build") ? label() : null;
20818
+ }
20819
+ return null;
20820
+ }
20821
+ const rule = TOOLS[name];
20822
+ if (!rule)
20823
+ return null;
20824
+ if (words.slice(1).some((word) => WATCH_FLAG.test(word) || word === "watch" || word === "dev"))
20825
+ return null;
20826
+ if (rule === "any")
20827
+ return label();
20828
+ const command = words.slice(1).find((word) => !word.startsWith("-") && !word.startsWith("+") || rule.has(word));
20829
+ return command !== undefined && rule.has(command) ? label() : null;
20830
+ }
20831
+ var globWord = (word) => new RegExp(`^${word.replace(/[.+?^${}()|[\]\\]/gu, "\\$&").replaceAll("*", ".*")}$`, "u");
20832
+ function parsePattern(pattern) {
20833
+ const words = pattern.trim().split(/\s+/u).filter(Boolean);
20834
+ return words.length ? words.map(globWord) : null;
20835
+ }
20836
+ 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]));
20837
+ var readJson = (file) => {
20838
+ try {
20839
+ return JSON.parse(fs17.readFileSync(file, "utf8"));
20840
+ } catch {
20841
+ return;
20842
+ }
20843
+ };
20844
+ var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
20845
+ var stringList = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
20846
+ function machinePatterns(env) {
20847
+ const value = readJson(heavyCommandsFile(env));
20848
+ return isRecord4(value) ? stringList(value.patterns) : [];
20849
+ }
20850
+ function repoPatterns(cwd) {
20851
+ return repoHeavyCommands(gitTop(cwd) ?? path22.resolve(cwd));
20852
+ }
20853
+ function heavyLines(lines, options) {
20854
+ const found = [];
20855
+ let patterns = null;
20856
+ for (const line of lines) {
20857
+ const reason = builtIn(line);
20858
+ if (reason) {
20859
+ found.push({ line, source: "catalog", reason });
20860
+ continue;
20861
+ }
20862
+ patterns ??= (options.patterns ?? [
20863
+ ...machinePatterns(options.env ?? process.env).map((pattern) => ({
20864
+ pattern,
20865
+ from: "machine"
20866
+ })),
20867
+ ...repoPatterns(options.cwd).map((pattern) => ({ pattern, from: "repo" }))
20868
+ ]).flatMap((entry) => {
20869
+ const matchers = parsePattern(entry.pattern);
20870
+ return matchers ? [{ ...entry, matchers }] : [];
20871
+ });
20872
+ const hit = patterns.find((entry) => matches(entry.matchers, line));
20873
+ if (hit)
20874
+ found.push({
20875
+ line,
20876
+ source: { pattern: hit.pattern, from: hit.from },
20877
+ reason: `${hit.from} pattern "${hit.pattern}"`
20878
+ });
20879
+ }
20880
+ return found;
20881
+ }
20882
+ var linesOf = (command, dialect) => {
20883
+ try {
20884
+ return commandLines(command, dialect);
20885
+ } catch {
20886
+ return null;
20887
+ }
20888
+ };
20889
+ var quoteWord = (word) => /^[\w@%+=:,./-]+$/u.test(word) ? word : `'${word.replaceAll("'", `'\\''`)}'`;
20890
+ var leaseCommand = (words) => `workit check --heavy -- ${words.map(quoteWord).join(" ")}`;
20891
+ function heavyPlan(command, options) {
20892
+ const dialect = options.dialect ?? "posix";
20893
+ if (dialect !== "posix" || !gitTop(options.cwd))
20894
+ return { kind: "none" };
20895
+ const lines = linesOf(command, dialect);
20896
+ if (!lines)
20897
+ return { kind: "none" };
20898
+ const heavy = heavyLines(lines, options);
20899
+ if (!heavy.length)
20900
+ return { kind: "none" };
20901
+ const simple = simpleCommand(command, dialect);
20902
+ const single = simple && !WORKIT.test(baseName2(simple[0])) && heavyLines([simple], options)[0];
20903
+ const judged = single ? [{ words: lines.flat(), text: command }] : heavy.map((match) => ({
20904
+ words: match.line,
20905
+ text: match.line.join(" ")
20906
+ }));
20907
+ if (options.rules !== null)
20908
+ for (const { words, text } of judged) {
20909
+ const verdict = wrapAllowed(options.rules, words, text, { bypass: options.bypass });
20910
+ if (!verdict.ok)
20911
+ return {
20912
+ kind: "passthrough",
20913
+ note: `workit: \`${command.trim()}\` is heavy but runs outside the heavy-check lease because a host permission rule names it (or \`workit\` is allowlisted); the host decides.`
20914
+ };
20915
+ }
20916
+ if (single) {
20917
+ const rewrite = leaseRewrite(command);
20918
+ return rewrite ? { kind: "rewrite", command: rewrite, reason: single.reason } : { kind: "none" };
20919
+ }
20920
+ const parts = heavy.map((match) => leaseCommand(match.line));
20921
+ return {
20922
+ kind: "split",
20923
+ reason: `heavy_command: \`${command.trim()}\` chains heavy work (${heavy.map((match) => match.reason).join("; ")}) with other commands, and a chain cannot run under the machine-wide heavy-check lease. Run each heavy part alone as \`workit check --heavy -- <segment>\` (here: ${parts.map((part) => `\`${part}\``).join("; ")}); run the other parts as their own commands.`,
20924
+ unblock: parts[0] ?? null
20925
+ };
20926
+ }
20927
+ function workitOnPath(env = process.env) {
20928
+ const names = process.platform === "win32" ? ["workit.exe", "workit.cmd", "workit"] : ["workit"];
20929
+ for (const dir of (env.PATH ?? "").split(path22.delimiter))
20930
+ for (const name of names) {
20931
+ if (!dir)
20932
+ continue;
20933
+ try {
20934
+ fs17.accessSync(path22.join(dir, name), fs17.constants.X_OK);
20935
+ return true;
20936
+ } catch {}
20937
+ }
20938
+ return false;
20939
+ }
20940
+ var ASSIGNMENTS = /^\s*((?:[A-Za-z_]\w*=(?:'[^']*'|"(?:[^"\\]|\\.)*"|[^\s'"])*\s+)*)/u;
20941
+ function leaseRewrite(command) {
20942
+ const text = command.trim();
20943
+ const prefix = ASSIGNMENTS.exec(text)?.[1] ?? "";
20944
+ const rest = text.slice(prefix.length).trim();
20945
+ if (!rest)
20946
+ return null;
20947
+ return `${prefix}workit check --heavy -- ${rest}`;
20948
+ }
20949
+
20950
+ // packages/workit-core/src/hooks/heavy-gate.ts
20951
+ var rulesFor = (host, cwd, env) => {
20952
+ switch (host) {
20953
+ case "claude_code":
20954
+ return claudeRules(cwd, env);
20955
+ case "opencode":
20956
+ return opencodeRules(cwd, env);
20957
+ case "codex_cli":
20958
+ case "codex_desktop":
20959
+ return codexRules(cwd, env);
20960
+ case "cursor":
20961
+ return cursorRules(cwd, env);
20962
+ case "pi":
20963
+ return null;
20964
+ }
20965
+ };
20966
+ function heavyGate(cwd, command, options) {
20967
+ const env = options.env ?? process.env;
20968
+ try {
20969
+ if (env.WORKIT_HEAVY_GATE === "0" || !maybeHeavy(command, cwd, env) || !workitOnPath(env))
20970
+ return { kind: "none" };
20971
+ return heavyPlan(command, {
20972
+ cwd,
20973
+ env,
20974
+ dialect: options.dialect ?? "posix",
20975
+ rules: rulesFor(options.host, cwd, env),
20976
+ bypass: options.permissionMode === "bypassPermissions"
20977
+ });
20978
+ } catch {
20979
+ return { kind: "none" };
20980
+ }
20981
+ }
20982
+ var rewriteNote = (plan) => `workit: this heavy command (${plan.reason}) runs under the machine-wide heavy-check lease as \`${plan.command}\`: it waits while another heavy check holds the lease (\`workit lock status\` shows who). Run heavy commands that way yourself; \`workit help lock\` explains the lease.`;
20983
+ var heavyDenial = (original, plan) => ({
20984
+ kind: "deny",
20985
+ reason: `heavy_command: \`${original.trim()}\` is heavy (${plan.reason}) and must run under the machine-wide heavy-check lease, so parallel agents cannot exhaust this machine's memory and CPU. Run exactly: ${plan.command}`,
20986
+ unblock: plan.command
20987
+ });
20988
+ var splitDenial = (plan) => ({
20989
+ kind: "deny",
20990
+ reason: plan.reason,
20991
+ unblock: plan.unblock
20992
+ });
20378
20993
  // packages/workit-core/src/hooks/write-gate.ts
20379
20994
  import { realpathSync as realpathSync5 } from "node:fs";
20380
- import os7 from "node:os";
20381
- import path23 from "node:path";
20995
+ import os9 from "node:os";
20996
+ import path24 from "node:path";
20382
20997
 
20383
20998
  // packages/workit-core/src/core/live-session.ts
20384
- import { spawnSync as spawnSync13 } from "node:child_process";
20999
+ import { spawnSync as spawnSync12 } from "node:child_process";
20385
21000
  import { createHash as createHash15 } from "node:crypto";
20386
- import fs17 from "node:fs";
20387
- import os6 from "node:os";
20388
- import path22 from "node:path";
21001
+ import fs18 from "node:fs";
21002
+ import os8 from "node:os";
21003
+ import path23 from "node:path";
20389
21004
  var LIVE_SESSION_TTL_MS = 15 * 60000;
20390
21005
  var HEARTBEAT_EVERY_MS = 30000;
20391
21006
  var liveProbe = {
20392
21007
  platform: process.platform,
20393
- run: (args) => spawnSync13("ps", args, { encoding: "utf8", timeout: 2000 }).stdout ?? "",
21008
+ run: (args) => spawnSync12("ps", args, { encoding: "utf8", timeout: 2000 }).stdout ?? "",
20394
21009
  start: (pid) => processStartOf(pid)
20395
21010
  };
20396
21011
  var leadOf = (session) => session.split(":")[0].replace(/-w-.*$/su, "") || session;
@@ -20406,9 +21021,9 @@ var processAlive = (pid) => {
20406
21021
  var processInfo = (pid) => {
20407
21022
  try {
20408
21023
  if (liveProbe.platform === "linux") {
20409
- const stat = fs17.readFileSync(`/proc/${pid}/stat`, "utf8");
21024
+ const stat = fs18.readFileSync(`/proc/${pid}/stat`, "utf8");
20410
21025
  const ppid = Number(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[1]);
20411
- const command = fs17.readFileSync(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ");
21026
+ const command = fs18.readFileSync(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ");
20412
21027
  return Number.isInteger(ppid) ? { ppid, command: command.trim() } : null;
20413
21028
  }
20414
21029
  if (liveProbe.platform === "win32")
@@ -20459,35 +21074,35 @@ var liveOwner = (input, transport, env = process.env) => {
20459
21074
  };
20460
21075
  };
20461
21076
  var checkoutOf = (target) => {
20462
- let dir = path22.resolve(target);
20463
- while (!fs17.existsSync(dir) && path22.dirname(dir) !== dir)
20464
- dir = path22.dirname(dir);
20465
- if (fs17.existsSync(dir) && !fs17.statSync(dir).isDirectory())
20466
- dir = path22.dirname(dir);
20467
- const parts = dir.split(path22.sep);
21077
+ let dir = path23.resolve(target);
21078
+ while (!fs18.existsSync(dir) && path23.dirname(dir) !== dir)
21079
+ dir = path23.dirname(dir);
21080
+ if (fs18.existsSync(dir) && !fs18.statSync(dir).isDirectory())
21081
+ dir = path23.dirname(dir);
21082
+ const parts = dir.split(path23.sep);
20468
21083
  const dotGit = parts.lastIndexOf(".git");
20469
21084
  if (dotGit > 0)
20470
- dir = parts.slice(0, dotGit).join(path22.sep) || path22.sep;
21085
+ dir = parts.slice(0, dotGit).join(path23.sep) || path23.sep;
20471
21086
  const location = resolveStore(dir);
20472
21087
  if (location instanceof Error || !location.shared || !location.top)
20473
21088
  return null;
20474
21089
  let top = location.top;
20475
21090
  try {
20476
- top = fs17.realpathSync.native(top);
21091
+ top = fs18.realpathSync.native(top);
20477
21092
  } catch {}
20478
21093
  return top;
20479
21094
  };
20480
- var markerFile2 = (top) => path22.join(resolveStateDir(), "live-sessions", `${createHash15("sha256").update(checkoutKey(top)).digest("hex").slice(0, 32)}.json`);
21095
+ var markerFile2 = (top) => path23.join(resolveStateDir(), "live-sessions", `${createHash15("sha256").update(checkoutKey(top)).digest("hex").slice(0, 32)}.json`);
20481
21096
  var checkoutKey = (top, platform = process.platform) => {
20482
- let key = path22.resolve(top);
21097
+ let key = path23.resolve(top);
20483
21098
  try {
20484
- key = fs17.realpathSync.native(key);
21099
+ key = fs18.realpathSync.native(key);
20485
21100
  } catch {}
20486
21101
  return platform === "win32" ? key.replaceAll("/", "\\").toLowerCase() : key;
20487
21102
  };
20488
21103
  var readMarker = (file) => {
20489
21104
  try {
20490
- const value = JSON.parse(fs17.readFileSync(file, "utf8"));
21105
+ const value = JSON.parse(fs18.readFileSync(file, "utf8"));
20491
21106
  if (value?.version !== 1 || typeof value.session !== "string" || typeof value.host !== "string" || typeof value.heartbeatAt !== "string" || Number.isNaN(Date.parse(value.heartbeatAt)))
20492
21107
  return null;
20493
21108
  return {
@@ -20510,7 +21125,7 @@ var isLive = (marker, deps) => {
20510
21125
  const age = ageOf2(marker, deps.now ?? new Date);
20511
21126
  if (age > (deps.ttlMs ?? LIVE_SESSION_TTL_MS))
20512
21127
  return false;
20513
- if (marker.machine !== (deps.machine ?? os6.hostname()) || marker.pid === null)
21128
+ if (marker.machine !== (deps.machine ?? os8.hostname()) || marker.pid === null)
20514
21129
  return true;
20515
21130
  if (!(deps.alive ?? processAlive)(marker.pid))
20516
21131
  return false;
@@ -20539,7 +21154,7 @@ var liveConflict = (target, owner, deps = {}) => {
20539
21154
  const marker = readMarker(file);
20540
21155
  if (!marker || sameLead(marker, owner) || !isLive(marker, deps))
20541
21156
  return null;
20542
- if (sameOwner(marker, owner, deps.machine ?? os6.hostname()))
21157
+ if (sameOwner(marker, owner, deps.machine ?? os8.hostname()))
20543
21158
  return null;
20544
21159
  return { marker, file, ageMs: ageOf2(marker, deps.now ?? new Date), checkout };
20545
21160
  } catch {
@@ -20553,7 +21168,7 @@ var claimLiveSession = (target, owner, deps = {}) => {
20553
21168
  return;
20554
21169
  const file = markerFile2(checkout);
20555
21170
  const now = deps.now ?? new Date;
20556
- const machine = deps.machine ?? os6.hostname();
21171
+ const machine = deps.machine ?? os8.hostname();
20557
21172
  const current = readMarker(file);
20558
21173
  if (current) {
20559
21174
  const age = ageOf2(current, now);
@@ -20574,10 +21189,10 @@ var claimLiveSession = (target, owner, deps = {}) => {
20574
21189
  checkout,
20575
21190
  heartbeatAt: now.toISOString()
20576
21191
  };
20577
- fs17.mkdirSync(path22.dirname(file), { recursive: true });
21192
+ fs18.mkdirSync(path23.dirname(file), { recursive: true });
20578
21193
  const temp = `${file}.${process.pid}.tmp`;
20579
- fs17.writeFileSync(temp, JSON.stringify(marker));
20580
- fs17.renameSync(temp, file);
21194
+ fs18.writeFileSync(temp, JSON.stringify(marker));
21195
+ fs18.renameSync(temp, file);
20581
21196
  } catch {}
20582
21197
  };
20583
21198
 
@@ -20586,27 +21201,42 @@ var NONE3 = { kind: "none" };
20586
21201
  var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
20587
21202
  var canonical2 = (file) => {
20588
21203
  let rest = "";
20589
- for (let dir = path23.resolve(file);; dir = path23.dirname(dir)) {
21204
+ for (let dir = path24.resolve(file);; dir = path24.dirname(dir)) {
20590
21205
  try {
20591
- return path23.join(realpathSync5(dir), rest);
21206
+ return path24.join(realpathSync5(dir), rest);
20592
21207
  } catch {
20593
- if (path23.dirname(dir) === dir)
20594
- return path23.resolve(file);
20595
- rest = rest ? path23.join(path23.basename(dir), rest) : path23.basename(dir);
21208
+ if (path24.dirname(dir) === dir)
21209
+ return path24.resolve(file);
21210
+ rest = rest ? path24.join(path24.basename(dir), rest) : path24.basename(dir);
20596
21211
  }
20597
21212
  }
20598
21213
  };
20599
21214
  var exempt = (cwd, root, file, plans) => {
20600
21215
  const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
20601
- const relative = path23.relative(fold(canonical2(root)), fold(canonical2(path23.resolve(cwd, file))));
20602
- if (relative.startsWith("..") || path23.isAbsolute(relative))
21216
+ const relative = path24.relative(fold(canonical2(root)), fold(canonical2(path24.resolve(cwd, file))));
21217
+ if (relative.startsWith("..") || path24.isAbsolute(relative))
20603
21218
  return true;
20604
- const posix = relative.split(path23.sep).join("/");
21219
+ const posix = relative.split(path24.sep).join("/");
20605
21220
  const segments = posix.split("/");
20606
21221
  return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
20607
21222
  };
20608
21223
  var PREFIXES2 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "xargs"]);
20609
21224
  var operands = (words) => words.filter((item) => !item.startsWith("-"));
21225
+ var SCRIPT_SHELLS = new Set(["sh", "bash", "zsh", "dash", "ksh"]);
21226
+ var wrappedScript = (input) => {
21227
+ let words = input;
21228
+ while (words.length && (PREFIXES2.has(words[0]) || /^\w+=/.test(words[0])))
21229
+ words = words.slice(1);
21230
+ const tail = workitCheckTail(words);
21231
+ if (!tail)
21232
+ return null;
21233
+ if ("script" in tail)
21234
+ return tail.script;
21235
+ const [shell, flag, script] = tail.argv;
21236
+ if (SCRIPT_SHELLS.has((shell.split(/[\\/]/).at(-1) ?? "").toLowerCase()) && /^-[a-z]*c$/.test(flag ?? ""))
21237
+ return script ?? null;
21238
+ return tail.argv.map(quoteWord2).join(" ");
21239
+ };
20610
21240
  var editsOf = (input) => {
20611
21241
  let words = input;
20612
21242
  while (words.length && (PREFIXES2.has(words[0]) || /^\w+=/.test(words[0])))
@@ -20683,10 +21313,18 @@ var editsOf = (input) => {
20683
21313
  return [];
20684
21314
  }
20685
21315
  };
20686
- var shellWrites = (command) => {
21316
+ var shellWrites = (command, depth = 0) => {
20687
21317
  const targets = [];
20688
21318
  let unknown = false;
20689
21319
  for (const segment of segmentsOf(command)) {
21320
+ const inner = depth < 4 ? wrappedScript(segment.words) : null;
21321
+ if (inner !== null) {
21322
+ const nested = shellWrites(inner, depth + 1);
21323
+ if (nested.writes && nested.targets === null)
21324
+ unknown = true;
21325
+ else if (nested.targets)
21326
+ targets.push(...nested.targets);
21327
+ }
20690
21328
  targets.push(...segment.redirects.filter((item) => !/^\/dev\/(?:null|stdout|stderr|tty)$/.test(item)));
20691
21329
  const edits = editsOf(segment.words);
20692
21330
  if (edits === null)
@@ -20699,7 +21337,7 @@ var shellWrites = (command) => {
20699
21337
  return { writes: true, targets: unknown ? null : targets };
20700
21338
  };
20701
21339
  var cache2 = new Map;
20702
- var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path23.resolve(root, file)) ?? "-").join("\x00");
21340
+ var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path24.resolve(root, file)) ?? "-").join("\x00");
20703
21341
  var gateFor = (cwd) => {
20704
21342
  const store = new TaskStore(cwd);
20705
21343
  const listed = store.listTaskIndex();
@@ -20778,7 +21416,7 @@ var gitMutationDirs = (cwd, command, dialect) => {
20778
21416
  return [];
20779
21417
  if (sub === "stash" && ["list", "show"].includes(rest[0] ?? ""))
20780
21418
  return [];
20781
- return [path23.resolve(cwd, invocation.dir ?? ".")];
21419
+ return [path24.resolve(cwd, invocation.dir ?? ".")];
20782
21420
  });
20783
21421
  };
20784
21422
  var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
@@ -20788,15 +21426,15 @@ var cdInto = (dir, words) => {
20788
21426
  const target = words.slice(1).find((word) => !word.startsWith("-") || word === "-");
20789
21427
  if (dir === undefined || target === "-" || target && /^~|[$`*?]/.test(target))
20790
21428
  return;
20791
- return target === undefined ? os7.homedir() : path23.resolve(dir, target);
21429
+ return target === undefined ? os9.homedir() : path24.resolve(dir, target);
20792
21430
  };
20793
- var quoteWord = (word) => /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`;
20794
- var segmentTargets = (cwd, command, dialect) => {
21431
+ var quoteWord2 = (word) => /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`;
21432
+ var segmentTargets = (cwd, command, dialect, depth = 0) => {
20795
21433
  const targets = [];
20796
21434
  let dir = cwd;
20797
21435
  let stack = [];
20798
21436
  const groups = [];
20799
- const at = (file) => path23.isAbsolute(file) ? file : dir === undefined ? null : path23.resolve(dir, file);
21437
+ const at = (file) => path24.isAbsolute(file) ? file : dir === undefined ? null : path24.resolve(dir, file);
20800
21438
  for (const segment of segmentsOf(command, dialect)) {
20801
21439
  if (segment.group === "open") {
20802
21440
  groups.push({ dir, stack: [...stack] });
@@ -20824,6 +21462,9 @@ var segmentTargets = (cwd, command, dialect) => {
20824
21462
  dir = stack.length ? stack.pop() : undefined;
20825
21463
  continue;
20826
21464
  }
21465
+ const inner = depth < 4 ? wrappedScript(words) : null;
21466
+ if (inner !== null && dir !== undefined)
21467
+ targets.push(...segmentTargets(dir, inner, "posix", depth + 1));
20827
21468
  for (const file of segment.redirects)
20828
21469
  if (!/^\/dev\/(?:null|stdout|stderr|tty)$/.test(file)) {
20829
21470
  const resolved = at(file);
@@ -20833,15 +21474,15 @@ var segmentTargets = (cwd, command, dialect) => {
20833
21474
  const edits = editsOf(segment.words);
20834
21475
  if (edits === null) {
20835
21476
  if (dir !== undefined)
20836
- targets.push(path23.join(dir, DIR_TARGET));
21477
+ targets.push(path24.join(dir, DIR_TARGET));
20837
21478
  } else
20838
21479
  for (const file of edits) {
20839
21480
  const resolved = at(file);
20840
21481
  if (resolved)
20841
21482
  targets.push(resolved);
20842
21483
  }
20843
- if (dir !== undefined && workitInvocations(segment.words.map(quoteWord).join(" "), "posix").some((args) => args[0] === "git" && MUTATING_WORKIT_GIT.has(args[1] ?? "") && !inert(args.slice(2), "")))
20844
- targets.push(path23.join(dir, DIR_TARGET));
21484
+ 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), "")))
21485
+ targets.push(path24.join(dir, DIR_TARGET));
20845
21486
  }
20846
21487
  return targets;
20847
21488
  };
@@ -20876,7 +21517,7 @@ var liveDeny = ({ marker, checkout, ageMs, file }) => {
20876
21517
  var guarded = (targets) => {
20877
21518
  const seen = new Set;
20878
21519
  return targets.filter((target) => {
20879
- const dir = path23.dirname(target);
21520
+ const dir = path24.dirname(target);
20880
21521
  if (seen.has(dir))
20881
21522
  return false;
20882
21523
  seen.add(dir);
@@ -20897,7 +21538,7 @@ var claimAll = (owner, targets, deps) => {
20897
21538
  for (const target of guarded(targets))
20898
21539
  claimLiveSession(target, owner, deps);
20899
21540
  };
20900
- var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) => path23.resolve(cwd, file)) : [path23.join(cwd, DIR_TARGET)];
21541
+ var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) => path24.resolve(cwd, file)) : [path24.join(cwd, DIR_TARGET)];
20901
21542
  function writeGate(cwd, paths, owner, deps) {
20902
21543
  if (!owner)
20903
21544
  return beforeWriteGate(cwd, paths);
@@ -20917,7 +21558,7 @@ function shellGate(cwd, command, owner, dialect = "posix", deps) {
20917
21558
  try {
20918
21559
  targets = [
20919
21560
  ...segmentTargets(cwd, command, dialect),
20920
- ...gitMutationDirs(cwd, command, dialect).map((dir) => path23.join(dir, DIR_TARGET))
21561
+ ...gitMutationDirs(cwd, command, dialect).map((dir) => path24.join(dir, DIR_TARGET))
20921
21562
  ];
20922
21563
  } catch {
20923
21564
  targets = [];
@@ -20966,7 +21607,7 @@ function beforeWriteGate(cwd, paths) {
20966
21607
  }
20967
21608
  }
20968
21609
  // packages/workit-core/src/hooks/stop.ts
20969
- import { spawnSync as spawnSync14 } from "node:child_process";
21610
+ import { spawnSync as spawnSync13 } from "node:child_process";
20970
21611
  var NONE4 = { kind: "none" };
20971
21612
  var QUESTION = /[??؟](?=[\s*_`"')\]>]*(?:\s|$))|¿/;
20972
21613
  var OFFER = /\b(?:let me know|want me to|should I|shall I|would you like|do you want|if you(?:'d| would) like|may I|can I go ahead)\b/i;
@@ -20987,7 +21628,7 @@ var asksUser = (message) => {
20987
21628
  };
20988
21629
  var short = (sha) => (sha ?? "?").slice(0, 12);
20989
21630
  var gitList = (cwd, args) => {
20990
- const run = spawnSync14("git", args, {
21631
+ const run = spawnSync13("git", args, {
20991
21632
  cwd,
20992
21633
  encoding: "utf8",
20993
21634
  timeout: 3000,
@@ -21351,12 +21992,12 @@ ${line}` };
21351
21992
  };
21352
21993
  // packages/workit-core/src/hooks/hosts/fields.ts
21353
21994
  import { existsSync as existsSync7, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
21354
- import path24 from "node:path";
21355
- var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
21995
+ import path25 from "node:path";
21996
+ var isRecord5 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
21356
21997
  var nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "";
21357
21998
  var optionalText = (value) => typeof value === "string" ? value : null;
21358
21999
  var existingDirectory = (value) => {
21359
- if (!nonEmpty2(value) || !path24.isAbsolute(value) || !existsSync7(value))
22000
+ if (!nonEmpty2(value) || !path25.isAbsolute(value) || !existsSync7(value))
21360
22001
  return null;
21361
22002
  try {
21362
22003
  return statSync2(value).isDirectory() ? realpathSync6(value) : null;
@@ -21409,7 +22050,7 @@ var isWriteTool = (name) => typeof name === "string" && WRITE_TOOLS.has(name.toL
21409
22050
  var PATH_KEYS = ["file_path", "filePath", "notebook_path", "path", "target_file", "file"];
21410
22051
  var PATCH_HEADER = /^[ \t]*\*\*\* (?:(?:Add|Update|Delete) File|Move to): (.+)$/gm;
21411
22052
  var writePaths = (input) => {
21412
- if (!isRecord4(input))
22053
+ if (!isRecord5(input))
21413
22054
  return [];
21414
22055
  const paths = PATH_KEYS.map((key) => input[key]).filter(nonEmpty2);
21415
22056
  for (const value of Object.values(input))
@@ -21504,10 +22145,32 @@ function handleHook(input, deps) {
21504
22145
  const gate = usable2(descriptor.events["write.pre"].support) ? shellGate(input.cwd, event.command, liveOwner(input, descriptor.transport), event.dialect) : NONE5;
21505
22146
  if (gate.kind === "deny")
21506
22147
  return gate;
22148
+ const plan = heavyGate(input.cwd, event.command, {
22149
+ host: input.host,
22150
+ dialect: event.dialect,
22151
+ permissionMode: input.permissionMode
22152
+ });
22153
+ if (plan.kind === "split" && canDeny)
22154
+ return splitDenial(plan);
22155
+ const rewrites = usable2(descriptor.shellPolicy.rewrite);
22156
+ if (plan.kind === "rewrite" && !rewrites && canDeny)
22157
+ return heavyDenial(event.command, plan);
22158
+ const lease = plan.kind === "rewrite" && rewrites ? plan : null;
22159
+ const aside = plan.kind === "passthrough" ? plan.note : null;
21507
22160
  noteRawCommit(input, event.command, postTool ? callKey(event.toolUseId, event.command) : NEXT_COMMAND);
22161
+ const rewritten = (text) => lease ? {
22162
+ kind: "rewrite",
22163
+ command: lease.command,
22164
+ input: event.toolInput ? { ...event.toolInput, command: lease.command } : null,
22165
+ text
22166
+ } : NONE5;
21508
22167
  if (descriptor.transport !== "hook-process")
21509
- return NONE5;
21510
- return withContextLine(canDeny ? rawGitPre(input, event.command) : NONE5, shipNudge(input, event.command));
22168
+ return rewritten(null);
22169
+ const nudged = withContextLine(withContextLine(canDeny ? rawGitPre(input, event.command) : NONE5, aside), shipNudge(input, event.command));
22170
+ if (!lease)
22171
+ return nudged;
22172
+ return rewritten([rewriteNote(lease), nudged.kind === "context" ? nudged.text : null].filter(Boolean).join(`
22173
+ `));
21511
22174
  }
21512
22175
  case "shell.post":
21513
22176
  if (usable2(descriptor.events["shell.post"].support))
@@ -21565,6 +22228,112 @@ var dispatchHook = (adapter, raw, env = process.env) => {
21565
22228
  };
21566
22229
  }
21567
22230
  };
22231
+ // packages/workit-core/src/hooks/deadline.ts
22232
+ import { appendFileSync, mkdirSync as mkdirSync3 } from "node:fs";
22233
+ import path26 from "node:path";
22234
+ var HOOK_SKIP_TEXT = "workit context skipped: host under load";
22235
+ var HOOK_DEADLINE_MS = 8000;
22236
+ var HOST_DEADLINES = {
22237
+ claude_code: { "": 8000, SessionStart: 16000, Stop: 16000 },
22238
+ codex_cli: { "": 45000, Stop: 16000 },
22239
+ codex_desktop: { "": 45000, Stop: 16000 },
22240
+ cursor: { "": 45000 }
22241
+ };
22242
+ var HOOK_SKIPS_FILE = "hook-skips.jsonl";
22243
+ var override = (env) => {
22244
+ const value = Number(env.WORKIT_HOOK_DEADLINE_MS);
22245
+ return Number.isFinite(value) && value > 0 ? value : null;
22246
+ };
22247
+ var hookDeadlineMs = (env, host = "", native) => {
22248
+ const row = HOST_DEADLINES[host];
22249
+ return override(env) ?? (row ? native === undefined ? Math.min(...Object.values(row)) : row[native] ?? row[""] : HOOK_DEADLINE_MS);
22250
+ };
22251
+ var skipsFile = (stateDir) => path26.join(stateDir, HOOK_SKIPS_FILE);
22252
+ var recordHookSkip = (skip, stateDir = resolveStateDir()) => {
22253
+ try {
22254
+ mkdirSync3(stateDir, { recursive: true });
22255
+ appendFileSync(skipsFile(stateDir), `${JSON.stringify(skip)}
22256
+ `);
22257
+ } catch {}
22258
+ };
22259
+ var QUIET = new Set([
22260
+ "stop",
22261
+ "subagent.stop",
22262
+ "shell.post",
22263
+ "compact.pre",
22264
+ "prompt.submit",
22265
+ null
22266
+ ]);
22267
+ var skipDecision = (event) => QUIET.has(event) ? { kind: "none" } : { kind: "context", text: HOOK_SKIP_TEXT };
22268
+ var TIMED_OUT = Symbol("timed out");
22269
+ var within = async (work, ms) => {
22270
+ let timer;
22271
+ const expired = new Promise((resolve) => {
22272
+ timer = setTimeout(() => resolve(TIMED_OUT), Math.max(0, ms));
22273
+ timer.unref?.();
22274
+ });
22275
+ try {
22276
+ return await Promise.race([work, expired]);
22277
+ } finally {
22278
+ clearTimeout(timer);
22279
+ }
22280
+ };
22281
+ var isTimedOut = (value) => value === TIMED_OUT;
22282
+ var PROCESS_START = performance.timeOrigin;
22283
+ var hookBudget = (env, options = {}, host = "") => {
22284
+ const now = options.now ?? Date.now;
22285
+ return {
22286
+ now,
22287
+ record: options.record ?? ((skip) => recordHookSkip(skip)),
22288
+ startedAt: options.startedAt ?? now(),
22289
+ deadlineMs: options.deadlineMs ?? hookDeadlineMs(env, host),
22290
+ host: options.deadlineMs === undefined ? host : null
22291
+ };
22292
+ };
22293
+ var readWithin = async (stdin, budget) => {
22294
+ const read = (async () => {
22295
+ let text = "";
22296
+ for await (const chunk of stdin)
22297
+ text += String(chunk);
22298
+ return text;
22299
+ })();
22300
+ const text = await within(read, budget.startedAt + budget.deadlineMs - budget.now());
22301
+ return isTimedOut(text) ? null : text;
22302
+ };
22303
+ var note = (adapter, raw, env, budget, outcome, stage) => {
22304
+ const parsed = raw === undefined ? null : adapter.parse(raw, env);
22305
+ const event = parsed ? parsed.ok ? parsed.input.event.kind : parsed.event : null;
22306
+ budget.record({
22307
+ at: new Date(budget.now()).toISOString(),
22308
+ host: adapter.descriptor.host,
22309
+ event,
22310
+ outcome,
22311
+ stage,
22312
+ elapsedMs: Math.round(budget.now() - budget.startedAt)
22313
+ });
22314
+ return { native: parsed?.native ?? null, event };
22315
+ };
22316
+ var skippedHook = (adapter, raw, env, budget, stage) => {
22317
+ const { native, event } = note(adapter, raw, env, budget, "skip", stage);
22318
+ return {
22319
+ ...adapter.render(skipDecision(event), native),
22320
+ error: `${HOOK_SKIP_TEXT} (past the ${budget.deadlineMs} ms hook deadline)`,
22321
+ skipped: true
22322
+ };
22323
+ };
22324
+ var dispatchWithin = async (adapter, raw, env, budget, dispatch = dispatchHook) => {
22325
+ const native = raw?.hook_event_name;
22326
+ if (budget.host !== null && typeof native === "string")
22327
+ budget.deadlineMs = hookDeadlineMs(env, budget.host, native);
22328
+ const remaining = () => budget.startedAt + budget.deadlineMs - budget.now();
22329
+ const result = remaining() > 0 ? await within(Promise.resolve().then(() => dispatch(adapter, raw, env)), remaining()) : TIMED_OUT;
22330
+ if (isTimedOut(result))
22331
+ return skippedHook(adapter, raw, env, budget, "dispatch");
22332
+ if (remaining() < 0)
22333
+ note(adapter, raw, env, budget, "late", "done");
22334
+ return { ...result, skipped: false };
22335
+ };
22336
+
21568
22337
  // packages/workit-core/src/hooks/hosts/claude-code.ts
21569
22338
  var CLAUDE_CODE_DESCRIPTOR = {
21570
22339
  host: "claude_code",
@@ -21585,7 +22354,12 @@ var CLAUDE_CODE_DESCRIPTOR = {
21585
22354
  "compact.pre": { support: "none", native: null },
21586
22355
  stop: { support: "native", native: "Stop" }
21587
22356
  },
21588
- shellPolicy: { deny: "native", channel: "permissionDecision", failClosed: false },
22357
+ shellPolicy: {
22358
+ deny: "native",
22359
+ channel: "permissionDecision",
22360
+ failClosed: false,
22361
+ rewrite: "native"
22362
+ },
21589
22363
  context: {
21590
22364
  sessionStart: "native",
21591
22365
  perTurn: "native",
@@ -21667,7 +22441,7 @@ var EVENTS = {
21667
22441
  var SOURCES = new Set(["startup", "resume", "clear", "compact", "fork"]);
21668
22442
  var SHELL_TOOLS = new Set(["Bash", "PowerShell"]);
21669
22443
  var dialectOf2 = (value) => value.tool_name === "PowerShell" ? "powershell" : "posix";
21670
- var toolCommand = (value) => isRecord4(value.tool_input) ? commandText(value.tool_input.command) : null;
22444
+ var toolCommand = (value) => isRecord5(value.tool_input) ? commandText(value.tool_input.command) : null;
21671
22445
  var eventOf = (name, value) => {
21672
22446
  const toolUseId = optionalText(value.tool_use_id);
21673
22447
  switch (name) {
@@ -21695,19 +22469,28 @@ var eventOf = (name, value) => {
21695
22469
  kind: "tool.pre",
21696
22470
  tool: value.tool_name,
21697
22471
  toolUseId,
21698
- skill: isRecord4(value.tool_input) ? optionalText(value.tool_input.skill) : null
22472
+ skill: isRecord5(value.tool_input) ? optionalText(value.tool_input.skill) : null
21699
22473
  }
21700
22474
  };
21701
22475
  if (!SHELL_TOOLS.has(value.tool_name))
21702
22476
  return { ok: true, event: { kind: "tool.pre", tool: value.tool_name, toolUseId } };
21703
22477
  const command = toolCommand(value);
21704
- return command ? { ok: true, event: { kind: "shell.pre", command, toolUseId, dialect: dialectOf2(value) } } : { ok: false, error: `tool_input.command is required for ${value.tool_name}` };
22478
+ return command ? {
22479
+ ok: true,
22480
+ event: {
22481
+ kind: "shell.pre",
22482
+ command,
22483
+ toolUseId,
22484
+ dialect: dialectOf2(value),
22485
+ toolInput: value.tool_input
22486
+ }
22487
+ } : { ok: false, error: `tool_input.command is required for ${value.tool_name}` };
21705
22488
  }
21706
22489
  case "PostToolUse": {
21707
22490
  const command = toolCommand(value);
21708
22491
  if (!SHELL_TOOLS.has(String(value.tool_name)) || !command)
21709
22492
  return { ok: false, error: "only shell PostToolUse is mapped" };
21710
- const response = isRecord4(value.tool_response) ? value.tool_response : {};
22493
+ const response = isRecord5(value.tool_response) ? value.tool_response : {};
21711
22494
  return {
21712
22495
  ok: true,
21713
22496
  event: {
@@ -21765,6 +22548,17 @@ var CONTEXT_EVENTS = new Set([
21765
22548
  "PostToolUse"
21766
22549
  ]);
21767
22550
  var render = (decision, native) => {
22551
+ if (decision.kind === "rewrite" && native === "PreToolUse" && decision.input)
22552
+ return {
22553
+ json: {
22554
+ hookSpecificOutput: {
22555
+ hookEventName: "PreToolUse",
22556
+ updatedInput: decision.input,
22557
+ ...decision.text ? { additionalContext: decision.text } : {}
22558
+ }
22559
+ },
22560
+ exitCode: 0
22561
+ };
21768
22562
  if (decision.kind === "deny" && native === "PreToolUse")
21769
22563
  return {
21770
22564
  json: {
@@ -21790,14 +22584,14 @@ var render = (decision, native) => {
21790
22584
  var claudeCodeAdapter = {
21791
22585
  descriptor: CLAUDE_CODE_DESCRIPTOR,
21792
22586
  parse(raw) {
21793
- const native = isRecord4(raw) && Object.hasOwn(EVENTS, String(raw.hook_event_name)) ? raw.hook_event_name : null;
22587
+ const native = isRecord5(raw) && Object.hasOwn(EVENTS, String(raw.hook_event_name)) ? raw.hook_event_name : null;
21794
22588
  const fail = (error) => ({
21795
22589
  ok: false,
21796
22590
  error,
21797
22591
  native,
21798
22592
  event: native ? EVENTS[native] : null
21799
22593
  });
21800
- if (!isRecord4(raw) || !native)
22594
+ if (!isRecord5(raw) || !native)
21801
22595
  return fail("hook_event_name is required");
21802
22596
  if (!nonEmpty2(raw.session_id))
21803
22597
  return fail("session_id is required");
@@ -21851,7 +22645,12 @@ var CODEX_DESCRIPTOR = {
21851
22645
  "compact.pre": { support: "none", native: null },
21852
22646
  stop: { support: "native", native: "Stop" }
21853
22647
  },
21854
- shellPolicy: { deny: "native", channel: "permissionDecision", failClosed: false },
22648
+ shellPolicy: {
22649
+ deny: "native",
22650
+ channel: "permissionDecision",
22651
+ failClosed: false,
22652
+ rewrite: "none"
22653
+ },
21855
22654
  context: {
21856
22655
  sessionStart: "native",
21857
22656
  perTurn: "native",
@@ -21943,7 +22742,7 @@ var SHELL_TOOLS2 = new Set(["bash", "unified-exec"]);
21943
22742
  var isShellTool = (name) => SHELL_TOOLS2.has(String(name).toLowerCase());
21944
22743
  var SOURCES2 = new Set(["startup", "resume", "clear", "compact", "fork"]);
21945
22744
  var parseCodexHookInput = (value) => {
21946
- if (!isRecord4(value) || !Object.hasOwn(EVENTS2, String(value.hook_event_name)))
22745
+ if (!isRecord5(value) || !Object.hasOwn(EVENTS2, String(value.hook_event_name)))
21947
22746
  return { ok: false, error: "hook_event_name is required" };
21948
22747
  const event = value.hook_event_name;
21949
22748
  const cwd = existingDirectory(value.cwd);
@@ -21952,7 +22751,7 @@ var parseCodexHookInput = (value) => {
21952
22751
  const toolEvent = event === "PreToolUse" || event === "PostToolUse";
21953
22752
  if (toolEvent && !nonEmpty2(value.tool_name))
21954
22753
  return { ok: false, error: "tool_name is required" };
21955
- const command = isRecord4(value.tool_input) ? commandText(value.tool_input.command) : null;
22754
+ const command = isRecord5(value.tool_input) ? commandText(value.tool_input.command) : null;
21956
22755
  if (toolEvent && isShellTool(value.tool_name) && !command)
21957
22756
  return { ok: false, error: "tool_input.command is required for shell tools" };
21958
22757
  if (event === "SubagentStart" && !nonEmpty2(value.agent_id))
@@ -22066,7 +22865,7 @@ var codexAdapter = {
22066
22865
  const host = detectCodexSurface(env);
22067
22866
  const parsed = parseCodexHookInput(raw);
22068
22867
  if (!parsed.ok) {
22069
- const native = isRecord4(raw) && Object.hasOwn(EVENTS2, String(raw.hook_event_name)) ? raw.hook_event_name : null;
22868
+ const native = isRecord5(raw) && Object.hasOwn(EVENTS2, String(raw.hook_event_name)) ? raw.hook_event_name : null;
22070
22869
  return { ok: false, error: parsed.error, native, event: native ? EVENTS2[native] : null };
22071
22870
  }
22072
22871
  const input = parsed.data;
@@ -22093,8 +22892,8 @@ var codexAdapter = {
22093
22892
  };
22094
22893
 
22095
22894
  // packages/workit-core/src/hooks/hosts/cursor.ts
22096
- import fs18 from "node:fs";
22097
- import path25 from "node:path";
22895
+ import fs19 from "node:fs";
22896
+ import path27 from "node:path";
22098
22897
  var undocumented = { support: "undocumented", native: null };
22099
22898
  var none = { support: "none", native: null };
22100
22899
  var CURSOR_DESCRIPTOR = {
@@ -22116,7 +22915,7 @@ var CURSOR_DESCRIPTOR = {
22116
22915
  "compact.pre": { support: "partial", native: "preCompact" },
22117
22916
  stop: { support: "native", native: "stop" }
22118
22917
  },
22119
- shellPolicy: { deny: "native", channel: "exit2+json", failClosed: false },
22918
+ shellPolicy: { deny: "native", channel: "exit2+json", failClosed: false, rewrite: "none" },
22120
22919
  context: {
22121
22920
  sessionStart: "native",
22122
22921
  perTurn: "none",
@@ -22209,7 +23008,7 @@ var EVENTS3 = {
22209
23008
  stop: "stop"
22210
23009
  };
22211
23010
  var parseCursorHookInput = (value) => {
22212
- if (!isRecord4(value) || !Object.hasOwn(EVENTS3, String(value.hook_event_name)))
23011
+ if (!isRecord5(value) || !Object.hasOwn(EVENTS3, String(value.hook_event_name)))
22213
23012
  return { ok: false, error: "hook_event_name is required" };
22214
23013
  const roots = value.workspace_roots;
22215
23014
  if (!Array.isArray(roots) || roots.length === 0 || !roots.every(nonEmpty2))
@@ -22291,17 +23090,17 @@ var protocolEvent2 = (input) => {
22291
23090
  };
22292
23091
  var TRANSCRIPT_TAIL_BYTES = 256 * 1024;
22293
23092
  var lastAssistantText = (file) => {
22294
- if (!file || !path25.isAbsolute(file))
23093
+ if (!file || !path27.isAbsolute(file))
22295
23094
  return null;
22296
23095
  try {
22297
- const size = fs18.statSync(file).size;
23096
+ const size = fs19.statSync(file).size;
22298
23097
  const start = Math.max(0, size - TRANSCRIPT_TAIL_BYTES);
22299
23098
  const buffer = Buffer.alloc(size - start);
22300
- const fd = fs18.openSync(file, "r");
23099
+ const fd = fs19.openSync(file, "r");
22301
23100
  try {
22302
- fs18.readSync(fd, buffer, 0, buffer.length, start);
23101
+ fs19.readSync(fd, buffer, 0, buffer.length, start);
22303
23102
  } finally {
22304
- fs18.closeSync(fd);
23103
+ fs19.closeSync(fd);
22305
23104
  }
22306
23105
  const lines = buffer.toString("utf8").split(`
22307
23106
  `);
@@ -22312,14 +23111,14 @@ var lastAssistantText = (file) => {
22312
23111
  } catch {
22313
23112
  continue;
22314
23113
  }
22315
- if (!isRecord4(entry) || entry.role !== "assistant")
23114
+ if (!isRecord5(entry) || entry.role !== "assistant")
22316
23115
  continue;
22317
- const content = isRecord4(entry.message) ? entry.message.content : entry.content;
23116
+ const content = isRecord5(entry.message) ? entry.message.content : entry.content;
22318
23117
  if (typeof content === "string")
22319
23118
  return content;
22320
23119
  if (!Array.isArray(content))
22321
23120
  return null;
22322
- const text = content.filter((part) => isRecord4(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join(`
23121
+ const text = content.filter((part) => isRecord5(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join(`
22323
23122
  `);
22324
23123
  return text || null;
22325
23124
  }
@@ -22328,7 +23127,7 @@ var lastAssistantText = (file) => {
22328
23127
  return null;
22329
23128
  }
22330
23129
  };
22331
- var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path25.sep) ? root : `${root}${path25.sep}`);
23130
+ var within2 = (root, dir) => dir === root || dir.startsWith(root.endsWith(path27.sep) ? root : `${root}${path27.sep}`);
22332
23131
  var hookCwd = (input) => {
22333
23132
  const cwd = existingDirectory(input.cwd);
22334
23133
  if (cwd && input.hook_event_name === "beforeShellExecution")
@@ -22337,7 +23136,7 @@ var hookCwd = (input) => {
22337
23136
  };
22338
23137
  var cursorWorkspaceRoot = (input) => {
22339
23138
  const cwd = existingDirectory(input.cwd);
22340
- return cwd && input.workspace_roots.find((root) => within(root, cwd)) || input.workspace_roots[0];
23139
+ return cwd && input.workspace_roots.find((root) => within2(root, cwd)) || input.workspace_roots[0];
22341
23140
  };
22342
23141
  var cursorDeny = (reason) => ({
22343
23142
  permission: "deny",
@@ -22369,7 +23168,7 @@ var cursorAdapter = {
22369
23168
  parse(raw) {
22370
23169
  const parsed = parseCursorHookInput(raw);
22371
23170
  if (!parsed.ok) {
22372
- const native = isRecord4(raw) && Object.hasOwn(EVENTS3, String(raw.hook_event_name)) ? raw.hook_event_name : null;
23171
+ const native = isRecord5(raw) && Object.hasOwn(EVENTS3, String(raw.hook_event_name)) ? raw.hook_event_name : null;
22373
23172
  return { ok: false, error: parsed.error, native, event: native ? EVENTS3[native] : null };
22374
23173
  }
22375
23174
  const input = parsed.data;
@@ -22402,19 +23201,21 @@ var HOOK_ADAPTERS = {
22402
23201
  codex_desktop: codexAdapter,
22403
23202
  cursor: cursorAdapter
22404
23203
  };
22405
- async function runHookProcess(host, stdin, stdout, stderr = process.stderr, env = process.env) {
23204
+ async function runHookProcess(host, stdin, stdout, stderr = process.stderr, env = process.env, deadline = {}) {
22406
23205
  const adapter = typeof host === "string" ? HOOK_ADAPTERS[host] : host;
22407
- let text = "";
22408
- for await (const chunk of stdin)
22409
- text += String(chunk);
23206
+ const budget = hookBudget(env, deadline, adapter.descriptor.host);
23207
+ const text = await readWithin(stdin, budget);
22410
23208
  let raw;
22411
23209
  try {
22412
- raw = JSON.parse(text || "{}");
23210
+ raw = text === null ? undefined : JSON.parse(text || "{}");
22413
23211
  } catch {
22414
23212
  raw = undefined;
22415
23213
  }
22416
- const result = dispatchHook(adapter, raw, env);
22417
- if (raw === undefined || result.error)
23214
+ const result = text === null ? skippedHook(adapter, undefined, env, budget, "input") : await dispatchWithin(adapter, raw, env, budget, deadline.dispatch);
23215
+ if (result.skipped)
23216
+ stderr.write(`[workit] ${result.error}
23217
+ `);
23218
+ else if (raw === undefined || result.error)
22418
23219
  stderr.write(`[workit] hook input rejected: ${raw === undefined ? "invalid JSON hook input" : result.error}
22419
23220
  `);
22420
23221
  stdout.write(`${JSON.stringify(result.json)}
@@ -22431,7 +23232,7 @@ function warnOnSurfaceFallback(env = process.env) {
22431
23232
  }
22432
23233
  var runCodexHook = async (stdin = process.stdin) => {
22433
23234
  warnOnSurfaceFallback();
22434
- process.exitCode = await runHookProcess(detectCodexSurface(process.env), stdin, process.stdout);
23235
+ process.exitCode = await runHookProcess(detectCodexSurface(process.env), stdin, process.stdout, process.stderr, process.env, { startedAt: PROCESS_START });
22435
23236
  };
22436
23237
  if (false)
22437
23238
  ;