@brainervirus/workit-cursor 8.22.3 → 8.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17476,6 +17476,23 @@ function workitInvocations(command, dialect = "posix", depth = 0) {
17476
17476
  }
17477
17477
  return found;
17478
17478
  }
17479
+ function skipWorkitGlobals(args) {
17480
+ let cwd = null;
17481
+ let at = 0;
17482
+ for (;at < args.length; at++) {
17483
+ const match = WORKIT_GLOBAL.exec(args[at]);
17484
+ if (match?.[1] === "=") {
17485
+ if (args[at].startsWith("--cwd="))
17486
+ cwd = args[at].slice(6);
17487
+ } else if (match && args[at + 1] !== undefined) {
17488
+ if (args[at] === "--cwd")
17489
+ cwd = args[at + 1];
17490
+ at++;
17491
+ } else if (args[at] !== "--json")
17492
+ break;
17493
+ }
17494
+ return { rest: args.slice(at), cwd };
17495
+ }
17479
17496
  function rawAction(invocation) {
17480
17497
  const args = invocation.args;
17481
17498
  if (invocation.tool !== "git" && args[0] === "api")
@@ -17875,7 +17892,7 @@ var NONE2, SHELLS, POWERSHELLS, EVALS, WRAPPERS, WRAPPER_VALUES, KEYWORDS, DECLA
17875
17892
  ...Object.keys(env).length ? { env } : {},
17876
17893
  ...stdin === undefined ? {} : { stdin }
17877
17894
  };
17878
- }, RECENT, LAUNCHERS, WORKIT_BIN, WORKIT_PACKAGE, PACKAGE_RUNNERS, PUSH_VALUE_OPTIONS, CURRENT_BRANCH, pushDestination = (destination) => {
17895
+ }, RECENT, LAUNCHERS, WORKIT_BIN, WORKIT_PACKAGE, PACKAGE_RUNNERS, WORKIT_GLOBAL, PUSH_VALUE_OPTIONS, CURRENT_BRANCH, pushDestination = (destination) => {
17879
17896
  if (destination === "HEAD" || destination === "@" || CURRENT_BRANCH.test(destination))
17880
17897
  return { name: null };
17881
17898
  if (destination.startsWith("refs/heads/"))
@@ -18569,6 +18586,7 @@ var init_raw_git = __esm(() => {
18569
18586
  WORKIT_BIN = /(?:^|[\\/])workit(?:\.exe)?$|^@brainervirus\/workit-cli$/;
18570
18587
  WORKIT_PACKAGE = /^@brainervirus\/workit-cli(?:@\S*)?$/;
18571
18588
  PACKAGE_RUNNERS = new Set(["npx", "bunx", "pnpx"]);
18589
+ WORKIT_GLOBAL = /^--(?:cwd|session|token|as)(=|$)/;
18572
18590
  PUSH_VALUE_OPTIONS = new Set(["-o", "--push-option", "--receive-pack", "--exec", "--repo"]);
18573
18591
  CURRENT_BRANCH = /^\$\(\s*git\s+(?:branch\s+--show-current|rev-parse\s+--abbrev-ref\s+HEAD|symbolic-ref\s+--short\s+HEAD)\s*\)$/;
18574
18592
  VALUE_OPTIONS = {
@@ -19794,7 +19812,7 @@ var init_live_session = __esm(() => {
19794
19812
  });
19795
19813
 
19796
19814
  // packages/workit-core/src/hooks/write-gate.ts
19797
- import { realpathSync as realpathSync5 } from "node:fs";
19815
+ import { existsSync as existsSync7, realpathSync as realpathSync5 } from "node:fs";
19798
19816
  import os10 from "node:os";
19799
19817
  import path27 from "node:path";
19800
19818
  function writeGate(cwd, paths, owner, deps) {
@@ -19820,16 +19838,8 @@ function shellGate(cwd, command, owner, dialect = "posix", deps) {
19820
19838
  } catch {}
19821
19839
  const writes = shellWrites(command);
19822
19840
  let targets = [];
19823
- if (owner) {
19824
- try {
19825
- targets = [
19826
- ...segmentTargets(cwd, command, dialect),
19827
- ...gitMutationDirs(cwd, command, dialect).map((dir) => path27.join(dir, DIR_TARGET))
19828
- ];
19829
- } catch {
19830
- targets = [];
19831
- }
19832
- }
19841
+ if (owner)
19842
+ targets = shellMutationTargets(cwd, command, dialect);
19833
19843
  if (owner && targets.length) {
19834
19844
  const live = liveGate(owner, targets, deps);
19835
19845
  if (live.kind !== "none") {
@@ -19888,9 +19898,9 @@ var NONE3, CASE_INSENSITIVE, canonical2 = (file) => {
19888
19898
  return null;
19889
19899
  if ("script" in tail)
19890
19900
  return tail.script;
19891
- const [shell, flag, script] = tail.argv;
19892
- if (SCRIPT_SHELLS.has((shell.split(/[\\/]/).at(-1) ?? "").toLowerCase()) && /^-[a-z]*c$/.test(flag ?? ""))
19893
- return script ?? null;
19901
+ const script = shellScript2(tail.argv);
19902
+ if (SCRIPT_SHELLS.has((tail.argv[0]?.split(/[\\/]/).at(-1) ?? "").toLowerCase()) && script)
19903
+ return script;
19894
19904
  return tail.argv.map(quoteWord2).join(" ");
19895
19905
  }, editsOf = (input) => {
19896
19906
  let words = input;
@@ -19967,6 +19977,89 @@ var NONE3, CASE_INSENSITIVE, canonical2 = (file) => {
19967
19977
  default:
19968
19978
  return [];
19969
19979
  }
19980
+ }, shellScript2 = (words) => {
19981
+ if (!SCRIPT_SHELLS.has((words[0]?.split(/[\\/]/).at(-1) ?? "").toLowerCase()))
19982
+ return null;
19983
+ for (let index = 1;index < words.length; index++) {
19984
+ const word = words[index];
19985
+ if (/^-[a-z]*c$/.test(word))
19986
+ return words[index + 1] ?? null;
19987
+ if (/^[-+][oO]$/.test(word))
19988
+ index++;
19989
+ else if (!/^[-+]/.test(word))
19990
+ return null;
19991
+ }
19992
+ return null;
19993
+ }, XARGS_VALUE, runsWriter = (words) => {
19994
+ const filled = [...words.filter((word) => word !== "{}" && word !== ";" && word !== "+"), "x"];
19995
+ const edits = editsOf(filled);
19996
+ return edits === null || edits.length > 0 || opaqueWrites(filled) !== null;
19997
+ }, opaqueWrites = (input) => {
19998
+ let words = input;
19999
+ while (words.length && (PREFIXES2.has(words[0]) || /^\w+=/.test(words[0]))) {
20000
+ if (words[0] === "xargs") {
20001
+ let at = 1;
20002
+ while (words[at]?.startsWith("-"))
20003
+ at += XARGS_VALUE.test(words[at]) ? 2 : 1;
20004
+ return runsWriter(words.slice(at)) ? ["."] : null;
20005
+ }
20006
+ words = words.slice(1);
20007
+ }
20008
+ const [verb, ...args] = words;
20009
+ const name = (verb?.split(/[\\/]/).at(-1) ?? "").toLowerCase();
20010
+ const files = operands(args);
20011
+ const has = (pattern) => args.some((arg) => pattern.test(arg));
20012
+ const listed = (named) => named.length ? named : ["."];
20013
+ if (name === "unlink" || name === "shred")
20014
+ return listed(files);
20015
+ if (/^(?:chmod|chown|chgrp|chattr)$/.test(name))
20016
+ return listed(has(/^--reference/) ? files : files.slice(1));
20017
+ if (name === "rsync") {
20018
+ const dest = files.at(-1);
20019
+ const remote = /^[\w.@-]*:/.test(dest ?? "") && !/^[A-Za-z]:[\\/]/.test(dest ?? "");
20020
+ return dest === undefined ? ["."] : remote ? [] : [dest];
20021
+ }
20022
+ if (name === "find") {
20023
+ const exec = args.findIndex((arg) => /^-(?:exec|execdir|ok|okdir)$/.test(arg));
20024
+ const writes = has(/^-(?:delete|fprint\w*|fls)$/) || exec >= 0 && runsWriter(args.slice(exec + 1));
20025
+ const end = args.findIndex((arg) => /^[-(!]/.test(arg));
20026
+ return writes ? listed(end < 0 ? args : args.slice(0, end)) : null;
20027
+ }
20028
+ if (/^g?awk$/.test(name)) {
20029
+ if (!has(/^-i|^--include/))
20030
+ return null;
20031
+ const named = [];
20032
+ let program = !has(/^-f$|^--file/);
20033
+ for (let index = 0;index < args.length; index++)
20034
+ if (/^(?:-[ifvF]|--(?:include|file|assign|field-separator))$/.test(args[index]))
20035
+ index++;
20036
+ else if (args[index].startsWith("-"))
20037
+ continue;
20038
+ else if (program)
20039
+ program = false;
20040
+ else
20041
+ named.push(args[index]);
20042
+ return listed(named);
20043
+ }
20044
+ if (name === "perl")
20045
+ return has(/^-[a-zA-Z]*[eE]/) ? ["."] : null;
20046
+ if (/^(?:python[\d.]*|node|bun|deno|ruby|php)$/.test(name))
20047
+ return has(/^-[a-zA-Z]*[ce]$|^--eval$|^-p$/) ? ["."] : null;
20048
+ return shellScript2(words) === null ? null : ["."];
20049
+ }, linkSources = (args, at) => {
20050
+ const names = operands([...args]);
20051
+ const into = args.indexOf("-t");
20052
+ const dest = into >= 0 ? args[into + 1] : names.length > 1 ? names.at(-1) : ".";
20053
+ const sources = names.filter((name, index) => into >= 0 ? name !== dest : index < names.length - 1 || names.length === 1);
20054
+ const target = dest === undefined ? null : at(dest);
20055
+ const symbolic = args.some((arg) => /^-[a-zA-Z]*s|^--symbolic$/.test(arg));
20056
+ const base = target === null ? null : into >= 0 || sources.length > 1 || existsSync7(target) || /[\\/]$/.test(dest ?? "") ? target : path27.dirname(target);
20057
+ return sources.flatMap((source) => {
20058
+ if (symbolic && base !== null && !path27.isAbsolute(homeExpanded(source)))
20059
+ return [path27.resolve(base, source)];
20060
+ const resolved = at(source);
20061
+ return resolved ? [resolved] : [];
20062
+ });
19970
20063
  }, shellWrites = (command, depth = 0) => {
19971
20064
  const targets = [];
19972
20065
  let unknown = false;
@@ -20044,16 +20137,19 @@ var NONE3, CASE_INSENSITIVE, canonical2 = (file) => {
20044
20137
  return [];
20045
20138
  return [path27.resolve(cwd, invocation.dir ?? ".")];
20046
20139
  });
20047
- }, CD2, PUSHD2, POPD2, cdInto = (dir, words) => {
20140
+ }, CD2, PUSHD2, POPD2, UNKNOWN_DIR, cdInto = (dir, words, strict = false) => {
20141
+ const lost = strict ? UNKNOWN_DIR : undefined;
20048
20142
  const named = words.slice(1).find((word) => !word.startsWith("-") || word === "-");
20049
20143
  const target = named === undefined ? undefined : homeExpanded(named);
20050
- if (dir === undefined || target === "-" || target && /^~|[$`*?]/.test(target))
20051
- return;
20144
+ if (target === "-" || target && /^~|[$`*?]/.test(target))
20145
+ return lost;
20146
+ if (dir === undefined)
20147
+ return lost;
20052
20148
  return target === undefined ? os10.homedir() : path27.resolve(dir, target);
20053
20149
  }, quoteWord2 = (word) => /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`, homeExpanded = (file) => {
20054
20150
  const match = /^(?:~|\$HOME|\$\{HOME\})(?=\/|$)/.exec(file);
20055
20151
  return match ? (process.env.HOME || os10.homedir()) + file.slice(match[0].length) : file;
20056
- }, segmentTargets = (cwd, command, dialect, depth = 0) => {
20152
+ }, segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
20057
20153
  const targets = [];
20058
20154
  let dir = cwd;
20059
20155
  let stack = [];
@@ -20077,21 +20173,35 @@ var NONE3, CASE_INSENSITIVE, canonical2 = (file) => {
20077
20173
  const words = lead < 0 ? [] : segment.words.slice(lead);
20078
20174
  const name = (words[0]?.split(/[\\/]/).at(-1) ?? "").toLowerCase();
20079
20175
  if (CD2.has(name)) {
20080
- dir = cdInto(dir, words);
20176
+ dir = cdInto(dir, words, strict);
20081
20177
  continue;
20082
20178
  }
20083
20179
  if (PUSHD2.has(name)) {
20084
20180
  stack.push(dir);
20085
- dir = cdInto(dir, words);
20181
+ dir = cdInto(dir, words, strict);
20086
20182
  continue;
20087
20183
  }
20088
20184
  if (POPD2.has(name)) {
20089
- dir = stack.length ? stack.pop() : undefined;
20185
+ dir = stack.length ? stack.pop() : strict ? UNKNOWN_DIR : undefined;
20090
20186
  continue;
20091
20187
  }
20092
- const inner = depth < 4 ? wrappedScript(words) : null;
20188
+ const inner = depth < 4 ? wrappedScript(words) ?? (strict ? shellScript2(words) : null) : null;
20093
20189
  if (inner !== null && dir !== undefined)
20094
- targets.push(...segmentTargets(dir, inner, "posix", depth + 1));
20190
+ targets.push(...segmentTargets(dir, inner, "posix", depth + 1, strict));
20191
+ if (strict && dir !== undefined) {
20192
+ const runIn = dir;
20193
+ for (const sub of depth < 4 ? segment.subs ?? [] : [])
20194
+ targets.push(...segmentTargets(runIn, sub, dialect, depth + 1, true));
20195
+ const opaque = segment.unanalyzable ? ["."] : inner === null ? opaqueWrites(words) : null;
20196
+ for (const file of opaque ?? []) {
20197
+ const resolved = at(file);
20198
+ if (resolved)
20199
+ targets.push(file === "." ? path27.join(resolved, DIR_TARGET) : resolved);
20200
+ }
20201
+ const ln = words.findIndex((word) => /^ln$/i.test(word.split(/[\\/]/).at(-1) ?? ""));
20202
+ if (ln >= 0 && words.slice(0, ln).every((word) => PREFIXES2.has(word)))
20203
+ targets.push(...linkSources(words.slice(ln + 1), at));
20204
+ }
20095
20205
  for (const file of segment.redirects)
20096
20206
  if (!/^\/dev\/(?:null|stdout|stderr|tty)$/.test(file)) {
20097
20207
  const resolved = at(file);
@@ -20108,10 +20218,26 @@ var NONE3, CASE_INSENSITIVE, canonical2 = (file) => {
20108
20218
  if (resolved)
20109
20219
  targets.push(resolved);
20110
20220
  }
20111
- 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), "")))
20112
- targets.push(path27.join(dir, DIR_TARGET));
20221
+ if (dir !== undefined)
20222
+ for (const invocation of workitInvocations(segment.words.map(quoteWord2).join(" "), "posix")) {
20223
+ const { at: runsIn, args } = workitCwd(dir, invocation);
20224
+ if (args[0] === "git" && MUTATING_WORKIT_GIT.has(args[1] ?? "") && !inert(args.slice(2), ""))
20225
+ targets.push(path27.join(runsIn, DIR_TARGET));
20226
+ }
20113
20227
  }
20114
20228
  return targets;
20229
+ }, workitCwd = (dir, args) => {
20230
+ const { rest, cwd } = skipWorkitGlobals(args);
20231
+ return { at: cwd === null ? dir : path27.resolve(dir, homeExpanded(cwd)), args: rest };
20232
+ }, shellMutationTargets = (cwd, command, dialect = "posix", strict = false) => {
20233
+ try {
20234
+ return [
20235
+ ...segmentTargets(cwd, command, dialect, 0, strict),
20236
+ ...gitMutationDirs(cwd, command, dialect).map((dir) => path27.join(dir, DIR_TARGET))
20237
+ ];
20238
+ } catch {
20239
+ return [];
20240
+ }
20115
20241
  }, overridden = (command, dialect) => {
20116
20242
  const segments = segmentsOf(command, dialect);
20117
20243
  if (segments.length !== 1 || segments[0].group || segments[0].subs?.length)
@@ -20199,8 +20325,9 @@ var init_write_gate = __esm(() => {
20199
20325
  init_shell_words();
20200
20326
  NONE3 = { kind: "none" };
20201
20327
  CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
20202
- PREFIXES2 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "xargs"]);
20328
+ PREFIXES2 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "xargs", "busybox"]);
20203
20329
  SCRIPT_SHELLS = new Set(["sh", "bash", "zsh", "dash", "ksh"]);
20330
+ XARGS_VALUE = /^-[IinLPdsEa]$/;
20204
20331
  cache2 = new Map;
20205
20332
  MUTATING_GIT = new Set([
20206
20333
  "add",
@@ -20226,6 +20353,7 @@ var init_write_gate = __esm(() => {
20226
20353
  CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
20227
20354
  PUSHD2 = new Set(["pushd", "push-location"]);
20228
20355
  POPD2 = new Set(["popd", "pop-location"]);
20356
+ UNKNOWN_DIR = path27.resolve(path27.parse(process.cwd()).root, ".workit-unknown-dir");
20229
20357
  HOST_LABELS = {
20230
20358
  claude_code: "Claude Code",
20231
20359
  opencode: "OpenCode",
@@ -20653,10 +20781,10 @@ var init_skill_nudge = __esm(() => {
20653
20781
  });
20654
20782
 
20655
20783
  // packages/workit-core/src/hooks/hosts/fields.ts
20656
- import { existsSync as existsSync7, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
20784
+ import { existsSync as existsSync8, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
20657
20785
  import path28 from "node:path";
20658
20786
  var isRecord6 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "", optionalText = (value) => typeof value === "string" ? value : null, existingDirectory = (value) => {
20659
- if (!nonEmpty2(value) || !path28.isAbsolute(value) || !existsSync7(value))
20787
+ if (!nonEmpty2(value) || !path28.isAbsolute(value) || !existsSync8(value))
20660
20788
  return null;
20661
20789
  try {
20662
20790
  return statSync2(value).isDirectory() ? realpathSync6(value) : null;
@@ -20857,6 +20985,252 @@ var init_cwd_normalize = __esm(() => {
20857
20985
  FILTERS = new Set(["tail", "head", "grep"]);
20858
20986
  });
20859
20987
 
20988
+ // packages/workit-core/src/hooks/worktree-confine.ts
20989
+ import { createHash as createHash17 } from "node:crypto";
20990
+ import fs23 from "node:fs";
20991
+ import path30 from "node:path";
20992
+ function confineImplementer(input, targets) {
20993
+ try {
20994
+ if (!input.session.agentId || hostIsolated(input.cwd, input.session.agentId))
20995
+ return NONE5;
20996
+ if (targets.some((target) => within(path30.resolve(target), UNKNOWN_DIR)))
20997
+ return unknownDirDeny(input, boundWorktree(input));
20998
+ const bindings = canonical3(bindingDir());
20999
+ const judged = targets.map((named) => ({ named, real: canonical3(named) })).filter(({ real }) => within(real, bindings) || checkoutOf2(real) !== null);
21000
+ if (judged.length === 0)
21001
+ return NONE5;
21002
+ let worktree = boundWorktree(input);
21003
+ if (!worktree) {
21004
+ for (const { real } of judged) {
21005
+ worktree = within(real, bindings) ? null : workitWorktreeOf(real);
21006
+ if (worktree)
21007
+ break;
21008
+ }
21009
+ if (!worktree)
21010
+ return unboundDeny(input, judged[0].named);
21011
+ bind(input, worktree);
21012
+ }
21013
+ const root = canonical3(worktree);
21014
+ const outside = judged.find(({ real }) => !within(real, root) || within(real, bindings));
21015
+ return outside ? outsideDeny(input, worktree, outside.named) : NONE5;
21016
+ } catch {
21017
+ return NONE5;
21018
+ }
21019
+ }
21020
+ function confineImplementerShell(input, command, dialect = "posix") {
21021
+ try {
21022
+ if (!input.session.agentId || hostIsolated(input.cwd, input.session.agentId))
21023
+ return NONE5;
21024
+ if (rawInvocations(command, dialect).some((invocation) => invocation.tool === "git" && leadOwnedGit(invocation.args)) || workitInvocations(command, dialect).some(leadOwnedWorkit))
21025
+ return leadOwnedDeny(input, command);
21026
+ } catch {}
21027
+ return confineImplementer(input, shellMutationTargets(input.cwd, command, dialect, true));
21028
+ }
21029
+ var FANOUT_TOKEN_FILE = "workit-fanout-token", NONE5, CASE_INSENSITIVE2, canonical3 = (file) => {
21030
+ let rest = "";
21031
+ for (let dir = path30.resolve(file);; dir = path30.dirname(dir)) {
21032
+ try {
21033
+ return path30.join(fs23.realpathSync.native(dir), rest);
21034
+ } catch {
21035
+ if (path30.dirname(dir) === dir)
21036
+ return path30.resolve(file);
21037
+ rest = rest ? path30.join(path30.basename(dir), rest) : path30.basename(dir);
21038
+ }
21039
+ }
21040
+ }, within = (child, parent) => {
21041
+ const fold = (value) => CASE_INSENSITIVE2 ? value.toLowerCase() : value;
21042
+ const relative = path30.relative(fold(parent), fold(child));
21043
+ return relative === "" || !relative.startsWith("..") && !path30.isAbsolute(relative);
21044
+ }, checkoutOf2 = (file) => {
21045
+ for (let dir = canonical3(file);; dir = path30.dirname(dir)) {
21046
+ const dotGit = path30.join(dir, ".git");
21047
+ if (fs23.existsSync(dotGit)) {
21048
+ if (!fs23.statSync(dotGit).isFile())
21049
+ return { root: dir, workit: false };
21050
+ const admin = /^gitdir:\s*(.+)$/mu.exec(fs23.readFileSync(dotGit, "utf8"))?.[1]?.trim();
21051
+ return {
21052
+ root: dir,
21053
+ workit: Boolean(admin) && fs23.existsSync(path30.join(path30.resolve(dir, admin), FANOUT_TOKEN_FILE))
21054
+ };
21055
+ }
21056
+ if (path30.dirname(dir) === dir)
21057
+ return null;
21058
+ }
21059
+ }, workitWorktreeOf = (file) => {
21060
+ try {
21061
+ const checkout = checkoutOf2(file);
21062
+ return checkout?.workit ? checkout.root : null;
21063
+ } catch {
21064
+ return null;
21065
+ }
21066
+ }, bindingDir = () => path30.join(resolveStateDir(), "worktree-bind"), bindingFile = (session, agentId) => path30.join(bindingDir(), `${createHash17("sha256").update(`${session}\x00${agentId}`).digest("hex").slice(0, 32)}.json`), readBinding = (file) => {
21067
+ try {
21068
+ const value = JSON.parse(fs23.readFileSync(file, "utf8"));
21069
+ return typeof value.worktree === "string" ? value : null;
21070
+ } catch {
21071
+ return null;
21072
+ }
21073
+ }, boundWorktree = (input) => {
21074
+ const agentId = input.session.agentId;
21075
+ if (!agentId)
21076
+ return null;
21077
+ const binding = readBinding(bindingFile(input.session.id, agentId));
21078
+ return binding && workitWorktreeOf(binding.worktree) === binding.worktree ? binding.worktree : null;
21079
+ }, bind = (input, worktree) => {
21080
+ const agentId = input.session.agentId;
21081
+ const file = bindingFile(input.session.id, agentId);
21082
+ const binding = {
21083
+ worktree,
21084
+ session: input.session.id,
21085
+ agentId,
21086
+ at: new Date().toISOString()
21087
+ };
21088
+ fs23.mkdirSync(path30.dirname(file), { recursive: true });
21089
+ fs23.writeFileSync(file, JSON.stringify(binding));
21090
+ try {
21091
+ if (inWorkitWorkspace(input.cwd))
21092
+ appendHookObserved(input.cwd, {
21093
+ type: "worktree.bound",
21094
+ actor: { host: input.host, session: input.session.id, agentId },
21095
+ agentType: input.session.agentType,
21096
+ worktree
21097
+ });
21098
+ } catch {}
21099
+ }, hostIsolated = (cwd, agentId) => {
21100
+ try {
21101
+ if (agentId === null)
21102
+ return false;
21103
+ const checkout = checkoutOf2(cwd);
21104
+ if (!checkout)
21105
+ return false;
21106
+ const dotGit = path30.join(checkout.root, ".git");
21107
+ if (!fs23.statSync(dotGit).isFile())
21108
+ return false;
21109
+ const admin = /^gitdir:\s*(.+)$/mu.exec(fs23.readFileSync(dotGit, "utf8"))?.[1]?.trim();
21110
+ if (!admin)
21111
+ return false;
21112
+ const adminDir = path30.resolve(checkout.root, admin);
21113
+ const back = fs23.readFileSync(path30.join(adminDir, "gitdir"), "utf8").trim();
21114
+ if (path30.relative(canonical3(path30.resolve(adminDir, back)), canonical3(dotGit)) !== "")
21115
+ return false;
21116
+ const common = path30.join(adminDir, "commondir");
21117
+ const gitDir = fs23.existsSync(common) ? path30.resolve(adminDir, fs23.readFileSync(common, "utf8").trim()) : adminDir;
21118
+ const expected = path30.join(path30.dirname(canonical3(gitDir)), ".claude", "worktrees", `agent-${agentId}`);
21119
+ return path30.relative(canonical3(expected), checkout.root) === "";
21120
+ } catch {
21121
+ return false;
21122
+ }
21123
+ }, shown = (target) => path30.basename(target) === ".workit-live-target" ? path30.dirname(target) : target, unboundDeny = (input, target) => {
21124
+ const unblock = "Work only in the worktree your brief names, which the lead made with `workit fanout worktree create <slice>`: edit files under it and run one verb per call against it (`workit --cwd <worktree> git commit -m … -- <paths>`, `workit --cwd <worktree> check <name>`). If your brief names no worktree, stop and report that to the lead.";
21125
+ return {
21126
+ kind: "deny",
21127
+ reason: `workit worktree confinement: implementer ${input.session.agentId} is not working in a Workit worktree yet, and ${shown(target)} is outside every worktree \`workit fanout worktree create\` made, so it would change the lead's checkout. ${unblock}`,
21128
+ unblock
21129
+ };
21130
+ }, outsideDeny = (input, worktree, target) => {
21131
+ const unblock = `Edit only under ${worktree} and run git there, one verb per call: \`workit --cwd ${worktree} git commit -m … -- <paths>\`, \`workit --cwd ${worktree} check <name>\` (or \`git -C ${worktree} …\`); a command whose writes Workit cannot see is judged by the directory it runs in. Anything outside it is a follow-up for your report.`;
21132
+ return {
21133
+ kind: "deny",
21134
+ reason: `workit worktree confinement: implementer ${input.session.agentId} is bound to the worktree ${worktree}, and ${shown(target)} is outside it. ${unblock}`,
21135
+ unblock
21136
+ };
21137
+ }, unknownDirDeny = (input, worktree) => {
21138
+ const wt = worktree ?? "<worktree>";
21139
+ const unblock = `Workit cannot resolve \`cd -\`, \`cd "$X"\` or \`popd\`: write by absolute path, \`git -C ${wt}\` or \`workit --cwd ${wt}\`.`;
21140
+ return {
21141
+ kind: "deny",
21142
+ reason: `workit worktree confinement: implementer ${input.session.agentId} writes after an unknown directory change. ${unblock}`,
21143
+ unblock
21144
+ };
21145
+ }, MUTATING_REMOTE, CONFIG_READ, CONFIG_WRITE, CONFIG_VALUE, leadOwnedGit = (args) => {
21146
+ const [sub = "", ...rest] = args;
21147
+ if (rest.some((arg) => arg === "--help" || arg === "-h"))
21148
+ return false;
21149
+ const names = rest.filter((arg) => !arg.startsWith("-"));
21150
+ const flag = (pattern) => rest.some((arg) => pattern.test(arg));
21151
+ switch (sub) {
21152
+ case "worktree":
21153
+ return names[0] !== undefined && names[0] !== "list";
21154
+ case "update-ref":
21155
+ return true;
21156
+ case "symbolic-ref":
21157
+ return names.length > 1 || flag(/^(?:-d|--delete)$/);
21158
+ case "branch":
21159
+ return flag(/^-[a-zA-Z]*[dDfmMcC]|^--(?:delete|force|move|copy)$/);
21160
+ case "tag":
21161
+ return flag(/^-[a-zA-Z]*[df]|^--(?:delete|force)$/);
21162
+ case "push": {
21163
+ if (flag(/^(?:-d|--delete|--mirror|--prune)$/))
21164
+ return true;
21165
+ const refspecs = names.slice(1);
21166
+ return refspecs.some((name) => name.includes(":") || name.startsWith("+")) || refspecs.length > 0 && flag(/^-[a-zA-Z]*f|^--force/);
21167
+ }
21168
+ case "replace":
21169
+ case "filter-branch":
21170
+ case "gc":
21171
+ case "prune":
21172
+ case "repack":
21173
+ case "sparse-checkout":
21174
+ return true;
21175
+ case "notes":
21176
+ case "reflog":
21177
+ case "submodule":
21178
+ return !/^(?:list|show|status|exists)$/.test(names[0] ?? "list");
21179
+ case "stash":
21180
+ return names[0] === "drop" || names[0] === "clear";
21181
+ case "remote":
21182
+ return MUTATING_REMOTE.has(names[0] ?? "");
21183
+ case "config": {
21184
+ if (rest.some((arg) => CONFIG_READ.test(arg)))
21185
+ return false;
21186
+ if (rest.some((arg) => CONFIG_WRITE.test(arg)))
21187
+ return true;
21188
+ let operands = 0;
21189
+ for (let index = 0;index < rest.length; index++)
21190
+ if (CONFIG_VALUE.test(rest[index]))
21191
+ index++;
21192
+ else if (!rest[index].startsWith("-"))
21193
+ operands++;
21194
+ return operands > 1;
21195
+ }
21196
+ default:
21197
+ return false;
21198
+ }
21199
+ }, leadOwnedWorkit = (args) => !args.includes("--help") && args.some((_, start) => {
21200
+ if (start > 0 && !/(?:^|[\\/])workit(?:\.exe|\.cmd)?$/.test(args[start - 1]))
21201
+ return false;
21202
+ const [verb, sub] = skipWorkitGlobals(args.slice(start)).rest;
21203
+ return verb === "fanout" && /^(?:plan|worktree)$/.test(sub ?? "");
21204
+ }), leadOwnedDeny = (input, command) => {
21205
+ const unblock = "Worktrees, branches other than your own, refs, tags, remotes, git config, the shared stash and the fan-out plan belong to the lead: report what you need changed as a follow-up instead.";
21206
+ return {
21207
+ kind: "deny",
21208
+ reason: `workit worktree confinement: implementer ${input.session.agentId} may not run \`${command.slice(0, 160)}\`. ${unblock}`,
21209
+ unblock
21210
+ };
21211
+ };
21212
+ var init_worktree_confine = __esm(() => {
21213
+ init_logger();
21214
+ init_ledger();
21215
+ init_raw_git();
21216
+ init_write_gate();
21217
+ NONE5 = { kind: "none" };
21218
+ CASE_INSENSITIVE2 = process.platform === "darwin" || process.platform === "win32";
21219
+ MUTATING_REMOTE = new Set([
21220
+ "add",
21221
+ "remove",
21222
+ "rm",
21223
+ "rename",
21224
+ "set-url",
21225
+ "set-head",
21226
+ "set-branches",
21227
+ "prune"
21228
+ ]);
21229
+ CONFIG_READ = /^(?:--get(?:-all|-regexp|-urlmatch)?|--list|-l|get|list)$/;
21230
+ CONFIG_WRITE = /^(?:--(?:unset(?:-all)?|add|replace-all|rename-section|remove-section|edit)|-e|set|unset|rename-section|remove-section|edit)$/;
21231
+ CONFIG_VALUE = /^(?:--file|-f|--blob|--type|--default|--comment)$/;
21232
+ });
21233
+
20860
21234
  // packages/workit-core/src/hooks/handle.ts
20861
21235
  function handleHook(input, deps) {
20862
21236
  const decision = decide(input, deps);
@@ -20874,7 +21248,7 @@ function decide(input, deps) {
20874
21248
  switch (event.kind) {
20875
21249
  case "session.start": {
20876
21250
  if (!usable2(descriptor.context.sessionStart))
20877
- return NONE5;
21251
+ return NONE6;
20878
21252
  const key = input.session.id ? `${input.host}\x00${input.session.id}` : null;
20879
21253
  const offer = event.source === "startup" && (key === null || !offered.has(key));
20880
21254
  if (offer && key !== null)
@@ -20889,26 +21263,31 @@ function decide(input, deps) {
20889
21263
  }
20890
21264
  case "context.turn": {
20891
21265
  if (!usable2(descriptor.context.perTurn))
20892
- return NONE5;
21266
+ return NONE6;
20893
21267
  const current = turnContextText(input, descriptor);
20894
21268
  const text = resendsOnChange(descriptor) ? changedTurnContext(input, current) : current;
20895
- return withContextLine(text ? { kind: "context", text } : NONE5, promptNudge(input, event.prompt));
21269
+ return withContextLine(text ? { kind: "context", text } : NONE6, promptNudge(input, event.prompt));
20896
21270
  }
20897
21271
  case "shell.pre": {
20898
21272
  const skillRead = skillReadIn(event.command, event.dialect);
20899
21273
  if (skillRead)
20900
21274
  recordSkillLoad(input, skillRead, "read");
20901
21275
  const canDeny = usable2(descriptor.shellPolicy.deny);
20902
- const policy = canDeny ? shellPolicy(input.cwd, event.command, event.dialect) : NONE5;
21276
+ const policy = canDeny ? shellPolicy(input.cwd, event.command, event.dialect) : NONE6;
20903
21277
  if (policy.kind !== "none")
20904
21278
  return policy;
20905
21279
  const postTool = usable2(descriptor.events["shell.post"].support);
20906
21280
  if (!postTool)
20907
21281
  settlePendingCommit(input);
20908
- const raw = canDeny ? rawGitPre(input, event.command, { nudge: false }) : NONE5;
21282
+ const raw = canDeny ? rawGitPre(input, event.command, { nudge: false }) : NONE6;
20909
21283
  if (raw.kind === "deny")
20910
21284
  return raw;
20911
- const gate = usable2(descriptor.events["write.pre"].support) ? shellGate(input.cwd, event.command, liveOwner(input, descriptor.transport), event.dialect) : NONE5;
21285
+ if (canDeny && implementerAgent(input, descriptor)) {
21286
+ const confined = confineImplementerShell(input, event.command, event.dialect);
21287
+ if (confined.kind === "deny")
21288
+ return confined;
21289
+ }
21290
+ const gate = usable2(descriptor.events["write.pre"].support) ? shellGate(input.cwd, event.command, liveOwner(input, descriptor.transport), event.dialect) : NONE6;
20912
21291
  if (gate.kind === "deny")
20913
21292
  return gate;
20914
21293
  const plan = heavyGate(input.cwd, event.command, {
@@ -20931,10 +21310,10 @@ function decide(input, deps) {
20931
21310
  command: rewrittenTo,
20932
21311
  input: event.toolInput ? { ...event.toolInput, command: rewrittenTo } : null,
20933
21312
  text
20934
- } : NONE5;
21313
+ } : NONE6;
20935
21314
  if (descriptor.transport !== "hook-process")
20936
21315
  return rewritten(null);
20937
- const nudged = withContextLine(withContextLine(canDeny ? rawGitPre(input, event.command) : NONE5, aside), shipNudge(input, event.command));
21316
+ const nudged = withContextLine(withContextLine(canDeny ? rawGitPre(input, event.command) : NONE6, aside), shipNudge(input, event.command));
20938
21317
  if (!lease)
20939
21318
  return cwdCommand && nudged.kind !== "deny" ? rewritten(nudged.kind === "context" ? nudged.text : null) : nudged;
20940
21319
  return rewritten([rewriteNote(lease), nudged.kind === "context" ? nudged.text : null].filter(Boolean).join(`
@@ -20943,9 +21322,17 @@ function decide(input, deps) {
20943
21322
  case "shell.post":
20944
21323
  if (usable2(descriptor.events["shell.post"].support))
20945
21324
  rawGitPost(input, event.command, callKey(event.toolUseId, event.command));
20946
- return NONE5;
20947
- case "write.pre":
20948
- return usable2(descriptor.events["write.pre"].support) ? writeGate(input.cwd, event.paths, liveOwner(input, descriptor.transport)) : NONE5;
21325
+ return NONE6;
21326
+ case "write.pre": {
21327
+ if (!usable2(descriptor.events["write.pre"].support))
21328
+ return NONE6;
21329
+ if (implementerAgent(input, descriptor)) {
21330
+ const confined = confineImplementer(input, liveTargets(input.cwd, event.paths));
21331
+ if (confined.kind === "deny")
21332
+ return confined;
21333
+ }
21334
+ return writeGate(input.cwd, event.paths, liveOwner(input, descriptor.transport));
21335
+ }
20949
21336
  case "subagent.start":
20950
21337
  if (workitRole(descriptor, event.agentType) === "judge")
20951
21338
  trackJudge(input, event.agentId, true);
@@ -20962,25 +21349,25 @@ function decide(input, deps) {
20962
21349
  case "tool.pre":
20963
21350
  if (event.skill)
20964
21351
  recordSkillLoad(input, event.skill, "tool");
20965
- return NONE5;
21352
+ return NONE6;
20966
21353
  case "stop":
20967
- return usable2(descriptor.events.stop.support) ? stopDecision(input, descriptor) : NONE5;
21354
+ return usable2(descriptor.events.stop.support) ? stopDecision(input, descriptor) : NONE6;
20968
21355
  case "subagent.stop":
20969
21356
  trackJudge(input, event.agentId, false);
20970
- return NONE5;
21357
+ return NONE6;
20971
21358
  case "prompt.submit":
20972
- return NONE5;
21359
+ return NONE6;
20973
21360
  }
20974
21361
  }
20975
- var usable2 = (value) => value === "native" || value === "partial", NONE5, resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn), offered, ROLES, workitRole = (descriptor, agentType) => {
21362
+ var usable2 = (value) => value === "native" || value === "partial", NONE6, resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn), offered, ROLES, workitRole = (descriptor, agentType) => {
20976
21363
  const prefix = descriptor.subagents.agentPrefix;
20977
21364
  const name = agentType.startsWith(prefix) ? agentType.slice(prefix.length) : "";
20978
21365
  return Object.hasOwn(ROLES, name) ? ROLES[name] : null;
20979
- }, subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128), CLAUDE_WORKTREE, isolatedGit = (cwd) => `Run git as plain, separate commands inside your worktree (\`git switch -c <branch> <base>\`, ${workspaceTrailers(cwd).enabled ? '`git commit --trailer "Workit-Session=<your session>"`, `git push`; `workit doctor --fix` can install a prepare-commit-msg hook that adds the trailer' : "`git commit` (this workspace sets trailers: false: add no Workit-Session trailer), `git push`"}; add Co-Authored-By with \`git commit --trailer\` in the same commit, never by amending), never \`workit git …\`: Claude Code's worktree isolation refuses a command that wraps git and cannot be turned off (https://code.claude.com/docs/en/worktrees#how-claude-code-enforces-isolation). Never dodge that check by renaming or re-wrapping git. Use workit for the non-git verbs (\`workit check\`, \`workit ledger\`, \`workit pr\`).`, subagentStartText = (input, descriptor, event) => {
21366
+ }, implementerAgent = (input, descriptor) => Boolean(input.session.agentId) && input.session.agentType !== null && workitRole(descriptor, input.session.agentType) === "implementer", subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128), CLAUDE_WORKTREE, isolatedGit = (cwd) => `Run git as plain, separate commands inside your worktree (\`git switch -c <branch> <base>\`, ${workspaceTrailers(cwd).enabled ? '`git commit --trailer "Workit-Session=<your session>"`, `git push`; `workit doctor --fix` can install a prepare-commit-msg hook that adds the trailer' : "`git commit` (this workspace sets trailers: false: add no Workit-Session trailer), `git push`"}; add Co-Authored-By with \`git commit --trailer\` in the same commit, never by amending), never \`workit git …\`: Claude Code's worktree isolation refuses a command that wraps git and cannot be turned off (https://code.claude.com/docs/en/worktrees#how-claude-code-enforces-isolation). Never dodge that check by renaming or re-wrapping git. Use workit for the non-git verbs (\`workit check\`, \`workit ledger\`, \`workit pr\`).`, subagentStartText = (input, descriptor, event) => {
20980
21367
  const session = input.session.id ?? null;
20981
21368
  const role = workitRole(descriptor, event.agentType);
20982
21369
  const who = `${descriptor.label} subagent ${event.agentId} (${event.agentType})`;
20983
- const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" || CLAUDE_WORKTREE.test(input.cwd));
21370
+ const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" ? hostIsolated(input.cwd, event.agentId) : CLAUDE_WORKTREE.test(input.cwd));
20984
21371
  const guide = role === "implementer" ? branchGuidance(input.cwd) : null;
20985
21372
  if (role === "implementer" && isolated)
20986
21373
  return `Workit observed ${who} working in its own git worktree: it may edit and commit there, within its brief's scope. ${isolatedGit(input.cwd)} Plain git is expected here, and the branch name is still policy-checked: a raw \`git switch -c\`, \`git checkout -b\`, \`git branch\` or \`git worktree add -b\` onto a protected or non-compliant name is denied, so use a policy-compliant branch.${guide ? ` ${guide}` : " (e.g. feature/<slug>)"} Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
@@ -20988,7 +21375,7 @@ var usable2 = (value) => value === "native" || value === "partial", NONE5, resen
20988
21375
  return `${isolatedGit(input.cwd)}
20989
21376
  ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
20990
21377
  if (role === "implementer")
20991
- return `Workit observed ${who} as an implementer: it edits and commits only in its own git worktree (the lead makes one with \`workit fanout worktree create <slice>\`), never in the lead's checkout, within its brief's scope. Before the first commit, switch to a policy-compliant branch with \`workit git branch <branch> --base <base>\` (or \`--kind <kind> --slug <slug>\`, which picks the base); branch policy hooks still deny protected or non-compliant branches, raw git included.${guide ? ` ${guide}` : " (e.g. feature/<slug>)"} Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
21378
+ return `Workit observed ${who} as an implementer: it edits and commits only in its own git worktree, the one its brief names (the lead makes it with \`workit fanout worktree create <slice>\` before spawning), never in the lead's checkout, within its brief's scope. Workit binds it to the first Workit worktree it changes: from then on an edit or a mutating git command outside that worktree is denied, and before then so is one outside every Workit worktree. Run Workit against the worktree one verb per call, never \`cd … &&\` chains or \`$VAR\` paths: \`workit --cwd <worktree> git commit -m "<message>" -- <paths>\`, \`workit --cwd <worktree> check <name>\`. The worktree is on the brief's branch once the lead made it; otherwise switch with \`workit --cwd <worktree> git branch <branch> --base <base>\` (or \`--kind <kind> --slug <slug>\`, which picks the base); branch policy hooks still deny protected or non-compliant branches, raw git included.${guide ? ` ${guide}` : " (e.g. feature/<slug>)"} Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
20992
21379
  const readOnly = `Workit observed ${who} as read-only/agent-guided.`;
20993
21380
  if (role !== "judge" || !event.agentId)
20994
21381
  return readOnly;
@@ -21003,10 +21390,10 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
21003
21390
  return `${readOnly} Its own Workit session is ${own}, so the ledger tells its verdicts apart from the author's. Record the verdict with exactly this command (pick the result${pick}, name the candidate branch if it differs, say what you ran): \`${line}\`.${token ? " The token is this subagent's alone: never write it into a report, a file or a commit. --token needs a workit CLI at least as new as this plugin; if the CLI answers that --token is an unknown option, update the workit CLI (workit upgrade --cli) and record again." : ""}`;
21004
21391
  }, PRE_TOOL, failureDecision = (descriptor, event, error) => {
21005
21392
  if (event === "shell.pre" || event === "tool.pre" || event === "write.pre")
21006
- return descriptor.shellPolicy.failClosed ? { kind: "deny", reason: error, unblock: null } : NONE5;
21393
+ return descriptor.shellPolicy.failClosed ? { kind: "deny", reason: error, unblock: null } : NONE6;
21007
21394
  if (event === "session.start" || event === "subagent.start")
21008
21395
  return { kind: "context", text: `[workit diagnostic: ${error}]` };
21009
- return NONE5;
21396
+ return NONE6;
21010
21397
  }, dispatchHook = (adapter, raw, env = process.env) => {
21011
21398
  const parsed = adapter.parse(raw, env);
21012
21399
  if (!parsed.ok)
@@ -21044,7 +21431,8 @@ var init_handle = __esm(() => {
21044
21431
  init_stop();
21045
21432
  init_live_session();
21046
21433
  init_write_gate();
21047
- NONE5 = { kind: "none" };
21434
+ init_worktree_confine();
21435
+ NONE6 = { kind: "none" };
21048
21436
  offered = new Set;
21049
21437
  ROLES = {
21050
21438
  implementer: "implementer",
@@ -21057,20 +21445,20 @@ var init_handle = __esm(() => {
21057
21445
 
21058
21446
  // packages/workit-core/src/hooks/deadline.ts
21059
21447
  import { appendFileSync, mkdirSync as mkdirSync3 } from "node:fs";
21060
- import path30 from "node:path";
21448
+ import path31 from "node:path";
21061
21449
  var HOOK_SKIP_TEXT = "workit context skipped: host under load", HOOK_DEADLINE_MS = 8000, HOST_DEADLINES, HOOK_SKIPS_FILE = "hook-skips.jsonl", override = (env) => {
21062
21450
  const value = Number(env.WORKIT_HOOK_DEADLINE_MS);
21063
21451
  return Number.isFinite(value) && value > 0 ? value : null;
21064
21452
  }, hookDeadlineMs = (env, host = "", native) => {
21065
21453
  const row = HOST_DEADLINES[host];
21066
21454
  return override(env) ?? (row ? native === undefined ? Math.min(...Object.values(row)) : row[native] ?? row[""] : HOOK_DEADLINE_MS);
21067
- }, skipsFile = (stateDir) => path30.join(stateDir, HOOK_SKIPS_FILE), recordHookSkip = (skip, stateDir = resolveStateDir()) => {
21455
+ }, skipsFile = (stateDir) => path31.join(stateDir, HOOK_SKIPS_FILE), recordHookSkip = (skip, stateDir = resolveStateDir()) => {
21068
21456
  try {
21069
21457
  mkdirSync3(stateDir, { recursive: true });
21070
21458
  appendFileSync(skipsFile(stateDir), `${JSON.stringify(skip)}
21071
21459
  `);
21072
21460
  } catch {}
21073
- }, QUIET, skipDecision = (event) => QUIET.has(event) ? { kind: "none" } : { kind: "context", text: HOOK_SKIP_TEXT }, TIMED_OUT, within = async (work, ms) => {
21461
+ }, QUIET, skipDecision = (event) => QUIET.has(event) ? { kind: "none" } : { kind: "context", text: HOOK_SKIP_TEXT }, TIMED_OUT, within2 = async (work, ms) => {
21074
21462
  let timer;
21075
21463
  const expired = new Promise((resolve) => {
21076
21464
  timer = setTimeout(() => resolve(TIMED_OUT), Math.max(0, ms));
@@ -21097,7 +21485,7 @@ var HOOK_SKIP_TEXT = "workit context skipped: host under load", HOOK_DEADLINE_MS
21097
21485
  text += String(chunk);
21098
21486
  return text;
21099
21487
  })();
21100
- const text = await within(read, budget.startedAt + budget.deadlineMs - budget.now());
21488
+ const text = await within2(read, budget.startedAt + budget.deadlineMs - budget.now());
21101
21489
  return isTimedOut(text) ? null : text;
21102
21490
  }, note = (adapter, raw, env, budget, outcome, stage) => {
21103
21491
  const parsed = raw === undefined ? null : adapter.parse(raw, env);
@@ -21123,7 +21511,7 @@ var HOOK_SKIP_TEXT = "workit context skipped: host under load", HOOK_DEADLINE_MS
21123
21511
  if (budget.host !== null && typeof native === "string")
21124
21512
  budget.deadlineMs = hookDeadlineMs(env, budget.host, native);
21125
21513
  const remaining = () => budget.startedAt + budget.deadlineMs - budget.now();
21126
- const result = remaining() > 0 ? await within(Promise.resolve().then(() => dispatch(adapter, raw, env)), remaining()) : TIMED_OUT;
21514
+ const result = remaining() > 0 ? await within2(Promise.resolve().then(() => dispatch(adapter, raw, env)), remaining()) : TIMED_OUT;
21127
21515
  if (isTimedOut(result))
21128
21516
  return skippedHook(adapter, raw, env, budget, "dispatch");
21129
21517
  if (remaining() < 0)
@@ -21708,8 +22096,8 @@ var init_codex = __esm(() => {
21708
22096
  });
21709
22097
 
21710
22098
  // packages/workit-core/src/hooks/hosts/cursor.ts
21711
- import fs23 from "node:fs";
21712
- import path31 from "node:path";
22099
+ import fs24 from "node:fs";
22100
+ import path32 from "node:path";
21713
22101
  var undocumented, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (value) => {
21714
22102
  if (!isRecord6(value) || !Object.hasOwn(EVENTS3, String(value.hook_event_name)))
21715
22103
  return { ok: false, error: "hook_event_name is required" };
@@ -21790,17 +22178,17 @@ var undocumented, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (valu
21790
22178
  };
21791
22179
  }
21792
22180
  }, TRANSCRIPT_TAIL_BYTES, lastAssistantText = (file) => {
21793
- if (!file || !path31.isAbsolute(file))
22181
+ if (!file || !path32.isAbsolute(file))
21794
22182
  return null;
21795
22183
  try {
21796
- const size = fs23.statSync(file).size;
22184
+ const size = fs24.statSync(file).size;
21797
22185
  const start = Math.max(0, size - TRANSCRIPT_TAIL_BYTES);
21798
22186
  const buffer = Buffer.alloc(size - start);
21799
- const fd = fs23.openSync(file, "r");
22187
+ const fd = fs24.openSync(file, "r");
21800
22188
  try {
21801
- fs23.readSync(fd, buffer, 0, buffer.length, start);
22189
+ fs24.readSync(fd, buffer, 0, buffer.length, start);
21802
22190
  } finally {
21803
- fs23.closeSync(fd);
22191
+ fs24.closeSync(fd);
21804
22192
  }
21805
22193
  const lines = buffer.toString("utf8").split(`
21806
22194
  `);
@@ -21826,14 +22214,14 @@ var undocumented, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (valu
21826
22214
  } catch {
21827
22215
  return null;
21828
22216
  }
21829
- }, within2 = (root, dir) => dir === root || dir.startsWith(root.endsWith(path31.sep) ? root : `${root}${path31.sep}`), hookCwd = (input) => {
22217
+ }, within3 = (root, dir) => dir === root || dir.startsWith(root.endsWith(path32.sep) ? root : `${root}${path32.sep}`), hookCwd = (input) => {
21830
22218
  const cwd = existingDirectory(input.cwd);
21831
22219
  if (cwd && input.hook_event_name === "beforeShellExecution")
21832
22220
  return cwd;
21833
22221
  return cursorWorkspaceRoot(input);
21834
22222
  }, cursorWorkspaceRoot = (input) => {
21835
22223
  const cwd = existingDirectory(input.cwd);
21836
- return cwd && input.workspace_roots.find((root) => within2(root, cwd)) || input.workspace_roots[0];
22224
+ return cwd && input.workspace_roots.find((root) => within3(root, cwd)) || input.workspace_roots[0];
21837
22225
  }, cursorDeny = (reason) => ({
21838
22226
  permission: "deny",
21839
22227
  user_message: "Workit blocked this action",