@brainervirus/workit-claude-code 8.41.0 → 8.42.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.
package/dist/workit.js CHANGED
@@ -9417,7 +9417,7 @@ var package_default;
9417
9417
  var init_package = __esm(() => {
9418
9418
  package_default = {
9419
9419
  name: "@brainervirus/workit-cli",
9420
- version: "8.41.0",
9420
+ version: "8.42.0",
9421
9421
  private: false,
9422
9422
  description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
9423
9423
  keywords: [
@@ -9455,13 +9455,13 @@ var init_package = __esm(() => {
9455
9455
  },
9456
9456
  dependencies: {
9457
9457
  "@babel/parser": "7.29.9",
9458
- "@brainervirus/workit-cursor": "^8.41.0",
9458
+ "@brainervirus/workit-cursor": "^8.42.0",
9459
9459
  "@inkjs/ui": "2.0.0",
9460
9460
  ink: "7.1.1",
9461
9461
  react: "19.2.8"
9462
9462
  },
9463
9463
  devDependencies: {
9464
- "@brainervirus/workit-core": "^8.41.0"
9464
+ "@brainervirus/workit-core": "^8.42.0"
9465
9465
  },
9466
9466
  engines: {
9467
9467
  node: ">=24"
@@ -21951,6 +21951,108 @@ var init_task = __esm(() => {
21951
21951
  };
21952
21952
  });
21953
21953
 
21954
+ // packages/workit-cli/src/style.ts
21955
+ import { stripVTControlCharacters } from "node:util";
21956
+ function createStyle(options = {}) {
21957
+ const enabled = colorEnabled(options);
21958
+ const pick = (open) => enabled ? sgr(open) : same2;
21959
+ return {
21960
+ enabled,
21961
+ width: enabled ? options.stream?.columns || undefined : undefined,
21962
+ ok: pick("32"),
21963
+ fail: pick("1;31"),
21964
+ warn: pick("33"),
21965
+ info: pick("2"),
21966
+ dim: pick("2"),
21967
+ bold: pick("1"),
21968
+ accent: pick("36"),
21969
+ diffAdd: pick("32"),
21970
+ diffDel: pick("31"),
21971
+ diffHunk: pick("36"),
21972
+ path: pick("2"),
21973
+ command: pick("1;36")
21974
+ };
21975
+ }
21976
+ function wrap(text, width, indent, firstUsed = indent) {
21977
+ if (!width || width <= indent + 10)
21978
+ return text;
21979
+ const lines = [];
21980
+ let line = "";
21981
+ let room = width - firstUsed;
21982
+ const place = (word) => {
21983
+ let rest = word;
21984
+ while (visibleLength(rest) > room) {
21985
+ const chars = Array.from(rest);
21986
+ lines.push(chars.slice(0, room).join(""));
21987
+ rest = chars.slice(room).join("");
21988
+ room = width - indent;
21989
+ }
21990
+ line = rest;
21991
+ };
21992
+ for (const word of text.split(/ +/)) {
21993
+ if (word === "")
21994
+ continue;
21995
+ if (line === "")
21996
+ place(word);
21997
+ else if (visibleLength(line) + 1 + visibleLength(word) <= room)
21998
+ line = `${line} ${word}`;
21999
+ else {
22000
+ lines.push(line);
22001
+ room = width - indent;
22002
+ place(word);
22003
+ }
22004
+ }
22005
+ lines.push(line);
22006
+ return lines.join(`
22007
+ ${" ".repeat(indent)}`);
22008
+ }
22009
+ function colorDiff(text, style) {
22010
+ if (!style.enabled)
22011
+ return text;
22012
+ return text.split(`
22013
+ `).map((line) => {
22014
+ if (line.startsWith("+++") || line.startsWith("---"))
22015
+ return style.bold(line);
22016
+ if (line.startsWith("+"))
22017
+ return style.diffAdd(line);
22018
+ if (line.startsWith("-"))
22019
+ return style.diffDel(line);
22020
+ if (line.startsWith("@@") || line.trim() === "…" || line.trim() === "...")
22021
+ return style.diffHunk(line);
22022
+ return style.dim(line);
22023
+ }).join(`
22024
+ `);
22025
+ }
22026
+ function spinnerPaint(elapsed, env, glyph) {
22027
+ const k = (Math.sin(elapsed / 2400 * Math.PI * 2) + 1) / 2;
22028
+ const [r, g, b] = [
22029
+ [170, 80],
22030
+ [120, 200],
22031
+ [255, 255]
22032
+ ].map(([from, to]) => Math.round(from + (to - from) * k));
22033
+ const depth = (env.COLORTERM || "").toLowerCase();
22034
+ const level = (v) => v < 48 ? 0 : v < 115 ? 1 : Math.min(5, Math.floor((v - 35) / 40));
22035
+ const code = depth === "truecolor" || depth === "24bit" ? `38;2;${r};${g};${b}` : /256/.test(env.TERM || "") ? `38;5;${16 + 36 * level(r) + 6 * level(g) + level(b)}` : "36";
22036
+ return `\x1B[${code}m${glyph}\x1B[0m`;
22037
+ }
22038
+ var truthy = (value) => value !== undefined && value !== "" && value !== "0" && value.toLowerCase() !== "false", terminalMode = (options) => {
22039
+ const env = options.env ?? process.env;
22040
+ if (options.json || !options.stream?.isTTY || truthy(env.CI))
22041
+ return "off";
22042
+ if (truthy(env.NO_COLOR) || env.TERM === "dumb")
22043
+ return "plain";
22044
+ return "spinner";
22045
+ }, colorEnabled = (options) => {
22046
+ if (options.json || !options.stream)
22047
+ return false;
22048
+ if (truthy((options.env ?? process.env).FORCE_COLOR))
22049
+ return true;
22050
+ return terminalMode(options) === "spinner";
22051
+ }, sgr = (open) => (text) => text === "" ? text : `\x1B[${open}m${text}\x1B[0m`, same2 = (text) => text, visibleLength = (text) => Array.from(stripVTControlCharacters(text)).length, SPINNER_FRAMES, SPINNER_FRAME_MS = 140;
22052
+ var init_style = __esm(() => {
22053
+ SPINNER_FRAMES = ["◐", "◓", "◑", "◒"];
22054
+ });
22055
+
21954
22056
  // packages/workit-cli/src/output.ts
21955
22057
  function emit(io, envelope, human) {
21956
22058
  if (io.json) {
@@ -21988,11 +22090,12 @@ async function withFailureLine(io, command, run, outcome) {
21988
22090
  });
21989
22091
  if (code === 0)
21990
22092
  return code;
22093
+ const red = createStyle({ stream: io.terminals?.stderr, env: io.env, json: io.json }).fail;
21991
22094
  if (outcome)
21992
- io.stderr(`workit: error: ${outcome} (${reason ?? EXIT_NAMES[code] ?? "failed"}, exit ${code})
22095
+ io.stderr(`${red(`workit: error: ${outcome} (${reason ?? EXIT_NAMES[code] ?? "failed"}, exit ${code})`)}
21993
22096
  `);
21994
22097
  else if (!wrote)
21995
- io.stderr(`workit: error: ${command} failed (exit ${code})
22098
+ io.stderr(`${red(`workit: error: ${command} failed (exit ${code})`)}
21996
22099
  `);
21997
22100
  return code;
21998
22101
  }
@@ -22017,6 +22120,7 @@ var EXIT, EXIT_BY_CODE, exitCodeFor = (code) => EXIT_BY_CODE[code], ok2 = (data)
22017
22120
  })));
22018
22121
  };
22019
22122
  var init_output = __esm(() => {
22123
+ init_style();
22020
22124
  EXIT = {
22021
22125
  ok: 0,
22022
22126
  failed: 1,
@@ -66193,7 +66297,7 @@ import path33 from "node:path";
66193
66297
  function hostCommand(name, args, options = {}) {
66194
66298
  const executable = findHostExecutable(name, options);
66195
66299
  if (!executable)
66196
- throw new Error(`${name} executable was not found on PATH or supported user bin directories`);
66300
+ throw new Error(path33.isAbsolute(name) || name.includes("/") || name.includes("\\") ? `${name} does not exist or is not executable` : `${name} executable was not found on PATH or supported user bin directories`);
66197
66301
  if (process.platform === "win32" && /\.(?:cmd|bat)$/i.test(executable)) {
66198
66302
  const node = findHostExecutable("node", options);
66199
66303
  if (!node)
@@ -66217,6 +66321,17 @@ function resolveWindowsShimEntry(contents, shim, exists = existsSync13) {
66217
66321
  return null;
66218
66322
  }
66219
66323
  function findHostExecutable(name, options = {}) {
66324
+ if (path33.isAbsolute(name) || name.includes("/") || name.includes("\\")) {
66325
+ try {
66326
+ if (!statSync2(name).isFile())
66327
+ return null;
66328
+ if (process.platform !== "win32")
66329
+ accessSync(name, constants2.X_OK);
66330
+ return name;
66331
+ } catch {
66332
+ return null;
66333
+ }
66334
+ }
66220
66335
  const env = options.env ?? process.env;
66221
66336
  const home = options.home ?? env.HOME ?? os9.homedir();
66222
66337
  const suffixes = process.platform === "win32" ? ["", ".exe", ".cmd", ".bat"] : [""];
@@ -67761,7 +67876,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67761
67876
  return null;
67762
67877
  dir = parent;
67763
67878
  }
67764
- }, listClaudeProcesses = () => {
67879
+ }, listProcessesMatching = (match) => {
67765
67880
  const r = spawnSync16("ps", ["-eo", "pid=,lstart=,args="], {
67766
67881
  encoding: "utf8",
67767
67882
  timeout: 5000
@@ -67772,14 +67887,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67772
67887
  for (const row of r.stdout.split(`
67773
67888
  `)) {
67774
67889
  const m = /^\s*(\d+)\s+(\w{3}\s+\w{3}\s+\d+\s+[\d:]+\s+\d{4})\s+(.*)$/.exec(row);
67775
- if (!m || !/^(\S*\/)?claude(\s|$)/.test(m[3]))
67890
+ if (!m || !match(m[3]))
67776
67891
  continue;
67777
67892
  const startedMs = Date.parse(m[2]);
67778
67893
  if (Number.isFinite(startedMs))
67779
67894
  found.push({ pid: Number(m[1]), startedMs, args: m[3] });
67780
67895
  }
67781
67896
  return found;
67782
- }, resolve = (options) => {
67897
+ }, listClaudeProcesses = () => listProcessesMatching((args) => /^(\S*\/)?claude(\s|$)/.test(args)), listCodexProcesses = () => listProcessesMatching((args) => /^(\S*\/)?codex(\.js)?(\s|$)|^(\S*\/)?node(js)?\s+(\S+\s+)*?\S*\/codex(\.js)?(\s|$)/.test(args) && !/\bdaemon\s+pid-update-loop\b/.test(args)), resolve = (options) => {
67783
67898
  const env = options.env ?? process.env;
67784
67899
  const home = options.home ?? env.HOME ?? os12.homedir();
67785
67900
  const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path39.join(home, ".config", "workit");
@@ -67807,7 +67922,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67807
67922
  installer: options.installer ?? false,
67808
67923
  cliVersion: options.cliVersion ?? null,
67809
67924
  scopeProbe: options.scopeProbe ?? probeScope,
67810
- claudeProcesses: options.claudeProcesses ?? listClaudeProcesses
67925
+ claudeProcesses: options.claudeProcesses ?? listClaudeProcesses,
67926
+ codexProcesses: options.codexProcesses ?? listCodexProcesses
67811
67927
  };
67812
67928
  }, readJson = (p) => {
67813
67929
  try {
@@ -68563,7 +68679,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
68563
68679
  id: "launcher",
68564
68680
  status: "fail",
68565
68681
  detail: `missing or invalid launcher entry: ${missing.join("; ")}`,
68566
- fix: `Rebuild and reinstall the workit package (bun run build) — dist entries must be non-empty Node launchers`
68682
+ fix: dev ? `Rebuild and reinstall the workit package (bun run build) — dist entries must be non-empty Node launchers` : "workit upgrade --hosts=cursor — it reinstalls the plugin files and re-registers the MCP launcher"
68567
68683
  };
68568
68684
  }
68569
68685
  if (!dev && res.host !== "cursor") {
@@ -69804,6 +69920,49 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
69804
69920
  status: "warn",
69805
69921
  detail: `started before Workit ${latest.install.version} was installed: ${rows.join("; ")}; quit and start \`claude --resume ${first ?? "<session id>"}\` to load it (\`/resume\` keeps the old plugin)`
69806
69922
  };
69923
+ }, checkCodexSessionPlugin = (res) => {
69924
+ const id = "codex_session_plugin";
69925
+ if (process.platform === "win32")
69926
+ return {
69927
+ id,
69928
+ status: "info",
69929
+ detail: "running Codex processes are not checked on Windows"
69930
+ };
69931
+ const installs = codexWorkitInstalls(res).filter((install) => install.root && install.version);
69932
+ const stamped = installs.flatMap((install) => {
69933
+ try {
69934
+ return [{ install, at: statSync6(install.root).mtimeMs }];
69935
+ } catch {
69936
+ return [];
69937
+ }
69938
+ });
69939
+ const latest = stamped.toSorted((a, b) => b.at - a.at)[0];
69940
+ if (!latest)
69941
+ return {
69942
+ id,
69943
+ status: "info",
69944
+ detail: "no Workit Codex plugin install recorded — skipping"
69945
+ };
69946
+ const running = res.codexProcesses();
69947
+ if (running === null)
69948
+ return {
69949
+ id,
69950
+ status: "info",
69951
+ detail: "could not list running codex processes (ps) — skipping"
69952
+ };
69953
+ const stale = running.filter((proc) => proc.startedMs < latest.at);
69954
+ if (stale.length === 0)
69955
+ return {
69956
+ id,
69957
+ status: "info",
69958
+ detail: `${running.length} running codex process(es), none started before Workit ${latest.install.version} was installed`
69959
+ };
69960
+ const rows = stale.map((proc) => `pid ${proc.pid} started ${new Date(proc.startedMs).toISOString()} (${proc.args.slice(0, 60)})`);
69961
+ return {
69962
+ id,
69963
+ status: "warn",
69964
+ detail: `started before Workit ${latest.install.version} was installed: ${rows.join("; ")}; they keep the old plugin until restarted, new Codex sessions load it`
69965
+ };
69807
69966
  }, HOOK_ISSUED_MARKER = "workit-issued-sessions/3", hookRecordsIssued = (root) => {
69808
69967
  let files;
69809
69968
  try {
@@ -70095,6 +70254,7 @@ var init_doctor = __esm(() => {
70095
70254
  checkOpencodeVersion,
70096
70255
  checkClaudePlugin,
70097
70256
  checkClaudeSessionPlugin,
70257
+ checkCodexSessionPlugin,
70098
70258
  checkHookIssuedSessions,
70099
70259
  checkWorkitOnPath,
70100
70260
  checkAssets,
@@ -75135,14 +75295,18 @@ async function run4(argv, io) {
75135
75295
  ...io.env.HOME ? { home: io.env.HOME } : {}
75136
75296
  });
75137
75297
  const say = io.json ? io.stderr : io.stdout;
75298
+ const style = createStyle({
75299
+ stream: io.json ? io.terminals?.stderr : io.terminals?.stdout,
75300
+ env: io.env
75301
+ });
75138
75302
  for (const note of plan.notes)
75139
75303
  say(`${note}
75140
75304
  `);
75141
75305
  for (const blocked of plan.blocked)
75142
- say(`blocked: ${blocked}
75306
+ say(`${style.warn("blocked:")} ${blocked}
75143
75307
  `);
75144
75308
  for (const change of plan.changes)
75145
- say(`${permissionDiff(change)}
75309
+ say(`${colorDiff(permissionDiff(change), style)}
75146
75310
  `);
75147
75311
  const summary = {
75148
75312
  changes: plan.changes.map((c) => ({ host: c.host, file: c.file })),
@@ -75164,7 +75328,7 @@ async function run4(argv, io) {
75164
75328
  data: summary,
75165
75329
  unblock: `review the diff above, then run ${USAGE2.replace("[--dry-run | --yes]", "--yes")} or run it in a terminal`
75166
75330
  }));
75167
- const answer = await askOrCancel(io, () => askLine("Write Workit's permission block shown above? [y/N] ", io.json ? process.stderr : process.stdout));
75331
+ const answer = await askOrCancel(io, () => askLine(`${style.bold("Write Workit's permission block shown above?")} [y/N] `, io.json ? process.stderr : process.stdout));
75168
75332
  if (answer === null)
75169
75333
  return cancelled(io);
75170
75334
  if (!/^y(es)?$/i.test(answer.trim()))
@@ -75179,7 +75343,7 @@ async function run4(argv, io) {
75179
75343
  if (failed.length)
75180
75344
  return emit(io, fail2("failed", failed.map((e) => `${e.file}: ${e.detail ?? "failed"}`).join("; "), { data }));
75181
75345
  return emit(io, ok2(data), () => [
75182
- ...entries.map((e) => `written ${e.file}`),
75346
+ ...entries.map((e) => `${style.ok("written")} ${style.path(e.file)}`),
75183
75347
  "Restart the host sessions to load the new permissions. `workit uninstall` removes them."
75184
75348
  ]);
75185
75349
  }
@@ -75215,13 +75379,16 @@ var init_setup2 = __esm(() => {
75215
75379
  init_host_permissions();
75216
75380
  init_output();
75217
75381
  init_prompt();
75382
+ init_style();
75218
75383
  ALL_HOSTS = ["claude-code", "codex", "cursor", "opencode", "pi"];
75219
75384
  });
75220
75385
 
75221
75386
  // packages/workit-cli/src/progress.ts
75387
+ import { spawn } from "node:child_process";
75388
+ import path44 from "node:path";
75222
75389
  function createProgress(options = {}) {
75223
75390
  const env = options.env ?? process.env;
75224
- const mode = modeFor(options, env);
75391
+ const mode = terminalMode({ ...options, env });
75225
75392
  const stream = options.stream;
75226
75393
  const now = options.now ?? Date.now;
75227
75394
  const every = options.setInterval ?? ((tick, ms) => setInterval(tick, ms));
@@ -75229,7 +75396,7 @@ function createProgress(options = {}) {
75229
75396
  const proc = options.proc ?? process;
75230
75397
  const ascii = env.TERM === "dumb";
75231
75398
  const glyphs = mode === "spinner" ? { done: "\x1B[32m✓\x1B[0m", failed: "\x1B[31m✗\x1B[0m", skipped: "–" } : ascii ? { done: "ok", failed: "x", skipped: "-" } : { done: "✓", failed: "✗", skipped: "–" };
75232
- const start = (initial) => {
75399
+ const start = (initial, signals = true) => {
75233
75400
  if (mode === "off" || !stream)
75234
75401
  return NOOP_STEP;
75235
75402
  let text = initial;
@@ -75238,10 +75405,11 @@ function createProgress(options = {}) {
75238
75405
  let frame = 0;
75239
75406
  const draw = () => {
75240
75407
  const seconds = Math.floor((now() - began) / 1000);
75241
- let line = `${FRAMES[frame % FRAMES.length]} ${text} (${seconds}s)`;
75242
- if (stream.columns && line.length >= stream.columns)
75243
- line = `${line.slice(0, Math.max(1, stream.columns - 2))}…`;
75244
- stream.write(`${CLEAR}${line}`);
75408
+ let line = `${text} (${seconds}s)`;
75409
+ if (stream.columns && line.length + 2 >= stream.columns)
75410
+ line = `${line.slice(0, Math.max(1, stream.columns - 4))}…`;
75411
+ const glyph = spinnerPaint(now() - began, env, FRAMES[frame % FRAMES.length] ?? "");
75412
+ stream.write(`${CLEAR}${glyph} ${line}`);
75245
75413
  };
75246
75414
  let timer;
75247
75415
  if (mode === "spinner") {
@@ -75257,7 +75425,7 @@ function createProgress(options = {}) {
75257
75425
  proc.off(event, handler);
75258
75426
  handlers.length = 0;
75259
75427
  };
75260
- if (mode === "spinner") {
75428
+ if (mode === "spinner" && signals) {
75261
75429
  const onSignal = (signal) => () => {
75262
75430
  if (!finished) {
75263
75431
  finished = true;
@@ -75268,11 +75436,13 @@ function createProgress(options = {}) {
75268
75436
  release();
75269
75437
  proc.kill(proc.pid, signal);
75270
75438
  };
75439
+ handlers.push(["SIGINT", onSignal("SIGINT")], ["SIGTERM", onSignal("SIGTERM")]);
75440
+ }
75441
+ if (mode === "spinner") {
75271
75442
  const onExit = () => {
75272
75443
  if (!finished)
75273
75444
  stream.write(CLEAR);
75274
75445
  };
75275
- handlers.push(["SIGINT", onSignal("SIGINT")], ["SIGTERM", onSignal("SIGTERM")]);
75276
75446
  handlers.push(["exit", onExit]);
75277
75447
  for (const [event, handler] of handlers)
75278
75448
  proc.on(event, handler);
@@ -75299,7 +75469,7 @@ function createProgress(options = {}) {
75299
75469
  mode,
75300
75470
  start,
75301
75471
  async run(label, fn, classify) {
75302
- const step = start(label);
75472
+ const step = start(label, false);
75303
75473
  try {
75304
75474
  const value = await fn();
75305
75475
  step.end(classify ? classify(value) : "done");
@@ -75310,63 +75480,111 @@ function createProgress(options = {}) {
75310
75480
  }
75311
75481
  },
75312
75482
  runSync(label, fn, classify) {
75313
- const step = start(label);
75483
+ const step = start(label, false);
75484
+ const ticker = mode === "spinner" && stream ? (options.spawnTicker ?? ((text, began) => defaultTicker(text, began, stream)))(label, now()) : undefined;
75314
75485
  try {
75315
75486
  const value = fn();
75487
+ ticker?.stop();
75316
75488
  step.end(classify ? classify(value) : "done");
75317
75489
  return value;
75318
75490
  } catch (error) {
75491
+ ticker?.stop();
75319
75492
  step.end("failed");
75320
75493
  throw error;
75321
75494
  }
75322
75495
  }
75323
75496
  };
75324
75497
  }
75325
- var FRAMES, FRAME_MS = 120, CLEAR = "\r\x1B[2K", truthy = (value) => value !== undefined && value !== "" && value !== "0" && value.toLowerCase() !== "false", modeFor = (options, env) => {
75326
- if (options.json || !options.stream?.isTTY || truthy(env.CI))
75327
- return "off";
75328
- if (truthy(env.NO_COLOR) || env.TERM === "dumb")
75329
- return "plain";
75330
- return "spinner";
75331
- }, NOOP_STEP;
75498
+ var FRAMES, FRAME_MS, CLEAR = "\r\x1B[2K", TICKER_SOURCE, defaultTicker = (label, began, stream) => {
75499
+ if (stream !== process.stderr)
75500
+ return;
75501
+ if (!/^(?:node|nodejs|bun)(?:\.exe)?$/i.test(path44.basename(process.execPath)))
75502
+ return;
75503
+ try {
75504
+ const child = spawn(process.execPath, ["-e", TICKER_SOURCE], {
75505
+ env: {
75506
+ ...process.env,
75507
+ WORKIT_TICK_LABEL: label,
75508
+ WORKIT_TICK_BEGAN: String(began),
75509
+ WORKIT_TICK_COLS: String(stream.columns ?? 0)
75510
+ },
75511
+ stdio: ["ignore", "ignore", "inherit"],
75512
+ windowsHide: true
75513
+ });
75514
+ child.on("error", () => {});
75515
+ child.unref();
75516
+ return { stop: () => void child.kill("SIGKILL") };
75517
+ } catch {
75518
+ return;
75519
+ }
75520
+ }, NOOP_STEP, progressFor = (io) => {
75521
+ const stderr = io.terminals?.stderr;
75522
+ const stream = stderr?.write ? stderr : undefined;
75523
+ return createProgress({ json: io.json, env: io.env, ...stream ? { stream } : {} });
75524
+ };
75332
75525
  var init_progress = __esm(() => {
75333
- FRAMES = ["·", "✢", "✳", "∗", "✻", "✽"];
75526
+ init_style();
75527
+ FRAMES = SPINNER_FRAMES;
75528
+ FRAME_MS = SPINNER_FRAME_MS;
75529
+ TICKER_SOURCE = `
75530
+ const frames = ${JSON.stringify(FRAMES)};
75531
+ const { WORKIT_TICK_LABEL: label, WORKIT_TICK_BEGAN: began, WORKIT_TICK_COLS: cols } = process.env;
75532
+ const spinnerPaint = ${spinnerPaint.toString()};
75533
+ const parent = process.ppid;
75534
+ let frame = 0;
75535
+ const timer = setInterval(() => {
75536
+ let alive = process.ppid === parent;
75537
+ if (alive) try { process.kill(parent, 0); } catch { alive = false; }
75538
+ if (!alive || Date.now() - Number(began) > 600000) process.exit(0);
75539
+ frame += 1;
75540
+ const seconds = Math.floor((Date.now() - Number(began)) / 1000);
75541
+ let line = label + " (" + seconds + "s)";
75542
+ if (Number(cols) && line.length + 2 >= Number(cols)) line = line.slice(0, Math.max(1, Number(cols) - 4)) + "…";
75543
+ process.stderr.write(${JSON.stringify(CLEAR)} + spinnerPaint(Date.now() - Number(began), process.env, frames[frame % frames.length]) + " " + line);
75544
+ }, ${FRAME_MS});
75545
+ `;
75334
75546
  NOOP_STEP = { label: () => {}, end: () => {} };
75335
75547
  });
75336
75548
 
75337
75549
  // packages/workit-cli/src/upgrade/shared.ts
75338
- import { spawn } from "node:child_process";
75550
+ import { spawn as spawn2 } from "node:child_process";
75339
75551
  import { existsSync as existsSync21, readFileSync as readFileSync22 } from "node:fs";
75340
- import path44 from "node:path";
75552
+ import path45 from "node:path";
75341
75553
  import os16 from "node:os";
75342
75554
  import { createHash as createHash15 } from "node:crypto";
75343
- var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-opencode", OPENCODE_UPDATE, CODEX_MARKETPLACE = "workflow-toolkit", CLI_FIX = "npm install --global @brainervirus/workit-cli@latest", fixFor = (host, selector = "") => host === "pi" ? `pi update --extension ${selector || "npm:@brainervirus/workit-pi"}` : host === "codex" ? `codex plugin marketplace upgrade ${CODEX_MARKETPLACE} && codex plugin add workit@${CODEX_MARKETPLACE}` : host === "claude-code" ? "claude plugin marketplace update workit && claude plugin update workit@workit" : host === "opencode" ? OPENCODE_UPDATE : host === "cursor" ? "workit upgrade --hosts=cursor" : CLI_FIX, upgradePaths = (deps) => {
75555
+ function errorText(error) {
75556
+ return error instanceof Error ? error.message : "installed source could not be read";
75557
+ }
75558
+ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-opencode", OPENCODE_UPDATE, CODEX_MARKETPLACE = "workflow-toolkit", CLI_FIX = "npm install --global @brainervirus/workit-cli@latest", stderrTail = (text, lines = 5) => (text ?? "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean).slice(-lines).join(" | "), failureReason = (command, result) => {
75559
+ const tail = stderrTail(result.stderr);
75560
+ return `\`${command.command} ${command.args.join(" ")}\` failed${tail ? `: ${tail}` : ""}`;
75561
+ }, fixFor = (host, selector = "") => host === "pi" ? `pi update --extension ${selector || "npm:@brainervirus/workit-pi"}` : host === "codex" ? `codex plugin marketplace upgrade ${CODEX_MARKETPLACE} && codex plugin add workit@${CODEX_MARKETPLACE}` : host === "claude-code" ? "claude plugin marketplace update workit && claude plugin update workit@workit" : host === "opencode" ? OPENCODE_UPDATE : host === "cursor" ? "workit upgrade --hosts=cursor" : CLI_FIX, upgradePaths = (deps) => {
75344
75562
  const home = deps.home ?? deps.env?.HOME ?? os16.homedir();
75345
75563
  const env = {
75346
75564
  ...process.env,
75347
75565
  ...deps.home || deps.env?.HOME ? {
75348
75566
  HOME: home,
75349
- CODEX_HOME: path44.join(home, ".codex"),
75350
- CLAUDE_CONFIG_DIR: path44.join(home, ".claude"),
75351
- PI_CODING_AGENT_DIR: path44.join(home, ".pi/agent"),
75352
- XDG_CONFIG_HOME: path44.join(home, ".config"),
75567
+ CODEX_HOME: path45.join(home, ".codex"),
75568
+ CLAUDE_CONFIG_DIR: path45.join(home, ".claude"),
75569
+ PI_CODING_AGENT_DIR: path45.join(home, ".pi/agent"),
75570
+ XDG_CONFIG_HOME: path45.join(home, ".config"),
75353
75571
  WORKFLOW_TOOLKIT_CONFIG: undefined,
75354
75572
  WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
75355
75573
  } : {},
75356
75574
  ...deps.env,
75357
75575
  HOME: home
75358
75576
  };
75359
- const xdg = env.XDG_CONFIG_HOME || path44.join(home, ".config");
75360
- const codexHome = env.CODEX_HOME ?? path44.join(home, ".codex");
75577
+ const xdg = env.XDG_CONFIG_HOME || path45.join(home, ".config");
75578
+ const codexHome = env.CODEX_HOME ?? path45.join(home, ".codex");
75361
75579
  return {
75362
75580
  home,
75363
75581
  env,
75364
- configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path44.join(xdg, "workit"),
75365
- opencodeConfig: path44.join(xdg, "opencode/opencode.json"),
75366
- piSettings: path44.join(env.PI_CODING_AGENT_DIR ?? path44.join(home, ".pi/agent"), "settings.json"),
75582
+ configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path45.join(xdg, "workit"),
75583
+ opencodeConfig: path45.join(xdg, "opencode/opencode.json"),
75584
+ piSettings: path45.join(env.PI_CODING_AGENT_DIR ?? path45.join(home, ".pi/agent"), "settings.json"),
75367
75585
  codexHome,
75368
- codexConfig: path44.join(codexHome, "config.toml"),
75369
- cursorRoot: path44.join(home, ".cursor/plugins/local/workit")
75586
+ codexConfig: path45.join(codexHome, "config.toml"),
75587
+ cursorRoot: path45.join(home, ".cursor/plugins/local/workit")
75370
75588
  };
75371
75589
  }, object2 = (file) => {
75372
75590
  if (!existsSync21(file))
@@ -75391,11 +75609,11 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75391
75609
  let step;
75392
75610
  try {
75393
75611
  step = hostCommand(command, args, { home, env });
75394
- } catch {
75395
- return { status: 1, stdout: "" };
75612
+ } catch (error) {
75613
+ return { status: 1, stdout: "", stderr: errorText(error) };
75396
75614
  }
75397
75615
  const result = runHostCommand(step, { home, env });
75398
- return { status: result.exitCode, stdout: result.stdout };
75616
+ return { status: result.exitCode, stdout: result.stdout, stderr: result.stderr };
75399
75617
  }), COMMAND_TIMEOUT_MS = 60000, asyncRunner = (deps) => {
75400
75618
  if (deps.runAsync)
75401
75619
  return deps.runAsync;
@@ -75407,37 +75625,42 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75407
75625
  let step;
75408
75626
  try {
75409
75627
  step = hostCommand(command, args, { home, env });
75410
- } catch {
75411
- return Promise.resolve({ status: 1, stdout: "" });
75628
+ } catch (error) {
75629
+ return Promise.resolve({ status: 1, stdout: "", stderr: errorText(error) });
75412
75630
  }
75413
75631
  if (process.platform === "win32" && /\.(?:cmd|bat)$/i.test(step.command))
75414
- return Promise.resolve({ status: 1, stdout: "" });
75632
+ return Promise.resolve({
75633
+ status: 1,
75634
+ stdout: "",
75635
+ stderr: `Cannot safely execute batch shim ${step.command}`
75636
+ });
75415
75637
  const childEnv = { ...process.env, ...env, HOME: home };
75416
- childEnv.CODEX_HOME = env.CODEX_HOME ?? path44.join(home, ".codex");
75417
- childEnv.PI_CODING_AGENT_DIR = env.PI_CODING_AGENT_DIR ?? path44.join(home, ".pi", "agent");
75418
- childEnv.CLAUDE_CONFIG_DIR = env.CLAUDE_CONFIG_DIR ?? path44.join(home, ".claude");
75419
- childEnv.XDG_CONFIG_HOME = env.XDG_CONFIG_HOME ?? path44.join(home, ".config");
75638
+ childEnv.CODEX_HOME = env.CODEX_HOME ?? path45.join(home, ".codex");
75639
+ childEnv.PI_CODING_AGENT_DIR = env.PI_CODING_AGENT_DIR ?? path45.join(home, ".pi", "agent");
75640
+ childEnv.CLAUDE_CONFIG_DIR = env.CLAUDE_CONFIG_DIR ?? path45.join(home, ".claude");
75641
+ childEnv.XDG_CONFIG_HOME = env.XDG_CONFIG_HOME ?? path45.join(home, ".config");
75420
75642
  return new Promise((resolve) => {
75421
75643
  let stdout = "";
75644
+ let stderr = "";
75422
75645
  let settled = false;
75423
75646
  const finish = (status) => {
75424
75647
  if (settled)
75425
75648
  return;
75426
75649
  settled = true;
75427
75650
  clearTimeout(timer);
75428
- resolve({ status, stdout });
75651
+ resolve({ status, stdout, stderr });
75429
75652
  };
75430
75653
  let child;
75431
75654
  try {
75432
- child = spawn(step.command, step.args, {
75655
+ child = spawn2(step.command, step.args, {
75433
75656
  cwd: step.cwd,
75434
75657
  env: childEnv,
75435
- stdio: ["ignore", "pipe", "ignore"],
75658
+ stdio: ["ignore", "pipe", "pipe"],
75436
75659
  windowsHide: true,
75437
75660
  shell: false
75438
75661
  });
75439
- } catch {
75440
- resolve({ status: 1, stdout: "" });
75662
+ } catch (error) {
75663
+ resolve({ status: 1, stdout: "", stderr: errorText(error) });
75441
75664
  return;
75442
75665
  }
75443
75666
  const timer = setTimeout(() => {
@@ -75446,16 +75669,21 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75446
75669
  }, COMMAND_TIMEOUT_MS);
75447
75670
  child.stdout?.setEncoding("utf8");
75448
75671
  child.stdout?.on("data", (chunk) => stdout += chunk);
75449
- child.on("error", () => finish(1));
75672
+ child.stderr?.setEncoding("utf8");
75673
+ child.stderr?.on("data", (chunk) => stderr = (stderr + chunk).slice(-4000));
75674
+ child.on("error", (error) => {
75675
+ stderr += error.message;
75676
+ finish(1);
75677
+ });
75450
75678
  child.on("close", (code) => finish(code ?? 1));
75451
75679
  });
75452
75680
  };
75453
- }, errorText = (error) => error instanceof Error ? error.message : "installed source could not be read", piInstalledVersion = (listing, selector) => {
75681
+ }, piInstalledVersion = (listing, selector) => {
75454
75682
  const lines = listing.split(/\r?\n/).map((line) => line.trim());
75455
75683
  const index = lines.indexOf(selector);
75456
- if (index < 0 || !lines[index + 1] || !path44.isAbsolute(lines[index + 1]))
75684
+ if (index < 0 || !lines[index + 1] || !path45.isAbsolute(lines[index + 1]))
75457
75685
  return;
75458
- const found = objectOrNull(path44.join(lines[index + 1], "package.json"));
75686
+ const found = objectOrNull(path45.join(lines[index + 1], "package.json"));
75459
75687
  return found?.name === "@brainervirus/workit-pi" ? found.version : undefined;
75460
75688
  }, versionAtLeast = (installed, latest) => {
75461
75689
  if (!/^\d+\.\d+\.\d+$/.test(installed))
@@ -75481,12 +75709,12 @@ var init_shared = __esm(() => {
75481
75709
  });
75482
75710
 
75483
75711
  // packages/workit-cli/src/upgrade/processes.ts
75484
- import path45 from "node:path";
75712
+ import path46 from "node:path";
75485
75713
  var PROCESS_HOSTS, SCRIPT_RUNTIMES, classifyProcess = (proc) => {
75486
75714
  if (proc.state.startsWith("Z") || proc.args.includes("<defunct>"))
75487
75715
  return null;
75488
75716
  const argv0 = proc.args.trim().split(/\s+/)[0] ?? "";
75489
- const baseName = (value) => path45.basename(value.replaceAll("\\", "/")).replace(/^\[|\]$/g, "").replace(/\.exe$/i, "").toLowerCase();
75717
+ const baseName = (value) => path46.basename(value.replaceAll("\\", "/")).replace(/^\[|\]$/g, "").replace(/\.exe$/i, "").toLowerCase();
75490
75718
  let host = PROCESS_HOSTS[baseName(argv0)];
75491
75719
  if (!host && SCRIPT_RUNTIMES.has(baseName(argv0))) {
75492
75720
  const script = proc.args.trim().split(/\s+/).slice(1).find((arg) => !arg.startsWith("-"));
@@ -75537,7 +75765,7 @@ var init_processes = __esm(() => {
75537
75765
 
75538
75766
  // packages/workit-cli/src/upgrade/apply.ts
75539
75767
  import { existsSync as existsSync22, readdirSync as readdirSync12, mkdirSync as mkdirSync11, copyFileSync as copyFileSync6, chmodSync as chmodSync2, cpSync as cpSync5 } from "node:fs";
75540
- import path46 from "node:path";
75768
+ import path47 from "node:path";
75541
75769
  import { createHash as createHash16 } from "node:crypto";
75542
75770
  async function applyUpgrade(plan, deps = {}) {
75543
75771
  const hosts = [...plan.failed];
@@ -75572,11 +75800,11 @@ async function applyUpgrade(plan, deps = {}) {
75572
75800
  };
75573
75801
  const paths = upgradePaths(deps);
75574
75802
  const { home, configDir } = paths;
75575
- const backup = path46.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
75803
+ const backup = path47.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
75576
75804
  mkdirSync11(backup, { recursive: true, mode: 448 });
75577
75805
  for (const file of Object.keys(plan.configDigests))
75578
75806
  if (existsSync22(file)) {
75579
- const target = path46.join(backup, createHash16("sha256").update(file).digest("hex").slice(0, 12) + "-" + path46.basename(file));
75807
+ const target = path47.join(backup, createHash16("sha256").update(file).digest("hex").slice(0, 12) + "-" + path47.basename(file));
75580
75808
  copyFileSync6(file, target);
75581
75809
  chmodSync2(target, 384);
75582
75810
  }
@@ -75593,14 +75821,13 @@ async function applyUpgrade(plan, deps = {}) {
75593
75821
  writeFileAtomic(migration.file, JSON.stringify(value, null, 2) + `
75594
75822
  `, 384);
75595
75823
  }
75596
- const run = runner(deps);
75597
75824
  const runAsync = asyncRunner(deps);
75598
75825
  const progress = deps.progress ?? createProgress({ json: true });
75599
75826
  const statusOf = (outcome) => outcome?.status === "failed" ? "failed" : outcome?.status === "updated" ? "done" : "skipped";
75600
75827
  let cursorBackupError = null;
75601
75828
  if (plan.entries.some((entry) => entry.host === "cursor") && existsSync22(paths.cursorRoot))
75602
75829
  try {
75603
- cpSync5(paths.cursorRoot, path46.join(backup, "cursor-package"), {
75830
+ cpSync5(paths.cursorRoot, path47.join(backup, "cursor-package"), {
75604
75831
  recursive: true
75605
75832
  });
75606
75833
  } catch (error) {
@@ -75649,14 +75876,14 @@ async function applyUpgrade(plan, deps = {}) {
75649
75876
  hosts.push({
75650
75877
  host: "codex",
75651
75878
  status: "failed",
75652
- reason: `could not stop the Codex app-server daemon (${daemons.map(describe2).join("; ")})`,
75879
+ reason: `could not stop the Codex app-server daemon (${daemons.map(describe2).join("; ")})${stderrTail(stopped.stderr) ? `: ${stderrTail(stopped.stderr)}` : ""}`,
75653
75880
  fix: "codex app-server daemon stop && workit upgrade --hosts=codex"
75654
75881
  });
75655
75882
  continue;
75656
75883
  }
75657
75884
  let outcome;
75658
75885
  try {
75659
- outcome = await applyEntry(entry, { run, runAsync, paths, configDir });
75886
+ outcome = await applyEntry(entry, { runAsync, paths, configDir });
75660
75887
  if (entry.host === "codex" && outcome.status === "updated") {
75661
75888
  const agents = await refreshCodexAgents(runAsync, paths.codexHome);
75662
75889
  if (!agents.ok)
@@ -75667,7 +75894,10 @@ async function applyUpgrade(plan, deps = {}) {
75667
75894
  fix: agents.fix
75668
75895
  };
75669
75896
  else if (agents.note)
75670
- outcome = { ...outcome, reason: `${outcome.reason}; ${agents.note}` };
75897
+ outcome = {
75898
+ ...outcome,
75899
+ reason: `${outcome.reason}; ${agents.note}`
75900
+ };
75671
75901
  }
75672
75902
  } catch (error) {
75673
75903
  outcome = {
@@ -75741,8 +75971,11 @@ async function applyUpgrade(plan, deps = {}) {
75741
75971
  }
75742
75972
  return done(backup);
75743
75973
  }
75744
- var codexPluginRoot = (codexHome) => {
75745
- const dir = path46.join(codexHome, "plugins", "cache", CODEX_MARKETPLACE, "workit");
75974
+ var briefDetail = (detail) => {
75975
+ const lines = detail.split(/\r?\n/).filter((line) => line.trim());
75976
+ return (lines.length > 6 ? [lines[0], ...lines.slice(-5)] : lines).join(" | ");
75977
+ }, codexPluginRoot = (codexHome) => {
75978
+ const dir = path47.join(codexHome, "plugins", "cache", CODEX_MARKETPLACE, "workit");
75746
75979
  let versions = [];
75747
75980
  try {
75748
75981
  versions = readdirSync12(dir).filter((version) => /^\d+\.\d+\.\d+$/.test(version));
@@ -75750,7 +75983,7 @@ var codexPluginRoot = (codexHome) => {
75750
75983
  return null;
75751
75984
  }
75752
75985
  const newest = versions.reduce((best, version) => best && versionAtLeast(best, version) ? best : version, null);
75753
- return newest ? path46.join(dir, newest) : null;
75986
+ return newest ? path47.join(dir, newest) : null;
75754
75987
  }, opencodeVersion = async (run) => {
75755
75988
  const listing = await run("opencode", ["plugin", "list"]);
75756
75989
  if (listing.status !== 0)
@@ -75766,7 +75999,7 @@ var codexPluginRoot = (codexHome) => {
75766
75999
  }
75767
76000
  return;
75768
76001
  }, applyEntry = async (entry, context) => {
75769
- const { run, runAsync, paths, configDir } = context;
76002
+ const { runAsync, paths, configDir } = context;
75770
76003
  const { home, env } = paths;
75771
76004
  const fail = (reason) => ({
75772
76005
  host: entry.host,
@@ -75775,6 +76008,30 @@ var codexPluginRoot = (codexHome) => {
75775
76008
  fix: entry.fix
75776
76009
  });
75777
76010
  if (entry.host === "cursor") {
76011
+ const commands = entry.commands.map((command) => ({
76012
+ ...command,
76013
+ purpose: command.purpose ?? "Upgrade Cursor"
76014
+ }));
76015
+ const recorded = new Map;
76016
+ let history = "";
76017
+ for (const command of commands) {
76018
+ if (command.skipWhenOutputIncludes && history.includes(command.skipWhenOutputIncludes))
76019
+ continue;
76020
+ const outcome = await runAsync(command.command, command.args);
76021
+ const result = {
76022
+ exitCode: outcome.status ?? 1,
76023
+ stdout: outcome.stdout,
76024
+ stderr: outcome.stderr ?? ""
76025
+ };
76026
+ recorded.set(command, result);
76027
+ history += `
76028
+ ${result.stdout}
76029
+ ${result.stderr}`;
76030
+ if (result.exitCode !== 0)
76031
+ break;
76032
+ }
76033
+ const cursorSettings = path47.join(home, ".cursor", "settings.json");
76034
+ const cursorMcp = path47.join(home, ".cursor", "mcp.json");
75778
76035
  const preview = {
75779
76036
  ok: true,
75780
76037
  blocked: [],
@@ -75786,13 +76043,12 @@ var codexPluginRoot = (codexHome) => {
75786
76043
  {
75787
76044
  type: "install-host",
75788
76045
  platform: "cursor",
75789
- path: path46.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
75790
- commands: entry.commands.map((command) => ({
75791
- ...command,
75792
- purpose: command.purpose ?? "Upgrade Cursor"
75793
- }))
76046
+ path: path47.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
76047
+ commands
75794
76048
  },
75795
- { type: "install-adapter", platform: "cursor", path: paths.cursorRoot }
76049
+ { type: "install-adapter", platform: "cursor", path: paths.cursorRoot },
76050
+ { type: "register-platform", platform: "cursor", path: cursorSettings },
76051
+ { type: "register-platform", platform: "cursor", path: cursorMcp }
75796
76052
  ]
75797
76053
  };
75798
76054
  const result = applySetupPreview(preview, {
@@ -75800,16 +76056,16 @@ var codexPluginRoot = (codexHome) => {
75800
76056
  env,
75801
76057
  cwd: home,
75802
76058
  preferInstalledAdapter: true,
75803
- runHostCommand: (command) => {
75804
- const outcome = run(command.command, command.args);
75805
- return {
75806
- exitCode: outcome.status ?? 1,
75807
- stdout: outcome.stdout,
75808
- stderr: ""
75809
- };
76059
+ runHostCommand: (command) => recorded.get(command) ?? {
76060
+ exitCode: 1,
76061
+ stdout: "",
76062
+ stderr: "command did not run"
75810
76063
  }
75811
76064
  });
75812
- const installed = objectOrNull(path46.join(paths.cursorRoot, "package.json"));
76065
+ const installed = objectOrNull(path47.join(paths.cursorRoot, "package.json"));
76066
+ const problems = result.entries.filter((one) => one.status === "Failed").map((one) => one.detail ?? `${one.file} failed`);
76067
+ if (problems.length)
76068
+ return fail(`Cursor install failed: ${problems.map(briefDetail).join("; ")}`);
75813
76069
  if (!result.ok || installed?.version !== entry.latest)
75814
76070
  return fail("Cursor install did not verify the requested package version; inspect the installer before retrying");
75815
76071
  return {
@@ -75819,9 +76075,13 @@ var codexPluginRoot = (codexHome) => {
75819
76075
  };
75820
76076
  }
75821
76077
  const before = entry.host === "opencode" ? await opencodeVersion(runAsync) : undefined;
75822
- for (const command of entry.commands)
75823
- if ((await runAsync(command.command, command.args)).status !== 0)
75824
- return fail(`\`${command.command} ${command.args.join(" ")}\` failed`);
76078
+ for (const command of entry.commands) {
76079
+ let result = await runAsync(command.command, command.args);
76080
+ if (result.status !== 0 && entry.host === "opencode")
76081
+ result = await runAsync(command.command, command.args);
76082
+ if (result.status !== 0)
76083
+ return fail(failureReason(command, result));
76084
+ }
75825
76085
  if (entry.host === "opencode") {
75826
76086
  const after = await opencodeVersion(runAsync);
75827
76087
  if (before && after)
@@ -75854,7 +76114,7 @@ var codexPluginRoot = (codexHome) => {
75854
76114
  }
75855
76115
  const verify = entry.host === "codex" ? await runAsync("codex", ["plugin", "list", "--json"]) : await runAsync("pi", ["list"]);
75856
76116
  if (verify.status !== 0)
75857
- return fail("update verification failed");
76117
+ return fail(`update verification failed${stderrTail(verify.stderr) ? `: ${stderrTail(verify.stderr)}` : ""}`);
75858
76118
  if (entry.host === "codex") {
75859
76119
  let installed = [];
75860
76120
  try {
@@ -75872,11 +76132,16 @@ var codexPluginRoot = (codexHome) => {
75872
76132
  };
75873
76133
  }, refreshCodexAgents = async (run, codexHome) => {
75874
76134
  const root = codexPluginRoot(codexHome);
75875
- const launcher = root && path46.join(root, "dist", "launch-mcp.js");
76135
+ const launcher = root && path47.join(root, "dist", "launch-mcp.js");
75876
76136
  if (!launcher || !existsSync22(launcher))
75877
76137
  return { ok: true, note: "" };
75878
76138
  const fix = `node ${JSON.stringify(launcher)} --install-agents`;
75879
- return (await run("node", [launcher, "--install-agents"])).status === 0 ? { ok: true, note: "agents refreshed" } : { ok: false, note: "agent refresh failed", fix };
76139
+ const refreshed = await run("node", [launcher, "--install-agents"]);
76140
+ return refreshed.status === 0 ? { ok: true, note: "agents refreshed" } : {
76141
+ ok: false,
76142
+ note: `agent refresh failed${stderrTail(refreshed.stderr) ? `: ${stderrTail(refreshed.stderr)}` : ""}`,
76143
+ fix
76144
+ };
75880
76145
  }, applyCli = async (cli, run, backup) => {
75881
76146
  const fail = (reason) => ({
75882
76147
  host: "cli",
@@ -75887,13 +76152,18 @@ var codexPluginRoot = (codexHome) => {
75887
76152
  const currentRoot = await run("npm", ["root", "--global"]);
75888
76153
  if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== cli.root)
75889
76154
  return fail("Global npm location changed; preview again");
75890
- const cliBackup = path46.join(backup, "cli-package");
75891
- cpSync5(path46.join(cli.root, "@brainervirus/workit-cli"), cliBackup, {
76155
+ const cliBackup = path47.join(backup, "cli-package");
76156
+ cpSync5(path47.join(cli.root, "@brainervirus/workit-cli"), cliBackup, {
75892
76157
  recursive: true
75893
76158
  });
75894
- if ((await run("npm", ["install", "--global", `@brainervirus/workit-cli@${cli.latest}`])).status !== 0)
75895
- return fail(`CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path46.join(cliBackup, "dist/index.js")}`);
75896
- const installed = objectOrNull(path46.join(cli.root, "@brainervirus/workit-cli/package.json"));
76159
+ const install = await run("npm", [
76160
+ "install",
76161
+ "--global",
76162
+ `@brainervirus/workit-cli@${cli.latest}`
76163
+ ]);
76164
+ if (install.status !== 0)
76165
+ return fail(`CLI update failed${stderrTail(install.stderr) ? ` (${stderrTail(install.stderr)})` : ""}; preserved package at ${cliBackup}; use npm to repair or run node ${path47.join(cliBackup, "dist/index.js")}`);
76166
+ const installed = objectOrNull(path47.join(cli.root, "@brainervirus/workit-cli/package.json"));
75897
76167
  if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== cli.latest)
75898
76168
  return fail(`CLI update did not verify the requested version; preserved package at ${cliBackup}`);
75899
76169
  return {
@@ -75914,7 +76184,7 @@ var init_apply = __esm(() => {
75914
76184
 
75915
76185
  // packages/workit-cli/src/upgrade/plan.ts
75916
76186
  import { existsSync as existsSync23, mkdtempSync as mkdtempSync3, rmSync as rmSync8, lstatSync as lstatSync8, readFileSync as readFileSync23 } from "node:fs";
75917
- import path47 from "node:path";
76187
+ import path48 from "node:path";
75918
76188
  import os17 from "node:os";
75919
76189
  function previewUpgrade(hosts = HOSTS2, deps = {}) {
75920
76190
  const paths = upgradePaths(deps);
@@ -75938,9 +76208,9 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
75938
76208
  for (const file of [
75939
76209
  paths.opencodeConfig,
75940
76210
  paths.opencodeConfig + "c",
75941
- path47.join(home, ".cursor/settings.json"),
75942
- path47.join(home, ".cursor/mcp.json"),
75943
- path47.join(paths.cursorRoot, "package.json"),
76211
+ path48.join(home, ".cursor/settings.json"),
76212
+ path48.join(home, ".cursor/mcp.json"),
76213
+ path48.join(paths.cursorRoot, "package.json"),
75944
76214
  paths.codexConfig,
75945
76215
  paths.piSettings
75946
76216
  ])
@@ -76110,8 +76380,8 @@ var codexRegistered = (configFile) => {
76110
76380
  result.push(classify("opencode", pin));
76111
76381
  });
76112
76382
  guard("cursor", () => {
76113
- const cursor = objectOrNull(path47.join(paths.cursorRoot, "package.json"));
76114
- const mcp = objectOrNull(path47.join(home, ".cursor/mcp.json"));
76383
+ const cursor = objectOrNull(path48.join(paths.cursorRoot, "package.json"));
76384
+ const mcp = objectOrNull(path48.join(home, ".cursor/mcp.json"));
76115
76385
  const args = mcp?.mcpServers?.workit?.args ?? [];
76116
76386
  const arg = args.find((value) => typeof value === "string" && value.startsWith("--package="));
76117
76387
  const selector = typeof arg === "string" ? arg.slice(10) : "local";
@@ -76122,7 +76392,7 @@ var codexRegistered = (configFile) => {
76122
76392
  });
76123
76393
  return;
76124
76394
  }
76125
- const settings = objectOrNull(path47.join(home, ".cursor/settings.json"));
76395
+ const settings = objectOrNull(path48.join(home, ".cursor/settings.json"));
76126
76396
  const dirs = Array.isArray(settings?.plugin_dirs) ? settings.plugin_dirs : [];
76127
76397
  const registered = mcp?.mcpServers?.workit !== undefined || dirs.some((dir) => String(dir).replaceAll("\\", "/").replace(/\/+$/, "").endsWith("local/workit"));
76128
76398
  if (registered)
@@ -76137,7 +76407,7 @@ var codexRegistered = (configFile) => {
76137
76407
  if (typeof source !== "string")
76138
76408
  continue;
76139
76409
  const npm = /^(?:npm:)?@brainervirus\/workit-pi(?:@[^/]+)?$/.test(source);
76140
- const local = path47.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path47.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
76410
+ const local = path48.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path48.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
76141
76411
  if (!npm && !local)
76142
76412
  continue;
76143
76413
  const found = classify("pi", source);
@@ -76197,15 +76467,15 @@ var codexRegistered = (configFile) => {
76197
76467
  });
76198
76468
  return result;
76199
76469
  }, opencodeProbe = (deps, args) => {
76200
- const scratch = mkdtempSync3(path47.join(os17.tmpdir(), "workit-upgrade-opencode-"));
76470
+ const scratch = mkdtempSync3(path48.join(os17.tmpdir(), "workit-upgrade-opencode-"));
76201
76471
  try {
76202
76472
  return runner({
76203
76473
  ...deps,
76204
76474
  env: {
76205
76475
  ...deps.env,
76206
- XDG_DATA_HOME: path47.join(scratch, "data"),
76207
- XDG_STATE_HOME: path47.join(scratch, "state"),
76208
- XDG_CACHE_HOME: path47.join(scratch, "cache")
76476
+ XDG_DATA_HOME: path48.join(scratch, "data"),
76477
+ XDG_STATE_HOME: path48.join(scratch, "state"),
76478
+ XDG_CACHE_HOME: path48.join(scratch, "cache")
76209
76479
  }
76210
76480
  })("opencode", args);
76211
76481
  } finally {
@@ -76213,7 +76483,7 @@ var codexRegistered = (configFile) => {
76213
76483
  }
76214
76484
  }, planCli = (plan, run) => {
76215
76485
  const root = run("npm", ["root", "--global"]);
76216
- if (root.status !== 0 || !path47.isAbsolute(root.stdout.trim())) {
76486
+ if (root.status !== 0 || !path48.isAbsolute(root.stdout.trim())) {
76217
76487
  plan.skipped.push({
76218
76488
  host: "cli",
76219
76489
  reason: "global npm location could not be verified",
@@ -76221,9 +76491,9 @@ var codexRegistered = (configFile) => {
76221
76491
  });
76222
76492
  return;
76223
76493
  }
76224
- const packageFile = path47.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
76494
+ const packageFile = path48.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
76225
76495
  const installed = objectOrNull(packageFile);
76226
- if (installed?.name !== "@brainervirus/workit-cli" || lstatSync8(path47.dirname(packageFile)).isSymbolicLink()) {
76496
+ if (installed?.name !== "@brainervirus/workit-cli" || lstatSync8(path48.dirname(packageFile)).isSymbolicLink()) {
76227
76497
  plan.skipped.push({
76228
76498
  host: "cli",
76229
76499
  reason: "no managed global CLI install (local links preserved); use npx @brainervirus/workit-cli@latest"
@@ -76261,33 +76531,44 @@ var init_plan = __esm(() => {
76261
76531
  });
76262
76532
 
76263
76533
  // packages/workit-cli/src/upgrade/report.ts
76264
- var pad2 = (text) => text.padEnd(12), summary = (plan, permissions) => {
76265
- const lines = ["Workit upgrade plan:"];
76534
+ var pad2 = (text) => text.padEnd(12), PLAIN, summary = (plan, permissions, style = PLAIN) => {
76535
+ const host = (name) => ` ${style.bold(pad2(name))}`;
76536
+ const run = (fix) => fix ? ` (run: ${style.command(fix)})` : "";
76537
+ const version = (from, to) => `update ${style.dim(from)} -> ${style.ok(to)}`;
76538
+ const lines = [style.bold("Workit upgrade plan:")];
76266
76539
  if (plan.cli)
76267
- lines.push(` ${pad2("cli")}update ${plan.cli.installed} -> ${plan.cli.latest}`);
76540
+ lines.push(`${host("cli")}${version(plan.cli.installed, plan.cli.latest)}`);
76268
76541
  for (const entry of plan.entries) {
76269
- const what = entry.repair ? `reinstall missing plugin files (${entry.latest})` : entry.latest ? `update ${entry.installedVersion ?? "?"} -> ${entry.latest}` : `update (${entry.commands.map((c) => `${c.command} ${c.args.join(" ")}`).join(" && ")})`;
76270
- lines.push(` ${pad2(entry.host)}${what}`);
76542
+ const what = entry.repair ? `reinstall missing plugin files (${entry.latest})` : entry.latest ? version(entry.installedVersion ?? "?", entry.latest) : `update (${style.command(entry.commands.map((c) => `${c.command} ${c.args.join(" ")}`).join(" && "))})`;
76543
+ lines.push(`${host(entry.host)}${what}`);
76271
76544
  }
76272
76545
  for (const skipped of plan.skipped)
76273
- lines.push(` ${pad2(skipped.host)}${skipped.reason.startsWith("already current") ? "" : "skip: "}${skipped.reason}${skipped.fix ? ` (run: ${skipped.fix})` : ""}`);
76546
+ lines.push(`${host(skipped.host)}${skipped.reason.startsWith("already current") ? style.dim(skipped.reason) : `${style.warn("skip:")} ${skipped.reason}`}${run(skipped.fix)}`);
76274
76547
  for (const failed of plan.failed)
76275
- lines.push(` ${pad2(failed.host)}cannot upgrade: ${failed.reason}${failed.fix ? ` (run: ${failed.fix})` : ""}`);
76548
+ lines.push(`${host(failed.host)}${style.fail("cannot upgrade:")} ${failed.reason}${run(failed.fix)}`);
76276
76549
  for (const migration of plan.migrations)
76277
- lines.push(` ${pad2("config")}${migration.description}`);
76550
+ lines.push(`${host("config")}${migration.description}`);
76278
76551
  for (const change of permissions)
76279
- lines.push(` ${pad2("permissions")}refresh the ${change.host} block in ${change.file}`);
76552
+ lines.push(`${host("permissions")}refresh the ${change.host} block in ${style.path(change.file)}`);
76280
76553
  for (const blocked of plan.blocked)
76281
- lines.push(` blocked: ${blocked}`);
76554
+ lines.push(` ${style.fail("blocked:")} ${blocked}`);
76282
76555
  for (const warning of plan.warnings ?? [])
76283
- lines.push(` warning: ${warning}`);
76556
+ lines.push(` ${style.warn("warning:")} ${warning}`);
76284
76557
  return lines.join(`
76285
76558
  `) + `
76286
76559
  `;
76287
- }, LABEL, table = (hosts) => [
76288
- "Result:",
76289
- ...hosts.map((entry) => ` ${pad2(entry.host)}${LABEL[entry.status].padEnd(16)}${entry.reason}${entry.fix && entry.status !== "updated" && entry.status !== "current" ? `
76290
- ${pad2("")}${"".padEnd(16)}fix: ${entry.fix}` : ""}`)
76560
+ }, LABEL, reasonFor = (entry) => {
76561
+ const label = LABEL[entry.status];
76562
+ const head = entry.reason.slice(0, label.length);
76563
+ return entry.status !== "failed" && head.toLowerCase() === label.toLowerCase() && !/^[a-z]/i.test(entry.reason[label.length] ?? "") ? entry.reason.slice(label.length).replace(/^[\s:;,-]+/, "") : entry.reason;
76564
+ }, PAINT, table = (hosts, style = PLAIN) => [
76565
+ style.bold("Result:"),
76566
+ ...hosts.map((entry) => {
76567
+ const paint = style[PAINT[entry.status]];
76568
+ const reason = reasonFor(entry);
76569
+ return ` ${style.bold(pad2(entry.host))}${paint(LABEL[entry.status])}${" ".repeat(16 - LABEL[entry.status].length)}${entry.status === "current" ? style.dim(reason) : reason}${entry.fix && entry.status !== "updated" && entry.status !== "current" ? `
76570
+ ${pad2("")}${"".padEnd(16)}fix: ${style.command(entry.fix)}` : ""}`;
76571
+ })
76291
76572
  ].join(`
76292
76573
  `) + `
76293
76574
  `, askConfirm = async (question, out) => {
@@ -76300,12 +76581,20 @@ var pad2 = (text) => text.padEnd(12), summary = (plan, permissions) => {
76300
76581
  return /^y(?:es)?$/i.test((await askLine(question)).trim());
76301
76582
  };
76302
76583
  var init_report = __esm(() => {
76584
+ init_style();
76585
+ PLAIN = createStyle({ json: true });
76303
76586
  LABEL = {
76304
76587
  updated: "updated",
76305
76588
  current: "already current",
76306
76589
  skipped: "skipped",
76307
76590
  failed: "FAILED"
76308
76591
  };
76592
+ PAINT = {
76593
+ updated: "ok",
76594
+ current: "dim",
76595
+ skipped: "warn",
76596
+ failed: "fail"
76597
+ };
76309
76598
  });
76310
76599
 
76311
76600
  // packages/workit-cli/src/upgrade.ts
@@ -76337,6 +76626,11 @@ async function runUpgradeCommand(argv, deps = {}) {
76337
76626
  });
76338
76627
  plan.ok = plan.blocked.length === 0 && plan.failed.length === 0;
76339
76628
  const { home, env } = upgradePaths(deps);
76629
+ const style = createStyle({
76630
+ stream: out === process.stdout ? process.stdout : undefined,
76631
+ env,
76632
+ json
76633
+ });
76340
76634
  const permissions = planHostPermissions({
76341
76635
  hosts: raw,
76342
76636
  refreshOnly: true,
@@ -76354,7 +76648,7 @@ async function runUpgradeCommand(argv, deps = {}) {
76354
76648
  };
76355
76649
  const withPermissions = (value) => permissions.changes.length ? { ...value, permissions: permissionPreview } : value;
76356
76650
  const applyCommand = `workit upgrade ${[...hostFlag === undefined ? [] : [`--hosts=${hostFlag}`], ...flags.has("--cli") ? ["--cli"] : [], "--yes"].join(" ")}`;
76357
- const nothingChanged = `preview only; nothing changed. Apply with: ${applyCommand}
76651
+ const nothingChanged = `${style.dim("preview only; nothing changed.")} Apply with: ${style.command(applyCommand)}
76358
76652
  `;
76359
76653
  if (json && !legacy && !flags.has("--yes")) {
76360
76654
  out.write(JSON.stringify(withPermissions(plan), null, 2) + `
@@ -76362,20 +76656,20 @@ async function runUpgradeCommand(argv, deps = {}) {
76362
76656
  return plan.blocked.length ? 1 : 0;
76363
76657
  }
76364
76658
  if (!json)
76365
- out.write(summary(plan, permissions.changes));
76659
+ out.write(summary(plan, permissions.changes, style));
76366
76660
  if (flags.has("--preview")) {
76367
76661
  out.write(nothingChanged);
76368
76662
  return plan.blocked.length ? 1 : 0;
76369
76663
  }
76370
76664
  if (plan.blocked.length) {
76371
- out.write(`Upgrade blocked: ${plan.blocked.join("; ")}
76665
+ out.write(`${style.fail("Upgrade blocked:")} ${plan.blocked.join("; ")}
76372
76666
  Nothing changed.
76373
76667
  `);
76374
76668
  return 1;
76375
76669
  }
76376
76670
  const work = plan.entries.length + plan.migrations.length + (plan.cli ? 1 : 0) + permissions.changes.length;
76377
76671
  if (work > 0 && !flags.has("--yes") && !legacy) {
76378
- const confirmed = await (deps.confirm ?? ((q) => askConfirm(q, out)))("Apply this upgrade? [y/N] ");
76672
+ const confirmed = await (deps.confirm ?? ((q) => askConfirm(q, out)))(`${style.bold("Apply this upgrade?")} [y/N] `);
76379
76673
  if (!confirmed) {
76380
76674
  out.write(nothingChanged);
76381
76675
  return 0;
@@ -76393,9 +76687,9 @@ Nothing changed.
76393
76687
  permissionsOk = written.every((entry) => entry.status === "written");
76394
76688
  for (const entry of written)
76395
76689
  result.hosts.push({
76396
- host: entry.host,
76690
+ host: "permissions",
76397
76691
  status: entry.status === "written" ? "updated" : "failed",
76398
- reason: `permission block ${entry.status === "written" ? "refreshed" : entry.status} in ${entry.file}`,
76692
+ reason: `${entry.host} block ${entry.status === "written" ? "refreshed" : entry.status} in ${entry.file}`,
76399
76693
  ...entry.status === "written" ? {} : { fix: `workit setup --hosts=${entry.host}` }
76400
76694
  });
76401
76695
  }
@@ -76414,19 +76708,19 @@ Nothing changed.
76414
76708
  return failed ? 1 : 0;
76415
76709
  }
76416
76710
  if (result.error && result.hosts.every((h) => h.status !== "failed"))
76417
- out.write(`Upgrade stopped: ${result.error}
76711
+ out.write(`${style.fail("Upgrade stopped:")} ${result.error}
76418
76712
  `);
76419
- out.write(table(result.hosts));
76713
+ out.write(table(result.hosts, style));
76420
76714
  if (permissions.refused)
76421
- out.write(`permissions: not refreshed: ${permissions.refused}
76715
+ out.write(`permissions: ${style.warn("not refreshed:")} ${permissions.refused}
76422
76716
  `);
76423
76717
  if (result.backup)
76424
- out.write(`Backup: ${result.backup}
76718
+ out.write(`Backup: ${style.path(result.backup)}
76425
76719
  `);
76426
- out.write(left.length === 0 ? `Verified: workit doctor is clean for versions, assets, agents and permissions.
76427
- ` : `Left after upgrade (workit doctor):
76428
- ${left.map((check) => ` ${check.id}: ${check.detail}${check.fix ? `
76429
- fix: ${check.fix}` : ""}`).join(`
76720
+ out.write(left.length === 0 ? `${style.ok("Verified:")} workit doctor is clean for versions, assets, agents and permissions.
76721
+ ` : `${style.warn("Left after upgrade (workit doctor):")}
76722
+ ${left.map((check) => ` ${style.bold(check.id)}: ${check.detail}${check.fix ? `
76723
+ fix: ${style.command(check.fix)}` : ""}`).join(`
76430
76724
  `)}
76431
76725
  `);
76432
76726
  return failed ? 1 : 0;
@@ -76489,6 +76783,7 @@ var init_upgrade = __esm(() => {
76489
76783
  init_doctor();
76490
76784
  init_host_permissions();
76491
76785
  init_progress();
76786
+ init_style();
76492
76787
  init_apply();
76493
76788
  init_plan();
76494
76789
  init_report();
@@ -76521,7 +76816,7 @@ var init_launch = __esm(() => {
76521
76816
  // packages/workit-core/src/knowledge.ts
76522
76817
  import { spawnSync as spawnSync18 } from "node:child_process";
76523
76818
  import fs20 from "node:fs";
76524
- import path48 from "node:path";
76819
+ import path49 from "node:path";
76525
76820
  function lintKnowledge(root) {
76526
76821
  const seen = new Set;
76527
76822
  const unreadable = [];
@@ -76625,7 +76920,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76625
76920
  const end = lines.indexOf("---", 1);
76626
76921
  return end === -1 ? lines : [...lines.slice(0, end + 1).map(() => ""), ...lines.slice(end + 1)];
76627
76922
  }, read = (root, file) => {
76628
- const full = path48.join(root, file);
76923
+ const full = path49.join(root, file);
76629
76924
  try {
76630
76925
  fs20.lstatSync(full);
76631
76926
  } catch {
@@ -76666,7 +76961,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76666
76961
  }
76667
76962
  }, brokenLinks = (root, doc, tracked) => {
76668
76963
  const findings = [];
76669
- const base = path48.dirname(path48.join(root, doc.file));
76964
+ const base = path49.dirname(path49.join(root, doc.file));
76670
76965
  const missing = (target, line, how) => findings.push({
76671
76966
  rule: "broken-link",
76672
76967
  file: doc.file,
@@ -76685,7 +76980,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76685
76980
  const local = localTarget(target);
76686
76981
  if (!local)
76687
76982
  continue;
76688
- const resolved = local.startsWith("/") ? path48.join(root, local) : path48.resolve(base, local);
76983
+ const resolved = local.startsWith("/") ? path49.join(root, local) : path49.resolve(base, local);
76689
76984
  if (!exists2(resolved))
76690
76985
  missing(target, index + 1, "link");
76691
76986
  }
@@ -76695,9 +76990,9 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76695
76990
  continue;
76696
76991
  const relative = /^\.\.?\//.test(candidate);
76697
76992
  const first = candidate.split("/")[0];
76698
- if (!relative && !(tracked ? tracked.has(first) : exists2(path48.join(root, first))))
76993
+ if (!relative && !(tracked ? tracked.has(first) : exists2(path49.join(root, first))))
76699
76994
  continue;
76700
- const resolved = relative ? path48.resolve(base, candidate) : path48.join(root, candidate);
76995
+ const resolved = relative ? path49.resolve(base, candidate) : path49.join(root, candidate);
76701
76996
  if (!exists2(resolved))
76702
76997
  missing(span, index + 1, "pointer");
76703
76998
  }
@@ -76785,6 +77080,7 @@ var init_knowledge = __esm(() => {
76785
77080
  // packages/workit-cli/src/verbs/doctor.ts
76786
77081
  var exports_doctor = {};
76787
77082
  __export(exports_doctor, {
77083
+ renderDoctor: () => renderDoctor,
76788
77084
  run: () => run7
76789
77085
  });
76790
77086
  async function confirmForcedLockClear(root, args, io) {
@@ -76849,12 +77145,12 @@ async function run7(argv, io) {
76849
77145
  };
76850
77146
  }
76851
77147
  }
76852
- const report = runDoctor({
77148
+ const report = progressFor(io).runSync("Checking Workit (workit doctor)", () => runDoctor({
76853
77149
  host: "cli",
76854
77150
  cwd: io.cwd,
76855
77151
  workspaceRoot: root,
76856
77152
  cliVersion: package_default.version
76857
- });
77153
+ }), (done) => done.ok ? "done" : "failed");
76858
77154
  let knowledge = null;
76859
77155
  try {
76860
77156
  knowledge = lintKnowledge(root);
@@ -76886,30 +77182,73 @@ async function run7(argv, io) {
76886
77182
  if (checksConfig && checksConfig.action !== "none")
76887
77183
  io.stdout(`fix: checks config ${checksConfig.action}: ${checksConfig.detail}
76888
77184
  `);
76889
- io.stdout(`workit doctor — ${report.ok ? "healthy" : "problems found"} (${report.offline ? "offline" : "online"})
77185
+ for (const line of renderDoctor(report, knowledgeLine, createStyle({ stream: io.terminals?.stdout, env: io.env, json: io.json })))
77186
+ io.stdout(`${line}
76890
77187
  `);
77188
+ return report.exitCode;
77189
+ }
77190
+ function renderDoctor(report, knowledgeLine, style) {
77191
+ const summary = `passed ${report.summary.passed} / warned ${report.summary.warned} / failed ${report.summary.failed}`;
77192
+ const header = `workit doctor — ${report.ok ? "healthy" : "problems found"} (${report.offline ? "offline" : "online"})`;
77193
+ if (!style.enabled) {
77194
+ const lines = [header];
77195
+ for (const check of report.checks) {
77196
+ const mark = check.status === "fail" ? "FAIL" : check.status === "warn" ? "WARN" : "ok ";
77197
+ lines.push(`${mark} ${check.id} — ${check.detail}`);
77198
+ if (check.fix)
77199
+ lines.push(` fix: ${check.fix.replaceAll(`
77200
+ `, `
77201
+ `)}`);
77202
+ }
77203
+ return [...lines, knowledgeLine, summary];
77204
+ }
77205
+ const marks = {
77206
+ pass: style.ok("ok "),
77207
+ info: style.info("info"),
77208
+ warn: style.warn("WARN"),
77209
+ fail: style.fail("FAIL")
77210
+ };
77211
+ const idWidth = Math.min(ID_COLUMN, Math.max(0, ...report.checks.map((check) => check.id.length)));
77212
+ const column = 5 + idWidth + 2;
77213
+ const fixLines = (fix) => ` fix: ${fix.split(`
77214
+ `).map((line) => style.command(line)).join(`
77215
+ `)}`;
77216
+ const row = (check) => {
77217
+ const id = check.id.padEnd(idWidth);
77218
+ const used = 5 + id.length + 2;
77219
+ return `${marks[check.status]} ${style.bold(id)} ${wrap(check.detail, style.width, column, used)}`;
77220
+ };
77221
+ const lines = [
77222
+ `workit doctor — ${report.ok ? style.ok("healthy") : style.fail("problems found")} ${style.dim(`(${report.offline ? "offline" : "online"})`)}`
77223
+ ];
76891
77224
  for (const check of report.checks) {
76892
- const mark = check.status === "fail" ? "FAIL" : check.status === "warn" ? "WARN" : "ok ";
76893
- io.stdout(`${mark} ${check.id} — ${check.detail}
76894
- `);
77225
+ lines.push(row(check));
76895
77226
  if (check.fix)
76896
- io.stdout(` fix: ${check.fix.replaceAll(`
76897
- `, `
76898
- `)}
76899
- `);
77227
+ lines.push(fixLines(check.fix));
76900
77228
  }
76901
- io.stdout(`${knowledgeLine}
76902
- `);
76903
- io.stdout(`passed ${report.summary.passed} / warned ${report.summary.warned} / failed ${report.summary.failed}
76904
- `);
76905
- return report.exitCode;
77229
+ lines.push(style.dim(wrap(knowledgeLine, style.width, 5)));
77230
+ const attention = report.checks.filter((c) => c.status === "fail" || c.status === "warn");
77231
+ if (attention.length > 0) {
77232
+ lines.push("", style.bold("Needs attention:"));
77233
+ for (const check of attention) {
77234
+ lines.push(row(check));
77235
+ if (check.fix)
77236
+ lines.push(fixLines(check.fix));
77237
+ }
77238
+ }
77239
+ const paint = report.summary.failed > 0 ? style.fail : report.summary.warned > 0 ? style.warn : style.ok;
77240
+ lines.push(paint(summary));
77241
+ return lines;
76906
77242
  }
77243
+ var ID_COLUMN = 28;
76907
77244
  var init_doctor2 = __esm(() => {
76908
77245
  init_package();
76909
77246
  init_doctor();
76910
77247
  init_knowledge();
76911
77248
  init_store_lock();
76912
77249
  init_output();
77250
+ init_progress();
77251
+ init_style();
76913
77252
  init_prompt();
76914
77253
  init_task();
76915
77254
  });
@@ -77019,11 +77358,11 @@ var init_redact = __esm(() => {
77019
77358
  });
77020
77359
 
77021
77360
  // packages/workit-core/src/checks.ts
77022
- import { spawn as spawn2, spawnSync as spawnSync19 } from "node:child_process";
77361
+ import { spawn as spawn3, spawnSync as spawnSync19 } from "node:child_process";
77023
77362
  import { createHash as createHash17 } from "node:crypto";
77024
77363
  import fs21 from "node:fs";
77025
77364
  import os18 from "node:os";
77026
- import path49 from "node:path";
77365
+ import path50 from "node:path";
77027
77366
  import { StringDecoder } from "node:string_decoder";
77028
77367
  function tailLines(text, lines = TAIL_LINES) {
77029
77368
  const all = text.replace(/\r\n?/gu, `
@@ -77143,7 +77482,7 @@ function planSpawn(argv, options) {
77143
77482
  return { file: argv[0], args: [], verbatim: false, shell: true };
77144
77483
  if (options.platform !== "win32")
77145
77484
  return { file: argv[0], args: argv.slice(1), verbatim: false, shell: false };
77146
- const win = path49.win32;
77485
+ const win = path50.win32;
77147
77486
  const isFile = options.isFile ?? ((file) => {
77148
77487
  try {
77149
77488
  return fs21.statSync(file).isFile();
@@ -77248,7 +77587,7 @@ function runCheckCommand(argv, options) {
77248
77587
  shell: plan.shell
77249
77588
  };
77250
77589
  try {
77251
- child = spawn2(plan.file, plan.args, spawnOptions);
77590
+ child = spawn3(plan.file, plan.args, spawnOptions);
77252
77591
  } catch (error) {
77253
77592
  finish(null, null, error.code ?? error.message);
77254
77593
  return;
@@ -77305,10 +77644,10 @@ function runCheckCommand(argv, options) {
77305
77644
  function storeLog(storeRoot, log) {
77306
77645
  const digest = logDigest(log);
77307
77646
  const ref = `blobs/logs/${digest.slice("sha256:".length)}.log`;
77308
- const file = path49.join(storeRoot, ref);
77647
+ const file = path50.join(storeRoot, ref);
77309
77648
  try {
77310
77649
  if (!fs21.existsSync(file)) {
77311
- fs21.mkdirSync(path49.dirname(file), { recursive: true });
77650
+ fs21.mkdirSync(path50.dirname(file), { recursive: true });
77312
77651
  const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
77313
77652
  fs21.writeFileSync(temp, log, { mode: 384 });
77314
77653
  fs21.renameSync(temp, file);
@@ -77321,7 +77660,7 @@ function storeLog(storeRoot, log) {
77321
77660
  function pruneCheckLogs(storeRoot, options = {}) {
77322
77661
  const limits = { ...LOG_RETENTION, ...options.retention };
77323
77662
  const now = options.now ?? Date.now();
77324
- const dir = path49.join(storeRoot, "blobs", "logs");
77663
+ const dir = path50.join(storeRoot, "blobs", "logs");
77325
77664
  const report = { removed: 0, removedBytes: 0, kept: 0 };
77326
77665
  let names;
77327
77666
  try {
@@ -77331,7 +77670,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
77331
77670
  }
77332
77671
  const files = names.flatMap((name) => {
77333
77672
  try {
77334
- const stat = fs21.statSync(path49.join(dir, name));
77673
+ const stat = fs21.statSync(path50.join(dir, name));
77335
77674
  return stat.isFile() ? [{ name, size: stat.size, mtimeMs: stat.mtimeMs }] : [];
77336
77675
  } catch {
77337
77676
  return [];
@@ -77350,7 +77689,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
77350
77689
  continue;
77351
77690
  if (!options.dryRun)
77352
77691
  try {
77353
- fs21.rmSync(path49.join(dir, file.name), { force: true });
77692
+ fs21.rmSync(path50.join(dir, file.name), { force: true });
77354
77693
  } catch {
77355
77694
  continue;
77356
77695
  }
@@ -77393,7 +77732,7 @@ async function run8(argv, io) {
77393
77732
  const store = new TaskStore(workspaceRootFor({ cwd: io.cwd }));
77394
77733
  const location = store.location();
77395
77734
  const logs = location.ok ? pruneCheckLogs(location.data.dir, { dryRun }) : null;
77396
- const result = store.collectGarbage({ dryRun, pruneRecovery });
77735
+ const result = progressFor(io).runSync("Collecting garbage", () => store.collectGarbage({ dryRun, pruneRecovery }), (r) => r.ok ? "done" : "failed");
77397
77736
  if (!result.ok)
77398
77737
  return emit(io, fail2(result.code === "busy" ? "busy" : "failed", `${result.code}: ${result.error}`, {
77399
77738
  data: { code: result.code, details: result.details },
@@ -77418,6 +77757,7 @@ async function run8(argv, io) {
77418
77757
  }
77419
77758
  var megabytes = (bytes) => (bytes / 1048576).toFixed(1);
77420
77759
  var init_gc = __esm(() => {
77760
+ init_progress();
77421
77761
  init_checks3();
77422
77762
  init_task_store();
77423
77763
  init_output();
@@ -78002,12 +78342,12 @@ var init_workspace = __esm(() => {
78002
78342
 
78003
78343
  // packages/workit-core/src/core/heavy-rules.ts
78004
78344
  import fs22 from "node:fs";
78005
- import path50 from "node:path";
78345
+ import path51 from "node:path";
78006
78346
  function gitTop(cwd) {
78007
- for (let dir = path50.resolve(cwd);; dir = path50.dirname(dir)) {
78008
- if (fs22.existsSync(path50.join(dir, ".git")))
78347
+ for (let dir = path51.resolve(cwd);; dir = path51.dirname(dir)) {
78348
+ if (fs22.existsSync(path51.join(dir, ".git")))
78009
78349
  return dir;
78010
- if (path50.dirname(dir) === dir)
78350
+ if (path51.dirname(dir) === dir)
78011
78351
  return null;
78012
78352
  }
78013
78353
  }
@@ -78049,18 +78389,18 @@ var init_heavy_rules = () => {};
78049
78389
  // packages/workit-core/src/core/heavy.ts
78050
78390
  import fs23 from "node:fs";
78051
78391
  import os19 from "node:os";
78052
- import path51 from "node:path";
78392
+ import path52 from "node:path";
78053
78393
  function stateDir2(env, platform = process.platform) {
78054
78394
  if (env.WORKFLOW_TOOLKIT_STATE)
78055
78395
  return env.WORKFLOW_TOOLKIT_STATE;
78056
78396
  if (env.XDG_STATE_HOME)
78057
- return path51.join(env.XDG_STATE_HOME, "workit");
78397
+ return path52.join(env.XDG_STATE_HOME, "workit");
78058
78398
  const home = env.HOME || os19.homedir();
78059
78399
  if (platform === "darwin")
78060
- return path51.join(home, "Library", "Application Support", "workit");
78400
+ return path52.join(home, "Library", "Application Support", "workit");
78061
78401
  if (platform === "win32")
78062
- return path51.join(env.LOCALAPPDATA ?? path51.join(home, "AppData", "Local"), "workit");
78063
- return path51.join(home, ".local", "state", "workit");
78402
+ return path52.join(env.LOCALAPPDATA ?? path52.join(home, "AppData", "Local"), "workit");
78403
+ return path52.join(home, ".local", "state", "workit");
78064
78404
  }
78065
78405
  function positional(words, from, values = PM_VALUES) {
78066
78406
  let index = from;
@@ -78200,7 +78540,7 @@ function machinePatterns(env) {
78200
78540
  return isRecord8(value) ? stringList2(value.patterns) : [];
78201
78541
  }
78202
78542
  function repoPatterns(cwd) {
78203
- return repoHeavyCommands(gitTop(cwd) ?? path51.resolve(cwd));
78543
+ return repoHeavyCommands(gitTop(cwd) ?? path52.resolve(cwd));
78204
78544
  }
78205
78545
  function heavyLines(lines, options) {
78206
78546
  const found = [];
@@ -78279,7 +78619,7 @@ function leaseRewrite(command) {
78279
78619
  return null;
78280
78620
  return `${prefix}workit check --heavy -- ${rest}`;
78281
78621
  }
78282
- var HEAVY_COMMANDS_FILE = "heavy-commands.json", heavyCommandsFile = (env) => path51.join(stateDir2(env), HEAVY_COMMANDS_FILE), HEAVY_SCRIPT, INFO_FLAGS, WATCH_FLAG, WATCH_SCRIPT, sub = (...names) => new Set(names), TOOLS, PM_VALUES, baseName2 = (word) => (word?.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat|ps1)$/u, ""), WORKIT, PYTHONS, NPM_INSTALL, NPM_RUN, NPM_TEST, EXEC, globWord = (word) => new RegExp(`^${word.replace(/[.+?^${}()|[\]\\]/gu, "\\$&").replaceAll("*", ".*")}$`, "u"), matches2 = (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])), readJson2 = (file) => {
78622
+ var HEAVY_COMMANDS_FILE = "heavy-commands.json", heavyCommandsFile = (env) => path52.join(stateDir2(env), HEAVY_COMMANDS_FILE), HEAVY_SCRIPT, INFO_FLAGS, WATCH_FLAG, WATCH_SCRIPT, sub = (...names) => new Set(names), TOOLS, PM_VALUES, baseName2 = (word) => (word?.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat|ps1)$/u, ""), WORKIT, PYTHONS, NPM_INSTALL, NPM_RUN, NPM_TEST, EXEC, globWord = (word) => new RegExp(`^${word.replace(/[.+?^${}()|[\]\\]/gu, "\\$&").replaceAll("*", ".*")}$`, "u"), matches2 = (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])), readJson2 = (file) => {
78283
78623
  try {
78284
78624
  return JSON.parse(fs23.readFileSync(file, "utf8"));
78285
78625
  } catch {
@@ -78426,7 +78766,7 @@ var init_heavy = __esm(() => {
78426
78766
  import { randomUUID as randomUUID5 } from "node:crypto";
78427
78767
  import fs24 from "node:fs";
78428
78768
  import os20 from "node:os";
78429
- import path52 from "node:path";
78769
+ import path53 from "node:path";
78430
78770
  function memoryValue(value, host) {
78431
78771
  const text = typeof value === "number" ? String(value) : typeof value === "string" ? value : "";
78432
78772
  const percent = PERCENT.exec(text.trim());
@@ -78622,7 +78962,7 @@ function tryOnce(options, record, reclaimed) {
78622
78962
  const text = `${JSON.stringify(record)}
78623
78963
  `;
78624
78964
  for (let slot = 0;slot < options.slots; slot += 1) {
78625
- const file = path52.join(options.dir, `slot-${slot}.json`);
78965
+ const file = path53.join(options.dir, `slot-${slot}.json`);
78626
78966
  for (let attempt = 0;attempt < 2; attempt += 1) {
78627
78967
  try {
78628
78968
  const fd = fs24.openSync(file, "wx", 384);
@@ -78667,7 +79007,7 @@ function leaseQueue(dir, probe = {}) {
78667
79007
  }
78668
79008
  const entries = [];
78669
79009
  for (const name of names.filter((item) => item.endsWith(".json")).toSorted()) {
78670
- const file = path52.join(queueDir(dir), name);
79010
+ const file = path53.join(queueDir(dir), name);
78671
79011
  const record = parseLease(readText5(file));
78672
79012
  if (!record)
78673
79013
  continue;
@@ -78683,9 +79023,9 @@ function leaseQueue(dir, probe = {}) {
78683
79023
  function waitersAhead(options, own) {
78684
79024
  let ahead = 0;
78685
79025
  for (const entry of leaseQueue(options.dir, options.probe)) {
78686
- if (path52.basename(entry.file) >= own)
79026
+ if (path53.basename(entry.file) >= own)
78687
79027
  break;
78688
- if (!TICKET.test(path52.basename(entry.file)))
79028
+ if (!TICKET.test(path53.basename(entry.file)))
78689
79029
  continue;
78690
79030
  if (entry.stale && reclaim(entry.file, (current) => !current || staleReason(current, options.probe) !== null))
78691
79031
  continue;
@@ -78697,7 +79037,7 @@ function liveHolders(options) {
78697
79037
  return leaseSlots(options.dir, options.slots, options.probe).filter((slot) => slot.holder && !slot.stale).map((slot) => slot.holder);
78698
79038
  }
78699
79039
  function writeTicket(file, record) {
78700
- fs24.mkdirSync(path52.dirname(file), { recursive: true, mode: 448 });
79040
+ fs24.mkdirSync(path53.dirname(file), { recursive: true, mode: 448 });
78701
79041
  fs24.writeFileSync(file, `${JSON.stringify(record)}
78702
79042
  `, { mode: 384 });
78703
79043
  }
@@ -78742,7 +79082,7 @@ async function acquireLease(options) {
78742
79082
  const reclaimed = [];
78743
79083
  let waitedOn = [];
78744
79084
  const name = ticketName(started, record.id);
78745
- const ticket = path52.join(queueDir(options.dir), name);
79085
+ const ticket = path53.join(queueDir(options.dir), name);
78746
79086
  const ticketRecord = {
78747
79087
  ...record,
78748
79088
  maxAgeMs: options.waitMs + 60000
@@ -78863,7 +79203,7 @@ function heldLease(dir, id, options = {}) {
78863
79203
  for (const name of names) {
78864
79204
  if (!/^slot-\d+\.json$/u.test(name))
78865
79205
  continue;
78866
- const lease = parseLease(readText5(path52.join(dir, name)));
79206
+ const lease = parseLease(readText5(path53.join(dir, name)));
78867
79207
  if (lease?.id === id && !staleReason(lease, options.probe) && (options.ancestor ?? isAncestor)(lease.pid))
78868
79208
  return lease;
78869
79209
  }
@@ -78918,10 +79258,10 @@ async function runScoped(run, wrapper, sinks) {
78918
79258
  }
78919
79259
  function firstNotice(env, session, key, now = Date.now()) {
78920
79260
  const id = (session ?? `ppid-${process.ppid}`).replace(/[^A-Za-z0-9_.-]/gu, "_").slice(0, 120);
78921
- const dir = path52.join(stateDir2(env), "notices");
79261
+ const dir = path53.join(stateDir2(env), "notices");
78922
79262
  try {
78923
79263
  fs24.mkdirSync(dir, { recursive: true, mode: 448 });
78924
- fs24.writeFileSync(path52.join(dir, `${key}-${id}`), `${new Date(now).toISOString()}
79264
+ fs24.writeFileSync(path53.join(dir, `${key}-${id}`), `${new Date(now).toISOString()}
78925
79265
  `, {
78926
79266
  flag: "wx",
78927
79267
  mode: 384
@@ -78931,7 +79271,7 @@ function firstNotice(env, session, key, now = Date.now()) {
78931
79271
  }
78932
79272
  try {
78933
79273
  for (const name of fs24.readdirSync(dir)) {
78934
- const file = path52.join(dir, name);
79274
+ const file = path53.join(dir, name);
78935
79275
  if (now - fs24.statSync(file).mtimeMs > NOTICE_TTL_MS)
78936
79276
  fs24.rmSync(file, { force: true });
78937
79277
  }
@@ -78941,7 +79281,7 @@ function firstNotice(env, session, key, now = Date.now()) {
78941
79281
  function leaseSlots(dir, slots, probe = {}) {
78942
79282
  const states = [];
78943
79283
  for (let slot = 0;slot < slots; slot += 1) {
78944
- const lease = parseLease(readText5(path52.join(dir, `slot-${slot}.json`)));
79284
+ const lease = parseLease(readText5(path53.join(dir, `slot-${slot}.json`)));
78945
79285
  states.push({
78946
79286
  slot,
78947
79287
  holder: lease ? holderOf(lease) : null,
@@ -78953,7 +79293,7 @@ function leaseSlots(dir, slots, probe = {}) {
78953
79293
  var DEFAULT_HEAVY_CHECKS, DEFAULT_LIGHT_CHECKS, DEFAULT_SLOTS = 1, DEFAULT_WAIT_S = 1800, DEFAULT_MEMORY_SHARE = 0.4, DEFAULT_CPU_SHARE = 0.7, MAX_SLOTS = 64, UNREADABLE_TTL_MS = 30000, GUARD_TTL_MS = 30000, hostShape = () => ({
78954
79294
  totalMemBytes: os20.totalmem(),
78955
79295
  cpus: Math.max(1, os20.availableParallelism?.() ?? os20.cpus().length)
78956
- }), isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SIZE, PERCENT, UNITS, leaseDir = (env) => path52.join(stateDir2(env), "leases"), readText5 = (file) => {
79296
+ }), isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SIZE, PERCENT, UNITS, leaseDir = (env) => path53.join(stateDir2(env), "leases"), readText5 = (file) => {
78957
79297
  try {
78958
79298
  return fs24.readFileSync(file, "utf8");
78959
79299
  } catch {
@@ -78984,7 +79324,7 @@ var DEFAULT_HEAVY_CHECKS, DEFAULT_LIGHT_CHECKS, DEFAULT_SLOTS = 1, DEFAULT_WAIT_
78984
79324
  cwd: lease.cwd,
78985
79325
  session: lease.session,
78986
79326
  startedAt: lease.startedAt
78987
- }), realClock, queueDir = (dir) => path52.join(dir, "queue"), TICKET, ticketName = (now, id) => `${String(now).padStart(15, "0")}-${String(process.hrtime.bigint() % 10n ** 16n).padStart(16, "0")}-${id}.json`, SCOPE_START_FAILURE, NOTICE_TTL_MS;
79327
+ }), realClock, queueDir = (dir) => path53.join(dir, "queue"), TICKET, ticketName = (now, id) => `${String(now).padStart(15, "0")}-${String(process.hrtime.bigint() % 10n ** 16n).padStart(16, "0")}-${id}.json`, SCOPE_START_FAILURE, NOTICE_TTL_MS;
78988
79328
  var init_resources = __esm(() => {
78989
79329
  init_checks3();
78990
79330
  init_heavy();
@@ -79014,7 +79354,7 @@ __export(exports_check, {
79014
79354
  workspaceResources: () => workspaceResources
79015
79355
  });
79016
79356
  import os21 from "node:os";
79017
- import path53 from "node:path";
79357
+ import path54 from "node:path";
79018
79358
  function parse6(argv) {
79019
79359
  const split = argv.indexOf("--");
79020
79360
  const head = split >= 0 ? argv.slice(0, split) : [...argv];
@@ -79245,7 +79585,7 @@ ${footer}`;
79245
79585
  }
79246
79586
  async function workspaceResources(io) {
79247
79587
  const env = io.env;
79248
- const dir = env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path53.join(env.XDG_CONFIG_HOME || path53.join(env.HOME || os21.homedir(), ".config"), "workit");
79588
+ const dir = env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path54.join(env.XDG_CONFIG_HOME || path54.join(env.HOME || os21.homedir(), ".config"), "workit");
79249
79589
  try {
79250
79590
  await Promise.resolve().then(() => init_workspaces());
79251
79591
  const workspace = resolveWorkspaceFrom(io.cwd, dir, env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined);
@@ -79266,7 +79606,7 @@ async function prepareHeavy(io, settings, label, runCwd, timeoutMs) {
79266
79606
  wrapper: null,
79267
79607
  env: io.env
79268
79608
  };
79269
- const progress = createProgress({ stream: process.stderr, json: io.json });
79609
+ const progress = progressFor(io);
79270
79610
  let waiting = null;
79271
79611
  const acquired = await acquireLease({
79272
79612
  dir,
@@ -79387,7 +79727,7 @@ async function run12(argv, io) {
79387
79727
  if (options.shell && command.length !== 1)
79388
79728
  return emit(io, fail2("invalid_input", '--shell takes the command as one string: workit check --shell -- "<cmd>"'));
79389
79729
  }
79390
- const relCwd = posix(path53.relative(top, runCwd));
79730
+ const relCwd = posix(path54.relative(top, runCwd));
79391
79731
  const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
79392
79732
  const shadowed = !configured && name !== null ? config.checks.find((item) => item.name === name) : undefined;
79393
79733
  if (shadowed)
@@ -79452,7 +79792,7 @@ async function run12(argv, io) {
79452
79792
  const modifiedWorktree = key.tree !== null && treeAfter !== key.tree;
79453
79793
  const store = storeRoot(io.cwd);
79454
79794
  const blob = store.ok ? storeLog(store.value.root, result.log) : null;
79455
- const logPath = store.ok && blob ? path53.join(store.value.root, blob.ref) : null;
79795
+ const logPath = store.ok && blob ? path54.join(store.value.root, blob.ref) : null;
79456
79796
  const tail = tailLines(result.log, TAIL_LINES);
79457
79797
  const passed = result.exitCode === 0 && !result.timedOut;
79458
79798
  const bounded = boundedArgv(command);
@@ -79567,7 +79907,7 @@ async function run12(argv, io) {
79567
79907
  return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
79568
79908
  return 0;
79569
79909
  }
79570
- var USAGE6 = 'workit check <name> [--full] [--wait <dur> | --no-wait] [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--heavy] [--full] [--wait <dur> | --no-wait] [--timeout <s>] [--task <id>] [--json] -- <cmd…>', OUTPUT_LINES = 60, MAX_UNVERIFIED_RUN_MS, RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path53.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS, ANSI_COLOR, WARNING_LINE, NO_WARNINGS, STDERR_TAIL_LINES = 10, STDERR_KEEP_CHARS = 65536, FAILURE_LINE, MAX_FAILURE_LINES = 15;
79910
+ var USAGE6 = 'workit check <name> [--full] [--wait <dur> | --no-wait] [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--heavy] [--full] [--wait <dur> | --no-wait] [--timeout <s>] [--task <id>] [--json] -- <cmd…>', OUTPUT_LINES = 60, MAX_UNVERIFIED_RUN_MS, RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path54.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS, ANSI_COLOR, WARNING_LINE, NO_WARNINGS, STDERR_TAIL_LINES = 10, STDERR_KEEP_CHARS = 65536, FAILURE_LINE, MAX_FAILURE_LINES = 15;
79571
79911
  var init_check = __esm(() => {
79572
79912
  init_check_config();
79573
79913
  init_checks3();
@@ -79598,7 +79938,7 @@ __export(exports_lock, {
79598
79938
  run: () => run13
79599
79939
  });
79600
79940
  import fs25 from "node:fs";
79601
- import path54 from "node:path";
79941
+ import path55 from "node:path";
79602
79942
  async function settingsFor(io) {
79603
79943
  const workspace = await workspaceResources(io);
79604
79944
  const config = loadCheckConfig(io.cwd);
@@ -79690,7 +80030,7 @@ function readPatterns(file) {
79690
80030
  return { patterns: [] };
79691
80031
  }
79692
80032
  function writePatterns(file, value) {
79693
- fs25.mkdirSync(path54.dirname(file), { recursive: true, mode: 448 });
80033
+ fs25.mkdirSync(path55.dirname(file), { recursive: true, mode: 448 });
79694
80034
  const temp = `${file}.${process.pid}.tmp`;
79695
80035
  fs25.writeFileSync(temp, `${JSON.stringify(value, null, 2)}
79696
80036
  `, { mode: 384 });
@@ -79778,7 +80118,7 @@ __export(exports_models, {
79778
80118
  });
79779
80119
  import { existsSync as existsSync25, readdirSync as readdirSync13, readFileSync as readFileSync24, statSync as statSync9 } from "node:fs";
79780
80120
  import os22 from "node:os";
79781
- import path55 from "node:path";
80121
+ import path56 from "node:path";
79782
80122
  async function run14(argv, io) {
79783
80123
  const [sub, ...args] = argv.filter((arg) => arg !== "--json");
79784
80124
  if (sub !== "show")
@@ -79853,20 +80193,20 @@ var USAGE8 = "workit models show [--role <role>] [--tier <tier>] [--host <host>]
79853
80193
  } catch {}
79854
80194
  return found;
79855
80195
  }, matches3 = (ran, configured) => ran.toLowerCase().includes(configured.toLowerCase()), usageReport = (cwd, env, days) => {
79856
- const projects = path55.join(env.CLAUDE_CONFIG_DIR || path55.join(env.HOME || os22.homedir(), ".claude"), "projects");
80196
+ const projects = path56.join(env.CLAUDE_CONFIG_DIR || path56.join(env.HOME || os22.homedir(), ".claude"), "projects");
79857
80197
  const since = Date.now() - days * 86400000;
79858
80198
  const types = {};
79859
80199
  let agents = 0;
79860
80200
  const dirs = (dir) => {
79861
80201
  try {
79862
- return readdirSync13(dir).map((name) => path55.join(dir, name));
80202
+ return readdirSync13(dir).map((name) => path56.join(dir, name));
79863
80203
  } catch {
79864
80204
  return [];
79865
80205
  }
79866
80206
  };
79867
80207
  for (const project of dirs(projects))
79868
80208
  for (const session of dirs(project))
79869
- for (const meta of dirs(path55.join(session, "subagents")).filter((f) => f.endsWith(".meta.json"))) {
80209
+ for (const meta of dirs(path56.join(session, "subagents")).filter((f) => f.endsWith(".meta.json"))) {
79870
80210
  try {
79871
80211
  if (statSync9(meta).mtimeMs < since)
79872
80212
  continue;
@@ -80012,7 +80352,7 @@ var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock)
80012
80352
  // packages/workit-core/src/git/ops.ts
80013
80353
  import { spawnSync as spawnSync20 } from "node:child_process";
80014
80354
  import { existsSync as existsSync26, readFileSync as readFileSync25 } from "node:fs";
80015
- import path56 from "node:path";
80355
+ import path57 from "node:path";
80016
80356
  function operationInProgress(cwd) {
80017
80357
  const markers = [
80018
80358
  ["rebase-merge", "rebase"],
@@ -80025,18 +80365,18 @@ function operationInProgress(cwd) {
80025
80365
  if (!run.ok)
80026
80366
  return null;
80027
80367
  const found = run.stdout.split(`
80028
- `).map((line) => path56.resolve(cwd, line.trim()));
80368
+ `).map((line) => path57.resolve(cwd, line.trim()));
80029
80369
  const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
80030
80370
  for (const [index, [, operation]] of markers.entries()) {
80031
80371
  const marker = found[index];
80032
80372
  if (!marker || !existsSync26(marker))
80033
80373
  continue;
80034
- if (index === 1 && existsSync26(path56.join(marker, "applying")))
80374
+ if (index === 1 && existsSync26(path57.join(marker, "applying")))
80035
80375
  return { operation: "am", commitAllowed: false, branch: null };
80036
- if (index === 0 && existsSync26(path56.join(marker, "amend")) && !conflicted()) {
80376
+ if (index === 0 && existsSync26(path57.join(marker, "amend")) && !conflicted()) {
80037
80377
  let headName = "";
80038
80378
  try {
80039
- headName = readFileSync25(path56.join(marker, "head-name"), "utf8").trim();
80379
+ headName = readFileSync25(path57.join(marker, "head-name"), "utf8").trim();
80040
80380
  } catch {}
80041
80381
  const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
80042
80382
  return { operation, commitAllowed: branch !== null, branch };
@@ -80364,7 +80704,7 @@ function gitCommit(cwd, input) {
80364
80704
  if (paths.some((value) => value.startsWith("-") || !value.trim()))
80365
80705
  return failure3("invalid_input", "paths must not be empty or start with -");
80366
80706
  const tracked = new Set(nulList(git5(cwd, ["ls-files", "-z", "--", ...paths]).stdout));
80367
- const addable = paths.filter((value) => existsSync26(path56.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
80707
+ const addable = paths.filter((value) => existsSync26(path57.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
80368
80708
  if (addable.length) {
80369
80709
  const added = git5(cwd, ["add", "-A", "--", ...addable]);
80370
80710
  if (!added.ok)
@@ -80903,12 +81243,12 @@ var init_ops = __esm(() => {
80903
81243
 
80904
81244
  // packages/workit-core/src/verdict-cover.ts
80905
81245
  import fs26 from "node:fs";
80906
- import path57 from "node:path";
81246
+ import path58 from "node:path";
80907
81247
  function chainsAbove(cwd, branch) {
80908
81248
  const root = storeRoot(cwd);
80909
81249
  if (!root.ok)
80910
81250
  return [];
80911
- const dir = path57.join(root.value.root, "stacks");
81251
+ const dir = path58.join(root.value.root, "stacks");
80912
81252
  let names = [];
80913
81253
  try {
80914
81254
  names = fs26.readdirSync(dir).filter((name) => name.endsWith(".json"));
@@ -80919,7 +81259,7 @@ function chainsAbove(cwd, branch) {
80919
81259
  for (const name of names.toSorted()) {
80920
81260
  let parsed;
80921
81261
  try {
80922
- parsed = JSON.parse(fs26.readFileSync(path57.join(dir, name), "utf8"));
81262
+ parsed = JSON.parse(fs26.readFileSync(path58.join(dir, name), "utf8"));
80923
81263
  } catch {
80924
81264
  continue;
80925
81265
  }
@@ -81075,10 +81415,10 @@ var init_check_evidence = __esm(() => {
81075
81415
 
81076
81416
  // packages/workit-core/src/forge/reruns.ts
81077
81417
  import fs27 from "node:fs";
81078
- import path58 from "node:path";
81418
+ import path59 from "node:path";
81079
81419
  function rerunLogPath(cwd) {
81080
81420
  const common = gitCommonDir(cwd);
81081
- return common ? path58.join(common, "workit", "ci-reruns.jsonl") : null;
81421
+ return common ? path59.join(common, "workit", "ci-reruns.jsonl") : null;
81082
81422
  }
81083
81423
  function rerunCounts(cwd, key) {
81084
81424
  const counts = new Map;
@@ -81113,7 +81453,7 @@ function recordReruns(cwd, rows) {
81113
81453
  if (!file)
81114
81454
  return false;
81115
81455
  try {
81116
- fs27.mkdirSync(path58.dirname(file), { recursive: true });
81456
+ fs27.mkdirSync(path59.dirname(file), { recursive: true });
81117
81457
  fs27.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
81118
81458
  `).join(""));
81119
81459
  return true;
@@ -81126,7 +81466,7 @@ function withRerunLock(cwd, fn) {
81126
81466
  if (!file)
81127
81467
  return fn();
81128
81468
  const lock = `${file.slice(0, -".jsonl".length)}.lock`;
81129
- fs27.mkdirSync(path58.dirname(lock), { recursive: true });
81469
+ fs27.mkdirSync(path59.dirname(lock), { recursive: true });
81130
81470
  const until = Date.now() + LOCK_WAIT_MS2;
81131
81471
  for (;; ) {
81132
81472
  try {
@@ -82122,7 +82462,7 @@ var init_pr_ops = __esm(() => {
82122
82462
  import { spawnSync as spawnSync22 } from "node:child_process";
82123
82463
  import { createHash as createHash18, randomBytes as randomBytes4 } from "node:crypto";
82124
82464
  import fs28 from "node:fs";
82125
- import path59 from "node:path";
82465
+ import path60 from "node:path";
82126
82466
  function worktreeOf(cwd, branch) {
82127
82467
  const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
82128
82468
  if (!list.ok)
@@ -82171,7 +82511,7 @@ function gitRestack(cwd, input) {
82171
82511
  error: "no store root"
82172
82512
  };
82173
82513
  fs28.mkdirSync(scratch, { recursive: true });
82174
- dir = path59.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
82514
+ dir = path60.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
82175
82515
  const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
82176
82516
  if (!added.ok)
82177
82517
  return {
@@ -82227,7 +82567,7 @@ function pruneScratch(cwd) {
82227
82567
  if (!scratch || !fs28.existsSync(scratch))
82228
82568
  return;
82229
82569
  for (const name of fs28.readdirSync(scratch)) {
82230
- const dir = path59.join(scratch, name);
82570
+ const dir = path60.join(scratch, name);
82231
82571
  if (!rebaseInProgress(dir) && !trackedDirt(dir))
82232
82572
  gitRun3(cwd, ["worktree", "remove", "--force", dir]);
82233
82573
  }
@@ -82237,7 +82577,7 @@ function stacksDir(cwd) {
82237
82577
  const root = storeRoot(cwd);
82238
82578
  if (!root.ok)
82239
82579
  return stackFail(root.code, root.error, root.unblock);
82240
- return { ok: true, data: path59.join(root.value.root, "stacks") };
82580
+ return { ok: true, data: path60.join(root.value.root, "stacks") };
82241
82581
  }
82242
82582
  function parseStack(raw) {
82243
82583
  if (!isRecord12(raw) || !Array.isArray(raw.branches))
@@ -82289,7 +82629,7 @@ function readStack(cwd, name) {
82289
82629
  const dir = stacksDir(cwd);
82290
82630
  if (!dir.ok)
82291
82631
  return dir;
82292
- const file = path59.join(dir.data, fileFor(name));
82632
+ const file = path60.join(dir.data, fileFor(name));
82293
82633
  let text;
82294
82634
  try {
82295
82635
  text = fs28.readFileSync(file, "utf8");
@@ -82310,7 +82650,7 @@ function writeStack(cwd, stack, now = new Date) {
82310
82650
  const dir = stacksDir(cwd);
82311
82651
  if (!dir.ok)
82312
82652
  return dir;
82313
- const file = path59.join(dir.data, fileFor(stack.name));
82653
+ const file = path60.join(dir.data, fileFor(stack.name));
82314
82654
  const temp = `${file}.${process.pid}.tmp`;
82315
82655
  try {
82316
82656
  fs28.mkdirSync(dir.data, { recursive: true });
@@ -82338,7 +82678,7 @@ function listStacks(cwd) {
82338
82678
  for (const name of names) {
82339
82679
  let parsed = null;
82340
82680
  try {
82341
- parsed = parseStack(JSON.parse(fs28.readFileSync(path59.join(dir.data, name), "utf8")));
82681
+ parsed = parseStack(JSON.parse(fs28.readFileSync(path60.join(dir.data, name), "utf8")));
82342
82682
  } catch {
82343
82683
  parsed = null;
82344
82684
  }
@@ -82400,7 +82740,7 @@ function takeLock(lock) {
82400
82740
  host: localLockHost(),
82401
82741
  nonce: randomBytes4(8).toString("hex")
82402
82742
  };
82403
- fs28.writeFileSync(path59.join(lock, OWNER), JSON.stringify(owner));
82743
+ fs28.writeFileSync(path60.join(lock, OWNER), JSON.stringify(owner));
82404
82744
  return owner;
82405
82745
  }
82406
82746
  function reapLock(lock, observed) {
@@ -82437,7 +82777,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
82437
82777
  return dir;
82438
82778
  if (!validName(name))
82439
82779
  return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
82440
- const lock = path59.join(dir.data, `${fileFor(name)}.lock`);
82780
+ const lock = path60.join(dir.data, `${fileFor(name)}.lock`);
82441
82781
  try {
82442
82782
  fs28.mkdirSync(dir.data, { recursive: true });
82443
82783
  } catch (error) {
@@ -82467,7 +82807,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
82467
82807
  const touch = () => {
82468
82808
  try {
82469
82809
  const now = new Date;
82470
- fs28.utimesSync(path59.join(lock, OWNER), now, now);
82810
+ fs28.utimesSync(path60.join(lock, OWNER), now, now);
82471
82811
  } catch {}
82472
82812
  };
82473
82813
  const beat = setInterval(touch, HEARTBEAT_MS);
@@ -83436,7 +83776,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
83436
83776
  return !status.ok || status.stdout.trim() !== "";
83437
83777
  }, scratchDir = (cwd) => {
83438
83778
  const dir = stacksDir(cwd);
83439
- return dir.ok ? path59.join(dir.data, "worktrees") : null;
83779
+ return dir.ok ? path60.join(dir.data, "worktrees") : null;
83440
83780
  }, firstLine = (run) => (`${run.stderr}
83441
83781
  ${run.stdout}`.split(`
83442
83782
  `).find((line) => line.trim()) ?? "git failed").trim().slice(0, 300), stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${createHash18("sha256").update(name).digest("hex").slice(0, 12)}.json`, fileFor, validName = (name) => {
@@ -83451,12 +83791,12 @@ ${run.stdout}`.split(`
83451
83791
  }, isRecord12 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), str3 = (value) => typeof value === "string" && value ? value : null, LOCK_WAIT_MS3 = 2000, HEARTBEAT_MS = 20000, HEARTBEAT_STALE_MS, OWNERLESS_STALE_MS = 30000, OWNER = "owner", readOwner = (lock) => {
83452
83792
  let raw = null;
83453
83793
  try {
83454
- raw = fs28.readFileSync(path59.join(lock, OWNER), "utf8");
83794
+ raw = fs28.readFileSync(path60.join(lock, OWNER), "utf8");
83455
83795
  } catch {
83456
83796
  raw = null;
83457
83797
  }
83458
83798
  let age = null;
83459
- for (const target of [path59.join(lock, OWNER), lock])
83799
+ for (const target of [path60.join(lock, OWNER), lock])
83460
83800
  try {
83461
83801
  age = Date.now() - fs28.statSync(target).mtimeMs;
83462
83802
  break;
@@ -83500,7 +83840,7 @@ var init_stack = __esm(() => {
83500
83840
  import { spawnSync as spawnSync23 } from "node:child_process";
83501
83841
  import { createHash as createHash19 } from "node:crypto";
83502
83842
  import fs29 from "node:fs";
83503
- import path60 from "node:path";
83843
+ import path61 from "node:path";
83504
83844
  function expandBraces2(pattern, limit = 64) {
83505
83845
  for (let index = 0;index < pattern.length; index += 1) {
83506
83846
  if (pattern[index] === "\\") {
@@ -83746,7 +84086,7 @@ function parsePlan(raw, defaults, name) {
83746
84086
  id,
83747
84087
  branch,
83748
84088
  base: optional("base") ?? "",
83749
- worktree: path60.resolve(defaults.root, optional("worktree") ?? path60.join(defaults.worktreeRoot, id)),
84089
+ worktree: path61.resolve(defaults.root, optional("worktree") ?? path61.join(defaults.worktreeRoot, id)),
83750
84090
  tier,
83751
84091
  reason,
83752
84092
  dependsOn: [...new Set(dependsOn ?? [])],
@@ -83875,12 +84215,12 @@ function regeneratedFiles(root, tracked) {
83875
84215
  const found = new Map;
83876
84216
  let scripts;
83877
84217
  try {
83878
- const manifest = JSON.parse(fs29.readFileSync(path60.join(root, "package.json"), "utf8"));
84218
+ const manifest = JSON.parse(fs29.readFileSync(path61.join(root, "package.json"), "utf8"));
83879
84219
  scripts = manifest.scripts ?? {};
83880
84220
  } catch {
83881
84221
  return found;
83882
84222
  }
83883
- const runner = fs29.existsSync(path60.join(root, "bun.lock")) ? "bun run" : fs29.existsSync(path60.join(root, "pnpm-lock.yaml")) ? "pnpm run" : fs29.existsSync(path60.join(root, "yarn.lock")) ? "yarn run" : "npm run";
84223
+ const runner = fs29.existsSync(path61.join(root, "bun.lock")) ? "bun run" : fs29.existsSync(path61.join(root, "pnpm-lock.yaml")) ? "pnpm run" : fs29.existsSync(path61.join(root, "yarn.lock")) ? "yarn run" : "npm run";
83884
84224
  const outputs = tracked.filter((file) => !CODE.test(file));
83885
84225
  for (const [name, command] of Object.entries(scripts)) {
83886
84226
  if (!name.startsWith("write:") || typeof command !== "string")
@@ -83888,7 +84228,7 @@ function regeneratedFiles(root, tracked) {
83888
84228
  for (const file of command.match(/[\w./-]+\.[cm]?[jt]s\b/gu) ?? []) {
83889
84229
  let source;
83890
84230
  try {
83891
- source = fs29.readFileSync(path60.join(root, file), "utf8");
84231
+ source = fs29.readFileSync(path61.join(root, file), "utf8");
83892
84232
  } catch {
83893
84233
  continue;
83894
84234
  }
@@ -84010,11 +84350,11 @@ function defaultTrunk(cwd) {
84010
84350
  }
84011
84351
  function mainCheckout(cwd) {
84012
84352
  const common = gitCommonDir(cwd);
84013
- return common && path60.basename(common) === ".git" ? path60.dirname(common) : path60.resolve(cwd);
84353
+ return common && path61.basename(common) === ".git" ? path61.dirname(common) : path61.resolve(cwd);
84014
84354
  }
84015
84355
  function worktreeRoot(cwd) {
84016
84356
  const main = mainCheckout(cwd);
84017
- return path60.join(path60.dirname(main), `${path60.basename(main)}-wt`);
84357
+ return path61.join(path61.dirname(main), `${path61.basename(main)}-wt`);
84018
84358
  }
84019
84359
  function sliceHash(slice) {
84020
84360
  const {
@@ -84034,7 +84374,7 @@ function fanoutsDir(cwd) {
84034
84374
  const root = storeRoot(cwd);
84035
84375
  if (!root.ok)
84036
84376
  return fanoutFail(root.code, root.error, root.unblock);
84037
- return { ok: true, data: path60.join(root.value.root, "fanouts") };
84377
+ return { ok: true, data: path61.join(root.value.root, "fanouts") };
84038
84378
  }
84039
84379
  function parseStored(raw) {
84040
84380
  if (!isRecord13(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
@@ -84102,7 +84442,7 @@ function readFanout(cwd, name) {
84102
84442
  const dir = fanoutsDir(cwd);
84103
84443
  if (!dir.ok)
84104
84444
  return dir;
84105
- const file = path60.join(dir.data, stackFileName(name));
84445
+ const file = path61.join(dir.data, stackFileName(name));
84106
84446
  let parsed = null;
84107
84447
  try {
84108
84448
  parsed = parseStored(JSON.parse(fs29.readFileSync(file, "utf8")));
@@ -84127,7 +84467,7 @@ function listFanouts(cwd) {
84127
84467
  for (const entry of names) {
84128
84468
  let parsed = null;
84129
84469
  try {
84130
- parsed = parseStored(JSON.parse(fs29.readFileSync(path60.join(dir.data, entry), "utf8")));
84470
+ parsed = parseStored(JSON.parse(fs29.readFileSync(path61.join(dir.data, entry), "utf8")));
84131
84471
  } catch {
84132
84472
  parsed = null;
84133
84473
  }
@@ -84166,7 +84506,7 @@ function writeFanout(cwd, plan) {
84166
84506
  const dir = fanoutsDir(cwd);
84167
84507
  if (!dir.ok)
84168
84508
  return dir;
84169
- const file = path60.join(dir.data, stackFileName(plan.name));
84509
+ const file = path61.join(dir.data, stackFileName(plan.name));
84170
84510
  const temp = `${file}.${process.pid}.tmp`;
84171
84511
  try {
84172
84512
  fs29.mkdirSync(dir.data, { recursive: true });
@@ -84377,13 +84717,13 @@ var init_fanout = __esm(() => {
84377
84717
  // packages/workit-core/src/forge/exec.ts
84378
84718
  import { spawnSync as spawnSync24 } from "node:child_process";
84379
84719
  import fs30 from "node:fs";
84380
- import path61 from "node:path";
84720
+ import path62 from "node:path";
84381
84721
  function findExecutable(bin, env) {
84382
- const dirs = (env.PATH ?? env.Path ?? "").split(path61.delimiter).filter(Boolean);
84722
+ const dirs = (env.PATH ?? env.Path ?? "").split(path62.delimiter).filter(Boolean);
84383
84723
  const exts = process.platform === "win32" ? [".exe"] : [""];
84384
84724
  for (const dir of dirs)
84385
84725
  for (const ext of exts) {
84386
- const candidate = path61.join(dir, `${bin}${ext}`);
84726
+ const candidate = path62.join(dir, `${bin}${ext}`);
84387
84727
  try {
84388
84728
  const stat = fs30.statSync(candidate);
84389
84729
  if (stat.isFile())
@@ -85511,13 +85851,13 @@ function placeRef(ref, forge, tracker, relation, youtrackBase) {
85511
85851
  const configured = tracker?.provider === ref.tracker;
85512
85852
  const home = ref.tracker === forge.kind ? forge.host : DEFAULT_HOST[ref.tracker];
85513
85853
  const host = ref.host ?? (configured ? tracker?.host : null) ?? home;
85514
- const repo = ref.repo ?? (configured ? tracker?.repo : null) ?? (ref.tracker === forge.kind && same2(host, forge.host) ? forge.repo : null);
85854
+ const repo = ref.repo ?? (configured ? tracker?.repo : null) ?? (ref.tracker === forge.kind && same3(host, forge.host) ? forge.repo : null);
85515
85855
  if (!repo)
85516
85856
  return {
85517
85857
  error: `#${ref.id} is a ${ref.tracker} issue, but the PR is on ${forge.kind}: set issues.repo to the ${ref.tracker} project that holds it, or pass the issue URL`
85518
85858
  };
85519
- if (ref.tracker === forge.kind && same2(host, forge.host)) {
85520
- const own = same2(repo, forge.repo);
85859
+ if (ref.tracker === forge.kind && same3(host, forge.host)) {
85860
+ const own = same3(repo, forge.repo);
85521
85861
  return {
85522
85862
  tracker: ref.tracker,
85523
85863
  id: ref.id,
@@ -85654,7 +85994,7 @@ function issueForge(resolved, link, runner) {
85654
85994
  if (link.repo === null && link.host === null)
85655
85995
  return resolved.forge;
85656
85996
  const apiHost = resolved.forge.apiHost;
85657
- if (link.tracker !== resolved.forge.kind || !same2(link.host ?? apiHost, apiHost))
85997
+ if (link.tracker !== resolved.forge.kind || !same3(link.host ?? apiHost, apiHost))
85658
85998
  return null;
85659
85999
  const options = {
85660
86000
  apiHost,
@@ -85721,7 +86061,7 @@ async function postBacklinks(cwd, resolved, pr, links, deps = {}) {
85721
86061
  }
85722
86062
  return out;
85723
86063
  }
85724
- var DEFAULT_HOST, same2 = (left, right) => (left ?? "").toLowerCase() === (right ?? "").toLowerCase(), issueUrl = (kind, host, repo, id) => `https://${host}/${repo}/${kind === "gitlab" ? "-/" : ""}issues/${id}`, label = (link) => link.tracker === "youtrack" ? link.id : link.url ?? `${link.repo ?? ""}#${link.id}`, defaultYouTrackComment = (root, issueId, text, marker) => writeOnce(issueId, marker, "comments", async () => {
86064
+ var DEFAULT_HOST, same3 = (left, right) => (left ?? "").toLowerCase() === (right ?? "").toLowerCase(), issueUrl = (kind, host, repo, id) => `https://${host}/${repo}/${kind === "gitlab" ? "-/" : ""}issues/${id}`, label = (link) => link.tracker === "youtrack" ? link.id : link.url ?? `${link.repo ?? ""}#${link.id}`, defaultYouTrackComment = (root, issueId, text, marker) => writeOnce(issueId, marker, "comments", async () => {
85725
86065
  try {
85726
86066
  return {
85727
86067
  ok: true,
@@ -86173,7 +86513,7 @@ var init_live_session = __esm(() => {
86173
86513
  });
86174
86514
 
86175
86515
  // packages/workit-core/src/hooks/write-gate.ts
86176
- import path62 from "node:path";
86516
+ import path63 from "node:path";
86177
86517
  var CASE_INSENSITIVE, PREFIXES2, SCRIPT_SHELLS, cache3, MUTATING_GIT, DRY_N, MUTATING_WORKIT_GIT, CD2, PUSHD2, POPD2, UNKNOWN_DIR;
86178
86518
  var init_write_gate = __esm(() => {
86179
86519
  init_task_store();
@@ -86213,7 +86553,7 @@ var init_write_gate = __esm(() => {
86213
86553
  CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
86214
86554
  PUSHD2 = new Set(["pushd", "push-location"]);
86215
86555
  POPD2 = new Set(["popd", "pop-location"]);
86216
- UNKNOWN_DIR = path62.resolve(path62.parse(process.cwd()).root, ".workit-unknown-dir");
86556
+ UNKNOWN_DIR = path63.resolve(path63.parse(process.cwd()).root, ".workit-unknown-dir");
86217
86557
  });
86218
86558
 
86219
86559
  // packages/workit-core/src/hooks/worktree-confine.ts
@@ -86238,20 +86578,20 @@ var init_worktree_confine = __esm(() => {
86238
86578
 
86239
86579
  // packages/workit-core/src/worktree-deps.ts
86240
86580
  import fs31 from "node:fs";
86241
- import path63 from "node:path";
86581
+ import path64 from "node:path";
86242
86582
  function moduleDirs(main) {
86243
86583
  const out = [];
86244
86584
  const walk = (relative, depth) => {
86245
86585
  let entries;
86246
86586
  try {
86247
- entries = fs31.readdirSync(path63.join(main, relative), { withFileTypes: true });
86587
+ entries = fs31.readdirSync(path64.join(main, relative), { withFileTypes: true });
86248
86588
  } catch {
86249
86589
  return;
86250
86590
  }
86251
86591
  for (const entry of entries) {
86252
86592
  if (!entry.isDirectory())
86253
86593
  continue;
86254
- const child = path63.join(relative, entry.name);
86594
+ const child = path64.join(relative, entry.name);
86255
86595
  if (entry.name === MODULES)
86256
86596
  out.push(child);
86257
86597
  else if (depth < MAX_DEPTH2 && !entry.name.startsWith("."))
@@ -86265,8 +86605,8 @@ function linkEntry(main, worktree, source, target) {
86265
86605
  const stat = fs31.lstatSync(source);
86266
86606
  if (stat.isSymbolicLink()) {
86267
86607
  const link = fs31.readlinkSync(source);
86268
- const outside = path63.isAbsolute(link) && within(link, main) && !path63.relative(main, link).split(path63.sep).includes(MODULES);
86269
- const to = outside ? path63.join(worktree, path63.relative(main, link)) : link;
86608
+ const outside = path64.isAbsolute(link) && within(link, main) && !path64.relative(main, link).split(path64.sep).includes(MODULES);
86609
+ const to = outside ? path64.join(worktree, path64.relative(main, link)) : link;
86270
86610
  fs31.symlinkSync(to, target, process.platform === "win32" ? "junction" : undefined);
86271
86611
  return;
86272
86612
  }
@@ -86276,8 +86616,8 @@ function mirror(main, worktree, source, target, top) {
86276
86616
  fs31.mkdirSync(target);
86277
86617
  let count = 0;
86278
86618
  for (const entry of fs31.readdirSync(source, { withFileTypes: true })) {
86279
- const from = path63.join(source, entry.name);
86280
- const to = path63.join(target, entry.name);
86619
+ const from = path64.join(source, entry.name);
86620
+ const to = path64.join(target, entry.name);
86281
86621
  if (top && entry.isDirectory() && (entry.name.startsWith("@") || entry.name === ".bin"))
86282
86622
  count += mirror(main, worktree, from, to, false);
86283
86623
  else {
@@ -86293,16 +86633,16 @@ function linkWorktreeDependencies(main, worktree) {
86293
86633
  const dirs = [];
86294
86634
  let entries = 0;
86295
86635
  for (const relative of moduleDirs(main)) {
86296
- const target = path63.join(worktree, relative);
86297
- if (!fs31.existsSync(path63.dirname(target)) || fs31.existsSync(target))
86636
+ const target = path64.join(worktree, relative);
86637
+ if (!fs31.existsSync(path64.dirname(target)) || fs31.existsSync(target))
86298
86638
  continue;
86299
- if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(path63.sep).join("/")}/`]).ok) {
86300
- notes.push(`${relative.split(path63.sep).join("/")} is not ignored by git, so it was not linked from ${main}; install dependencies in the worktree yourself`);
86639
+ if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(path64.sep).join("/")}/`]).ok) {
86640
+ notes.push(`${relative.split(path64.sep).join("/")} is not ignored by git, so it was not linked from ${main}; install dependencies in the worktree yourself`);
86301
86641
  continue;
86302
86642
  }
86303
86643
  try {
86304
- entries += mirror(main, worktree, path63.join(main, relative), target, true);
86305
- dirs.push(relative.split(path63.sep).join("/"));
86644
+ entries += mirror(main, worktree, path64.join(main, relative), target, true);
86645
+ dirs.push(relative.split(path64.sep).join("/"));
86306
86646
  } catch (error) {
86307
86647
  fs31.rmSync(target, { recursive: true, force: true });
86308
86648
  notes.push(`could not link ${relative} from ${main} (${error.message}); install dependencies in the worktree yourself`);
@@ -86315,8 +86655,8 @@ function linkWorktreeDependencies(main, worktree) {
86315
86655
  return { linked: { from: main, dirs, entries, ms }, notes };
86316
86656
  }
86317
86657
  var MODULES = "node_modules", MAX_DEPTH2 = 2, within = (child, parent) => {
86318
- const relative = path63.relative(parent, child);
86319
- return relative === "" || !relative.startsWith("..") && !path63.isAbsolute(relative);
86658
+ const relative = path64.relative(parent, child);
86659
+ return relative === "" || !relative.startsWith("..") && !path64.isAbsolute(relative);
86320
86660
  };
86321
86661
  var init_worktree_deps = __esm(() => {
86322
86662
  init_fanout();
@@ -86325,7 +86665,7 @@ var init_worktree_deps = __esm(() => {
86325
86665
  // packages/workit-core/src/fanout-worktree.ts
86326
86666
  import { randomBytes as randomBytes5 } from "node:crypto";
86327
86667
  import fs32 from "node:fs";
86328
- import path64 from "node:path";
86668
+ import path65 from "node:path";
86329
86669
  function rowSample(lines) {
86330
86670
  const out = [];
86331
86671
  let bytes = 0;
@@ -86385,7 +86725,7 @@ function adminDir(worktree) {
86385
86725
  const file = dir.stdout.trim();
86386
86726
  let token = null;
86387
86727
  try {
86388
- token = fs32.readFileSync(path64.join(file, FANOUT_TOKEN_FILE), "utf8").trim() || null;
86728
+ token = fs32.readFileSync(path65.join(file, FANOUT_TOKEN_FILE), "utf8").trim() || null;
86389
86729
  } catch {
86390
86730
  token = null;
86391
86731
  }
@@ -86393,7 +86733,7 @@ function adminDir(worktree) {
86393
86733
  const stat = worktreeDeps.stat(file);
86394
86734
  return {
86395
86735
  path: file,
86396
- id: path64.basename(file),
86736
+ id: path65.basename(file),
86397
86737
  ino: stat.ino.toString(),
86398
86738
  token,
86399
86739
  birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
@@ -86409,7 +86749,7 @@ function markAdminDir(worktree) {
86409
86749
  return null;
86410
86750
  const token = randomBytes5(16).toString("hex");
86411
86751
  try {
86412
- fs32.writeFileSync(path64.join(admin.path, FANOUT_TOKEN_FILE), `${token}
86752
+ fs32.writeFileSync(path65.join(admin.path, FANOUT_TOKEN_FILE), `${token}
86413
86753
  `);
86414
86754
  } catch {
86415
86755
  return null;
@@ -86424,7 +86764,7 @@ function excludeScratch(cwd) {
86424
86764
  const common = gitCommonDir(cwd);
86425
86765
  if (!common)
86426
86766
  return;
86427
- const file = path64.join(common, "info", "exclude");
86767
+ const file = path65.join(common, "info", "exclude");
86428
86768
  let text = "";
86429
86769
  try {
86430
86770
  text = fs32.readFileSync(file, "utf8");
@@ -86433,7 +86773,7 @@ function excludeScratch(cwd) {
86433
86773
  }
86434
86774
  if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
86435
86775
  return;
86436
- fs32.mkdirSync(path64.dirname(file), { recursive: true });
86776
+ fs32.mkdirSync(path65.dirname(file), { recursive: true });
86437
86777
  fs32.appendFileSync(file, `${text && !text.endsWith(`
86438
86778
  `) ? `
86439
86779
  ` : ""}# workit fanout: per-worker scratch dirs
@@ -86442,13 +86782,13 @@ ${EXCLUDE_LINE}
86442
86782
  }
86443
86783
  function worktreeDependencies(main, worktree) {
86444
86784
  for (const [name, install] of LOCKFILES2) {
86445
- const ours = readBytes(path64.join(main, name));
86446
- const theirs = readBytes(path64.join(worktree, name));
86785
+ const ours = readBytes(path65.join(main, name));
86786
+ const theirs = readBytes(path65.join(worktree, name));
86447
86787
  if (ours === null && theirs === null)
86448
86788
  continue;
86449
86789
  if (ours !== null && theirs !== null && ours.equals(theirs))
86450
86790
  continue;
86451
- if (fs32.existsSync(path64.join(worktree, "node_modules")))
86791
+ if (fs32.existsSync(path65.join(worktree, "node_modules")))
86452
86792
  break;
86453
86793
  const command = install(worktree);
86454
86794
  return {
@@ -86460,7 +86800,7 @@ function worktreeDependencies(main, worktree) {
86460
86800
  };
86461
86801
  }
86462
86802
  const stale = staleBunInstall(main);
86463
- if (stale && !fs32.existsSync(path64.join(worktree, "node_modules"))) {
86803
+ if (stale && !fs32.existsSync(path65.join(worktree, "node_modules"))) {
86464
86804
  const command = `bun install --frozen-lockfile --cwd ${worktree}`;
86465
86805
  return {
86466
86806
  linked: null,
@@ -86473,9 +86813,9 @@ function worktreeDependencies(main, worktree) {
86473
86813
  return { ...linkWorktreeDependencies(main, worktree), install: null };
86474
86814
  }
86475
86815
  function staleBunInstall(main) {
86476
- if (!fs32.existsSync(path64.join(main, "node_modules")))
86816
+ if (!fs32.existsSync(path65.join(main, "node_modules")))
86477
86817
  return null;
86478
- const text = readBytes(path64.join(main, "bun.lock"))?.toString("utf8");
86818
+ const text = readBytes(path65.join(main, "bun.lock"))?.toString("utf8");
86479
86819
  if (!text)
86480
86820
  return null;
86481
86821
  let packages;
@@ -86502,7 +86842,7 @@ function staleBunInstall(main) {
86502
86842
  const version = spec.slice(at + 1);
86503
86843
  if (name !== key || version.includes(":"))
86504
86844
  continue;
86505
- const manifest = readBytes(path64.join(main, "node_modules", key, "package.json"));
86845
+ const manifest = readBytes(path65.join(main, "node_modules", key, "package.json"));
86506
86846
  if (!manifest) {
86507
86847
  problems.push(`${key} missing`);
86508
86848
  continue;
@@ -86519,7 +86859,7 @@ function staleBunInstall(main) {
86519
86859
  return problems.length ? problems.join("; ") : null;
86520
86860
  }
86521
86861
  function ensureScratch(worktree) {
86522
- const scratch = path64.join(worktree, SCRATCH_DIR);
86862
+ const scratch = path65.join(worktree, SCRATCH_DIR);
86523
86863
  fs32.mkdirSync(scratch, { recursive: true });
86524
86864
  return scratch;
86525
86865
  }
@@ -86793,7 +87133,7 @@ function unpushedCount(cwd, branch) {
86793
87133
  return count.ok ? Number(count.stdout.trim()) : null;
86794
87134
  }
86795
87135
  function removeScratch(worktree) {
86796
- const scratch = path64.join(worktree, SCRATCH_DIR);
87136
+ const scratch = path65.join(worktree, SCRATCH_DIR);
86797
87137
  let stat;
86798
87138
  try {
86799
87139
  stat = fs32.lstatSync(scratch);
@@ -86809,16 +87149,16 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
86809
87149
  try {
86810
87150
  return fs32.realpathSync.native(target);
86811
87151
  } catch {
86812
- return path64.resolve(target);
87152
+ return path65.resolve(target);
86813
87153
  }
86814
87154
  }, samePath = (a, b) => {
86815
87155
  const left = canonical2(a);
86816
87156
  const right = canonical2(b);
86817
87157
  return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
86818
87158
  }, inside3 = (child, parent) => {
86819
- const relative = path64.relative(canonical2(parent), canonical2(child));
86820
- return relative === "" || !relative.startsWith("..") && !path64.isAbsolute(relative);
86821
- }, slicePath = (cwd, slice) => path64.isAbsolute(slice.worktree) ? slice.worktree : path64.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps, LOCKFILES2, readBytes = (file) => {
87159
+ const relative = path65.relative(canonical2(parent), canonical2(child));
87160
+ return relative === "" || !relative.startsWith("..") && !path65.isAbsolute(relative);
87161
+ }, slicePath = (cwd, slice) => path65.isAbsolute(slice.worktree) ? slice.worktree : path65.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps, LOCKFILES2, readBytes = (file) => {
86822
87162
  try {
86823
87163
  return fs32.readFileSync(file);
86824
87164
  } catch {
@@ -86850,7 +87190,7 @@ var init_fanout_worktree = __esm(() => {
86850
87190
 
86851
87191
  // packages/workit-core/src/forge/merge-cleanup.ts
86852
87192
  import fs33 from "node:fs";
86853
- import path65 from "node:path";
87193
+ import path66 from "node:path";
86854
87194
  function cleanupMergedBranch(cwd, branch, mergedHead) {
86855
87195
  const out = { branchDeleted: false, worktreeRemoved: null, notes: [] };
86856
87196
  if (!branch || branch.startsWith("-"))
@@ -86910,13 +87250,13 @@ var SLOW2, isFanoutWorktree = (worktree) => {
86910
87250
  if (!dir.ok)
86911
87251
  return false;
86912
87252
  try {
86913
- return fs33.readFileSync(path65.join(dir.stdout.trim(), FANOUT_TOKEN_FILE), "utf8").trim() !== "";
87253
+ return fs33.readFileSync(path66.join(dir.stdout.trim(), FANOUT_TOKEN_FILE), "utf8").trim() !== "";
86914
87254
  } catch {
86915
87255
  return false;
86916
87256
  }
86917
87257
  }, inside4 = (child, parent) => {
86918
- const relative = path65.relative(fs33.realpathSync.native(parent), fs33.realpathSync.native(child));
86919
- return relative === "" || !relative.startsWith("..") && !path65.isAbsolute(relative);
87258
+ const relative = path66.relative(fs33.realpathSync.native(parent), fs33.realpathSync.native(child));
87259
+ return relative === "" || !relative.startsWith("..") && !path66.isAbsolute(relative);
86920
87260
  };
86921
87261
  var init_merge_cleanup = __esm(() => {
86922
87262
  init_fanout();
@@ -87368,7 +87708,7 @@ __export(exports_pr, {
87368
87708
  run: () => run15
87369
87709
  });
87370
87710
  import { existsSync as existsSync27, readFileSync as readFileSync27 } from "node:fs";
87371
- import path66 from "node:path";
87711
+ import path67 from "node:path";
87372
87712
  function titleRules(cwd) {
87373
87713
  let root;
87374
87714
  try {
@@ -87379,7 +87719,7 @@ function titleRules(cwd) {
87379
87719
  let text = null;
87380
87720
  let name = "";
87381
87721
  for (const candidate of COMMITLINT_FILES) {
87382
- const full = path66.join(root, candidate);
87722
+ const full = path67.join(root, candidate);
87383
87723
  if (!existsSync27(full))
87384
87724
  continue;
87385
87725
  text = readFileSync27(full, "utf8");
@@ -87388,7 +87728,7 @@ function titleRules(cwd) {
87388
87728
  }
87389
87729
  if (text === null) {
87390
87730
  try {
87391
- const pkg = JSON.parse(readFileSync27(path66.join(root, "package.json"), "utf8"));
87731
+ const pkg = JSON.parse(readFileSync27(path67.join(root, "package.json"), "utf8"));
87392
87732
  if (pkg.commitlint === undefined)
87393
87733
  return { rules: null, note: null };
87394
87734
  text = JSON.stringify(pkg.commitlint);
@@ -87485,7 +87825,7 @@ function refuseTitle(io, title, line) {
87485
87825
  function readBodyFile(io, file) {
87486
87826
  try {
87487
87827
  return {
87488
- body: file === "-" ? forgeDeps.readStdin() : readFileSync27(path66.resolve(io.cwd, file), "utf8")
87828
+ body: file === "-" ? forgeDeps.readStdin() : readFileSync27(path67.resolve(io.cwd, file), "utf8")
87489
87829
  };
87490
87830
  } catch {
87491
87831
  return `cannot read --body-file ${file}`;
@@ -87681,7 +88021,7 @@ async function create4(argv, io) {
87681
88021
  return usage4(io, planned.error, CREATE_USAGE);
87682
88022
  const links = planned.data.links;
87683
88023
  const actor = actorFromEnv(io.env);
87684
- const result = await createPullRequest(io.cwd, connected.data, {
88024
+ const result = await progressFor(io).run("Opening the pull request", () => createPullRequest(io.cwd, connected.data, {
87685
88025
  base,
87686
88026
  title,
87687
88027
  body: withIssueLines(body ?? "", links),
@@ -87689,12 +88029,12 @@ async function create4(argv, io) {
87689
88029
  actor,
87690
88030
  labels: flags.lists.label ?? [],
87691
88031
  reviewers: flags.lists.reviewer ?? []
87692
- }, forgeDeps.sleep);
88032
+ }, forgeDeps.sleep), (r) => r.ok ? "done" : "failed");
87693
88033
  if (!result.ok)
87694
88034
  return forgeFail(io, result);
87695
88035
  const opened = result.data.created;
87696
88036
  const linked = opened ? recordIssueLinks(io.cwd, result.data, links, { actor, forge: forge.kind, repo: forge.repo }) : [];
87697
- const backlinks = opened && planned.data.backlink && links.length ? await postBacklinks(io.cwd, connected.data, result.data, links, { env: io.env }) : [];
88037
+ const backlinks = opened && planned.data.backlink && links.length ? await progressFor(io).run("Posting issue backlinks", () => postBacklinks(io.cwd, connected.data, result.data, links, { env: io.env })) : [];
87698
88038
  const created = {
87699
88039
  ...result.data,
87700
88040
  issues: links.map((link) => ({
@@ -87803,7 +88143,7 @@ async function merge3(argv, io) {
87803
88143
  const connected = connect(io);
87804
88144
  if (!connected.ok)
87805
88145
  return forgeFail(io, connected);
87806
- const result = await mergePullRequest(io.cwd, connected.data, {
88146
+ const result = await progressFor(io).run(`Merging PR #${pr}`, () => mergePullRequest(io.cwd, connected.data, {
87807
88147
  pr,
87808
88148
  method,
87809
88149
  deleteBranch: flags.booleans.has("delete-branch"),
@@ -87813,7 +88153,7 @@ async function merge3(argv, io) {
87813
88153
  ...baseRedOk && baseRedReason ? { baseRedOk: { reason: baseRedReason } } : {},
87814
88154
  ...subject !== undefined ? { subject } : {},
87815
88155
  ...body !== undefined ? { body } : {}
87816
- }, forgeDeps.sleep);
88156
+ }, forgeDeps.sleep), (r) => r.ok ? "done" : "failed");
87817
88157
  if (!result.ok)
87818
88158
  return emit(io, fail2(result.code, result.error, {
87819
88159
  unblock: result.unblock,
@@ -88017,6 +88357,7 @@ var CONVENTIONAL_TYPES, COMMITLINT_FILES, DEFAULT_IGNORES, UNCHECKED = (what) =>
88017
88357
  return `verdict ${verdict.verdictId} accepted for that head${verdict.cover ? ` (stack verdict on ${verdict.cover.branch} @ ${verdict.cover.head.slice(0, 12)})` : verdict.carry ? ` (${carryLabel(verdict.carry)})` : ""}`;
88018
88358
  }, acceptedHow = (verdict) => verdict.cover ? `stack verdict ${verdict.cover.verdictId} on ${verdict.cover.branch} @ ${verdict.cover.head.slice(0, 12)}` : verdict.carry ? carryLabel(verdict.carry) : verdict.basis, METHODS2;
88019
88359
  var init_pr = __esm(() => {
88360
+ init_progress();
88020
88361
  init_autonomy();
88021
88362
  init_issue_link();
88022
88363
  init_pr_edit();
@@ -88130,7 +88471,7 @@ async function wait2(argv, io) {
88130
88471
  let verdict = { state: "waiting", reason: "not_polled" };
88131
88472
  let baseContexts = null;
88132
88473
  let expectedMissing = [];
88133
- const waiting = createProgress({ stream: process.stderr, json: io.json }).start("Waiting for CI");
88474
+ const waiting = progressFor(io).start("Waiting for CI");
88134
88475
  const abort = (...args) => {
88135
88476
  waiting.end("failed");
88136
88477
  return forgeFail(io, ...args);
@@ -88253,15 +88594,15 @@ async function rerun(argv, io) {
88253
88594
  const number = selectPr(io.cwd, resolved, { pr, branch: flags.values.branch ?? null });
88254
88595
  if (!number.ok)
88255
88596
  return forgeFail(io, number);
88256
- const status = resolved.forge.prStatus(number.data);
88597
+ const status = progressFor(io).runSync(`Reading PR #${number.data} checks`, () => resolved.forge.prStatus(number.data), (r) => r.ok ? "done" : "failed");
88257
88598
  if (!status.ok)
88258
88599
  return forgeFail(io, status);
88259
- const done = executeRerun(io.cwd, resolved, status.data, {
88600
+ const done = progressFor(io).runSync("Rerunning the checks", () => executeRerun(io.cwd, resolved, status.data, {
88260
88601
  failed: names.length === 0,
88261
88602
  names,
88262
88603
  reason,
88263
88604
  force: flags.booleans.has("force")
88264
- });
88605
+ }), (r) => r.ok ? "done" : "failed");
88265
88606
  if (!done.ok)
88266
88607
  return forgeFail(io, done);
88267
88608
  const outcome = done.data;
@@ -88374,7 +88715,7 @@ __export(exports_git, {
88374
88715
  run: () => run17
88375
88716
  });
88376
88717
  import { readFileSync as readFileSync28 } from "node:fs";
88377
- import path67 from "node:path";
88718
+ import path68 from "node:path";
88378
88719
  function kindHint(cwd, kind) {
88379
88720
  let kinds = [...BRANCH_KINDS];
88380
88721
  try {
@@ -88478,7 +88819,7 @@ function commitMessage(parsed, io) {
88478
88819
 
88479
88820
  `);
88480
88821
  try {
88481
- return file === "-" ? readFileSync28(0, "utf8") : readFileSync28(path67.resolve(io.cwd, file), "utf8");
88822
+ return file === "-" ? readFileSync28(0, "utf8") : readFileSync28(path68.resolve(io.cwd, file), "utf8");
88482
88823
  } catch (error) {
88483
88824
  return {
88484
88825
  error: `cannot read -F ${file}: ${error instanceof Error ? error.message : String(error)}`
@@ -89375,17 +89716,17 @@ async function releasePr(io, plan, dryRun) {
89375
89716
  const switched = switchToRelease(io.cwd, plan);
89376
89717
  if (!switched.ok)
89377
89718
  return forgeFail(io, switched);
89378
- const pushed = await subVerb(() => Promise.resolve().then(() => (init_git2(), exports_git)), ["push", "--set-upstream"], io);
89719
+ const pushed = await progressFor(io).run(`Pushing ${plan.branch}`, () => subVerb(() => Promise.resolve().then(() => (init_git2(), exports_git)), ["push", "--set-upstream"], io), (r) => r.ok ? "done" : "failed");
89379
89720
  if (!pushed.ok)
89380
89721
  return emit(io, pushed);
89381
- const pr = await subVerb(() => Promise.resolve().then(() => (init_pr(), exports_pr)), [
89722
+ const pr = await progressFor(io).run("Opening the release PR", () => subVerb(() => Promise.resolve().then(() => (init_pr(), exports_pr)), [
89382
89723
  "create",
89383
89724
  "--base",
89384
89725
  plan.production,
89385
89726
  "--title",
89386
89727
  title,
89387
89728
  `--body=${plan.changelog ?? `Release ${plan.version}`}`
89388
- ], io);
89729
+ ], io), (r) => r.ok ? "done" : "failed");
89389
89730
  if (!pr.ok)
89390
89731
  return emit(io, pr);
89391
89732
  recordReleaseStep(io.cwd, actorFromEnv(io.env), plan, {
@@ -89441,11 +89782,11 @@ async function finish2(argv, io) {
89441
89782
  if (!push.allowed)
89442
89783
  return blocked(io, push);
89443
89784
  const resume = `workit release finish ${plan.version}${plan.track ? ` --track ${plan.track}` : ""}`;
89444
- const merged = finishLocally(io.cwd, plan, actor);
89785
+ const merged = progressFor(io).runSync(`Merging release ${plan.version} locally`, () => finishLocally(io.cwd, plan, actor), (r) => r.ok ? "done" : "failed");
89445
89786
  if (!merged.ok)
89446
89787
  return forgeFail(io, merged, { step: "merge", resume });
89447
89788
  const notes = [...plan.notes];
89448
- const pushed = await subVerb(() => Promise.resolve().then(() => (init_git2(), exports_git)), ["push", ...[...plan.pushBranches, plan.tag].flatMap((ref) => ["--release", ref])], io);
89789
+ const pushed = await progressFor(io).run("Pushing the release branches and tag", () => subVerb(() => Promise.resolve().then(() => (init_git2(), exports_git)), ["push", ...[...plan.pushBranches, plan.tag].flatMap((ref) => ["--release", ref])], io), (r) => r.ok ? "done" : "failed");
89449
89790
  if (!pushed.ok)
89450
89791
  return emit(io, { ...pushed, data: { ...pushed.data, step: "push", resume } });
89451
89792
  if (plan.published && plan.remote) {
@@ -89577,6 +89918,7 @@ var START_USAGE = "workit release start <version> [--hotfix] [--track <t>] [--js
89577
89918
  { step: `verify ${plan.tag} on the remote`, done: false }
89578
89919
  ];
89579
89920
  var init_release2 = __esm(() => {
89921
+ init_progress();
89580
89922
  init_autonomy();
89581
89923
  init_verify();
89582
89924
  init_ops();
@@ -89627,14 +89969,14 @@ async function run19(argv, io) {
89627
89969
  if (expect === "pushed") {
89628
89970
  if (pr)
89629
89971
  return usage4(io, "push is checked by --branch, not --pr", USAGE12);
89630
- result = verifyPushed(io.cwd, { branch, sha, actor });
89972
+ result = progressFor(io).runSync("Checking the push", () => verifyPushed(io.cwd, { branch, sha, actor }), (r) => r.ok ? "done" : "failed");
89631
89973
  } else if (expect === "released") {
89632
- result = verifyReleased(io.cwd, { tag: flags.values.tag ?? null, pkg: flags.values.package ?? null, sha, actor }, forgeDeps.npm);
89974
+ result = progressFor(io).runSync("Checking the release", () => verifyReleased(io.cwd, { tag: flags.values.tag ?? null, pkg: flags.values.package ?? null, sha, actor }, forgeDeps.npm), (r) => r.ok ? "done" : "failed");
89633
89975
  } else {
89634
89976
  const connected = connect(io, branch);
89635
89977
  if (!connected.ok)
89636
89978
  return forgeFail(io, connected);
89637
- result = expect === "pr" ? verifyPr(io.cwd, connected.data, { pr, branch, sha, actor }) : verifyMerged(io.cwd, connected.data, { pr, branch, actor });
89979
+ result = expect === "pr" ? progressFor(io).runSync(`Checking the PR`, () => verifyPr(io.cwd, connected.data, { pr, branch, sha, actor }), (r) => r.ok ? "done" : "failed") : progressFor(io).runSync("Checking the merge", () => verifyMerged(io.cwd, connected.data, { pr, branch, actor }), (r) => r.ok ? "done" : "failed");
89638
89980
  }
89639
89981
  if (!result.ok)
89640
89982
  return forgeFail(io, result);
@@ -89661,6 +90003,7 @@ var USAGE12 = "workit verify-delivery [push|pr|merge|release] [--expect pushed|p
89661
90003
  ...report.observations.map((entry) => ` ${entry.ok ? "ok" : "x "} ${entry.kind}: expected ${entry.expected ?? "-"}, observed ${entry.observed ?? "(none)"}${entry.note ? ` — ${entry.note}` : ""}`)
89662
90004
  ];
89663
90005
  var init_verify_delivery = __esm(() => {
90006
+ init_progress();
89664
90007
  init_verify();
89665
90008
  init_task_store();
89666
90009
  init_task_delivery();
@@ -89796,7 +90139,7 @@ async function sync(argv, io, restack = false) {
89796
90139
  };
89797
90140
  }
89798
90141
  const name = selected.data.name;
89799
- const result = await withStackLock(io.cwd, name, async () => {
90142
+ const result = await progressFor(io).run(restack ? `Restacking ${name}` : `Syncing ${name}`, () => withStackLock(io.cwd, name, async () => {
89800
90143
  const fresh = readStack(io.cwd, name);
89801
90144
  if (!fresh.ok)
89802
90145
  return fresh;
@@ -89809,10 +90152,13 @@ async function sync(argv, io, restack = false) {
89809
90152
  ok: true,
89810
90153
  data: {
89811
90154
  ...synced.data,
89812
- pruned: pruneMergedBranches(io.cwd, ctx, stack, { dryRun, actor: actorFromEnv(io.env) })
90155
+ pruned: pruneMergedBranches(io.cwd, ctx, stack, {
90156
+ dryRun,
90157
+ actor: actorFromEnv(io.env)
90158
+ })
89813
90159
  }
89814
90160
  };
89815
- });
90161
+ }), (r) => r.ok ? "done" : "failed");
89816
90162
  if (!result.ok)
89817
90163
  return stackFailed(io, result);
89818
90164
  if (restack)
@@ -89861,7 +90207,7 @@ async function land(argv, io) {
89861
90207
  if (!connected.ok)
89862
90208
  return forgeFail(io, connected);
89863
90209
  const name = selected.data.name;
89864
- const result = await withStackLock(io.cwd, name, async () => {
90210
+ const result = await progressFor(io).run(`Landing ${name}`, () => withStackLock(io.cwd, name, async () => {
89865
90211
  const fresh = readStack(io.cwd, name);
89866
90212
  if (!fresh.ok)
89867
90213
  return fresh;
@@ -89879,7 +90225,7 @@ async function land(argv, io) {
89879
90225
  unverified,
89880
90226
  baseRedOk: baseRedOk && baseRedReason ? { reason: baseRedReason } : null
89881
90227
  });
89882
- });
90228
+ }), (r) => r.ok ? "done" : "failed");
89883
90229
  if (!result.ok)
89884
90230
  return stackFailed(io, result);
89885
90231
  const kind = connected.data.forge.kind;
@@ -89926,6 +90272,7 @@ var PLAN_USAGE = "workit stack plan [--name <n>] [--trunk <b> | --track <t>] [<b
89926
90272
  ...data.pruned.kept.map((item) => `kept merged branch ${item.branch}: ${item.reason}`)
89927
90273
  ], METHODS3;
89928
90274
  var init_stack2 = __esm(() => {
90275
+ init_progress();
89929
90276
  init_ledger();
89930
90277
  init_stack();
89931
90278
  init_output();
@@ -89936,7 +90283,7 @@ var init_stack2 = __esm(() => {
89936
90283
  // packages/workit-core/src/fanout-brief.ts
89937
90284
  import { createHash as createHash20 } from "node:crypto";
89938
90285
  import fs35 from "node:fs";
89939
- import path68 from "node:path";
90286
+ import path69 from "node:path";
89940
90287
  function workerSession(lead, slice, attempt) {
89941
90288
  const tail = attempt === null ? "" : `+try${attempt}`;
89942
90289
  const full = `${lead}-w-${slice}${tail}`;
@@ -90019,7 +90366,7 @@ function renderBrief(cwd, plan, input) {
90019
90366
  "STANDING:",
90020
90367
  ...standing.length ? standing.map((order) => ` - ${order.what}`) : [" - none recorded beyond this brief"],
90021
90368
  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)`,
90022
- ...exists && typeof made?.install === "string" && !fs35.existsSync(path68.join(planned, "node_modules")) ? [`INSTALL: \`${made.install}\` first: the main checkout's node_modules was not linked here`] : [],
90369
+ ...exists && typeof made?.install === "string" && !fs35.existsSync(path69.join(planned, "node_modules")) ? [`INSTALL: \`${made.install}\` first: the main checkout's node_modules was not linked here`] : [],
90023
90370
  ...identityLines(identity, minted),
90024
90371
  ...rules(mode, branch, sliceBase, exists ? planned : null)
90025
90372
  ];
@@ -90561,7 +90908,7 @@ __export(exports_fanout, {
90561
90908
  run: () => run21
90562
90909
  });
90563
90910
  import fs36 from "node:fs";
90564
- import path69 from "node:path";
90911
+ import path70 from "node:path";
90565
90912
  function forgeFor(io, offline) {
90566
90913
  if (offline)
90567
90914
  return { forge: null, error: "--offline" };
@@ -90622,7 +90969,7 @@ function plan2(argv, io) {
90622
90969
  return usage4(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
90623
90970
  if (flags.positionals.length !== 1)
90624
90971
  return usage4(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
90625
- const file = path69.resolve(io.cwd, flags.positionals[0]);
90972
+ const file = path70.resolve(io.cwd, flags.positionals[0]);
90626
90973
  let raw;
90627
90974
  try {
90628
90975
  raw = JSON.parse(fs36.readFileSync(file, "utf8"));
@@ -90688,11 +91035,11 @@ function check2(argv, io) {
90688
91035
  const selected = selectFanout(io.cwd, flags.values.name ?? null, currentBranch(io.cwd));
90689
91036
  if (!selected.ok)
90690
91037
  return failed(io, selected);
90691
- const result = checkFanout(io.cwd, selected.data, {
91038
+ const result = progressFor(io).runSync("Checking the fan-out slices", () => checkFanout(io.cwd, selected.data, {
90692
91039
  only: flags.positionals,
90693
91040
  trunkRef: flags.values.base ?? null,
90694
91041
  forge: forgeFor(io, flags.booleans.has("offline")).forge
90695
- });
91042
+ }), (r) => r.ok ? "done" : "failed");
90696
91043
  if (!result.ok)
90697
91044
  return failed(io, result);
90698
91045
  if (result.data.ready)
@@ -90721,11 +91068,11 @@ function status4(argv, io) {
90721
91068
  if (!selected.ok)
90722
91069
  return failed(io, selected);
90723
91070
  const forge = forgeFor(io, flags.booleans.has("offline"));
90724
- const result = fanoutStatus(io.cwd, selected.data, {
91071
+ const result = progressFor(io).runSync("Reading the fan-out status", () => fanoutStatus(io.cwd, selected.data, {
90725
91072
  forge: forge.forge,
90726
91073
  forgeError: forge.error,
90727
91074
  stuckAfterMs
90728
- });
91075
+ }), (r) => r.ok ? "done" : "failed");
90729
91076
  if (!result.ok)
90730
91077
  return failed(io, result);
90731
91078
  return emit(io, ok2(result.data), renderStatus2);
@@ -90831,6 +91178,7 @@ var PLAN_USAGE2 = "workit fanout plan <plan.json> [--name <n>] [--trunk <b> | --
90831
91178
  ];
90832
91179
  };
90833
91180
  var init_fanout2 = __esm(() => {
91181
+ init_progress();
90834
91182
  init_fanout_brief();
90835
91183
  init_fanout_check();
90836
91184
  init_fanout_status();
@@ -106197,7 +106545,7 @@ var init_ast = __esm(() => {
106197
106545
 
106198
106546
  // packages/workit-cli/src/test-audit/rules.ts
106199
106547
  import { builtinModules } from "node:module";
106200
- import path70 from "node:path";
106548
+ import path71 from "node:path";
106201
106549
  function testCallee(call) {
106202
106550
  let callee = call.callee;
106203
106551
  if (callee.type === "CallExpression")
@@ -106690,12 +107038,12 @@ function checkConstantsOnly(ctx, emit) {
106690
107038
  }
106691
107039
  function checkOverMocking(ctx, emit) {
106692
107040
  const { program } = ctx.parsed;
106693
- const unit = path70.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
107041
+ const unit = path71.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
106694
107042
  const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
106695
107043
  const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
106696
107044
  for (const call of mocked) {
106697
107045
  const spec = call.arguments[0].value;
106698
- const base = path70.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
107046
+ const base = path71.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
106699
107047
  if (base === unit)
106700
107048
  emit({
106701
107049
  rule: "over-mocking",
@@ -107085,7 +107433,7 @@ var init_rules = __esm(() => {
107085
107433
  // packages/workit-cli/src/test-audit/audit.ts
107086
107434
  import { spawnSync as spawnSync29 } from "node:child_process";
107087
107435
  import { existsSync as existsSync28, readdirSync as readdirSync14, readFileSync as readFileSync29, statSync as statSync10 } from "node:fs";
107088
- import path71 from "node:path";
107436
+ import path72 from "node:path";
107089
107437
  function git7(cwd, args) {
107090
107438
  const run = spawnSync29("git", ["-c", "core.quotepath=off", ...args], {
107091
107439
  cwd,
@@ -107098,7 +107446,7 @@ function walkTests(dir, out) {
107098
107446
  for (const entry of readdirSync14(dir, { withFileTypes: true })) {
107099
107447
  if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
107100
107448
  continue;
107101
- const full = path71.join(dir, entry.name);
107449
+ const full = path72.join(dir, entry.name);
107102
107450
  if (entry.isDirectory()) {
107103
107451
  if (!SKIP_DIRS.has(entry.name))
107104
107452
  walkTests(full, out);
@@ -107110,7 +107458,7 @@ function expandPaths(cwd, inputs) {
107110
107458
  const files = [];
107111
107459
  const missing = [];
107112
107460
  for (const input of inputs.length > 0 ? inputs : ["."]) {
107113
- const full = path71.resolve(cwd, input);
107461
+ const full = path72.resolve(cwd, input);
107114
107462
  if (!existsSync28(full))
107115
107463
  missing.push(input);
107116
107464
  else if (statSync10(full).isDirectory())
@@ -107147,11 +107495,11 @@ function changedLines(cwd, base) {
107147
107495
  for (let offset = 0;offset < count; offset += 1)
107148
107496
  lines.add(start + offset);
107149
107497
  }
107150
- changed.set(path71.join(root, file), lines);
107498
+ changed.set(path72.join(root, file), lines);
107151
107499
  }
107152
107500
  const untracked = git7(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
107153
107501
  for (const file of untracked.stdout.split("\x00").filter(Boolean))
107154
- changed.set(path71.join(root, file), "all");
107502
+ changed.set(path72.join(root, file), "all");
107155
107503
  return changed;
107156
107504
  }
107157
107505
  function auditFiles(files, display) {
@@ -107213,7 +107561,7 @@ function auditFiles(files, display) {
107213
107561
  durationMs: Math.round(performance.now() - started)
107214
107562
  };
107215
107563
  }
107216
- var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path71.sep).join("/"), SEVERITY_ORDER, ruleIds;
107564
+ var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path72.sep).join("/"), SEVERITY_ORDER, ruleIds;
107217
107565
  var init_audit = __esm(() => {
107218
107566
  init_ast();
107219
107567
  init_rules();
@@ -107225,7 +107573,7 @@ var init_audit = __esm(() => {
107225
107573
  });
107226
107574
 
107227
107575
  // packages/workit-cli/src/test-audit/mutate.ts
107228
- import { spawn as spawn3 } from "node:child_process";
107576
+ import { spawn as spawn4 } from "node:child_process";
107229
107577
  import {
107230
107578
  existsSync as existsSync29,
107231
107579
  lstatSync as lstatSync9,
@@ -107243,7 +107591,7 @@ import {
107243
107591
  copyFileSync as copyFileSync8
107244
107592
  } from "node:fs";
107245
107593
  import os23 from "node:os";
107246
- import path72 from "node:path";
107594
+ import path73 from "node:path";
107247
107595
  function mutantsFor(source, file, lines) {
107248
107596
  const parsed = parseSource(source, file);
107249
107597
  const out = [];
@@ -107316,7 +107664,7 @@ function relatedTests(source, testFiles) {
107316
107664
  for (const match of text.matchAll(SPECIFIER)) {
107317
107665
  const spec = match[1];
107318
107666
  if (spec.startsWith(".")) {
107319
- if (stripExt(path72.posix.join(path72.posix.dirname(file), spec)) === target)
107667
+ if (stripExt(path73.posix.join(path73.posix.dirname(file), spec)) === target)
107320
107668
  return true;
107321
107669
  } else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
107322
107670
  return true;
@@ -107336,12 +107684,12 @@ function removeStaleCopies(tmp = os23.tmpdir()) {
107336
107684
  for (const name of names) {
107337
107685
  if (!name.startsWith(TEMP_PREFIX))
107338
107686
  continue;
107339
- const dir = path72.join(tmp, name);
107687
+ const dir = path73.join(tmp, name);
107340
107688
  try {
107341
107689
  const stat = lstatSync9(dir);
107342
107690
  if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
107343
107691
  continue;
107344
- const pid = Number(readFileSync30(path72.join(dir, PID_FILE), "utf8"));
107692
+ const pid = Number(readFileSync30(path73.join(dir, PID_FILE), "utf8"));
107345
107693
  if (Number.isInteger(pid) && pid > 0 && alive(pid))
107346
107694
  continue;
107347
107695
  } catch (error) {
@@ -107358,8 +107706,8 @@ function removeStaleCopies(tmp = os23.tmpdir()) {
107358
107706
  function linkNodeModules(origin, target, repo, copy) {
107359
107707
  mkdirSync12(target, { recursive: true });
107360
107708
  for (const entry of readdirSync15(origin, { withFileTypes: true })) {
107361
- const from = path72.join(origin, entry.name);
107362
- const to = path72.join(target, entry.name);
107709
+ const from = path73.join(origin, entry.name);
107710
+ const to = path73.join(target, entry.name);
107363
107711
  if (entry.name.startsWith("@") && entry.isDirectory()) {
107364
107712
  linkNodeModules(from, to, repo, copy);
107365
107713
  continue;
@@ -107375,9 +107723,9 @@ function linkNodeModules(origin, target, repo, copy) {
107375
107723
  } catch {
107376
107724
  continue;
107377
107725
  }
107378
- const relative = path72.relative(repo, real);
107379
- if (!relative.startsWith("..") && !path72.isAbsolute(relative) && !relative.split(path72.sep).includes("node_modules")) {
107380
- symlinkSync(path72.join(copy, relative), to, "junction");
107726
+ const relative = path73.relative(repo, real);
107727
+ if (!relative.startsWith("..") && !path73.isAbsolute(relative) && !relative.split(path73.sep).includes("node_modules")) {
107728
+ symlinkSync(path73.join(copy, relative), to, "junction");
107381
107729
  continue;
107382
107730
  }
107383
107731
  }
@@ -107393,7 +107741,7 @@ function copySymlink(repo, tree, from, to) {
107393
107741
  }
107394
107742
  const realRepo = realpathSync11(repo);
107395
107743
  if (real && inside5(realRepo, real)) {
107396
- symlinkSync(path72.relative(path72.dirname(to), path72.join(tree, path72.relative(realRepo, real))), to);
107744
+ symlinkSync(path73.relative(path73.dirname(to), path73.join(tree, path73.relative(realRepo, real))), to);
107397
107745
  return;
107398
107746
  }
107399
107747
  if (real && statSync11(real).isFile())
@@ -107402,10 +107750,10 @@ function copySymlink(repo, tree, from, to) {
107402
107750
  symlinkSync(readlinkSync3(from), to);
107403
107751
  }
107404
107752
  function writeInside(copy, file, content) {
107405
- const target = path72.join(copy, file);
107753
+ const target = path73.join(copy, file);
107406
107754
  try {
107407
107755
  const stat = lstatSync9(target);
107408
- if (!stat.isFile() || !inside5(realpathSync11(copy), realpathSync11(path72.dirname(target))))
107756
+ if (!stat.isFile() || !inside5(realpathSync11(copy), realpathSync11(path73.dirname(target))))
107409
107757
  return false;
107410
107758
  } catch {
107411
107759
  return false;
@@ -107416,9 +107764,9 @@ function writeInside(copy, file, content) {
107416
107764
  return true;
107417
107765
  }
107418
107766
  function copyWorkingTree(repo) {
107419
- const dir = mkdtempSync4(path72.join(os23.tmpdir(), TEMP_PREFIX));
107420
- writeFileSync13(path72.join(dir, PID_FILE), String(process.pid));
107421
- const tree = path72.join(dir, "tree");
107767
+ const dir = mkdtempSync4(path73.join(os23.tmpdir(), TEMP_PREFIX));
107768
+ writeFileSync13(path73.join(dir, PID_FILE), String(process.pid));
107769
+ const tree = path73.join(dir, "tree");
107422
107770
  const head = git7(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
107423
107771
  if (head && git7(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
107424
107772
  const branch = git7(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
@@ -107435,36 +107783,36 @@ function copyWorkingTree(repo) {
107435
107783
  for (const relative of listed) {
107436
107784
  if (!relative)
107437
107785
  continue;
107438
- const from = path72.join(repo, relative);
107786
+ const from = path73.join(repo, relative);
107439
107787
  let stat;
107440
107788
  try {
107441
107789
  stat = lstatSync9(from);
107442
107790
  } catch {
107443
107791
  continue;
107444
107792
  }
107445
- const to = path72.join(tree, relative);
107446
- mkdirSync12(path72.dirname(to), { recursive: true });
107793
+ const to = path73.join(tree, relative);
107794
+ mkdirSync12(path73.dirname(to), { recursive: true });
107447
107795
  if (stat.isSymbolicLink())
107448
107796
  copySymlink(repo, tree, from, to);
107449
107797
  else if (stat.isFile())
107450
107798
  copyFileSync8(from, to);
107451
- let parent = path72.dirname(relative);
107799
+ let parent = path73.dirname(relative);
107452
107800
  while (parent !== "." && !dirs.has(parent)) {
107453
107801
  dirs.add(parent);
107454
- parent = path72.dirname(parent);
107802
+ parent = path73.dirname(parent);
107455
107803
  }
107456
107804
  }
107457
107805
  for (const parent of dirs) {
107458
- const modules = path72.join(repo, parent, "node_modules");
107459
- if (existsSync29(modules) && !existsSync29(path72.join(tree, parent, "node_modules")))
107460
- linkNodeModules(modules, path72.join(tree, parent, "node_modules"), repo, tree);
107806
+ const modules = path73.join(repo, parent, "node_modules");
107807
+ if (existsSync29(modules) && !existsSync29(path73.join(tree, parent, "node_modules")))
107808
+ linkNodeModules(modules, path73.join(tree, parent, "node_modules"), repo, tree);
107461
107809
  }
107462
107810
  return { dir, tree };
107463
107811
  }
107464
107812
  function runCommand(command, cwd, timeoutMs, env) {
107465
107813
  const started = performance.now();
107466
107814
  return new Promise((resolve) => {
107467
- const child = spawn3(command, {
107815
+ const child = spawn4(command, {
107468
107816
  cwd,
107469
107817
  env,
107470
107818
  shell: true,
@@ -107496,14 +107844,14 @@ async function runMutation(options) {
107496
107844
  const tracked = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
107497
107845
  const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
107498
107846
  try {
107499
- return { file, text: readFileSync30(path72.join(repo, file), "utf8") };
107847
+ return { file, text: readFileSync30(path73.join(repo, file), "utf8") };
107500
107848
  } catch {
107501
107849
  return { file, text: "" };
107502
107850
  }
107503
107851
  });
107504
107852
  const candidates = [];
107505
107853
  for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
107506
- const relative = toPosix(path72.relative(repo, absolute));
107854
+ const relative = toPosix(path73.relative(repo, absolute));
107507
107855
  if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
107508
107856
  continue;
107509
107857
  if (NOT_SOURCE.test(relative) || !existsSync29(absolute))
@@ -107517,9 +107865,9 @@ async function runMutation(options) {
107517
107865
  for (const mutant of mutants)
107518
107866
  if (!related.has(mutant.file))
107519
107867
  related.set(mutant.file, relatedTests(mutant.file, testFiles));
107520
- const cwdRelative = path72.relative(repo, options.cwd);
107868
+ const cwdRelative = path73.relative(repo, options.cwd);
107521
107869
  const asArg = (file) => {
107522
- const relative = toPosix(path72.relative(cwdRelative, file));
107870
+ const relative = toPosix(path73.relative(cwdRelative, file));
107523
107871
  return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
107524
107872
  };
107525
107873
  const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
@@ -107555,7 +107903,7 @@ async function runMutation(options) {
107555
107903
  return finish3(options, 0, results, counts, started);
107556
107904
  removeStaleCopies();
107557
107905
  const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
107558
- const copyCwd = path72.join(copy, cwdRelative);
107906
+ const copyCwd = path73.join(copy, cwdRelative);
107559
107907
  let current = null;
107560
107908
  const restore = () => {
107561
107909
  if (current)
@@ -107590,7 +107938,7 @@ async function runMutation(options) {
107590
107938
  record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
107591
107939
  continue;
107592
107940
  }
107593
- const original = readFileSync30(path72.join(copy, mutant.file), "utf8");
107941
+ const original = readFileSync30(path73.join(copy, mutant.file), "utf8");
107594
107942
  const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
107595
107943
  current = { file: mutant.file, original };
107596
107944
  if (!writeInside(copy, mutant.file, mutated)) {
@@ -107647,8 +107995,8 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
107647
107995
  return error.code === "EPERM";
107648
107996
  }
107649
107997
  }, inside5 = (root, file) => {
107650
- const relative = path72.relative(root, file);
107651
- return relative === "" || !relative.startsWith("..") && !path72.isAbsolute(relative);
107998
+ const relative = path73.relative(root, file);
107999
+ return relative === "" || !relative.startsWith("..") && !path73.isAbsolute(relative);
107652
108000
  }, active, killTree = (child) => {
107653
108001
  try {
107654
108002
  if (child.pid && process.platform !== "win32")
@@ -107697,7 +108045,7 @@ __export(exports_test_audit, {
107697
108045
  run: () => run23
107698
108046
  });
107699
108047
  import { existsSync as existsSync30 } from "node:fs";
107700
- import path73 from "node:path";
108048
+ import path74 from "node:path";
107701
108049
  function parse8(argv) {
107702
108050
  const options = {
107703
108051
  paths: [],
@@ -107802,8 +108150,8 @@ async function run23(argv, io) {
107802
108150
  return emit(io, fail2("invalid_input", `${options}
107803
108151
  usage: ${USAGE16}`));
107804
108152
  const top = git7(io.cwd, ["rev-parse", "--show-toplevel"]);
107805
- const repo = top.ok ? path73.resolve(top.stdout.trim()) : null;
107806
- const display = (file) => toPosix(path73.relative(io.cwd, file) || file);
108153
+ const repo = top.ok ? path74.resolve(top.stdout.trim()) : null;
108154
+ const display = (file) => toPosix(path74.relative(io.cwd, file) || file);
107807
108155
  let base = null;
107808
108156
  let changed = null;
107809
108157
  if (options.diff || options.mutate) {
@@ -107942,7 +108290,7 @@ __export(exports_youtrack, {
107942
108290
  run: () => run25
107943
108291
  });
107944
108292
  import { readFileSync as readFileSync31 } from "node:fs";
107945
- import path74 from "node:path";
108293
+ import path75 from "node:path";
107946
108294
  async function run25(argv, io) {
107947
108295
  const [sub, ...rest] = argv;
107948
108296
  if (sub !== "note" && sub !== "time" && sub !== "meeting")
@@ -107988,7 +108336,7 @@ async function run25(argv, io) {
107988
108336
  let markdown = flags.values.markdown ?? "";
107989
108337
  if (flags.values.file)
107990
108338
  try {
107991
- markdown = readFileSync31(path74.resolve(io.cwd, flags.values.file), "utf8");
108339
+ markdown = readFileSync31(path75.resolve(io.cwd, flags.values.file), "utf8");
107992
108340
  } catch (error) {
107993
108341
  return usage4(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE18);
107994
108342
  }
@@ -108009,7 +108357,7 @@ async function run25(argv, io) {
108009
108357
  }
108010
108358
  const results = [];
108011
108359
  for (const entry of steps) {
108012
- const outcome = await entry.run();
108360
+ const outcome = await progressFor(io).run(entry.label, () => entry.run());
108013
108361
  results.push({
108014
108362
  step: entry.label,
108015
108363
  status: outcome.status,
@@ -108044,6 +108392,7 @@ var USAGE18 = "workit youtrack note <ISSUE> (--markdown <t> | --file <p>) [--min
108044
108392
  }
108045
108393
  };
108046
108394
  var init_youtrack2 = __esm(() => {
108395
+ init_progress();
108047
108396
  init_youtrack();
108048
108397
  init_youtrack_tools();
108049
108398
  init_youtrack_writes();
@@ -108057,7 +108406,7 @@ __export(exports_changelog, {
108057
108406
  run: () => run26
108058
108407
  });
108059
108408
  import { readFileSync as readFileSync32 } from "node:fs";
108060
- import path75 from "node:path";
108409
+ import path76 from "node:path";
108061
108410
  async function run26(argv, io) {
108062
108411
  const [sub, ...rest] = argv;
108063
108412
  if (sub !== "apply")
@@ -108103,7 +108452,7 @@ async function run26(argv, io) {
108103
108452
  ]);
108104
108453
  }
108105
108454
  var USAGE19 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
108106
- const text = raw === "-" ? readFileSync32(0, "utf8") : raw.startsWith("@") ? readFileSync32(path75.resolve(cwd, raw.slice(1)), "utf8") : raw;
108455
+ const text = raw === "-" ? readFileSync32(0, "utf8") : raw.startsWith("@") ? readFileSync32(path76.resolve(cwd, raw.slice(1)), "utf8") : raw;
108107
108456
  return JSON.parse(text);
108108
108457
  };
108109
108458
  var init_changelog2 = __esm(() => {
@@ -108119,7 +108468,7 @@ __export(exports_handoff, {
108119
108468
  run: () => run27
108120
108469
  });
108121
108470
  import fs37 from "node:fs";
108122
- import path76 from "node:path";
108471
+ import path77 from "node:path";
108123
108472
  import { parseArgs as parseArgs2 } from "node:util";
108124
108473
  function render3(brief) {
108125
108474
  const lines = [
@@ -108159,9 +108508,9 @@ function bounded(brief, cwd) {
108159
108508
  let file = null;
108160
108509
  if (store.ok)
108161
108510
  try {
108162
- const dir = path76.join(store.value.root, "handoff");
108511
+ const dir = path77.join(store.value.root, "handoff");
108163
108512
  fs37.mkdirSync(dir, { recursive: true });
108164
- file = path76.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
108513
+ file = path77.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
108165
108514
  fs37.writeFileSync(file, `${[...body, ...tail].join(`
108166
108515
  `)}
108167
108516
  `, {
@@ -108236,7 +108585,7 @@ var init_handoff = __esm(() => {
108236
108585
  });
108237
108586
 
108238
108587
  // packages/workit-cli/src/main.ts
108239
- import path77 from "node:path";
108588
+ import path78 from "node:path";
108240
108589
 
108241
108590
  // packages/workit-core/src/git/env-redirect.ts
108242
108591
  var GIT_REDIRECT_ENV = [
@@ -109185,8 +109534,17 @@ var defaultIo = (json) => ({
109185
109534
  });
109186
109535
  async function main(argv, overrides = {}, options = {}) {
109187
109536
  const parsed = parseGlobals(argv);
109188
- const cwd = path77.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
109189
- const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
109537
+ const cwd = path78.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
109538
+ const io = {
109539
+ ...defaultIo(parsed.json),
109540
+ terminals: {
109541
+ ...overrides.stdout ? {} : { stdout: process.stdout },
109542
+ ...overrides.stderr ? {} : { stderr: process.stderr }
109543
+ },
109544
+ ...overrides,
109545
+ json: parsed.json,
109546
+ cwd
109547
+ };
109190
109548
  if (parsed.error)
109191
109549
  return emit(io, fail2("invalid_input", parsed.error));
109192
109550
  if (parsed.session !== undefined) {