@brainervirus/workit-cli 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.
Files changed (2) hide show
  1. package/dist/index.js +274 -95
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -9050,7 +9050,7 @@ var package_default;
9050
9050
  var init_package = __esm(() => {
9051
9051
  package_default = {
9052
9052
  name: "@brainervirus/workit-cli",
9053
- version: "8.22.3",
9053
+ version: "8.23.0",
9054
9054
  private: false,
9055
9055
  description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
9056
9056
  keywords: [
@@ -9088,13 +9088,13 @@ var init_package = __esm(() => {
9088
9088
  },
9089
9089
  dependencies: {
9090
9090
  "@babel/parser": "7.29.9",
9091
- "@brainervirus/workit-cursor": "^8.22.3",
9091
+ "@brainervirus/workit-cursor": "^8.23.0",
9092
9092
  "@inkjs/ui": "2.0.0",
9093
9093
  ink: "7.1.1",
9094
9094
  react: "19.2.8"
9095
9095
  },
9096
9096
  devDependencies: {
9097
- "@brainervirus/workit-core": "^8.22.3"
9097
+ "@brainervirus/workit-core": "^8.23.0"
9098
9098
  },
9099
9099
  engines: {
9100
9100
  node: ">=24"
@@ -82928,10 +82928,176 @@ var init_stack2 = __esm(() => {
82928
82928
  METHODS3 = new Set(["squash", "merge", "rebase"]);
82929
82929
  });
82930
82930
 
82931
+ // packages/workit-core/src/core/live-session.ts
82932
+ import { spawnSync as spawnSync27 } from "node:child_process";
82933
+ var LIVE_SESSION_TTL_MS, liveProbe, PIDS;
82934
+ var init_live_session = __esm(() => {
82935
+ init_paths();
82936
+ init_logger();
82937
+ init_store_lock();
82938
+ LIVE_SESSION_TTL_MS = 15 * 60000;
82939
+ liveProbe = {
82940
+ platform: process.platform,
82941
+ run: (args) => spawnSync27("ps", args, { encoding: "utf8", timeout: 2000 }).stdout ?? "",
82942
+ start: (pid) => processStartOf(pid)
82943
+ };
82944
+ PIDS = new Map;
82945
+ });
82946
+
82947
+ // packages/workit-core/src/hooks/write-gate.ts
82948
+ import path55 from "node:path";
82949
+ var CASE_INSENSITIVE, PREFIXES2, SCRIPT_SHELLS, cache3, MUTATING_GIT, DRY_N, MUTATING_WORKIT_GIT, CD2, PUSHD2, POPD2, UNKNOWN_DIR;
82950
+ var init_write_gate = __esm(() => {
82951
+ init_task_store();
82952
+ init_derive();
82953
+ init_task_evaluation();
82954
+ init_live_session();
82955
+ init_logger();
82956
+ init_workspaces();
82957
+ init_ledger();
82958
+ init_raw_git();
82959
+ init_shell_words();
82960
+ CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
82961
+ PREFIXES2 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "xargs", "busybox"]);
82962
+ SCRIPT_SHELLS = new Set(["sh", "bash", "zsh", "dash", "ksh"]);
82963
+ cache3 = new Map;
82964
+ MUTATING_GIT = new Set([
82965
+ "add",
82966
+ "am",
82967
+ "apply",
82968
+ "checkout",
82969
+ "cherry-pick",
82970
+ "clean",
82971
+ "commit",
82972
+ "merge",
82973
+ "mv",
82974
+ "pull",
82975
+ "rebase",
82976
+ "reset",
82977
+ "restore",
82978
+ "revert",
82979
+ "rm",
82980
+ "stash",
82981
+ "switch"
82982
+ ]);
82983
+ DRY_N = new Set(["add", "clean", "rm", "mv"]);
82984
+ MUTATING_WORKIT_GIT = new Set(["commit", "branch"]);
82985
+ CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
82986
+ PUSHD2 = new Set(["pushd", "push-location"]);
82987
+ POPD2 = new Set(["popd", "pop-location"]);
82988
+ UNKNOWN_DIR = path55.resolve(path55.parse(process.cwd()).root, ".workit-unknown-dir");
82989
+ });
82990
+
82991
+ // packages/workit-core/src/hooks/worktree-confine.ts
82992
+ var FANOUT_TOKEN_FILE = "workit-fanout-token", CASE_INSENSITIVE2, MUTATING_REMOTE;
82993
+ var init_worktree_confine = __esm(() => {
82994
+ init_logger();
82995
+ init_ledger();
82996
+ init_raw_git();
82997
+ init_write_gate();
82998
+ CASE_INSENSITIVE2 = process.platform === "darwin" || process.platform === "win32";
82999
+ MUTATING_REMOTE = new Set([
83000
+ "add",
83001
+ "remove",
83002
+ "rm",
83003
+ "rename",
83004
+ "set-url",
83005
+ "set-head",
83006
+ "set-branches",
83007
+ "prune"
83008
+ ]);
83009
+ });
83010
+
83011
+ // packages/workit-core/src/worktree-deps.ts
83012
+ import fs31 from "node:fs";
83013
+ import path56 from "node:path";
83014
+ function moduleDirs(main) {
83015
+ const out = [];
83016
+ const walk = (relative, depth) => {
83017
+ let entries;
83018
+ try {
83019
+ entries = fs31.readdirSync(path56.join(main, relative), { withFileTypes: true });
83020
+ } catch {
83021
+ return;
83022
+ }
83023
+ for (const entry of entries) {
83024
+ if (!entry.isDirectory())
83025
+ continue;
83026
+ const child = path56.join(relative, entry.name);
83027
+ if (entry.name === MODULES)
83028
+ out.push(child);
83029
+ else if (depth < MAX_DEPTH2 && !entry.name.startsWith("."))
83030
+ walk(child, depth + 1);
83031
+ }
83032
+ };
83033
+ walk("", 0);
83034
+ return out;
83035
+ }
83036
+ function linkEntry(main, worktree, source, target) {
83037
+ const stat = fs31.lstatSync(source);
83038
+ if (stat.isSymbolicLink()) {
83039
+ const link = fs31.readlinkSync(source);
83040
+ const outside = path56.isAbsolute(link) && within(link, main) && !path56.relative(main, link).split(path56.sep).includes(MODULES);
83041
+ const to = outside ? path56.join(worktree, path56.relative(main, link)) : link;
83042
+ fs31.symlinkSync(to, target, process.platform === "win32" ? "junction" : undefined);
83043
+ return;
83044
+ }
83045
+ fs31.symlinkSync(source, target, process.platform === "win32" ? stat.isDirectory() ? "junction" : "file" : undefined);
83046
+ }
83047
+ function mirror(main, worktree, source, target, top) {
83048
+ fs31.mkdirSync(target);
83049
+ let count = 0;
83050
+ for (const entry of fs31.readdirSync(source, { withFileTypes: true })) {
83051
+ const from = path56.join(source, entry.name);
83052
+ const to = path56.join(target, entry.name);
83053
+ if (top && entry.isDirectory() && (entry.name.startsWith("@") || entry.name === ".bin"))
83054
+ count += mirror(main, worktree, from, to, false);
83055
+ else {
83056
+ linkEntry(main, worktree, from, to);
83057
+ count += 1;
83058
+ }
83059
+ }
83060
+ return count;
83061
+ }
83062
+ function linkWorktreeDependencies(main, worktree) {
83063
+ const started = performance.now();
83064
+ const notes = [];
83065
+ const dirs = [];
83066
+ let entries = 0;
83067
+ for (const relative of moduleDirs(main)) {
83068
+ const target = path56.join(worktree, relative);
83069
+ if (!fs31.existsSync(path56.dirname(target)) || fs31.existsSync(target))
83070
+ continue;
83071
+ if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(path56.sep).join("/")}/`]).ok) {
83072
+ notes.push(`${relative.split(path56.sep).join("/")} is not ignored by git, so it was not linked from ${main}; install dependencies in the worktree yourself`);
83073
+ continue;
83074
+ }
83075
+ try {
83076
+ entries += mirror(main, worktree, path56.join(main, relative), target, true);
83077
+ dirs.push(relative.split(path56.sep).join("/"));
83078
+ } catch (error) {
83079
+ fs31.rmSync(target, { recursive: true, force: true });
83080
+ notes.push(`could not link ${relative} from ${main} (${error.message}); install dependencies in the worktree yourself`);
83081
+ }
83082
+ }
83083
+ if (dirs.length === 0)
83084
+ return { linked: null, notes };
83085
+ const ms = Math.round(performance.now() - started);
83086
+ notes.push(`linked ${dirs.join(", ")} from ${main} (${entries} entries, ${ms} ms): workspace packages resolve to this worktree, installed packages are shared`);
83087
+ return { linked: { from: main, dirs, entries, ms }, notes };
83088
+ }
83089
+ var MODULES = "node_modules", MAX_DEPTH2 = 2, within = (child, parent) => {
83090
+ const relative = path56.relative(parent, child);
83091
+ return relative === "" || !relative.startsWith("..") && !path56.isAbsolute(relative);
83092
+ };
83093
+ var init_worktree_deps = __esm(() => {
83094
+ init_fanout();
83095
+ });
83096
+
82931
83097
  // packages/workit-core/src/fanout-worktree.ts
82932
83098
  import { randomBytes as randomBytes5 } from "node:crypto";
82933
- import fs31 from "node:fs";
82934
- import path55 from "node:path";
83099
+ import fs32 from "node:fs";
83100
+ import path57 from "node:path";
82935
83101
  function rowSample(lines) {
82936
83102
  const out = [];
82937
83103
  let bytes = 0;
@@ -82991,7 +83157,7 @@ function adminDir(worktree) {
82991
83157
  const file = dir.stdout.trim();
82992
83158
  let token = null;
82993
83159
  try {
82994
- token = fs31.readFileSync(path55.join(file, TOKEN_FILE), "utf8").trim() || null;
83160
+ token = fs32.readFileSync(path57.join(file, FANOUT_TOKEN_FILE), "utf8").trim() || null;
82995
83161
  } catch {
82996
83162
  token = null;
82997
83163
  }
@@ -82999,7 +83165,7 @@ function adminDir(worktree) {
82999
83165
  const stat = worktreeDeps.stat(file);
83000
83166
  return {
83001
83167
  path: file,
83002
- id: path55.basename(file),
83168
+ id: path57.basename(file),
83003
83169
  ino: stat.ino.toString(),
83004
83170
  token,
83005
83171
  birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
@@ -83015,7 +83181,7 @@ function markAdminDir(worktree) {
83015
83181
  return null;
83016
83182
  const token = randomBytes5(16).toString("hex");
83017
83183
  try {
83018
- fs31.writeFileSync(path55.join(admin.path, TOKEN_FILE), `${token}
83184
+ fs32.writeFileSync(path57.join(admin.path, FANOUT_TOKEN_FILE), `${token}
83019
83185
  `);
83020
83186
  } catch {
83021
83187
  return null;
@@ -83030,25 +83196,25 @@ function excludeScratch(cwd) {
83030
83196
  const common = gitCommonDir(cwd);
83031
83197
  if (!common)
83032
83198
  return;
83033
- const file = path55.join(common, "info", "exclude");
83199
+ const file = path57.join(common, "info", "exclude");
83034
83200
  let text = "";
83035
83201
  try {
83036
- text = fs31.readFileSync(file, "utf8");
83202
+ text = fs32.readFileSync(file, "utf8");
83037
83203
  } catch {
83038
83204
  text = "";
83039
83205
  }
83040
83206
  if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
83041
83207
  return;
83042
- fs31.mkdirSync(path55.dirname(file), { recursive: true });
83043
- fs31.appendFileSync(file, `${text && !text.endsWith(`
83208
+ fs32.mkdirSync(path57.dirname(file), { recursive: true });
83209
+ fs32.appendFileSync(file, `${text && !text.endsWith(`
83044
83210
  `) ? `
83045
83211
  ` : ""}# workit fanout: per-worker scratch dirs
83046
83212
  ${EXCLUDE_LINE}
83047
83213
  `);
83048
83214
  }
83049
83215
  function ensureScratch(worktree) {
83050
- const scratch = path55.join(worktree, SCRATCH_DIR);
83051
- fs31.mkdirSync(scratch, { recursive: true });
83216
+ const scratch = path57.join(worktree, SCRATCH_DIR);
83217
+ fs32.mkdirSync(scratch, { recursive: true });
83052
83218
  return scratch;
83053
83219
  }
83054
83220
  function createSliceWorktree(cwd, plan, input) {
@@ -83075,6 +83241,7 @@ function createSliceWorktree(cwd, plan, input) {
83075
83241
  if (!createdRow(cwd, plan, slice, target))
83076
83242
  return fanoutFail("blocked", `${target} is a worktree that workit fanout worktree create did not make for slice ${slice.id}`, `remove it yourself (git worktree remove ${target}) once you know what it holds`);
83077
83243
  excludeScratch(cwd);
83244
+ const deps = linkWorktreeDependencies(mainCheckout(cwd), target);
83078
83245
  return {
83079
83246
  ok: true,
83080
83247
  data: {
@@ -83083,7 +83250,11 @@ function createSliceWorktree(cwd, plan, input) {
83083
83250
  head: existing.head ?? "",
83084
83251
  mode: resolveRef(cwd, localRef) ? "resume" : "new",
83085
83252
  created: false,
83086
- notes: ["the worktree already exists; nothing was changed"]
83253
+ dependencies: deps.linked,
83254
+ notes: [
83255
+ deps.linked ? "the worktree already exists; only its missing dependencies were linked" : "the worktree already exists; nothing was changed",
83256
+ ...deps.notes
83257
+ ]
83087
83258
  }
83088
83259
  };
83089
83260
  }
@@ -83092,8 +83263,8 @@ function createSliceWorktree(cwd, plan, input) {
83092
83263
  return fanoutFail("blocked", `${slice.branch} is checked out at ${elsewhere.path}: never two live workers on one branch`, `stop that worker, then workit fanout worktree release ${slice.id} (or git worktree remove ${elsewhere.path})`);
83093
83264
  let dirExisted = false;
83094
83265
  try {
83095
- const stat = fs31.statSync(target);
83096
- if (!stat.isDirectory() || fs31.readdirSync(target).length > 0)
83266
+ const stat = fs32.statSync(target);
83267
+ if (!stat.isDirectory() || fs32.readdirSync(target).length > 0)
83097
83268
  return fanoutFail("blocked", `${target} exists and is ${stat.isDirectory() ? "not empty" : "not a directory"} (not a worktree of this repository)`, `move it away, or set slice ${slice.id}'s worktree to another path`);
83098
83269
  dirExisted = true;
83099
83270
  } catch (error) {
@@ -83133,6 +83304,8 @@ function createSliceWorktree(cwd, plan, input) {
83133
83304
  }
83134
83305
  excludeScratch(cwd);
83135
83306
  const scratch = ensureScratch(target);
83307
+ const deps = linkWorktreeDependencies(mainCheckout(cwd), target);
83308
+ notes.push(...deps.notes);
83136
83309
  const head = gitRun4(target, ["rev-parse", "HEAD"]).stdout.trim();
83137
83310
  const baseSha = mode === "new" ? head : null;
83138
83311
  const admin = markAdminDir(target);
@@ -83152,7 +83325,10 @@ function createSliceWorktree(cwd, plan, input) {
83152
83325
  ...admin ? { adminId: admin.id, adminIno: admin.ino, adminToken: admin.token } : {},
83153
83326
  ...baseSha ? { baseSha } : {}
83154
83327
  });
83155
- return { ok: true, data: { ...base, scratch, head, mode, created: true, notes } };
83328
+ return {
83329
+ ok: true,
83330
+ data: { ...base, scratch, head, mode, created: true, dependencies: deps.linked, notes }
83331
+ };
83156
83332
  }
83157
83333
  function releaseSliceWorktree(cwd, plan, input) {
83158
83334
  const found = findSlice(plan, input.slice);
@@ -83175,7 +83351,7 @@ function releaseSliceWorktree(cwd, plan, input) {
83175
83351
  notes: []
83176
83352
  };
83177
83353
  if (index < 0) {
83178
- if (fs31.existsSync(target))
83354
+ if (fs32.existsSync(target))
83179
83355
  return fanoutFail("blocked", `${target} is not a worktree of this repository; nothing was removed`, "remove it yourself once you know what it holds");
83180
83356
  out.notes.push(`no worktree at ${target}; nothing to release`);
83181
83357
  return { ok: true, data: out };
@@ -83237,7 +83413,7 @@ function releaseSliceWorktree(cwd, plan, input) {
83237
83413
  `)[0]}`, entry.locked ? `git worktree unlock ${entry.path}, then release again` : undefined, { ...out });
83238
83414
  out.removed = true;
83239
83415
  if (made.dirExisted === true)
83240
- fs31.mkdirSync(entry.path, { recursive: true });
83416
+ fs32.mkdirSync(entry.path, { recursive: true });
83241
83417
  if (out.unpushed)
83242
83418
  out.notes.push(`${slice.branch} is kept with ${out.unpushed} commit(s) not on the remote`);
83243
83419
  return { ok: true, data: out };
@@ -83265,42 +83441,44 @@ function unpushedCount(cwd, branch) {
83265
83441
  return count.ok ? Number(count.stdout.trim()) : null;
83266
83442
  }
83267
83443
  function removeScratch(worktree) {
83268
- const scratch = path55.join(worktree, SCRATCH_DIR);
83444
+ const scratch = path57.join(worktree, SCRATCH_DIR);
83269
83445
  let stat;
83270
83446
  try {
83271
- stat = fs31.lstatSync(scratch);
83447
+ stat = fs32.lstatSync(scratch);
83272
83448
  } catch {
83273
83449
  return;
83274
83450
  }
83275
83451
  if (stat.isSymbolicLink() || !stat.isDirectory())
83276
- fs31.unlinkSync(scratch);
83452
+ fs32.unlinkSync(scratch);
83277
83453
  else
83278
- fs31.rmSync(scratch, { recursive: true, force: true, maxRetries: 2 });
83454
+ fs32.rmSync(scratch, { recursive: true, force: true, maxRetries: 2 });
83279
83455
  }
83280
83456
  var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000, canonical2 = (target) => {
83281
83457
  try {
83282
- return fs31.realpathSync.native(target);
83458
+ return fs32.realpathSync.native(target);
83283
83459
  } catch {
83284
- return path55.resolve(target);
83460
+ return path57.resolve(target);
83285
83461
  }
83286
83462
  }, samePath = (a, b) => {
83287
83463
  const left = canonical2(a);
83288
83464
  const right = canonical2(b);
83289
83465
  return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
83290
83466
  }, inside3 = (child, parent) => {
83291
- const relative = path55.relative(canonical2(parent), canonical2(child));
83292
- return relative === "" || !relative.startsWith("..") && !path55.isAbsolute(relative);
83293
- }, slicePath = (cwd, slice) => path55.isAbsolute(slice.worktree) ? slice.worktree : path55.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, TOKEN_FILE = "workit-fanout-token", worktreeDeps, worktreeFailed = (stderr) => fanoutFail("failed", `git worktree add failed: ${stderr.trim().split(`
83467
+ const relative = path57.relative(canonical2(parent), canonical2(child));
83468
+ return relative === "" || !relative.startsWith("..") && !path57.isAbsolute(relative);
83469
+ }, slicePath = (cwd, slice) => path57.isAbsolute(slice.worktree) ? slice.worktree : path57.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps, worktreeFailed = (stderr) => fanoutFail("failed", `git worktree add failed: ${stderr.trim().split(`
83294
83470
  `)[0] || "unknown error"}`);
83295
83471
  var init_fanout_worktree = __esm(() => {
83296
83472
  init_ops();
83297
83473
  init_rev();
83298
83474
  init_ledger();
83475
+ init_worktree_confine();
83476
+ init_worktree_deps();
83299
83477
  init_fanout();
83300
83478
  SLOW = GIT_TIMEOUTS.worktree;
83301
83479
  EXCLUDE_LINE = `/${SCRATCH_DIR}/`;
83302
83480
  worktreeDeps = {
83303
- stat: (file) => fs31.statSync(file, { bigint: true })
83481
+ stat: (file) => fs32.statSync(file, { bigint: true })
83304
83482
  };
83305
83483
  });
83306
83484
 
@@ -83378,8 +83556,9 @@ function renderBrief(cwd, plan, input) {
83378
83556
  ...REPORT,
83379
83557
  "STANDING:",
83380
83558
  ...standing.length ? standing.map((order) => ` - ${order.what}`) : [" - none recorded beyond this brief"],
83559
+ exists ? `WORKTREE: ${planned} (made by \`workit fanout worktree create ${slice.id}\`; yours alone)` : `WORKTREE: ${planned} (not made yet: the lead runs \`workit fanout worktree create ${slice.id}\` before spawning, then renders this brief again)`,
83381
83560
  ...identityLines(identity, minted),
83382
- ...rules(identity, mode, branch, slice.base)
83561
+ ...rules(mode, branch, slice.base, exists ? planned : null)
83383
83562
  ];
83384
83563
  return {
83385
83564
  ok: true,
@@ -83412,25 +83591,25 @@ var DEFAULT_TIMEBOX = "30 minutes", REPORT, identityOf = (host) => {
83412
83591
  }, identityLines = (identity, session) => {
83413
83592
  if (identity === "issued")
83414
83593
  return [
83415
- " Session: your env already has WORKIT_SESSION_ID (the lead's id; SubagentStart issues ids only to verifiers and reviewers). Use it as is, in your Workit-Session trailer and workit commands; never export or hand-mint one."
83594
+ " Session: your env already has WORKIT_SESSION_ID (the lead's id; SubagentStart issues ids only to verifiers and reviewers). Use it as is: workit commands read it and `workit git commit` adds the Workit-Session trailer; never export or hand-mint one."
83416
83595
  ];
83417
83596
  if (identity === "derived")
83418
83597
  return [
83419
83598
  " Session: your host already sets WORKIT_SESSION_ID in your shell; export nothing and never hand-mint one."
83420
83599
  ];
83421
83600
  return [` export WORKIT_SESSION_ID=${session}`];
83422
- }, rules = (identity, mode, branch, base) => {
83423
- const plain = identity === "issued";
83601
+ }, rules = (mode, branch, base, worktree) => {
83602
+ const workit = worktree ? `workit --cwd ${worktree}` : "workit";
83424
83603
  let first = ` 1. First command: \`workit git branch ${branch} --base ${base}\` (your worktree may start on another name).`;
83425
- if (mode === "resume")
83604
+ if (worktree)
83605
+ first = ` 1. Work only in WORKTREE, already on ${branch}${mode === "resume" ? " at its head" : ""}: edit files under it and run each git and check command against it, one verb per call (\`${workit} git commit …\`, \`${workit} check <name>\`), never \`cd … &&\` chains or \`$VAR\` paths. An implementer's change outside it is denied.`;
83606
+ else if (mode === "resume")
83426
83607
  first = ` 1. First command: \`git switch ${branch}\`, then continue from its head.`;
83427
- else if (plain)
83428
- first = ` 1. First command: \`git fetch origin && git switch -c ${branch} origin/${base}\` (plain git: worktree isolation refuses every \`workit git\` form).`;
83429
83608
  return [
83430
83609
  "RULES:",
83431
83610
  first,
83432
83611
  ' 2. Decide ambiguities yourself: `workit ledger ruling "<what>" --why "<why>" --cost-if-wrong "<cost>"`; stop only for an irreversible, security-sensitive or out-of-worktree action.',
83433
- plain ? ' 3. Commit with plain `git commit -m <msg> --trailer "Workit-Session: <the WORKIT_SESSION_ID in your env>" --trailer "<your host attribution trailer>" -- <paths in SCOPE>`; push only if this brief says so.' : " 3. Commit with `workit git commit -m <msg> -- <paths in SCOPE>`; push only if this brief says so.",
83612
+ ` 3. Commit with \`${workit} git commit -m <msg> -- <paths in SCOPE>\`; push only if this brief says so.`,
83434
83613
  " 4. Never record a verdict on your own work.",
83435
83614
  " 5. Run tests, lint, typecheck and builds only through `workit check` (a named check, or `workit check --heavy -- <cmd>`): one machine-wide lease queues every agent, so never a hand-made flock; `workit lock status` shows who holds it.",
83436
83615
  " 6. A failed review gets one fix round and one recheck. Still failing: stop and report the open finding, never a third round (the lead spawns a decider). A product choice is the user's: report it, do not decide it."
@@ -83449,7 +83628,7 @@ var init_fanout_brief = __esm(() => {
83449
83628
  });
83450
83629
 
83451
83630
  // packages/workit-core/src/fanout-landed.ts
83452
- import { spawnSync as spawnSync27 } from "node:child_process";
83631
+ import { spawnSync as spawnSync28 } from "node:child_process";
83453
83632
  function forgeBreaker(resolved) {
83454
83633
  if (!resolved)
83455
83634
  return { forge: null, down: () => null };
@@ -83540,7 +83719,7 @@ function trunkPatchIds(ctx, fork) {
83540
83719
  "--"
83541
83720
  ]);
83542
83721
  if (log.ok && log.stdout.trim()) {
83543
- const run = spawnSync27("git", ["patch-id", "--stable"], {
83722
+ const run = spawnSync28("git", ["patch-id", "--stable"], {
83544
83723
  cwd: ctx.cwd,
83545
83724
  input: log.stdout,
83546
83725
  encoding: "utf8",
@@ -84114,8 +84293,8 @@ var exports_fanout = {};
84114
84293
  __export(exports_fanout, {
84115
84294
  run: () => run18
84116
84295
  });
84117
- import fs32 from "node:fs";
84118
- import path56 from "node:path";
84296
+ import fs33 from "node:fs";
84297
+ import path58 from "node:path";
84119
84298
  function forgeFor(io, offline) {
84120
84299
  if (offline)
84121
84300
  return { forge: null, error: "--offline" };
@@ -84176,10 +84355,10 @@ function plan2(argv, io) {
84176
84355
  return usage3(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
84177
84356
  if (flags.positionals.length !== 1)
84178
84357
  return usage3(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
84179
- const file = path56.resolve(io.cwd, flags.positionals[0]);
84358
+ const file = path58.resolve(io.cwd, flags.positionals[0]);
84180
84359
  let raw;
84181
84360
  try {
84182
- raw = JSON.parse(fs32.readFileSync(file, "utf8"));
84361
+ raw = JSON.parse(fs33.readFileSync(file, "utf8"));
84183
84362
  } catch (error) {
84184
84363
  return usage3(io, `cannot read ${file} as JSON: ${error.message}`, PLAN_USAGE2);
84185
84364
  }
@@ -99710,7 +99889,7 @@ var init_ast = __esm(() => {
99710
99889
 
99711
99890
  // packages/workit-cli/src/test-audit/rules.ts
99712
99891
  import { builtinModules } from "node:module";
99713
- import path57 from "node:path";
99892
+ import path59 from "node:path";
99714
99893
  function testCallee(call) {
99715
99894
  let callee = call.callee;
99716
99895
  if (callee.type === "CallExpression")
@@ -100203,12 +100382,12 @@ function checkConstantsOnly(ctx, emit) {
100203
100382
  }
100204
100383
  function checkOverMocking(ctx, emit) {
100205
100384
  const { program } = ctx.parsed;
100206
- const unit = path57.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
100385
+ const unit = path59.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
100207
100386
  const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
100208
100387
  const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
100209
100388
  for (const call of mocked) {
100210
100389
  const spec = call.arguments[0].value;
100211
- const base = path57.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
100390
+ const base = path59.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
100212
100391
  if (base === unit)
100213
100392
  emit({
100214
100393
  rule: "over-mocking",
@@ -100596,11 +100775,11 @@ var init_rules = __esm(() => {
100596
100775
  });
100597
100776
 
100598
100777
  // packages/workit-cli/src/test-audit/audit.ts
100599
- import { spawnSync as spawnSync28 } from "node:child_process";
100778
+ import { spawnSync as spawnSync29 } from "node:child_process";
100600
100779
  import { existsSync as existsSync20, readdirSync as readdirSync10, readFileSync as readFileSync23, statSync as statSync8 } from "node:fs";
100601
- import path58 from "node:path";
100780
+ import path60 from "node:path";
100602
100781
  function git7(cwd, args) {
100603
- const run = spawnSync28("git", ["-c", "core.quotepath=off", ...args], {
100782
+ const run = spawnSync29("git", ["-c", "core.quotepath=off", ...args], {
100604
100783
  cwd,
100605
100784
  encoding: "utf8",
100606
100785
  maxBuffer: 64 * 1024 * 1024
@@ -100611,7 +100790,7 @@ function walkTests(dir, out) {
100611
100790
  for (const entry of readdirSync10(dir, { withFileTypes: true })) {
100612
100791
  if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
100613
100792
  continue;
100614
- const full = path58.join(dir, entry.name);
100793
+ const full = path60.join(dir, entry.name);
100615
100794
  if (entry.isDirectory()) {
100616
100795
  if (!SKIP_DIRS.has(entry.name))
100617
100796
  walkTests(full, out);
@@ -100623,7 +100802,7 @@ function expandPaths(cwd, inputs) {
100623
100802
  const files = [];
100624
100803
  const missing = [];
100625
100804
  for (const input of inputs.length > 0 ? inputs : ["."]) {
100626
- const full = path58.resolve(cwd, input);
100805
+ const full = path60.resolve(cwd, input);
100627
100806
  if (!existsSync20(full))
100628
100807
  missing.push(input);
100629
100808
  else if (statSync8(full).isDirectory())
@@ -100660,11 +100839,11 @@ function changedLines(cwd, base) {
100660
100839
  for (let offset = 0;offset < count; offset += 1)
100661
100840
  lines.add(start + offset);
100662
100841
  }
100663
- changed.set(path58.join(root, file), lines);
100842
+ changed.set(path60.join(root, file), lines);
100664
100843
  }
100665
100844
  const untracked = git7(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
100666
100845
  for (const file of untracked.stdout.split("\x00").filter(Boolean))
100667
- changed.set(path58.join(root, file), "all");
100846
+ changed.set(path60.join(root, file), "all");
100668
100847
  return changed;
100669
100848
  }
100670
100849
  function auditFiles(files, display) {
@@ -100726,7 +100905,7 @@ function auditFiles(files, display) {
100726
100905
  durationMs: Math.round(performance.now() - started)
100727
100906
  };
100728
100907
  }
100729
- var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path58.sep).join("/"), SEVERITY_ORDER, ruleIds;
100908
+ var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path60.sep).join("/"), SEVERITY_ORDER, ruleIds;
100730
100909
  var init_audit = __esm(() => {
100731
100910
  init_ast();
100732
100911
  init_rules();
@@ -100756,7 +100935,7 @@ import {
100756
100935
  copyFileSync as copyFileSync6
100757
100936
  } from "node:fs";
100758
100937
  import os18 from "node:os";
100759
- import path59 from "node:path";
100938
+ import path61 from "node:path";
100760
100939
  function mutantsFor(source, file, lines) {
100761
100940
  const parsed = parseSource(source, file);
100762
100941
  const out = [];
@@ -100829,7 +101008,7 @@ function relatedTests(source, testFiles) {
100829
101008
  for (const match of text.matchAll(SPECIFIER)) {
100830
101009
  const spec = match[1];
100831
101010
  if (spec.startsWith(".")) {
100832
- if (stripExt(path59.posix.join(path59.posix.dirname(file), spec)) === target)
101011
+ if (stripExt(path61.posix.join(path61.posix.dirname(file), spec)) === target)
100833
101012
  return true;
100834
101013
  } else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
100835
101014
  return true;
@@ -100849,12 +101028,12 @@ function removeStaleCopies(tmp = os18.tmpdir()) {
100849
101028
  for (const name of names) {
100850
101029
  if (!name.startsWith(TEMP_PREFIX))
100851
101030
  continue;
100852
- const dir = path59.join(tmp, name);
101031
+ const dir = path61.join(tmp, name);
100853
101032
  try {
100854
101033
  const stat = lstatSync8(dir);
100855
101034
  if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
100856
101035
  continue;
100857
- const pid = Number(readFileSync24(path59.join(dir, PID_FILE), "utf8"));
101036
+ const pid = Number(readFileSync24(path61.join(dir, PID_FILE), "utf8"));
100858
101037
  if (Number.isInteger(pid) && pid > 0 && alive(pid))
100859
101038
  continue;
100860
101039
  } catch (error) {
@@ -100871,8 +101050,8 @@ function removeStaleCopies(tmp = os18.tmpdir()) {
100871
101050
  function linkNodeModules(origin, target, repo, copy) {
100872
101051
  mkdirSync10(target, { recursive: true });
100873
101052
  for (const entry of readdirSync11(origin, { withFileTypes: true })) {
100874
- const from = path59.join(origin, entry.name);
100875
- const to = path59.join(target, entry.name);
101053
+ const from = path61.join(origin, entry.name);
101054
+ const to = path61.join(target, entry.name);
100876
101055
  if (entry.name.startsWith("@") && entry.isDirectory()) {
100877
101056
  linkNodeModules(from, to, repo, copy);
100878
101057
  continue;
@@ -100888,9 +101067,9 @@ function linkNodeModules(origin, target, repo, copy) {
100888
101067
  } catch {
100889
101068
  continue;
100890
101069
  }
100891
- const relative = path59.relative(repo, real);
100892
- if (!relative.startsWith("..") && !path59.isAbsolute(relative) && !relative.split(path59.sep).includes("node_modules")) {
100893
- symlinkSync(path59.join(copy, relative), to, "junction");
101070
+ const relative = path61.relative(repo, real);
101071
+ if (!relative.startsWith("..") && !path61.isAbsolute(relative) && !relative.split(path61.sep).includes("node_modules")) {
101072
+ symlinkSync(path61.join(copy, relative), to, "junction");
100894
101073
  continue;
100895
101074
  }
100896
101075
  }
@@ -100906,7 +101085,7 @@ function copySymlink(repo, tree, from, to) {
100906
101085
  }
100907
101086
  const realRepo = realpathSync9(repo);
100908
101087
  if (real && inside4(realRepo, real)) {
100909
- symlinkSync(path59.relative(path59.dirname(to), path59.join(tree, path59.relative(realRepo, real))), to);
101088
+ symlinkSync(path61.relative(path61.dirname(to), path61.join(tree, path61.relative(realRepo, real))), to);
100910
101089
  return;
100911
101090
  }
100912
101091
  if (real && statSync9(real).isFile())
@@ -100915,10 +101094,10 @@ function copySymlink(repo, tree, from, to) {
100915
101094
  symlinkSync(readlinkSync3(from), to);
100916
101095
  }
100917
101096
  function writeInside(copy, file, content) {
100918
- const target = path59.join(copy, file);
101097
+ const target = path61.join(copy, file);
100919
101098
  try {
100920
101099
  const stat = lstatSync8(target);
100921
- if (!stat.isFile() || !inside4(realpathSync9(copy), realpathSync9(path59.dirname(target))))
101100
+ if (!stat.isFile() || !inside4(realpathSync9(copy), realpathSync9(path61.dirname(target))))
100922
101101
  return false;
100923
101102
  } catch {
100924
101103
  return false;
@@ -100929,9 +101108,9 @@ function writeInside(copy, file, content) {
100929
101108
  return true;
100930
101109
  }
100931
101110
  function copyWorkingTree(repo) {
100932
- const dir = mkdtempSync4(path59.join(os18.tmpdir(), TEMP_PREFIX));
100933
- writeFileSync11(path59.join(dir, PID_FILE), String(process.pid));
100934
- const tree = path59.join(dir, "tree");
101111
+ const dir = mkdtempSync4(path61.join(os18.tmpdir(), TEMP_PREFIX));
101112
+ writeFileSync11(path61.join(dir, PID_FILE), String(process.pid));
101113
+ const tree = path61.join(dir, "tree");
100935
101114
  const head = git7(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
100936
101115
  if (head && git7(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
100937
101116
  const branch = git7(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
@@ -100948,29 +101127,29 @@ function copyWorkingTree(repo) {
100948
101127
  for (const relative of listed) {
100949
101128
  if (!relative)
100950
101129
  continue;
100951
- const from = path59.join(repo, relative);
101130
+ const from = path61.join(repo, relative);
100952
101131
  let stat;
100953
101132
  try {
100954
101133
  stat = lstatSync8(from);
100955
101134
  } catch {
100956
101135
  continue;
100957
101136
  }
100958
- const to = path59.join(tree, relative);
100959
- mkdirSync10(path59.dirname(to), { recursive: true });
101137
+ const to = path61.join(tree, relative);
101138
+ mkdirSync10(path61.dirname(to), { recursive: true });
100960
101139
  if (stat.isSymbolicLink())
100961
101140
  copySymlink(repo, tree, from, to);
100962
101141
  else if (stat.isFile())
100963
101142
  copyFileSync6(from, to);
100964
- let parent = path59.dirname(relative);
101143
+ let parent = path61.dirname(relative);
100965
101144
  while (parent !== "." && !dirs.has(parent)) {
100966
101145
  dirs.add(parent);
100967
- parent = path59.dirname(parent);
101146
+ parent = path61.dirname(parent);
100968
101147
  }
100969
101148
  }
100970
101149
  for (const parent of dirs) {
100971
- const modules = path59.join(repo, parent, "node_modules");
100972
- if (existsSync21(modules) && !existsSync21(path59.join(tree, parent, "node_modules")))
100973
- linkNodeModules(modules, path59.join(tree, parent, "node_modules"), repo, tree);
101150
+ const modules = path61.join(repo, parent, "node_modules");
101151
+ if (existsSync21(modules) && !existsSync21(path61.join(tree, parent, "node_modules")))
101152
+ linkNodeModules(modules, path61.join(tree, parent, "node_modules"), repo, tree);
100974
101153
  }
100975
101154
  return { dir, tree };
100976
101155
  }
@@ -101009,14 +101188,14 @@ async function runMutation(options) {
101009
101188
  const tracked = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
101010
101189
  const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
101011
101190
  try {
101012
- return { file, text: readFileSync24(path59.join(repo, file), "utf8") };
101191
+ return { file, text: readFileSync24(path61.join(repo, file), "utf8") };
101013
101192
  } catch {
101014
101193
  return { file, text: "" };
101015
101194
  }
101016
101195
  });
101017
101196
  const candidates = [];
101018
101197
  for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
101019
- const relative = toPosix(path59.relative(repo, absolute));
101198
+ const relative = toPosix(path61.relative(repo, absolute));
101020
101199
  if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
101021
101200
  continue;
101022
101201
  if (NOT_SOURCE.test(relative) || !existsSync21(absolute))
@@ -101030,9 +101209,9 @@ async function runMutation(options) {
101030
101209
  for (const mutant of mutants)
101031
101210
  if (!related.has(mutant.file))
101032
101211
  related.set(mutant.file, relatedTests(mutant.file, testFiles));
101033
- const cwdRelative = path59.relative(repo, options.cwd);
101212
+ const cwdRelative = path61.relative(repo, options.cwd);
101034
101213
  const asArg = (file) => {
101035
- const relative = toPosix(path59.relative(cwdRelative, file));
101214
+ const relative = toPosix(path61.relative(cwdRelative, file));
101036
101215
  return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
101037
101216
  };
101038
101217
  const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
@@ -101068,7 +101247,7 @@ async function runMutation(options) {
101068
101247
  return finish3(options, 0, results, counts, started);
101069
101248
  removeStaleCopies();
101070
101249
  const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
101071
- const copyCwd = path59.join(copy, cwdRelative);
101250
+ const copyCwd = path61.join(copy, cwdRelative);
101072
101251
  let current = null;
101073
101252
  const restore = () => {
101074
101253
  if (current)
@@ -101103,7 +101282,7 @@ async function runMutation(options) {
101103
101282
  record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
101104
101283
  continue;
101105
101284
  }
101106
- const original = readFileSync24(path59.join(copy, mutant.file), "utf8");
101285
+ const original = readFileSync24(path61.join(copy, mutant.file), "utf8");
101107
101286
  const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
101108
101287
  current = { file: mutant.file, original };
101109
101288
  if (!writeInside(copy, mutant.file, mutated)) {
@@ -101160,8 +101339,8 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
101160
101339
  return error.code === "EPERM";
101161
101340
  }
101162
101341
  }, inside4 = (root, file) => {
101163
- const relative = path59.relative(root, file);
101164
- return relative === "" || !relative.startsWith("..") && !path59.isAbsolute(relative);
101342
+ const relative = path61.relative(root, file);
101343
+ return relative === "" || !relative.startsWith("..") && !path61.isAbsolute(relative);
101165
101344
  }, active, killTree = (child) => {
101166
101345
  try {
101167
101346
  if (child.pid && process.platform !== "win32")
@@ -101210,7 +101389,7 @@ __export(exports_test_audit, {
101210
101389
  run: () => run20
101211
101390
  });
101212
101391
  import { existsSync as existsSync22 } from "node:fs";
101213
- import path60 from "node:path";
101392
+ import path62 from "node:path";
101214
101393
  function parse7(argv) {
101215
101394
  const options = {
101216
101395
  paths: [],
@@ -101315,8 +101494,8 @@ async function run20(argv, io) {
101315
101494
  return emit(io, fail2("invalid_input", `${options}
101316
101495
  usage: ${USAGE12}`));
101317
101496
  const top = git7(io.cwd, ["rev-parse", "--show-toplevel"]);
101318
- const repo = top.ok ? path60.resolve(top.stdout.trim()) : null;
101319
- const display = (file) => toPosix(path60.relative(io.cwd, file) || file);
101497
+ const repo = top.ok ? path62.resolve(top.stdout.trim()) : null;
101498
+ const display = (file) => toPosix(path62.relative(io.cwd, file) || file);
101320
101499
  let base = null;
101321
101500
  let changed = null;
101322
101501
  if (options.diff || options.mutate) {
@@ -101455,7 +101634,7 @@ __export(exports_youtrack, {
101455
101634
  run: () => run22
101456
101635
  });
101457
101636
  import { readFileSync as readFileSync25 } from "node:fs";
101458
- import path61 from "node:path";
101637
+ import path63 from "node:path";
101459
101638
  async function run22(argv, io) {
101460
101639
  const [sub, ...rest] = argv;
101461
101640
  if (sub !== "note" && sub !== "time" && sub !== "meeting")
@@ -101501,7 +101680,7 @@ async function run22(argv, io) {
101501
101680
  let markdown = flags.values.markdown ?? "";
101502
101681
  if (flags.values.file)
101503
101682
  try {
101504
- markdown = readFileSync25(path61.resolve(io.cwd, flags.values.file), "utf8");
101683
+ markdown = readFileSync25(path63.resolve(io.cwd, flags.values.file), "utf8");
101505
101684
  } catch (error) {
101506
101685
  return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE14);
101507
101686
  }
@@ -101570,7 +101749,7 @@ __export(exports_changelog, {
101570
101749
  run: () => run23
101571
101750
  });
101572
101751
  import { readFileSync as readFileSync26 } from "node:fs";
101573
- import path62 from "node:path";
101752
+ import path64 from "node:path";
101574
101753
  async function run23(argv, io) {
101575
101754
  const [sub, ...rest] = argv;
101576
101755
  if (sub !== "apply")
@@ -101616,7 +101795,7 @@ async function run23(argv, io) {
101616
101795
  ]);
101617
101796
  }
101618
101797
  var USAGE15 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
101619
- const text = raw === "-" ? readFileSync26(0, "utf8") : raw.startsWith("@") ? readFileSync26(path62.resolve(cwd, raw.slice(1)), "utf8") : raw;
101798
+ const text = raw === "-" ? readFileSync26(0, "utf8") : raw.startsWith("@") ? readFileSync26(path64.resolve(cwd, raw.slice(1)), "utf8") : raw;
101620
101799
  return JSON.parse(text);
101621
101800
  };
101622
101801
  var init_changelog2 = __esm(() => {
@@ -101713,7 +101892,7 @@ var init_handoff = __esm(() => {
101713
101892
  // packages/workit-cli/src/main.ts
101714
101893
  init_host_session();
101715
101894
  init_package();
101716
- import path63 from "node:path";
101895
+ import path65 from "node:path";
101717
101896
 
101718
101897
  // packages/workit-cli/src/verbs/registry.ts
101719
101898
  var TASK_FAMILY_NAMES = [
@@ -102551,7 +102730,7 @@ var defaultIo = (json) => ({
102551
102730
  });
102552
102731
  async function main(argv, overrides = {}, options = {}) {
102553
102732
  const parsed = parseGlobals(argv);
102554
- const cwd = path63.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
102733
+ const cwd = path65.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
102555
102734
  const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
102556
102735
  if (parsed.error)
102557
102736
  return emit(io, fail2("invalid_input", parsed.error));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cli",
3
- "version": "8.22.3",
3
+ "version": "8.23.0",
4
4
  "private": false,
5
5
  "description": "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
6
6
  "keywords": [
@@ -38,13 +38,13 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@babel/parser": "7.29.9",
41
- "@brainervirus/workit-cursor": "^8.22.3",
41
+ "@brainervirus/workit-cursor": "^8.23.0",
42
42
  "@inkjs/ui": "2.0.0",
43
43
  "ink": "7.1.1",
44
44
  "react": "19.2.8"
45
45
  },
46
46
  "devDependencies": {
47
- "@brainervirus/workit-core": "^8.22.3"
47
+ "@brainervirus/workit-core": "^8.23.0"
48
48
  },
49
49
  "engines": {
50
50
  "node": ">=24"