@brainervirus/workit-cli 8.40.8 → 8.41.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +745 -374
  2. package/package.json +3 -3
package/dist/index.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.40.8",
9420
+ version: "8.41.1",
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.40.8",
9458
+ "@brainervirus/workit-cursor": "^8.41.1",
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.40.8"
9464
+ "@brainervirus/workit-core": "^8.41.1"
9465
9465
  },
9466
9466
  engines: {
9467
9467
  node: ">=24"
@@ -66193,7 +66193,7 @@ import path33 from "node:path";
66193
66193
  function hostCommand(name, args, options = {}) {
66194
66194
  const executable = findHostExecutable(name, options);
66195
66195
  if (!executable)
66196
- throw new Error(`${name} executable was not found on PATH or supported user bin directories`);
66196
+ 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
66197
  if (process.platform === "win32" && /\.(?:cmd|bat)$/i.test(executable)) {
66198
66198
  const node = findHostExecutable("node", options);
66199
66199
  if (!node)
@@ -66217,6 +66217,17 @@ function resolveWindowsShimEntry(contents, shim, exists = existsSync13) {
66217
66217
  return null;
66218
66218
  }
66219
66219
  function findHostExecutable(name, options = {}) {
66220
+ if (path33.isAbsolute(name) || name.includes("/") || name.includes("\\")) {
66221
+ try {
66222
+ if (!statSync2(name).isFile())
66223
+ return null;
66224
+ if (process.platform !== "win32")
66225
+ accessSync(name, constants2.X_OK);
66226
+ return name;
66227
+ } catch {
66228
+ return null;
66229
+ }
66230
+ }
66220
66231
  const env = options.env ?? process.env;
66221
66232
  const home = options.home ?? env.HOME ?? os9.homedir();
66222
66233
  const suffixes = process.platform === "win32" ? ["", ".exe", ".cmd", ".bat"] : [""];
@@ -67761,7 +67772,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67761
67772
  return null;
67762
67773
  dir = parent;
67763
67774
  }
67764
- }, listClaudeProcesses = () => {
67775
+ }, listProcessesMatching = (match) => {
67765
67776
  const r = spawnSync16("ps", ["-eo", "pid=,lstart=,args="], {
67766
67777
  encoding: "utf8",
67767
67778
  timeout: 5000
@@ -67772,14 +67783,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67772
67783
  for (const row of r.stdout.split(`
67773
67784
  `)) {
67774
67785
  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]))
67786
+ if (!m || !match(m[3]))
67776
67787
  continue;
67777
67788
  const startedMs = Date.parse(m[2]);
67778
67789
  if (Number.isFinite(startedMs))
67779
67790
  found.push({ pid: Number(m[1]), startedMs, args: m[3] });
67780
67791
  }
67781
67792
  return found;
67782
- }, resolve = (options) => {
67793
+ }, 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
67794
  const env = options.env ?? process.env;
67784
67795
  const home = options.home ?? env.HOME ?? os12.homedir();
67785
67796
  const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path39.join(home, ".config", "workit");
@@ -67807,7 +67818,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67807
67818
  installer: options.installer ?? false,
67808
67819
  cliVersion: options.cliVersion ?? null,
67809
67820
  scopeProbe: options.scopeProbe ?? probeScope,
67810
- claudeProcesses: options.claudeProcesses ?? listClaudeProcesses
67821
+ claudeProcesses: options.claudeProcesses ?? listClaudeProcesses,
67822
+ codexProcesses: options.codexProcesses ?? listCodexProcesses
67811
67823
  };
67812
67824
  }, readJson = (p) => {
67813
67825
  try {
@@ -68563,7 +68575,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
68563
68575
  id: "launcher",
68564
68576
  status: "fail",
68565
68577
  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`
68578
+ 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
68579
  };
68568
68580
  }
68569
68581
  if (!dev && res.host !== "cursor") {
@@ -69804,6 +69816,49 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
69804
69816
  status: "warn",
69805
69817
  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
69818
  };
69819
+ }, checkCodexSessionPlugin = (res) => {
69820
+ const id = "codex_session_plugin";
69821
+ if (process.platform === "win32")
69822
+ return {
69823
+ id,
69824
+ status: "info",
69825
+ detail: "running Codex processes are not checked on Windows"
69826
+ };
69827
+ const installs = codexWorkitInstalls(res).filter((install) => install.root && install.version);
69828
+ const stamped = installs.flatMap((install) => {
69829
+ try {
69830
+ return [{ install, at: statSync6(install.root).mtimeMs }];
69831
+ } catch {
69832
+ return [];
69833
+ }
69834
+ });
69835
+ const latest = stamped.toSorted((a, b) => b.at - a.at)[0];
69836
+ if (!latest)
69837
+ return {
69838
+ id,
69839
+ status: "info",
69840
+ detail: "no Workit Codex plugin install recorded — skipping"
69841
+ };
69842
+ const running = res.codexProcesses();
69843
+ if (running === null)
69844
+ return {
69845
+ id,
69846
+ status: "info",
69847
+ detail: "could not list running codex processes (ps) — skipping"
69848
+ };
69849
+ const stale = running.filter((proc) => proc.startedMs < latest.at);
69850
+ if (stale.length === 0)
69851
+ return {
69852
+ id,
69853
+ status: "info",
69854
+ detail: `${running.length} running codex process(es), none started before Workit ${latest.install.version} was installed`
69855
+ };
69856
+ const rows = stale.map((proc) => `pid ${proc.pid} started ${new Date(proc.startedMs).toISOString()} (${proc.args.slice(0, 60)})`);
69857
+ return {
69858
+ id,
69859
+ status: "warn",
69860
+ detail: `started before Workit ${latest.install.version} was installed: ${rows.join("; ")}; they keep the old plugin until restarted, new Codex sessions load it`
69861
+ };
69807
69862
  }, HOOK_ISSUED_MARKER = "workit-issued-sessions/3", hookRecordsIssued = (root) => {
69808
69863
  let files;
69809
69864
  try {
@@ -70095,6 +70150,7 @@ var init_doctor = __esm(() => {
70095
70150
  checkOpencodeVersion,
70096
70151
  checkClaudePlugin,
70097
70152
  checkClaudeSessionPlugin,
70153
+ checkCodexSessionPlugin,
70098
70154
  checkHookIssuedSessions,
70099
70155
  checkWorkitOnPath,
70100
70156
  checkAssets,
@@ -75218,38 +75274,204 @@ var init_setup2 = __esm(() => {
75218
75274
  ALL_HOSTS = ["claude-code", "codex", "cursor", "opencode", "pi"];
75219
75275
  });
75220
75276
 
75277
+ // packages/workit-cli/src/progress.ts
75278
+ import { spawn } from "node:child_process";
75279
+ import path44 from "node:path";
75280
+ function createProgress(options = {}) {
75281
+ const env = options.env ?? process.env;
75282
+ const mode = modeFor(options, env);
75283
+ const stream = options.stream;
75284
+ const now = options.now ?? Date.now;
75285
+ const every = options.setInterval ?? ((tick, ms) => setInterval(tick, ms));
75286
+ const stop = options.clearInterval ?? ((timer) => clearInterval(timer));
75287
+ const proc = options.proc ?? process;
75288
+ const ascii = env.TERM === "dumb";
75289
+ const glyphs = mode === "spinner" ? { done: "\x1B[32m✓\x1B[0m", failed: "\x1B[31m✗\x1B[0m", skipped: "–" } : ascii ? { done: "ok", failed: "x", skipped: "-" } : { done: "✓", failed: "✗", skipped: "–" };
75290
+ const start = (initial) => {
75291
+ if (mode === "off" || !stream)
75292
+ return NOOP_STEP;
75293
+ let text = initial;
75294
+ let finished = false;
75295
+ const began = now();
75296
+ let frame = 0;
75297
+ const draw = () => {
75298
+ const seconds = Math.floor((now() - began) / 1000);
75299
+ let line = `${FRAMES[frame % FRAMES.length]} ${text} (${seconds}s)`;
75300
+ if (stream.columns && line.length >= stream.columns)
75301
+ line = `${line.slice(0, Math.max(1, stream.columns - 2))}…`;
75302
+ stream.write(`${CLEAR}${line}`);
75303
+ };
75304
+ let timer;
75305
+ if (mode === "spinner") {
75306
+ draw();
75307
+ timer = every(() => {
75308
+ frame += 1;
75309
+ draw();
75310
+ }, FRAME_MS);
75311
+ }
75312
+ const handlers = [];
75313
+ const release = () => {
75314
+ for (const [event, handler] of handlers)
75315
+ proc.off(event, handler);
75316
+ handlers.length = 0;
75317
+ };
75318
+ if (mode === "spinner") {
75319
+ const onSignal = (signal) => () => {
75320
+ if (!finished) {
75321
+ finished = true;
75322
+ if (timer !== undefined)
75323
+ stop(timer);
75324
+ stream.write(CLEAR);
75325
+ }
75326
+ release();
75327
+ proc.kill(proc.pid, signal);
75328
+ };
75329
+ const onExit = () => {
75330
+ if (!finished)
75331
+ stream.write(CLEAR);
75332
+ };
75333
+ handlers.push(["SIGINT", onSignal("SIGINT")], ["SIGTERM", onSignal("SIGTERM")]);
75334
+ handlers.push(["exit", onExit]);
75335
+ for (const [event, handler] of handlers)
75336
+ proc.on(event, handler);
75337
+ }
75338
+ return {
75339
+ label: (next) => {
75340
+ text = next;
75341
+ if (mode === "spinner" && !finished)
75342
+ draw();
75343
+ },
75344
+ end: (status, note) => {
75345
+ if (finished)
75346
+ return;
75347
+ finished = true;
75348
+ if (timer !== undefined)
75349
+ stop(timer);
75350
+ release();
75351
+ stream.write(`${mode === "spinner" ? CLEAR : ""}${glyphs[status]} ${text}${note ? `: ${note}` : ""}
75352
+ `);
75353
+ }
75354
+ };
75355
+ };
75356
+ return {
75357
+ mode,
75358
+ start,
75359
+ async run(label, fn, classify) {
75360
+ const step = start(label);
75361
+ try {
75362
+ const value = await fn();
75363
+ step.end(classify ? classify(value) : "done");
75364
+ return value;
75365
+ } catch (error) {
75366
+ step.end("failed");
75367
+ throw error;
75368
+ }
75369
+ },
75370
+ runSync(label, fn, classify) {
75371
+ const step = start(label);
75372
+ const ticker = mode === "spinner" && stream ? (options.spawnTicker ?? ((text, began) => defaultTicker(text, began, stream)))(label, now()) : undefined;
75373
+ try {
75374
+ const value = fn();
75375
+ ticker?.stop();
75376
+ step.end(classify ? classify(value) : "done");
75377
+ return value;
75378
+ } catch (error) {
75379
+ ticker?.stop();
75380
+ step.end("failed");
75381
+ throw error;
75382
+ }
75383
+ }
75384
+ };
75385
+ }
75386
+ var FRAMES, FRAME_MS = 120, CLEAR = "\r\x1B[2K", TICKER_SOURCE, defaultTicker = (label, began, stream) => {
75387
+ if (stream !== process.stderr)
75388
+ return;
75389
+ if (!/^(?:node|nodejs|bun)(?:\.exe)?$/i.test(path44.basename(process.execPath)))
75390
+ return;
75391
+ try {
75392
+ const child = spawn(process.execPath, ["-e", TICKER_SOURCE], {
75393
+ env: {
75394
+ ...process.env,
75395
+ WORKIT_TICK_LABEL: label,
75396
+ WORKIT_TICK_BEGAN: String(began),
75397
+ WORKIT_TICK_COLS: String(stream.columns ?? 0)
75398
+ },
75399
+ stdio: ["ignore", "ignore", "inherit"],
75400
+ windowsHide: true
75401
+ });
75402
+ child.on("error", () => {});
75403
+ child.unref();
75404
+ return { stop: () => void child.kill("SIGKILL") };
75405
+ } catch {
75406
+ return;
75407
+ }
75408
+ }, truthy = (value) => value !== undefined && value !== "" && value !== "0" && value.toLowerCase() !== "false", modeFor = (options, env) => {
75409
+ if (options.json || !options.stream?.isTTY || truthy(env.CI))
75410
+ return "off";
75411
+ if (truthy(env.NO_COLOR) || env.TERM === "dumb")
75412
+ return "plain";
75413
+ return "spinner";
75414
+ }, NOOP_STEP;
75415
+ var init_progress = __esm(() => {
75416
+ FRAMES = ["·", "✢", "✳", "∗", "✻", "✽"];
75417
+ TICKER_SOURCE = `
75418
+ const frames = ${JSON.stringify(FRAMES)};
75419
+ const { WORKIT_TICK_LABEL: label, WORKIT_TICK_BEGAN: began, WORKIT_TICK_COLS: cols } = process.env;
75420
+ const parent = process.ppid;
75421
+ let frame = 0;
75422
+ const timer = setInterval(() => {
75423
+ let alive = process.ppid === parent;
75424
+ if (alive) try { process.kill(parent, 0); } catch { alive = false; }
75425
+ if (!alive || Date.now() - Number(began) > 600000) process.exit(0);
75426
+ frame += 1;
75427
+ const seconds = Math.floor((Date.now() - Number(began)) / 1000);
75428
+ let line = frames[frame % frames.length] + " " + label + " (" + seconds + "s)";
75429
+ if (Number(cols) && line.length >= Number(cols)) line = line.slice(0, Math.max(1, Number(cols) - 2)) + "…";
75430
+ process.stderr.write(${JSON.stringify(CLEAR)} + line);
75431
+ }, ${FRAME_MS});
75432
+ `;
75433
+ NOOP_STEP = { label: () => {}, end: () => {} };
75434
+ });
75435
+
75221
75436
  // packages/workit-cli/src/upgrade/shared.ts
75437
+ import { spawn as spawn2 } from "node:child_process";
75222
75438
  import { existsSync as existsSync21, readFileSync as readFileSync22 } from "node:fs";
75223
- import path44 from "node:path";
75439
+ import path45 from "node:path";
75224
75440
  import os16 from "node:os";
75225
75441
  import { createHash as createHash15 } from "node:crypto";
75226
- 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) => {
75442
+ function errorText(error) {
75443
+ return error instanceof Error ? error.message : "installed source could not be read";
75444
+ }
75445
+ 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) => {
75446
+ const tail = stderrTail(result.stderr);
75447
+ return `\`${command.command} ${command.args.join(" ")}\` failed${tail ? `: ${tail}` : ""}`;
75448
+ }, 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) => {
75227
75449
  const home = deps.home ?? deps.env?.HOME ?? os16.homedir();
75228
75450
  const env = {
75229
75451
  ...process.env,
75230
75452
  ...deps.home || deps.env?.HOME ? {
75231
75453
  HOME: home,
75232
- CODEX_HOME: path44.join(home, ".codex"),
75233
- CLAUDE_CONFIG_DIR: path44.join(home, ".claude"),
75234
- PI_CODING_AGENT_DIR: path44.join(home, ".pi/agent"),
75235
- XDG_CONFIG_HOME: path44.join(home, ".config"),
75454
+ CODEX_HOME: path45.join(home, ".codex"),
75455
+ CLAUDE_CONFIG_DIR: path45.join(home, ".claude"),
75456
+ PI_CODING_AGENT_DIR: path45.join(home, ".pi/agent"),
75457
+ XDG_CONFIG_HOME: path45.join(home, ".config"),
75236
75458
  WORKFLOW_TOOLKIT_CONFIG: undefined,
75237
75459
  WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
75238
75460
  } : {},
75239
75461
  ...deps.env,
75240
75462
  HOME: home
75241
75463
  };
75242
- const xdg = env.XDG_CONFIG_HOME || path44.join(home, ".config");
75243
- const codexHome = env.CODEX_HOME ?? path44.join(home, ".codex");
75464
+ const xdg = env.XDG_CONFIG_HOME || path45.join(home, ".config");
75465
+ const codexHome = env.CODEX_HOME ?? path45.join(home, ".codex");
75244
75466
  return {
75245
75467
  home,
75246
75468
  env,
75247
- configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path44.join(xdg, "workit"),
75248
- opencodeConfig: path44.join(xdg, "opencode/opencode.json"),
75249
- piSettings: path44.join(env.PI_CODING_AGENT_DIR ?? path44.join(home, ".pi/agent"), "settings.json"),
75469
+ configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path45.join(xdg, "workit"),
75470
+ opencodeConfig: path45.join(xdg, "opencode/opencode.json"),
75471
+ piSettings: path45.join(env.PI_CODING_AGENT_DIR ?? path45.join(home, ".pi/agent"), "settings.json"),
75250
75472
  codexHome,
75251
- codexConfig: path44.join(codexHome, "config.toml"),
75252
- cursorRoot: path44.join(home, ".cursor/plugins/local/workit")
75473
+ codexConfig: path45.join(codexHome, "config.toml"),
75474
+ cursorRoot: path45.join(home, ".cursor/plugins/local/workit")
75253
75475
  };
75254
75476
  }, object2 = (file) => {
75255
75477
  if (!existsSync21(file))
@@ -75274,17 +75496,81 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75274
75496
  let step;
75275
75497
  try {
75276
75498
  step = hostCommand(command, args, { home, env });
75277
- } catch {
75278
- return { status: 1, stdout: "" };
75499
+ } catch (error) {
75500
+ return { status: 1, stdout: "", stderr: errorText(error) };
75279
75501
  }
75280
75502
  const result = runHostCommand(step, { home, env });
75281
- return { status: result.exitCode, stdout: result.stdout };
75282
- }), errorText = (error) => error instanceof Error ? error.message : "installed source could not be read", piInstalledVersion = (listing, selector) => {
75503
+ return { status: result.exitCode, stdout: result.stdout, stderr: result.stderr };
75504
+ }), COMMAND_TIMEOUT_MS = 60000, asyncRunner = (deps) => {
75505
+ if (deps.runAsync)
75506
+ return deps.runAsync;
75507
+ const injected = deps.run;
75508
+ if (injected)
75509
+ return async (command, args) => injected(command, args);
75510
+ return (command, args) => {
75511
+ const { home, env } = upgradePaths(deps);
75512
+ let step;
75513
+ try {
75514
+ step = hostCommand(command, args, { home, env });
75515
+ } catch (error) {
75516
+ return Promise.resolve({ status: 1, stdout: "", stderr: errorText(error) });
75517
+ }
75518
+ if (process.platform === "win32" && /\.(?:cmd|bat)$/i.test(step.command))
75519
+ return Promise.resolve({
75520
+ status: 1,
75521
+ stdout: "",
75522
+ stderr: `Cannot safely execute batch shim ${step.command}`
75523
+ });
75524
+ const childEnv = { ...process.env, ...env, HOME: home };
75525
+ childEnv.CODEX_HOME = env.CODEX_HOME ?? path45.join(home, ".codex");
75526
+ childEnv.PI_CODING_AGENT_DIR = env.PI_CODING_AGENT_DIR ?? path45.join(home, ".pi", "agent");
75527
+ childEnv.CLAUDE_CONFIG_DIR = env.CLAUDE_CONFIG_DIR ?? path45.join(home, ".claude");
75528
+ childEnv.XDG_CONFIG_HOME = env.XDG_CONFIG_HOME ?? path45.join(home, ".config");
75529
+ return new Promise((resolve) => {
75530
+ let stdout = "";
75531
+ let stderr = "";
75532
+ let settled = false;
75533
+ const finish = (status) => {
75534
+ if (settled)
75535
+ return;
75536
+ settled = true;
75537
+ clearTimeout(timer);
75538
+ resolve({ status, stdout, stderr });
75539
+ };
75540
+ let child;
75541
+ try {
75542
+ child = spawn2(step.command, step.args, {
75543
+ cwd: step.cwd,
75544
+ env: childEnv,
75545
+ stdio: ["ignore", "pipe", "pipe"],
75546
+ windowsHide: true,
75547
+ shell: false
75548
+ });
75549
+ } catch (error) {
75550
+ resolve({ status: 1, stdout: "", stderr: errorText(error) });
75551
+ return;
75552
+ }
75553
+ const timer = setTimeout(() => {
75554
+ child.kill("SIGKILL");
75555
+ finish(1);
75556
+ }, COMMAND_TIMEOUT_MS);
75557
+ child.stdout?.setEncoding("utf8");
75558
+ child.stdout?.on("data", (chunk) => stdout += chunk);
75559
+ child.stderr?.setEncoding("utf8");
75560
+ child.stderr?.on("data", (chunk) => stderr = (stderr + chunk).slice(-4000));
75561
+ child.on("error", (error) => {
75562
+ stderr += error.message;
75563
+ finish(1);
75564
+ });
75565
+ child.on("close", (code) => finish(code ?? 1));
75566
+ });
75567
+ };
75568
+ }, piInstalledVersion = (listing, selector) => {
75283
75569
  const lines = listing.split(/\r?\n/).map((line) => line.trim());
75284
75570
  const index = lines.indexOf(selector);
75285
- if (index < 0 || !lines[index + 1] || !path44.isAbsolute(lines[index + 1]))
75571
+ if (index < 0 || !lines[index + 1] || !path45.isAbsolute(lines[index + 1]))
75286
75572
  return;
75287
- const found = objectOrNull(path44.join(lines[index + 1], "package.json"));
75573
+ const found = objectOrNull(path45.join(lines[index + 1], "package.json"));
75288
75574
  return found?.name === "@brainervirus/workit-pi" ? found.version : undefined;
75289
75575
  }, versionAtLeast = (installed, latest) => {
75290
75576
  if (!/^\d+\.\d+\.\d+$/.test(installed))
@@ -75310,12 +75596,12 @@ var init_shared = __esm(() => {
75310
75596
  });
75311
75597
 
75312
75598
  // packages/workit-cli/src/upgrade/processes.ts
75313
- import path45 from "node:path";
75599
+ import path46 from "node:path";
75314
75600
  var PROCESS_HOSTS, SCRIPT_RUNTIMES, classifyProcess = (proc) => {
75315
75601
  if (proc.state.startsWith("Z") || proc.args.includes("<defunct>"))
75316
75602
  return null;
75317
75603
  const argv0 = proc.args.trim().split(/\s+/)[0] ?? "";
75318
- const baseName = (value) => path45.basename(value.replaceAll("\\", "/")).replace(/^\[|\]$/g, "").replace(/\.exe$/i, "").toLowerCase();
75604
+ const baseName = (value) => path46.basename(value.replaceAll("\\", "/")).replace(/^\[|\]$/g, "").replace(/\.exe$/i, "").toLowerCase();
75319
75605
  let host = PROCESS_HOSTS[baseName(argv0)];
75320
75606
  if (!host && SCRIPT_RUNTIMES.has(baseName(argv0))) {
75321
75607
  const script = proc.args.trim().split(/\s+/).slice(1).find((arg) => !arg.startsWith("-"));
@@ -75366,9 +75652,9 @@ var init_processes = __esm(() => {
75366
75652
 
75367
75653
  // packages/workit-cli/src/upgrade/apply.ts
75368
75654
  import { existsSync as existsSync22, readdirSync as readdirSync12, mkdirSync as mkdirSync11, copyFileSync as copyFileSync6, chmodSync as chmodSync2, cpSync as cpSync5 } from "node:fs";
75369
- import path46 from "node:path";
75655
+ import path47 from "node:path";
75370
75656
  import { createHash as createHash16 } from "node:crypto";
75371
- function applyUpgrade(plan, deps = {}) {
75657
+ async function applyUpgrade(plan, deps = {}) {
75372
75658
  const hosts = [...plan.failed];
75373
75659
  const done = (backup) => {
75374
75660
  const failures = hosts.filter((entry) => entry.status === "failed");
@@ -75401,11 +75687,11 @@ function applyUpgrade(plan, deps = {}) {
75401
75687
  };
75402
75688
  const paths = upgradePaths(deps);
75403
75689
  const { home, configDir } = paths;
75404
- const backup = path46.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
75690
+ const backup = path47.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
75405
75691
  mkdirSync11(backup, { recursive: true, mode: 448 });
75406
75692
  for (const file of Object.keys(plan.configDigests))
75407
75693
  if (existsSync22(file)) {
75408
- const target = path46.join(backup, createHash16("sha256").update(file).digest("hex").slice(0, 12) + "-" + path46.basename(file));
75694
+ const target = path47.join(backup, createHash16("sha256").update(file).digest("hex").slice(0, 12) + "-" + path47.basename(file));
75409
75695
  copyFileSync6(file, target);
75410
75696
  chmodSync2(target, 384);
75411
75697
  }
@@ -75422,11 +75708,13 @@ function applyUpgrade(plan, deps = {}) {
75422
75708
  writeFileAtomic(migration.file, JSON.stringify(value, null, 2) + `
75423
75709
  `, 384);
75424
75710
  }
75425
- const run = runner(deps);
75711
+ const runAsync = asyncRunner(deps);
75712
+ const progress = deps.progress ?? createProgress({ json: true });
75713
+ const statusOf = (outcome) => outcome?.status === "failed" ? "failed" : outcome?.status === "updated" ? "done" : "skipped";
75426
75714
  let cursorBackupError = null;
75427
75715
  if (plan.entries.some((entry) => entry.host === "cursor") && existsSync22(paths.cursorRoot))
75428
75716
  try {
75429
- cpSync5(paths.cursorRoot, path46.join(backup, "cursor-package"), {
75717
+ cpSync5(paths.cursorRoot, path47.join(backup, "cursor-package"), {
75430
75718
  recursive: true
75431
75719
  });
75432
75720
  } catch (error) {
@@ -75435,96 +75723,107 @@ function applyUpgrade(plan, deps = {}) {
75435
75723
  const listed = plan.entries.length ? listProcesses(deps) : [];
75436
75724
  const running = (listed ?? []).flatMap((entry) => classifyProcess(entry) ?? []);
75437
75725
  for (const entry of plan.entries) {
75438
- if (entry.host === "cursor" && cursorBackupError) {
75439
- hosts.push({
75440
- host: "cursor",
75441
- status: "failed",
75442
- reason: cursorBackupError,
75443
- fix: entry.fix
75444
- });
75445
- continue;
75446
- }
75447
- if (!LIVE_HOSTS.has(entry.host)) {
75448
- if (listed === null) {
75726
+ const before = hosts.length;
75727
+ const step = progress.start(`Updating ${entry.host}`);
75728
+ try {
75729
+ if (entry.host === "cursor" && cursorBackupError) {
75449
75730
  hosts.push({
75450
- host: entry.host,
75451
- status: "skipped",
75452
- reason: `running processes could not be listed; close ${entry.host} and rerun`,
75453
- fix: `workit upgrade --hosts=${entry.host}`
75731
+ host: "cursor",
75732
+ status: "failed",
75733
+ reason: cursorBackupError,
75734
+ fix: entry.fix
75454
75735
  });
75455
75736
  continue;
75456
75737
  }
75457
- const sessions = running.filter((proc) => proc.host === entry.host && proc.kind === "session");
75458
- if (sessions.length) {
75738
+ if (!LIVE_HOSTS.has(entry.host)) {
75739
+ if (listed === null) {
75740
+ hosts.push({
75741
+ host: entry.host,
75742
+ status: "skipped",
75743
+ reason: `running processes could not be listed; close ${entry.host} and rerun`,
75744
+ fix: `workit upgrade --hosts=${entry.host}`
75745
+ });
75746
+ continue;
75747
+ }
75748
+ const sessions = running.filter((proc) => proc.host === entry.host && proc.kind === "session");
75749
+ if (sessions.length) {
75750
+ hosts.push({
75751
+ host: entry.host,
75752
+ status: "skipped",
75753
+ reason: `close ${entry.host} (${sessions.map(describe2).join("; ")}), then rerun`,
75754
+ fix: `workit upgrade --hosts=${entry.host}`
75755
+ });
75756
+ continue;
75757
+ }
75758
+ }
75759
+ const daemons = running.filter((proc) => proc.host === "codex" && proc.kind === "daemon");
75760
+ const stopDaemon = entry.host === "codex" && daemons.length > 0;
75761
+ const stopped = stopDaemon ? await progress.run("Stopping the Codex app-server daemon", () => runAsync("codex", ["app-server", "daemon", "stop"]), (result) => result.status === 0 ? "done" : "failed") : null;
75762
+ if (stopped && stopped.status !== 0) {
75459
75763
  hosts.push({
75460
- host: entry.host,
75461
- status: "skipped",
75462
- reason: `close ${entry.host} (${sessions.map(describe2).join("; ")}), then rerun`,
75463
- fix: `workit upgrade --hosts=${entry.host}`
75764
+ host: "codex",
75765
+ status: "failed",
75766
+ reason: `could not stop the Codex app-server daemon (${daemons.map(describe2).join("; ")})${stderrTail(stopped.stderr) ? `: ${stderrTail(stopped.stderr)}` : ""}`,
75767
+ fix: "codex app-server daemon stop && workit upgrade --hosts=codex"
75464
75768
  });
75465
75769
  continue;
75466
75770
  }
75467
- }
75468
- const daemons = running.filter((proc) => proc.host === "codex" && proc.kind === "daemon");
75469
- const stopDaemon = entry.host === "codex" && daemons.length > 0;
75470
- if (stopDaemon && run("codex", ["app-server", "daemon", "stop"]).status !== 0) {
75471
- hosts.push({
75472
- host: "codex",
75473
- status: "failed",
75474
- reason: `could not stop the Codex app-server daemon (${daemons.map(describe2).join("; ")})`,
75475
- fix: "codex app-server daemon stop && workit upgrade --hosts=codex"
75476
- });
75477
- continue;
75478
- }
75479
- let outcome;
75480
- try {
75481
- outcome = applyEntry(entry, { run, paths, configDir });
75482
- if (entry.host === "codex" && outcome.status === "updated") {
75483
- const agents = refreshCodexAgents(run, paths.codexHome);
75484
- if (!agents.ok)
75771
+ let outcome;
75772
+ try {
75773
+ outcome = await applyEntry(entry, { runAsync, paths, configDir });
75774
+ if (entry.host === "codex" && outcome.status === "updated") {
75775
+ const agents = await refreshCodexAgents(runAsync, paths.codexHome);
75776
+ if (!agents.ok)
75777
+ outcome = {
75778
+ ...outcome,
75779
+ status: "failed",
75780
+ reason: `${outcome.reason}; ${agents.note}`,
75781
+ fix: agents.fix
75782
+ };
75783
+ else if (agents.note)
75784
+ outcome = {
75785
+ ...outcome,
75786
+ reason: `${outcome.reason}; ${agents.note}`
75787
+ };
75788
+ }
75789
+ } catch (error) {
75790
+ outcome = {
75791
+ host: entry.host,
75792
+ status: "failed",
75793
+ reason: errorText(error),
75794
+ fix: entry.fix
75795
+ };
75796
+ }
75797
+ if (stopDaemon) {
75798
+ const started = (await progress.run("Restarting the Codex app-server daemon", () => runAsync("codex", ["app-server", "daemon", "start"]), (result) => result.status === 0 ? "done" : "failed")).status === 0;
75799
+ outcome = started ? {
75800
+ ...outcome,
75801
+ reason: `${outcome.reason}; app-server daemon stopped and started again`
75802
+ } : {
75803
+ ...outcome,
75804
+ status: "failed",
75805
+ reason: `${outcome.reason}; the app-server daemon did not start again`,
75806
+ fix: "codex app-server daemon start"
75807
+ };
75808
+ }
75809
+ if (entry.host === "opencode") {
75810
+ const servers = running.filter((proc) => proc.host === "opencode" && proc.kind === "daemon");
75811
+ if (servers.length && outcome.status === "updated")
75485
75812
  outcome = {
75486
75813
  ...outcome,
75487
- status: "failed",
75488
- reason: `${outcome.reason}; ${agents.note}`,
75489
- fix: agents.fix
75814
+ reason: `${outcome.reason}; restart opencode serve (${servers.map(describe2).join("; ")}) to load it`
75490
75815
  };
75491
- else if (agents.note)
75492
- outcome = { ...outcome, reason: `${outcome.reason}; ${agents.note}` };
75493
75816
  }
75494
- } catch (error) {
75495
- outcome = {
75496
- host: entry.host,
75497
- status: "failed",
75498
- reason: errorText(error),
75499
- fix: entry.fix
75500
- };
75501
- }
75502
- if (stopDaemon) {
75503
- const started = run("codex", ["app-server", "daemon", "start"]).status === 0;
75504
- outcome = started ? {
75505
- ...outcome,
75506
- reason: `${outcome.reason}; app-server daemon stopped and started again`
75507
- } : {
75508
- ...outcome,
75509
- status: "failed",
75510
- reason: `${outcome.reason}; the app-server daemon did not start again`,
75511
- fix: "codex app-server daemon start"
75512
- };
75513
- }
75514
- if (entry.host === "opencode") {
75515
- const servers = running.filter((proc) => proc.host === "opencode" && proc.kind === "daemon");
75516
- if (servers.length && outcome.status === "updated")
75517
- outcome = {
75518
- ...outcome,
75519
- reason: `${outcome.reason}; restart opencode serve (${servers.map(describe2).join("; ")}) to load it`
75520
- };
75817
+ hosts.push(outcome);
75818
+ } finally {
75819
+ const added = hosts.length > before ? hosts[hosts.length - 1] : undefined;
75820
+ step.end(statusOf(added), added && added.status !== "updated" ? added.reason : undefined);
75521
75821
  }
75522
- hosts.push(outcome);
75523
75822
  }
75524
75823
  if (hosts.some((entry) => entry.host === "codex" && entry.status === "current")) {
75525
75824
  let agents;
75526
75825
  try {
75527
- agents = refreshCodexAgents(run, paths.codexHome);
75826
+ agents = await refreshCodexAgents(runAsync, paths.codexHome);
75528
75827
  } catch (error) {
75529
75828
  agents = {
75530
75829
  ok: false,
@@ -75548,7 +75847,7 @@ function applyUpgrade(plan, deps = {}) {
75548
75847
  }
75549
75848
  if (plan.cli)
75550
75849
  try {
75551
- hosts.push(applyCli(plan.cli, run, backup));
75850
+ hosts.push(await progress.run("Updating the CLI", () => applyCli(plan.cli, runAsync, backup), statusOf));
75552
75851
  } catch (error) {
75553
75852
  hosts.push({
75554
75853
  host: "cli",
@@ -75559,8 +75858,11 @@ function applyUpgrade(plan, deps = {}) {
75559
75858
  }
75560
75859
  return done(backup);
75561
75860
  }
75562
- var codexPluginRoot = (codexHome) => {
75563
- const dir = path46.join(codexHome, "plugins", "cache", CODEX_MARKETPLACE, "workit");
75861
+ var briefDetail = (detail) => {
75862
+ const lines = detail.split(/\r?\n/).filter((line) => line.trim());
75863
+ return (lines.length > 6 ? [lines[0], ...lines.slice(-5)] : lines).join(" | ");
75864
+ }, codexPluginRoot = (codexHome) => {
75865
+ const dir = path47.join(codexHome, "plugins", "cache", CODEX_MARKETPLACE, "workit");
75564
75866
  let versions = [];
75565
75867
  try {
75566
75868
  versions = readdirSync12(dir).filter((version) => /^\d+\.\d+\.\d+$/.test(version));
@@ -75568,9 +75870,9 @@ var codexPluginRoot = (codexHome) => {
75568
75870
  return null;
75569
75871
  }
75570
75872
  const newest = versions.reduce((best, version) => best && versionAtLeast(best, version) ? best : version, null);
75571
- return newest ? path46.join(dir, newest) : null;
75572
- }, opencodeVersion = (run) => {
75573
- const listing = run("opencode", ["plugin", "list"]);
75873
+ return newest ? path47.join(dir, newest) : null;
75874
+ }, opencodeVersion = async (run) => {
75875
+ const listing = await run("opencode", ["plugin", "list"]);
75574
75876
  if (listing.status !== 0)
75575
75877
  return;
75576
75878
  for (const line of listing.stdout.split(/\r?\n/)) {
@@ -75583,8 +75885,8 @@ var codexPluginRoot = (codexHome) => {
75583
75885
  return version;
75584
75886
  }
75585
75887
  return;
75586
- }, applyEntry = (entry, context) => {
75587
- const { run, paths, configDir } = context;
75888
+ }, applyEntry = async (entry, context) => {
75889
+ const { runAsync, paths, configDir } = context;
75588
75890
  const { home, env } = paths;
75589
75891
  const fail = (reason) => ({
75590
75892
  host: entry.host,
@@ -75593,6 +75895,30 @@ var codexPluginRoot = (codexHome) => {
75593
75895
  fix: entry.fix
75594
75896
  });
75595
75897
  if (entry.host === "cursor") {
75898
+ const commands = entry.commands.map((command) => ({
75899
+ ...command,
75900
+ purpose: command.purpose ?? "Upgrade Cursor"
75901
+ }));
75902
+ const recorded = new Map;
75903
+ let history = "";
75904
+ for (const command of commands) {
75905
+ if (command.skipWhenOutputIncludes && history.includes(command.skipWhenOutputIncludes))
75906
+ continue;
75907
+ const outcome = await runAsync(command.command, command.args);
75908
+ const result = {
75909
+ exitCode: outcome.status ?? 1,
75910
+ stdout: outcome.stdout,
75911
+ stderr: outcome.stderr ?? ""
75912
+ };
75913
+ recorded.set(command, result);
75914
+ history += `
75915
+ ${result.stdout}
75916
+ ${result.stderr}`;
75917
+ if (result.exitCode !== 0)
75918
+ break;
75919
+ }
75920
+ const cursorSettings = path47.join(home, ".cursor", "settings.json");
75921
+ const cursorMcp = path47.join(home, ".cursor", "mcp.json");
75596
75922
  const preview = {
75597
75923
  ok: true,
75598
75924
  blocked: [],
@@ -75604,13 +75930,12 @@ var codexPluginRoot = (codexHome) => {
75604
75930
  {
75605
75931
  type: "install-host",
75606
75932
  platform: "cursor",
75607
- path: path46.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
75608
- commands: entry.commands.map((command) => ({
75609
- ...command,
75610
- purpose: command.purpose ?? "Upgrade Cursor"
75611
- }))
75933
+ path: path47.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
75934
+ commands
75612
75935
  },
75613
- { type: "install-adapter", platform: "cursor", path: paths.cursorRoot }
75936
+ { type: "install-adapter", platform: "cursor", path: paths.cursorRoot },
75937
+ { type: "register-platform", platform: "cursor", path: cursorSettings },
75938
+ { type: "register-platform", platform: "cursor", path: cursorMcp }
75614
75939
  ]
75615
75940
  };
75616
75941
  const result = applySetupPreview(preview, {
@@ -75618,16 +75943,16 @@ var codexPluginRoot = (codexHome) => {
75618
75943
  env,
75619
75944
  cwd: home,
75620
75945
  preferInstalledAdapter: true,
75621
- runHostCommand: (command) => {
75622
- const outcome = run(command.command, command.args);
75623
- return {
75624
- exitCode: outcome.status ?? 1,
75625
- stdout: outcome.stdout,
75626
- stderr: ""
75627
- };
75946
+ runHostCommand: (command) => recorded.get(command) ?? {
75947
+ exitCode: 1,
75948
+ stdout: "",
75949
+ stderr: "command did not run"
75628
75950
  }
75629
75951
  });
75630
- const installed = objectOrNull(path46.join(paths.cursorRoot, "package.json"));
75952
+ const installed = objectOrNull(path47.join(paths.cursorRoot, "package.json"));
75953
+ const problems = result.entries.filter((one) => one.status === "Failed").map((one) => one.detail ?? `${one.file} failed`);
75954
+ if (problems.length)
75955
+ return fail(`Cursor install failed: ${problems.map(briefDetail).join("; ")}`);
75631
75956
  if (!result.ok || installed?.version !== entry.latest)
75632
75957
  return fail("Cursor install did not verify the requested package version; inspect the installer before retrying");
75633
75958
  return {
@@ -75636,12 +75961,16 @@ var codexPluginRoot = (codexHome) => {
75636
75961
  reason: entry.repair ? `reinstalled missing plugin files (${entry.latest})` : `${entry.installedVersion ?? "?"} -> ${entry.latest}`
75637
75962
  };
75638
75963
  }
75639
- const before = entry.host === "opencode" ? opencodeVersion(run) : undefined;
75640
- for (const command of entry.commands)
75641
- if (run(command.command, command.args).status !== 0)
75642
- return fail(`\`${command.command} ${command.args.join(" ")}\` failed`);
75964
+ const before = entry.host === "opencode" ? await opencodeVersion(runAsync) : undefined;
75965
+ for (const command of entry.commands) {
75966
+ let result = await runAsync(command.command, command.args);
75967
+ if (result.status !== 0 && entry.host === "opencode")
75968
+ result = await runAsync(command.command, command.args);
75969
+ if (result.status !== 0)
75970
+ return fail(failureReason(command, result));
75971
+ }
75643
75972
  if (entry.host === "opencode") {
75644
- const after = opencodeVersion(run);
75973
+ const after = await opencodeVersion(runAsync);
75645
75974
  if (before && after)
75646
75975
  return after === before ? {
75647
75976
  host: "opencode",
@@ -75670,9 +75999,9 @@ var codexPluginRoot = (codexHome) => {
75670
75999
  reason: `${entry.installedVersion ?? "?"} -> ${after ?? "?"}; new sessions load it`
75671
76000
  };
75672
76001
  }
75673
- const verify = entry.host === "codex" ? run("codex", ["plugin", "list", "--json"]) : run("pi", ["list"]);
76002
+ const verify = entry.host === "codex" ? await runAsync("codex", ["plugin", "list", "--json"]) : await runAsync("pi", ["list"]);
75674
76003
  if (verify.status !== 0)
75675
- return fail("update verification failed");
76004
+ return fail(`update verification failed${stderrTail(verify.stderr) ? `: ${stderrTail(verify.stderr)}` : ""}`);
75676
76005
  if (entry.host === "codex") {
75677
76006
  let installed = [];
75678
76007
  try {
@@ -75688,30 +76017,40 @@ var codexPluginRoot = (codexHome) => {
75688
76017
  status: "updated",
75689
76018
  reason: entry.repair ? `reinstalled missing plugin files (${entry.latest})` : `${entry.installedVersion ?? "?"} -> ${entry.latest}`
75690
76019
  };
75691
- }, refreshCodexAgents = (run, codexHome) => {
76020
+ }, refreshCodexAgents = async (run, codexHome) => {
75692
76021
  const root = codexPluginRoot(codexHome);
75693
- const launcher = root && path46.join(root, "dist", "launch-mcp.js");
76022
+ const launcher = root && path47.join(root, "dist", "launch-mcp.js");
75694
76023
  if (!launcher || !existsSync22(launcher))
75695
76024
  return { ok: true, note: "" };
75696
76025
  const fix = `node ${JSON.stringify(launcher)} --install-agents`;
75697
- return run("node", [launcher, "--install-agents"]).status === 0 ? { ok: true, note: "agents refreshed" } : { ok: false, note: "agent refresh failed", fix };
75698
- }, applyCli = (cli, run, backup) => {
76026
+ const refreshed = await run("node", [launcher, "--install-agents"]);
76027
+ return refreshed.status === 0 ? { ok: true, note: "agents refreshed" } : {
76028
+ ok: false,
76029
+ note: `agent refresh failed${stderrTail(refreshed.stderr) ? `: ${stderrTail(refreshed.stderr)}` : ""}`,
76030
+ fix
76031
+ };
76032
+ }, applyCli = async (cli, run, backup) => {
75699
76033
  const fail = (reason) => ({
75700
76034
  host: "cli",
75701
76035
  status: "failed",
75702
76036
  reason,
75703
76037
  fix: CLI_FIX
75704
76038
  });
75705
- const currentRoot = run("npm", ["root", "--global"]);
76039
+ const currentRoot = await run("npm", ["root", "--global"]);
75706
76040
  if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== cli.root)
75707
76041
  return fail("Global npm location changed; preview again");
75708
- const cliBackup = path46.join(backup, "cli-package");
75709
- cpSync5(path46.join(cli.root, "@brainervirus/workit-cli"), cliBackup, {
76042
+ const cliBackup = path47.join(backup, "cli-package");
76043
+ cpSync5(path47.join(cli.root, "@brainervirus/workit-cli"), cliBackup, {
75710
76044
  recursive: true
75711
76045
  });
75712
- if (run("npm", ["install", "--global", `@brainervirus/workit-cli@${cli.latest}`]).status !== 0)
75713
- return fail(`CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path46.join(cliBackup, "dist/index.js")}`);
75714
- const installed = objectOrNull(path46.join(cli.root, "@brainervirus/workit-cli/package.json"));
76046
+ const install = await run("npm", [
76047
+ "install",
76048
+ "--global",
76049
+ `@brainervirus/workit-cli@${cli.latest}`
76050
+ ]);
76051
+ if (install.status !== 0)
76052
+ 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")}`);
76053
+ const installed = objectOrNull(path47.join(cli.root, "@brainervirus/workit-cli/package.json"));
75715
76054
  if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== cli.latest)
75716
76055
  return fail(`CLI update did not verify the requested version; preserved package at ${cliBackup}`);
75717
76056
  return {
@@ -75725,13 +76064,14 @@ var init_apply = __esm(() => {
75725
76064
  init_setup_state();
75726
76065
  init_setup();
75727
76066
  init_safe_write();
76067
+ init_progress();
75728
76068
  init_processes();
75729
76069
  init_shared();
75730
76070
  });
75731
76071
 
75732
76072
  // packages/workit-cli/src/upgrade/plan.ts
75733
76073
  import { existsSync as existsSync23, mkdtempSync as mkdtempSync3, rmSync as rmSync8, lstatSync as lstatSync8, readFileSync as readFileSync23 } from "node:fs";
75734
- import path47 from "node:path";
76074
+ import path48 from "node:path";
75735
76075
  import os17 from "node:os";
75736
76076
  function previewUpgrade(hosts = HOSTS2, deps = {}) {
75737
76077
  const paths = upgradePaths(deps);
@@ -75755,9 +76095,9 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
75755
76095
  for (const file of [
75756
76096
  paths.opencodeConfig,
75757
76097
  paths.opencodeConfig + "c",
75758
- path47.join(home, ".cursor/settings.json"),
75759
- path47.join(home, ".cursor/mcp.json"),
75760
- path47.join(paths.cursorRoot, "package.json"),
76098
+ path48.join(home, ".cursor/settings.json"),
76099
+ path48.join(home, ".cursor/mcp.json"),
76100
+ path48.join(paths.cursorRoot, "package.json"),
75761
76101
  paths.codexConfig,
75762
76102
  paths.piSettings
75763
76103
  ])
@@ -75927,8 +76267,8 @@ var codexRegistered = (configFile) => {
75927
76267
  result.push(classify("opencode", pin));
75928
76268
  });
75929
76269
  guard("cursor", () => {
75930
- const cursor = objectOrNull(path47.join(paths.cursorRoot, "package.json"));
75931
- const mcp = objectOrNull(path47.join(home, ".cursor/mcp.json"));
76270
+ const cursor = objectOrNull(path48.join(paths.cursorRoot, "package.json"));
76271
+ const mcp = objectOrNull(path48.join(home, ".cursor/mcp.json"));
75932
76272
  const args = mcp?.mcpServers?.workit?.args ?? [];
75933
76273
  const arg = args.find((value) => typeof value === "string" && value.startsWith("--package="));
75934
76274
  const selector = typeof arg === "string" ? arg.slice(10) : "local";
@@ -75939,7 +76279,7 @@ var codexRegistered = (configFile) => {
75939
76279
  });
75940
76280
  return;
75941
76281
  }
75942
- const settings = objectOrNull(path47.join(home, ".cursor/settings.json"));
76282
+ const settings = objectOrNull(path48.join(home, ".cursor/settings.json"));
75943
76283
  const dirs = Array.isArray(settings?.plugin_dirs) ? settings.plugin_dirs : [];
75944
76284
  const registered = mcp?.mcpServers?.workit !== undefined || dirs.some((dir) => String(dir).replaceAll("\\", "/").replace(/\/+$/, "").endsWith("local/workit"));
75945
76285
  if (registered)
@@ -75954,7 +76294,7 @@ var codexRegistered = (configFile) => {
75954
76294
  if (typeof source !== "string")
75955
76295
  continue;
75956
76296
  const npm = /^(?:npm:)?@brainervirus\/workit-pi(?:@[^/]+)?$/.test(source);
75957
- const local = path47.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path47.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
76297
+ const local = path48.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path48.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
75958
76298
  if (!npm && !local)
75959
76299
  continue;
75960
76300
  const found = classify("pi", source);
@@ -76014,15 +76354,15 @@ var codexRegistered = (configFile) => {
76014
76354
  });
76015
76355
  return result;
76016
76356
  }, opencodeProbe = (deps, args) => {
76017
- const scratch = mkdtempSync3(path47.join(os17.tmpdir(), "workit-upgrade-opencode-"));
76357
+ const scratch = mkdtempSync3(path48.join(os17.tmpdir(), "workit-upgrade-opencode-"));
76018
76358
  try {
76019
76359
  return runner({
76020
76360
  ...deps,
76021
76361
  env: {
76022
76362
  ...deps.env,
76023
- XDG_DATA_HOME: path47.join(scratch, "data"),
76024
- XDG_STATE_HOME: path47.join(scratch, "state"),
76025
- XDG_CACHE_HOME: path47.join(scratch, "cache")
76363
+ XDG_DATA_HOME: path48.join(scratch, "data"),
76364
+ XDG_STATE_HOME: path48.join(scratch, "state"),
76365
+ XDG_CACHE_HOME: path48.join(scratch, "cache")
76026
76366
  }
76027
76367
  })("opencode", args);
76028
76368
  } finally {
@@ -76030,7 +76370,7 @@ var codexRegistered = (configFile) => {
76030
76370
  }
76031
76371
  }, planCli = (plan, run) => {
76032
76372
  const root = run("npm", ["root", "--global"]);
76033
- if (root.status !== 0 || !path47.isAbsolute(root.stdout.trim())) {
76373
+ if (root.status !== 0 || !path48.isAbsolute(root.stdout.trim())) {
76034
76374
  plan.skipped.push({
76035
76375
  host: "cli",
76036
76376
  reason: "global npm location could not be verified",
@@ -76038,9 +76378,9 @@ var codexRegistered = (configFile) => {
76038
76378
  });
76039
76379
  return;
76040
76380
  }
76041
- const packageFile = path47.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
76381
+ const packageFile = path48.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
76042
76382
  const installed = objectOrNull(packageFile);
76043
- if (installed?.name !== "@brainervirus/workit-cli" || lstatSync8(path47.dirname(packageFile)).isSymbolicLink()) {
76383
+ if (installed?.name !== "@brainervirus/workit-cli" || lstatSync8(path48.dirname(packageFile)).isSymbolicLink()) {
76044
76384
  plan.skipped.push({
76045
76385
  host: "cli",
76046
76386
  reason: "no managed global CLI install (local links preserved); use npx @brainervirus/workit-cli@latest"
@@ -76101,9 +76441,13 @@ var pad2 = (text) => text.padEnd(12), summary = (plan, permissions) => {
76101
76441
  return lines.join(`
76102
76442
  `) + `
76103
76443
  `;
76104
- }, LABEL, table = (hosts) => [
76444
+ }, LABEL, reasonFor = (entry) => {
76445
+ const label = LABEL[entry.status];
76446
+ const head = entry.reason.slice(0, label.length);
76447
+ 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;
76448
+ }, table = (hosts) => [
76105
76449
  "Result:",
76106
- ...hosts.map((entry) => ` ${pad2(entry.host)}${LABEL[entry.status].padEnd(16)}${entry.reason}${entry.fix && entry.status !== "updated" && entry.status !== "current" ? `
76450
+ ...hosts.map((entry) => ` ${pad2(entry.host)}${LABEL[entry.status].padEnd(16)}${reasonFor(entry)}${entry.fix && entry.status !== "updated" && entry.status !== "current" ? `
76107
76451
  ${pad2("")}${"".padEnd(16)}fix: ${entry.fix}` : ""}`)
76108
76452
  ].join(`
76109
76453
  `) + `
@@ -76145,9 +76489,13 @@ async function runUpgradeCommand(argv, deps = {}) {
76145
76489
  const legacy = flags.has("--apply");
76146
76490
  const json = flags.has("--json") || legacy;
76147
76491
  const run = runner(deps);
76148
- const plan = previewUpgrade(raw, deps);
76149
- if (hostFlag === undefined || flags.has("--cli"))
76150
- planCli(plan, run);
76492
+ const progress = deps.progress ?? createProgress({ stream: process.stderr, json });
76493
+ const plan = progress.runSync("Planning the upgrade", () => {
76494
+ const planned = previewUpgrade(raw, deps);
76495
+ if (hostFlag === undefined || flags.has("--cli"))
76496
+ planCli(planned, run);
76497
+ return planned;
76498
+ });
76151
76499
  plan.ok = plan.blocked.length === 0 && plan.failed.length === 0;
76152
76500
  const { home, env } = upgradePaths(deps);
76153
76501
  const permissions = planHostPermissions({
@@ -76198,23 +76546,23 @@ Nothing changed.
76198
76546
  for (const warning of plan.warnings ?? [])
76199
76547
  out.write(`warning: ${warning}
76200
76548
  `);
76201
- const result = applyUpgrade(plan, deps);
76549
+ const result = await applyUpgrade(plan, { ...deps, progress });
76202
76550
  let permissionsOk = true;
76203
76551
  let written;
76204
76552
  if (permissions.changes.length && !permissions.refused && !result.error?.startsWith("configuration changed")) {
76205
- written = applyHostPermissions(permissions, { home, env });
76553
+ written = progress.runSync("Refreshing the permission block", () => applyHostPermissions(permissions, { home, env }), (entries) => entries.every((entry) => entry.status === "written") ? "done" : "failed");
76206
76554
  permissionsOk = written.every((entry) => entry.status === "written");
76207
76555
  for (const entry of written)
76208
76556
  result.hosts.push({
76209
- host: entry.host,
76557
+ host: "permissions",
76210
76558
  status: entry.status === "written" ? "updated" : "failed",
76211
- reason: `permission block ${entry.status === "written" ? "refreshed" : entry.status} in ${entry.file}`,
76559
+ reason: `${entry.host} block ${entry.status === "written" ? "refreshed" : entry.status} in ${entry.file}`,
76212
76560
  ...entry.status === "written" ? {} : { fix: `workit setup --hosts=${entry.host}` }
76213
76561
  });
76214
76562
  }
76215
76563
  const failed = !result.ok || !permissionsOk;
76216
76564
  const cliVersion = result.hosts.some((h) => h.host === "cli" && h.status === "updated") ? plan.cli.latest : package_default.version;
76217
- const report = (deps.doctor ?? ((version) => runDoctor({ home, env, cliVersion: version, only: "upgrade" })))(cliVersion);
76565
+ const report = progress.runSync("Checking the result with workit doctor", () => (deps.doctor ?? ((version) => runDoctor({ home, env, cliVersion: version, only: "upgrade" })))(cliVersion));
76218
76566
  const left = report.checks.filter((check) => check.status === "warn" || check.status === "fail");
76219
76567
  if (json) {
76220
76568
  out.write(JSON.stringify({
@@ -76272,7 +76620,7 @@ async function runLaunchCommand(argv, deps = {}) {
76272
76620
  for (const skipped of plan.skipped)
76273
76621
  (deps.out ?? process.stderr).write(`${skipped.host}: ${skipped.reason}${skipped.fix ? ` (run: ${skipped.fix})` : ""}
76274
76622
  `);
76275
- const result = applyUpgrade(plan, deps);
76623
+ const result = await applyUpgrade(plan, deps);
76276
76624
  if (!result.ok) {
76277
76625
  (deps.out ?? process.stdout).write(`${result.error}
76278
76626
  `);
@@ -76301,6 +76649,7 @@ var init_upgrade = __esm(() => {
76301
76649
  init_host_install();
76302
76650
  init_doctor();
76303
76651
  init_host_permissions();
76652
+ init_progress();
76304
76653
  init_apply();
76305
76654
  init_plan();
76306
76655
  init_report();
@@ -76333,7 +76682,7 @@ var init_launch = __esm(() => {
76333
76682
  // packages/workit-core/src/knowledge.ts
76334
76683
  import { spawnSync as spawnSync18 } from "node:child_process";
76335
76684
  import fs20 from "node:fs";
76336
- import path48 from "node:path";
76685
+ import path49 from "node:path";
76337
76686
  function lintKnowledge(root) {
76338
76687
  const seen = new Set;
76339
76688
  const unreadable = [];
@@ -76437,7 +76786,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76437
76786
  const end = lines.indexOf("---", 1);
76438
76787
  return end === -1 ? lines : [...lines.slice(0, end + 1).map(() => ""), ...lines.slice(end + 1)];
76439
76788
  }, read = (root, file) => {
76440
- const full = path48.join(root, file);
76789
+ const full = path49.join(root, file);
76441
76790
  try {
76442
76791
  fs20.lstatSync(full);
76443
76792
  } catch {
@@ -76478,7 +76827,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76478
76827
  }
76479
76828
  }, brokenLinks = (root, doc, tracked) => {
76480
76829
  const findings = [];
76481
- const base = path48.dirname(path48.join(root, doc.file));
76830
+ const base = path49.dirname(path49.join(root, doc.file));
76482
76831
  const missing = (target, line, how) => findings.push({
76483
76832
  rule: "broken-link",
76484
76833
  file: doc.file,
@@ -76497,7 +76846,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76497
76846
  const local = localTarget(target);
76498
76847
  if (!local)
76499
76848
  continue;
76500
- const resolved = local.startsWith("/") ? path48.join(root, local) : path48.resolve(base, local);
76849
+ const resolved = local.startsWith("/") ? path49.join(root, local) : path49.resolve(base, local);
76501
76850
  if (!exists2(resolved))
76502
76851
  missing(target, index + 1, "link");
76503
76852
  }
@@ -76507,9 +76856,9 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76507
76856
  continue;
76508
76857
  const relative = /^\.\.?\//.test(candidate);
76509
76858
  const first = candidate.split("/")[0];
76510
- if (!relative && !(tracked ? tracked.has(first) : exists2(path48.join(root, first))))
76859
+ if (!relative && !(tracked ? tracked.has(first) : exists2(path49.join(root, first))))
76511
76860
  continue;
76512
- const resolved = relative ? path48.resolve(base, candidate) : path48.join(root, candidate);
76861
+ const resolved = relative ? path49.resolve(base, candidate) : path49.join(root, candidate);
76513
76862
  if (!exists2(resolved))
76514
76863
  missing(span, index + 1, "pointer");
76515
76864
  }
@@ -76661,12 +77010,12 @@ async function run7(argv, io) {
76661
77010
  };
76662
77011
  }
76663
77012
  }
76664
- const report = runDoctor({
77013
+ const report = createProgress({ stream: process.stderr, json: io.json }).runSync("Checking Workit (workit doctor)", () => runDoctor({
76665
77014
  host: "cli",
76666
77015
  cwd: io.cwd,
76667
77016
  workspaceRoot: root,
76668
77017
  cliVersion: package_default.version
76669
- });
77018
+ }), (done) => done.ok ? "done" : "failed");
76670
77019
  let knowledge = null;
76671
77020
  try {
76672
77021
  knowledge = lintKnowledge(root);
@@ -76722,6 +77071,7 @@ var init_doctor2 = __esm(() => {
76722
77071
  init_knowledge();
76723
77072
  init_store_lock();
76724
77073
  init_output();
77074
+ init_progress();
76725
77075
  init_prompt();
76726
77076
  init_task();
76727
77077
  });
@@ -76831,11 +77181,11 @@ var init_redact = __esm(() => {
76831
77181
  });
76832
77182
 
76833
77183
  // packages/workit-core/src/checks.ts
76834
- import { spawn, spawnSync as spawnSync19 } from "node:child_process";
77184
+ import { spawn as spawn3, spawnSync as spawnSync19 } from "node:child_process";
76835
77185
  import { createHash as createHash17 } from "node:crypto";
76836
77186
  import fs21 from "node:fs";
76837
77187
  import os18 from "node:os";
76838
- import path49 from "node:path";
77188
+ import path50 from "node:path";
76839
77189
  import { StringDecoder } from "node:string_decoder";
76840
77190
  function tailLines(text, lines = TAIL_LINES) {
76841
77191
  const all = text.replace(/\r\n?/gu, `
@@ -76955,7 +77305,7 @@ function planSpawn(argv, options) {
76955
77305
  return { file: argv[0], args: [], verbatim: false, shell: true };
76956
77306
  if (options.platform !== "win32")
76957
77307
  return { file: argv[0], args: argv.slice(1), verbatim: false, shell: false };
76958
- const win = path49.win32;
77308
+ const win = path50.win32;
76959
77309
  const isFile = options.isFile ?? ((file) => {
76960
77310
  try {
76961
77311
  return fs21.statSync(file).isFile();
@@ -77060,7 +77410,7 @@ function runCheckCommand(argv, options) {
77060
77410
  shell: plan.shell
77061
77411
  };
77062
77412
  try {
77063
- child = spawn(plan.file, plan.args, spawnOptions);
77413
+ child = spawn3(plan.file, plan.args, spawnOptions);
77064
77414
  } catch (error) {
77065
77415
  finish(null, null, error.code ?? error.message);
77066
77416
  return;
@@ -77117,10 +77467,10 @@ function runCheckCommand(argv, options) {
77117
77467
  function storeLog(storeRoot, log) {
77118
77468
  const digest = logDigest(log);
77119
77469
  const ref = `blobs/logs/${digest.slice("sha256:".length)}.log`;
77120
- const file = path49.join(storeRoot, ref);
77470
+ const file = path50.join(storeRoot, ref);
77121
77471
  try {
77122
77472
  if (!fs21.existsSync(file)) {
77123
- fs21.mkdirSync(path49.dirname(file), { recursive: true });
77473
+ fs21.mkdirSync(path50.dirname(file), { recursive: true });
77124
77474
  const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
77125
77475
  fs21.writeFileSync(temp, log, { mode: 384 });
77126
77476
  fs21.renameSync(temp, file);
@@ -77133,7 +77483,7 @@ function storeLog(storeRoot, log) {
77133
77483
  function pruneCheckLogs(storeRoot, options = {}) {
77134
77484
  const limits = { ...LOG_RETENTION, ...options.retention };
77135
77485
  const now = options.now ?? Date.now();
77136
- const dir = path49.join(storeRoot, "blobs", "logs");
77486
+ const dir = path50.join(storeRoot, "blobs", "logs");
77137
77487
  const report = { removed: 0, removedBytes: 0, kept: 0 };
77138
77488
  let names;
77139
77489
  try {
@@ -77143,7 +77493,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
77143
77493
  }
77144
77494
  const files = names.flatMap((name) => {
77145
77495
  try {
77146
- const stat = fs21.statSync(path49.join(dir, name));
77496
+ const stat = fs21.statSync(path50.join(dir, name));
77147
77497
  return stat.isFile() ? [{ name, size: stat.size, mtimeMs: stat.mtimeMs }] : [];
77148
77498
  } catch {
77149
77499
  return [];
@@ -77162,7 +77512,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
77162
77512
  continue;
77163
77513
  if (!options.dryRun)
77164
77514
  try {
77165
- fs21.rmSync(path49.join(dir, file.name), { force: true });
77515
+ fs21.rmSync(path50.join(dir, file.name), { force: true });
77166
77516
  } catch {
77167
77517
  continue;
77168
77518
  }
@@ -77814,12 +78164,12 @@ var init_workspace = __esm(() => {
77814
78164
 
77815
78165
  // packages/workit-core/src/core/heavy-rules.ts
77816
78166
  import fs22 from "node:fs";
77817
- import path50 from "node:path";
78167
+ import path51 from "node:path";
77818
78168
  function gitTop(cwd) {
77819
- for (let dir = path50.resolve(cwd);; dir = path50.dirname(dir)) {
77820
- if (fs22.existsSync(path50.join(dir, ".git")))
78169
+ for (let dir = path51.resolve(cwd);; dir = path51.dirname(dir)) {
78170
+ if (fs22.existsSync(path51.join(dir, ".git")))
77821
78171
  return dir;
77822
- if (path50.dirname(dir) === dir)
78172
+ if (path51.dirname(dir) === dir)
77823
78173
  return null;
77824
78174
  }
77825
78175
  }
@@ -77861,18 +78211,18 @@ var init_heavy_rules = () => {};
77861
78211
  // packages/workit-core/src/core/heavy.ts
77862
78212
  import fs23 from "node:fs";
77863
78213
  import os19 from "node:os";
77864
- import path51 from "node:path";
78214
+ import path52 from "node:path";
77865
78215
  function stateDir2(env, platform = process.platform) {
77866
78216
  if (env.WORKFLOW_TOOLKIT_STATE)
77867
78217
  return env.WORKFLOW_TOOLKIT_STATE;
77868
78218
  if (env.XDG_STATE_HOME)
77869
- return path51.join(env.XDG_STATE_HOME, "workit");
78219
+ return path52.join(env.XDG_STATE_HOME, "workit");
77870
78220
  const home = env.HOME || os19.homedir();
77871
78221
  if (platform === "darwin")
77872
- return path51.join(home, "Library", "Application Support", "workit");
78222
+ return path52.join(home, "Library", "Application Support", "workit");
77873
78223
  if (platform === "win32")
77874
- return path51.join(env.LOCALAPPDATA ?? path51.join(home, "AppData", "Local"), "workit");
77875
- return path51.join(home, ".local", "state", "workit");
78224
+ return path52.join(env.LOCALAPPDATA ?? path52.join(home, "AppData", "Local"), "workit");
78225
+ return path52.join(home, ".local", "state", "workit");
77876
78226
  }
77877
78227
  function positional(words, from, values = PM_VALUES) {
77878
78228
  let index = from;
@@ -78012,7 +78362,7 @@ function machinePatterns(env) {
78012
78362
  return isRecord8(value) ? stringList2(value.patterns) : [];
78013
78363
  }
78014
78364
  function repoPatterns(cwd) {
78015
- return repoHeavyCommands(gitTop(cwd) ?? path51.resolve(cwd));
78365
+ return repoHeavyCommands(gitTop(cwd) ?? path52.resolve(cwd));
78016
78366
  }
78017
78367
  function heavyLines(lines, options) {
78018
78368
  const found = [];
@@ -78091,7 +78441,7 @@ function leaseRewrite(command) {
78091
78441
  return null;
78092
78442
  return `${prefix}workit check --heavy -- ${rest}`;
78093
78443
  }
78094
- 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) => {
78444
+ 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) => {
78095
78445
  try {
78096
78446
  return JSON.parse(fs23.readFileSync(file, "utf8"));
78097
78447
  } catch {
@@ -78238,7 +78588,7 @@ var init_heavy = __esm(() => {
78238
78588
  import { randomUUID as randomUUID5 } from "node:crypto";
78239
78589
  import fs24 from "node:fs";
78240
78590
  import os20 from "node:os";
78241
- import path52 from "node:path";
78591
+ import path53 from "node:path";
78242
78592
  function memoryValue(value, host) {
78243
78593
  const text = typeof value === "number" ? String(value) : typeof value === "string" ? value : "";
78244
78594
  const percent = PERCENT.exec(text.trim());
@@ -78434,7 +78784,7 @@ function tryOnce(options, record, reclaimed) {
78434
78784
  const text = `${JSON.stringify(record)}
78435
78785
  `;
78436
78786
  for (let slot = 0;slot < options.slots; slot += 1) {
78437
- const file = path52.join(options.dir, `slot-${slot}.json`);
78787
+ const file = path53.join(options.dir, `slot-${slot}.json`);
78438
78788
  for (let attempt = 0;attempt < 2; attempt += 1) {
78439
78789
  try {
78440
78790
  const fd = fs24.openSync(file, "wx", 384);
@@ -78479,7 +78829,7 @@ function leaseQueue(dir, probe = {}) {
78479
78829
  }
78480
78830
  const entries = [];
78481
78831
  for (const name of names.filter((item) => item.endsWith(".json")).toSorted()) {
78482
- const file = path52.join(queueDir(dir), name);
78832
+ const file = path53.join(queueDir(dir), name);
78483
78833
  const record = parseLease(readText5(file));
78484
78834
  if (!record)
78485
78835
  continue;
@@ -78495,9 +78845,9 @@ function leaseQueue(dir, probe = {}) {
78495
78845
  function waitersAhead(options, own) {
78496
78846
  let ahead = 0;
78497
78847
  for (const entry of leaseQueue(options.dir, options.probe)) {
78498
- if (path52.basename(entry.file) >= own)
78848
+ if (path53.basename(entry.file) >= own)
78499
78849
  break;
78500
- if (!TICKET.test(path52.basename(entry.file)))
78850
+ if (!TICKET.test(path53.basename(entry.file)))
78501
78851
  continue;
78502
78852
  if (entry.stale && reclaim(entry.file, (current) => !current || staleReason(current, options.probe) !== null))
78503
78853
  continue;
@@ -78509,7 +78859,7 @@ function liveHolders(options) {
78509
78859
  return leaseSlots(options.dir, options.slots, options.probe).filter((slot) => slot.holder && !slot.stale).map((slot) => slot.holder);
78510
78860
  }
78511
78861
  function writeTicket(file, record) {
78512
- fs24.mkdirSync(path52.dirname(file), { recursive: true, mode: 448 });
78862
+ fs24.mkdirSync(path53.dirname(file), { recursive: true, mode: 448 });
78513
78863
  fs24.writeFileSync(file, `${JSON.stringify(record)}
78514
78864
  `, { mode: 384 });
78515
78865
  }
@@ -78554,7 +78904,7 @@ async function acquireLease(options) {
78554
78904
  const reclaimed = [];
78555
78905
  let waitedOn = [];
78556
78906
  const name = ticketName(started, record.id);
78557
- const ticket = path52.join(queueDir(options.dir), name);
78907
+ const ticket = path53.join(queueDir(options.dir), name);
78558
78908
  const ticketRecord = {
78559
78909
  ...record,
78560
78910
  maxAgeMs: options.waitMs + 60000
@@ -78675,7 +79025,7 @@ function heldLease(dir, id, options = {}) {
78675
79025
  for (const name of names) {
78676
79026
  if (!/^slot-\d+\.json$/u.test(name))
78677
79027
  continue;
78678
- const lease = parseLease(readText5(path52.join(dir, name)));
79028
+ const lease = parseLease(readText5(path53.join(dir, name)));
78679
79029
  if (lease?.id === id && !staleReason(lease, options.probe) && (options.ancestor ?? isAncestor)(lease.pid))
78680
79030
  return lease;
78681
79031
  }
@@ -78730,10 +79080,10 @@ async function runScoped(run, wrapper, sinks) {
78730
79080
  }
78731
79081
  function firstNotice(env, session, key, now = Date.now()) {
78732
79082
  const id = (session ?? `ppid-${process.ppid}`).replace(/[^A-Za-z0-9_.-]/gu, "_").slice(0, 120);
78733
- const dir = path52.join(stateDir2(env), "notices");
79083
+ const dir = path53.join(stateDir2(env), "notices");
78734
79084
  try {
78735
79085
  fs24.mkdirSync(dir, { recursive: true, mode: 448 });
78736
- fs24.writeFileSync(path52.join(dir, `${key}-${id}`), `${new Date(now).toISOString()}
79086
+ fs24.writeFileSync(path53.join(dir, `${key}-${id}`), `${new Date(now).toISOString()}
78737
79087
  `, {
78738
79088
  flag: "wx",
78739
79089
  mode: 384
@@ -78743,7 +79093,7 @@ function firstNotice(env, session, key, now = Date.now()) {
78743
79093
  }
78744
79094
  try {
78745
79095
  for (const name of fs24.readdirSync(dir)) {
78746
- const file = path52.join(dir, name);
79096
+ const file = path53.join(dir, name);
78747
79097
  if (now - fs24.statSync(file).mtimeMs > NOTICE_TTL_MS)
78748
79098
  fs24.rmSync(file, { force: true });
78749
79099
  }
@@ -78753,7 +79103,7 @@ function firstNotice(env, session, key, now = Date.now()) {
78753
79103
  function leaseSlots(dir, slots, probe = {}) {
78754
79104
  const states = [];
78755
79105
  for (let slot = 0;slot < slots; slot += 1) {
78756
- const lease = parseLease(readText5(path52.join(dir, `slot-${slot}.json`)));
79106
+ const lease = parseLease(readText5(path53.join(dir, `slot-${slot}.json`)));
78757
79107
  states.push({
78758
79108
  slot,
78759
79109
  holder: lease ? holderOf(lease) : null,
@@ -78765,7 +79115,7 @@ function leaseSlots(dir, slots, probe = {}) {
78765
79115
  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 = () => ({
78766
79116
  totalMemBytes: os20.totalmem(),
78767
79117
  cpus: Math.max(1, os20.availableParallelism?.() ?? os20.cpus().length)
78768
- }), isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SIZE, PERCENT, UNITS, leaseDir = (env) => path52.join(stateDir2(env), "leases"), readText5 = (file) => {
79118
+ }), isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SIZE, PERCENT, UNITS, leaseDir = (env) => path53.join(stateDir2(env), "leases"), readText5 = (file) => {
78769
79119
  try {
78770
79120
  return fs24.readFileSync(file, "utf8");
78771
79121
  } catch {
@@ -78796,7 +79146,7 @@ var DEFAULT_HEAVY_CHECKS, DEFAULT_LIGHT_CHECKS, DEFAULT_SLOTS = 1, DEFAULT_WAIT_
78796
79146
  cwd: lease.cwd,
78797
79147
  session: lease.session,
78798
79148
  startedAt: lease.startedAt
78799
- }), 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;
79149
+ }), 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;
78800
79150
  var init_resources = __esm(() => {
78801
79151
  init_checks3();
78802
79152
  init_heavy();
@@ -78826,7 +79176,7 @@ __export(exports_check, {
78826
79176
  workspaceResources: () => workspaceResources
78827
79177
  });
78828
79178
  import os21 from "node:os";
78829
- import path53 from "node:path";
79179
+ import path54 from "node:path";
78830
79180
  function parse6(argv) {
78831
79181
  const split = argv.indexOf("--");
78832
79182
  const head = split >= 0 ? argv.slice(0, split) : [...argv];
@@ -79057,7 +79407,7 @@ ${footer}`;
79057
79407
  }
79058
79408
  async function workspaceResources(io) {
79059
79409
  const env = io.env;
79060
- 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");
79410
+ 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");
79061
79411
  try {
79062
79412
  await Promise.resolve().then(() => init_workspaces());
79063
79413
  const workspace = resolveWorkspaceFrom(io.cwd, dir, env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined);
@@ -79078,6 +79428,8 @@ async function prepareHeavy(io, settings, label, runCwd, timeoutMs) {
79078
79428
  wrapper: null,
79079
79429
  env: io.env
79080
79430
  };
79431
+ const progress = createProgress({ stream: process.stderr, json: io.json });
79432
+ let waiting = null;
79081
79433
  const acquired = await acquireLease({
79082
79434
  dir,
79083
79435
  slots: settings.slots,
@@ -79090,11 +79442,20 @@ async function prepareHeavy(io, settings, label, runCwd, timeoutMs) {
79090
79442
  onStatus: (status) => {
79091
79443
  const slots = `${settings.slots} slot${settings.slots === 1 ? "" : "s"}`;
79092
79444
  const holders = status.holders.map((holder) => describeHolder(holder)).join("; ");
79445
+ if (progress.mode === "spinner") {
79446
+ const text = `Waiting for the heavy-check lease: held by ${holders || "nobody; waiters ahead"}, queue position ${status.position}`;
79447
+ if (waiting)
79448
+ waiting.label(text);
79449
+ else
79450
+ waiting = progress.start(text);
79451
+ return;
79452
+ }
79093
79453
  io.stderr(status.first ? `workit: waiting for the heavy-check lease (${slots}): held by ${holders || "nobody; waiters ahead"}; queued at position ${status.position}, waiting up to ${formatWait(settings.waitMs)} (--wait <dur> sets it)
79094
79454
  ` : `workit: still queued for the heavy-check lease: position ${status.position}, ${formatWait(status.waitedMs)} of ${formatWait(settings.waitMs)} waited; held by ${holders || "nobody; waiters ahead"}
79095
79455
  `);
79096
79456
  }
79097
79457
  });
79458
+ waiting?.end(acquired.ok ? "done" : "failed");
79098
79459
  if (!acquired.ok && acquired.reason === "timeout") {
79099
79460
  const holders = acquired.holders.map((holder) => describeHolder(holder)).join("; ");
79100
79461
  const waited = formatWait(acquired.waitedMs);
@@ -79188,7 +79549,7 @@ async function run12(argv, io) {
79188
79549
  if (options.shell && command.length !== 1)
79189
79550
  return emit(io, fail2("invalid_input", '--shell takes the command as one string: workit check --shell -- "<cmd>"'));
79190
79551
  }
79191
- const relCwd = posix(path53.relative(top, runCwd));
79552
+ const relCwd = posix(path54.relative(top, runCwd));
79192
79553
  const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
79193
79554
  const shadowed = !configured && name !== null ? config.checks.find((item) => item.name === name) : undefined;
79194
79555
  if (shadowed)
@@ -79253,7 +79614,7 @@ async function run12(argv, io) {
79253
79614
  const modifiedWorktree = key.tree !== null && treeAfter !== key.tree;
79254
79615
  const store = storeRoot(io.cwd);
79255
79616
  const blob = store.ok ? storeLog(store.value.root, result.log) : null;
79256
- const logPath = store.ok && blob ? path53.join(store.value.root, blob.ref) : null;
79617
+ const logPath = store.ok && blob ? path54.join(store.value.root, blob.ref) : null;
79257
79618
  const tail = tailLines(result.log, TAIL_LINES);
79258
79619
  const passed = result.exitCode === 0 && !result.timedOut;
79259
79620
  const bounded = boundedArgv(command);
@@ -79368,7 +79729,7 @@ async function run12(argv, io) {
79368
79729
  return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
79369
79730
  return 0;
79370
79731
  }
79371
- 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;
79732
+ 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;
79372
79733
  var init_check = __esm(() => {
79373
79734
  init_check_config();
79374
79735
  init_checks3();
@@ -79376,6 +79737,7 @@ var init_check = __esm(() => {
79376
79737
  init_package();
79377
79738
  init_ledger();
79378
79739
  init_output();
79740
+ init_progress();
79379
79741
  init_host_session();
79380
79742
  init_resources();
79381
79743
  MAX_UNVERIFIED_RUN_MS = 6 * 3600000;
@@ -79398,7 +79760,7 @@ __export(exports_lock, {
79398
79760
  run: () => run13
79399
79761
  });
79400
79762
  import fs25 from "node:fs";
79401
- import path54 from "node:path";
79763
+ import path55 from "node:path";
79402
79764
  async function settingsFor(io) {
79403
79765
  const workspace = await workspaceResources(io);
79404
79766
  const config = loadCheckConfig(io.cwd);
@@ -79490,7 +79852,7 @@ function readPatterns(file) {
79490
79852
  return { patterns: [] };
79491
79853
  }
79492
79854
  function writePatterns(file, value) {
79493
- fs25.mkdirSync(path54.dirname(file), { recursive: true, mode: 448 });
79855
+ fs25.mkdirSync(path55.dirname(file), { recursive: true, mode: 448 });
79494
79856
  const temp = `${file}.${process.pid}.tmp`;
79495
79857
  fs25.writeFileSync(temp, `${JSON.stringify(value, null, 2)}
79496
79858
  `, { mode: 384 });
@@ -79578,7 +79940,7 @@ __export(exports_models, {
79578
79940
  });
79579
79941
  import { existsSync as existsSync25, readdirSync as readdirSync13, readFileSync as readFileSync24, statSync as statSync9 } from "node:fs";
79580
79942
  import os22 from "node:os";
79581
- import path55 from "node:path";
79943
+ import path56 from "node:path";
79582
79944
  async function run14(argv, io) {
79583
79945
  const [sub, ...args] = argv.filter((arg) => arg !== "--json");
79584
79946
  if (sub !== "show")
@@ -79653,20 +80015,20 @@ var USAGE8 = "workit models show [--role <role>] [--tier <tier>] [--host <host>]
79653
80015
  } catch {}
79654
80016
  return found;
79655
80017
  }, matches3 = (ran, configured) => ran.toLowerCase().includes(configured.toLowerCase()), usageReport = (cwd, env, days) => {
79656
- const projects = path55.join(env.CLAUDE_CONFIG_DIR || path55.join(env.HOME || os22.homedir(), ".claude"), "projects");
80018
+ const projects = path56.join(env.CLAUDE_CONFIG_DIR || path56.join(env.HOME || os22.homedir(), ".claude"), "projects");
79657
80019
  const since = Date.now() - days * 86400000;
79658
80020
  const types = {};
79659
80021
  let agents = 0;
79660
80022
  const dirs = (dir) => {
79661
80023
  try {
79662
- return readdirSync13(dir).map((name) => path55.join(dir, name));
80024
+ return readdirSync13(dir).map((name) => path56.join(dir, name));
79663
80025
  } catch {
79664
80026
  return [];
79665
80027
  }
79666
80028
  };
79667
80029
  for (const project of dirs(projects))
79668
80030
  for (const session of dirs(project))
79669
- for (const meta of dirs(path55.join(session, "subagents")).filter((f) => f.endsWith(".meta.json"))) {
80031
+ for (const meta of dirs(path56.join(session, "subagents")).filter((f) => f.endsWith(".meta.json"))) {
79670
80032
  try {
79671
80033
  if (statSync9(meta).mtimeMs < since)
79672
80034
  continue;
@@ -79812,7 +80174,7 @@ var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock)
79812
80174
  // packages/workit-core/src/git/ops.ts
79813
80175
  import { spawnSync as spawnSync20 } from "node:child_process";
79814
80176
  import { existsSync as existsSync26, readFileSync as readFileSync25 } from "node:fs";
79815
- import path56 from "node:path";
80177
+ import path57 from "node:path";
79816
80178
  function operationInProgress(cwd) {
79817
80179
  const markers = [
79818
80180
  ["rebase-merge", "rebase"],
@@ -79825,18 +80187,18 @@ function operationInProgress(cwd) {
79825
80187
  if (!run.ok)
79826
80188
  return null;
79827
80189
  const found = run.stdout.split(`
79828
- `).map((line) => path56.resolve(cwd, line.trim()));
80190
+ `).map((line) => path57.resolve(cwd, line.trim()));
79829
80191
  const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
79830
80192
  for (const [index, [, operation]] of markers.entries()) {
79831
80193
  const marker = found[index];
79832
80194
  if (!marker || !existsSync26(marker))
79833
80195
  continue;
79834
- if (index === 1 && existsSync26(path56.join(marker, "applying")))
80196
+ if (index === 1 && existsSync26(path57.join(marker, "applying")))
79835
80197
  return { operation: "am", commitAllowed: false, branch: null };
79836
- if (index === 0 && existsSync26(path56.join(marker, "amend")) && !conflicted()) {
80198
+ if (index === 0 && existsSync26(path57.join(marker, "amend")) && !conflicted()) {
79837
80199
  let headName = "";
79838
80200
  try {
79839
- headName = readFileSync25(path56.join(marker, "head-name"), "utf8").trim();
80201
+ headName = readFileSync25(path57.join(marker, "head-name"), "utf8").trim();
79840
80202
  } catch {}
79841
80203
  const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
79842
80204
  return { operation, commitAllowed: branch !== null, branch };
@@ -80164,7 +80526,7 @@ function gitCommit(cwd, input) {
80164
80526
  if (paths.some((value) => value.startsWith("-") || !value.trim()))
80165
80527
  return failure3("invalid_input", "paths must not be empty or start with -");
80166
80528
  const tracked = new Set(nulList(git5(cwd, ["ls-files", "-z", "--", ...paths]).stdout));
80167
- const addable = paths.filter((value) => existsSync26(path56.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
80529
+ const addable = paths.filter((value) => existsSync26(path57.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
80168
80530
  if (addable.length) {
80169
80531
  const added = git5(cwd, ["add", "-A", "--", ...addable]);
80170
80532
  if (!added.ok)
@@ -80703,12 +81065,12 @@ var init_ops = __esm(() => {
80703
81065
 
80704
81066
  // packages/workit-core/src/verdict-cover.ts
80705
81067
  import fs26 from "node:fs";
80706
- import path57 from "node:path";
81068
+ import path58 from "node:path";
80707
81069
  function chainsAbove(cwd, branch) {
80708
81070
  const root = storeRoot(cwd);
80709
81071
  if (!root.ok)
80710
81072
  return [];
80711
- const dir = path57.join(root.value.root, "stacks");
81073
+ const dir = path58.join(root.value.root, "stacks");
80712
81074
  let names = [];
80713
81075
  try {
80714
81076
  names = fs26.readdirSync(dir).filter((name) => name.endsWith(".json"));
@@ -80719,7 +81081,7 @@ function chainsAbove(cwd, branch) {
80719
81081
  for (const name of names.toSorted()) {
80720
81082
  let parsed;
80721
81083
  try {
80722
- parsed = JSON.parse(fs26.readFileSync(path57.join(dir, name), "utf8"));
81084
+ parsed = JSON.parse(fs26.readFileSync(path58.join(dir, name), "utf8"));
80723
81085
  } catch {
80724
81086
  continue;
80725
81087
  }
@@ -80875,10 +81237,10 @@ var init_check_evidence = __esm(() => {
80875
81237
 
80876
81238
  // packages/workit-core/src/forge/reruns.ts
80877
81239
  import fs27 from "node:fs";
80878
- import path58 from "node:path";
81240
+ import path59 from "node:path";
80879
81241
  function rerunLogPath(cwd) {
80880
81242
  const common = gitCommonDir(cwd);
80881
- return common ? path58.join(common, "workit", "ci-reruns.jsonl") : null;
81243
+ return common ? path59.join(common, "workit", "ci-reruns.jsonl") : null;
80882
81244
  }
80883
81245
  function rerunCounts(cwd, key) {
80884
81246
  const counts = new Map;
@@ -80913,7 +81275,7 @@ function recordReruns(cwd, rows) {
80913
81275
  if (!file)
80914
81276
  return false;
80915
81277
  try {
80916
- fs27.mkdirSync(path58.dirname(file), { recursive: true });
81278
+ fs27.mkdirSync(path59.dirname(file), { recursive: true });
80917
81279
  fs27.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
80918
81280
  `).join(""));
80919
81281
  return true;
@@ -80926,7 +81288,7 @@ function withRerunLock(cwd, fn) {
80926
81288
  if (!file)
80927
81289
  return fn();
80928
81290
  const lock = `${file.slice(0, -".jsonl".length)}.lock`;
80929
- fs27.mkdirSync(path58.dirname(lock), { recursive: true });
81291
+ fs27.mkdirSync(path59.dirname(lock), { recursive: true });
80930
81292
  const until = Date.now() + LOCK_WAIT_MS2;
80931
81293
  for (;; ) {
80932
81294
  try {
@@ -81922,7 +82284,7 @@ var init_pr_ops = __esm(() => {
81922
82284
  import { spawnSync as spawnSync22 } from "node:child_process";
81923
82285
  import { createHash as createHash18, randomBytes as randomBytes4 } from "node:crypto";
81924
82286
  import fs28 from "node:fs";
81925
- import path59 from "node:path";
82287
+ import path60 from "node:path";
81926
82288
  function worktreeOf(cwd, branch) {
81927
82289
  const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
81928
82290
  if (!list.ok)
@@ -81971,7 +82333,7 @@ function gitRestack(cwd, input) {
81971
82333
  error: "no store root"
81972
82334
  };
81973
82335
  fs28.mkdirSync(scratch, { recursive: true });
81974
- dir = path59.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
82336
+ dir = path60.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
81975
82337
  const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
81976
82338
  if (!added.ok)
81977
82339
  return {
@@ -82027,7 +82389,7 @@ function pruneScratch(cwd) {
82027
82389
  if (!scratch || !fs28.existsSync(scratch))
82028
82390
  return;
82029
82391
  for (const name of fs28.readdirSync(scratch)) {
82030
- const dir = path59.join(scratch, name);
82392
+ const dir = path60.join(scratch, name);
82031
82393
  if (!rebaseInProgress(dir) && !trackedDirt(dir))
82032
82394
  gitRun3(cwd, ["worktree", "remove", "--force", dir]);
82033
82395
  }
@@ -82037,7 +82399,7 @@ function stacksDir(cwd) {
82037
82399
  const root = storeRoot(cwd);
82038
82400
  if (!root.ok)
82039
82401
  return stackFail(root.code, root.error, root.unblock);
82040
- return { ok: true, data: path59.join(root.value.root, "stacks") };
82402
+ return { ok: true, data: path60.join(root.value.root, "stacks") };
82041
82403
  }
82042
82404
  function parseStack(raw) {
82043
82405
  if (!isRecord12(raw) || !Array.isArray(raw.branches))
@@ -82089,7 +82451,7 @@ function readStack(cwd, name) {
82089
82451
  const dir = stacksDir(cwd);
82090
82452
  if (!dir.ok)
82091
82453
  return dir;
82092
- const file = path59.join(dir.data, fileFor(name));
82454
+ const file = path60.join(dir.data, fileFor(name));
82093
82455
  let text;
82094
82456
  try {
82095
82457
  text = fs28.readFileSync(file, "utf8");
@@ -82110,7 +82472,7 @@ function writeStack(cwd, stack, now = new Date) {
82110
82472
  const dir = stacksDir(cwd);
82111
82473
  if (!dir.ok)
82112
82474
  return dir;
82113
- const file = path59.join(dir.data, fileFor(stack.name));
82475
+ const file = path60.join(dir.data, fileFor(stack.name));
82114
82476
  const temp = `${file}.${process.pid}.tmp`;
82115
82477
  try {
82116
82478
  fs28.mkdirSync(dir.data, { recursive: true });
@@ -82138,7 +82500,7 @@ function listStacks(cwd) {
82138
82500
  for (const name of names) {
82139
82501
  let parsed = null;
82140
82502
  try {
82141
- parsed = parseStack(JSON.parse(fs28.readFileSync(path59.join(dir.data, name), "utf8")));
82503
+ parsed = parseStack(JSON.parse(fs28.readFileSync(path60.join(dir.data, name), "utf8")));
82142
82504
  } catch {
82143
82505
  parsed = null;
82144
82506
  }
@@ -82200,7 +82562,7 @@ function takeLock(lock) {
82200
82562
  host: localLockHost(),
82201
82563
  nonce: randomBytes4(8).toString("hex")
82202
82564
  };
82203
- fs28.writeFileSync(path59.join(lock, OWNER), JSON.stringify(owner));
82565
+ fs28.writeFileSync(path60.join(lock, OWNER), JSON.stringify(owner));
82204
82566
  return owner;
82205
82567
  }
82206
82568
  function reapLock(lock, observed) {
@@ -82237,7 +82599,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
82237
82599
  return dir;
82238
82600
  if (!validName(name))
82239
82601
  return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
82240
- const lock = path59.join(dir.data, `${fileFor(name)}.lock`);
82602
+ const lock = path60.join(dir.data, `${fileFor(name)}.lock`);
82241
82603
  try {
82242
82604
  fs28.mkdirSync(dir.data, { recursive: true });
82243
82605
  } catch (error) {
@@ -82267,7 +82629,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
82267
82629
  const touch = () => {
82268
82630
  try {
82269
82631
  const now = new Date;
82270
- fs28.utimesSync(path59.join(lock, OWNER), now, now);
82632
+ fs28.utimesSync(path60.join(lock, OWNER), now, now);
82271
82633
  } catch {}
82272
82634
  };
82273
82635
  const beat = setInterval(touch, HEARTBEAT_MS);
@@ -83236,7 +83598,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
83236
83598
  return !status.ok || status.stdout.trim() !== "";
83237
83599
  }, scratchDir = (cwd) => {
83238
83600
  const dir = stacksDir(cwd);
83239
- return dir.ok ? path59.join(dir.data, "worktrees") : null;
83601
+ return dir.ok ? path60.join(dir.data, "worktrees") : null;
83240
83602
  }, firstLine = (run) => (`${run.stderr}
83241
83603
  ${run.stdout}`.split(`
83242
83604
  `).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) => {
@@ -83251,12 +83613,12 @@ ${run.stdout}`.split(`
83251
83613
  }, 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) => {
83252
83614
  let raw = null;
83253
83615
  try {
83254
- raw = fs28.readFileSync(path59.join(lock, OWNER), "utf8");
83616
+ raw = fs28.readFileSync(path60.join(lock, OWNER), "utf8");
83255
83617
  } catch {
83256
83618
  raw = null;
83257
83619
  }
83258
83620
  let age = null;
83259
- for (const target of [path59.join(lock, OWNER), lock])
83621
+ for (const target of [path60.join(lock, OWNER), lock])
83260
83622
  try {
83261
83623
  age = Date.now() - fs28.statSync(target).mtimeMs;
83262
83624
  break;
@@ -83300,7 +83662,7 @@ var init_stack = __esm(() => {
83300
83662
  import { spawnSync as spawnSync23 } from "node:child_process";
83301
83663
  import { createHash as createHash19 } from "node:crypto";
83302
83664
  import fs29 from "node:fs";
83303
- import path60 from "node:path";
83665
+ import path61 from "node:path";
83304
83666
  function expandBraces2(pattern, limit = 64) {
83305
83667
  for (let index = 0;index < pattern.length; index += 1) {
83306
83668
  if (pattern[index] === "\\") {
@@ -83546,7 +83908,7 @@ function parsePlan(raw, defaults, name) {
83546
83908
  id,
83547
83909
  branch,
83548
83910
  base: optional("base") ?? "",
83549
- worktree: path60.resolve(defaults.root, optional("worktree") ?? path60.join(defaults.worktreeRoot, id)),
83911
+ worktree: path61.resolve(defaults.root, optional("worktree") ?? path61.join(defaults.worktreeRoot, id)),
83550
83912
  tier,
83551
83913
  reason,
83552
83914
  dependsOn: [...new Set(dependsOn ?? [])],
@@ -83675,12 +84037,12 @@ function regeneratedFiles(root, tracked) {
83675
84037
  const found = new Map;
83676
84038
  let scripts;
83677
84039
  try {
83678
- const manifest = JSON.parse(fs29.readFileSync(path60.join(root, "package.json"), "utf8"));
84040
+ const manifest = JSON.parse(fs29.readFileSync(path61.join(root, "package.json"), "utf8"));
83679
84041
  scripts = manifest.scripts ?? {};
83680
84042
  } catch {
83681
84043
  return found;
83682
84044
  }
83683
- 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";
84045
+ 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";
83684
84046
  const outputs = tracked.filter((file) => !CODE.test(file));
83685
84047
  for (const [name, command] of Object.entries(scripts)) {
83686
84048
  if (!name.startsWith("write:") || typeof command !== "string")
@@ -83688,7 +84050,7 @@ function regeneratedFiles(root, tracked) {
83688
84050
  for (const file of command.match(/[\w./-]+\.[cm]?[jt]s\b/gu) ?? []) {
83689
84051
  let source;
83690
84052
  try {
83691
- source = fs29.readFileSync(path60.join(root, file), "utf8");
84053
+ source = fs29.readFileSync(path61.join(root, file), "utf8");
83692
84054
  } catch {
83693
84055
  continue;
83694
84056
  }
@@ -83810,11 +84172,11 @@ function defaultTrunk(cwd) {
83810
84172
  }
83811
84173
  function mainCheckout(cwd) {
83812
84174
  const common = gitCommonDir(cwd);
83813
- return common && path60.basename(common) === ".git" ? path60.dirname(common) : path60.resolve(cwd);
84175
+ return common && path61.basename(common) === ".git" ? path61.dirname(common) : path61.resolve(cwd);
83814
84176
  }
83815
84177
  function worktreeRoot(cwd) {
83816
84178
  const main = mainCheckout(cwd);
83817
- return path60.join(path60.dirname(main), `${path60.basename(main)}-wt`);
84179
+ return path61.join(path61.dirname(main), `${path61.basename(main)}-wt`);
83818
84180
  }
83819
84181
  function sliceHash(slice) {
83820
84182
  const {
@@ -83834,7 +84196,7 @@ function fanoutsDir(cwd) {
83834
84196
  const root = storeRoot(cwd);
83835
84197
  if (!root.ok)
83836
84198
  return fanoutFail(root.code, root.error, root.unblock);
83837
- return { ok: true, data: path60.join(root.value.root, "fanouts") };
84199
+ return { ok: true, data: path61.join(root.value.root, "fanouts") };
83838
84200
  }
83839
84201
  function parseStored(raw) {
83840
84202
  if (!isRecord13(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
@@ -83902,7 +84264,7 @@ function readFanout(cwd, name) {
83902
84264
  const dir = fanoutsDir(cwd);
83903
84265
  if (!dir.ok)
83904
84266
  return dir;
83905
- const file = path60.join(dir.data, stackFileName(name));
84267
+ const file = path61.join(dir.data, stackFileName(name));
83906
84268
  let parsed = null;
83907
84269
  try {
83908
84270
  parsed = parseStored(JSON.parse(fs29.readFileSync(file, "utf8")));
@@ -83927,7 +84289,7 @@ function listFanouts(cwd) {
83927
84289
  for (const entry of names) {
83928
84290
  let parsed = null;
83929
84291
  try {
83930
- parsed = parseStored(JSON.parse(fs29.readFileSync(path60.join(dir.data, entry), "utf8")));
84292
+ parsed = parseStored(JSON.parse(fs29.readFileSync(path61.join(dir.data, entry), "utf8")));
83931
84293
  } catch {
83932
84294
  parsed = null;
83933
84295
  }
@@ -83966,7 +84328,7 @@ function writeFanout(cwd, plan) {
83966
84328
  const dir = fanoutsDir(cwd);
83967
84329
  if (!dir.ok)
83968
84330
  return dir;
83969
- const file = path60.join(dir.data, stackFileName(plan.name));
84331
+ const file = path61.join(dir.data, stackFileName(plan.name));
83970
84332
  const temp = `${file}.${process.pid}.tmp`;
83971
84333
  try {
83972
84334
  fs29.mkdirSync(dir.data, { recursive: true });
@@ -84177,13 +84539,13 @@ var init_fanout = __esm(() => {
84177
84539
  // packages/workit-core/src/forge/exec.ts
84178
84540
  import { spawnSync as spawnSync24 } from "node:child_process";
84179
84541
  import fs30 from "node:fs";
84180
- import path61 from "node:path";
84542
+ import path62 from "node:path";
84181
84543
  function findExecutable(bin, env) {
84182
- const dirs = (env.PATH ?? env.Path ?? "").split(path61.delimiter).filter(Boolean);
84544
+ const dirs = (env.PATH ?? env.Path ?? "").split(path62.delimiter).filter(Boolean);
84183
84545
  const exts = process.platform === "win32" ? [".exe"] : [""];
84184
84546
  for (const dir of dirs)
84185
84547
  for (const ext of exts) {
84186
- const candidate = path61.join(dir, `${bin}${ext}`);
84548
+ const candidate = path62.join(dir, `${bin}${ext}`);
84187
84549
  try {
84188
84550
  const stat = fs30.statSync(candidate);
84189
84551
  if (stat.isFile())
@@ -85973,7 +86335,7 @@ var init_live_session = __esm(() => {
85973
86335
  });
85974
86336
 
85975
86337
  // packages/workit-core/src/hooks/write-gate.ts
85976
- import path62 from "node:path";
86338
+ import path63 from "node:path";
85977
86339
  var CASE_INSENSITIVE, PREFIXES2, SCRIPT_SHELLS, cache3, MUTATING_GIT, DRY_N, MUTATING_WORKIT_GIT, CD2, PUSHD2, POPD2, UNKNOWN_DIR;
85978
86340
  var init_write_gate = __esm(() => {
85979
86341
  init_task_store();
@@ -86013,7 +86375,7 @@ var init_write_gate = __esm(() => {
86013
86375
  CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
86014
86376
  PUSHD2 = new Set(["pushd", "push-location"]);
86015
86377
  POPD2 = new Set(["popd", "pop-location"]);
86016
- UNKNOWN_DIR = path62.resolve(path62.parse(process.cwd()).root, ".workit-unknown-dir");
86378
+ UNKNOWN_DIR = path63.resolve(path63.parse(process.cwd()).root, ".workit-unknown-dir");
86017
86379
  });
86018
86380
 
86019
86381
  // packages/workit-core/src/hooks/worktree-confine.ts
@@ -86038,20 +86400,20 @@ var init_worktree_confine = __esm(() => {
86038
86400
 
86039
86401
  // packages/workit-core/src/worktree-deps.ts
86040
86402
  import fs31 from "node:fs";
86041
- import path63 from "node:path";
86403
+ import path64 from "node:path";
86042
86404
  function moduleDirs(main) {
86043
86405
  const out = [];
86044
86406
  const walk = (relative, depth) => {
86045
86407
  let entries;
86046
86408
  try {
86047
- entries = fs31.readdirSync(path63.join(main, relative), { withFileTypes: true });
86409
+ entries = fs31.readdirSync(path64.join(main, relative), { withFileTypes: true });
86048
86410
  } catch {
86049
86411
  return;
86050
86412
  }
86051
86413
  for (const entry of entries) {
86052
86414
  if (!entry.isDirectory())
86053
86415
  continue;
86054
- const child = path63.join(relative, entry.name);
86416
+ const child = path64.join(relative, entry.name);
86055
86417
  if (entry.name === MODULES)
86056
86418
  out.push(child);
86057
86419
  else if (depth < MAX_DEPTH2 && !entry.name.startsWith("."))
@@ -86065,8 +86427,8 @@ function linkEntry(main, worktree, source, target) {
86065
86427
  const stat = fs31.lstatSync(source);
86066
86428
  if (stat.isSymbolicLink()) {
86067
86429
  const link = fs31.readlinkSync(source);
86068
- const outside = path63.isAbsolute(link) && within(link, main) && !path63.relative(main, link).split(path63.sep).includes(MODULES);
86069
- const to = outside ? path63.join(worktree, path63.relative(main, link)) : link;
86430
+ const outside = path64.isAbsolute(link) && within(link, main) && !path64.relative(main, link).split(path64.sep).includes(MODULES);
86431
+ const to = outside ? path64.join(worktree, path64.relative(main, link)) : link;
86070
86432
  fs31.symlinkSync(to, target, process.platform === "win32" ? "junction" : undefined);
86071
86433
  return;
86072
86434
  }
@@ -86076,8 +86438,8 @@ function mirror(main, worktree, source, target, top) {
86076
86438
  fs31.mkdirSync(target);
86077
86439
  let count = 0;
86078
86440
  for (const entry of fs31.readdirSync(source, { withFileTypes: true })) {
86079
- const from = path63.join(source, entry.name);
86080
- const to = path63.join(target, entry.name);
86441
+ const from = path64.join(source, entry.name);
86442
+ const to = path64.join(target, entry.name);
86081
86443
  if (top && entry.isDirectory() && (entry.name.startsWith("@") || entry.name === ".bin"))
86082
86444
  count += mirror(main, worktree, from, to, false);
86083
86445
  else {
@@ -86093,16 +86455,16 @@ function linkWorktreeDependencies(main, worktree) {
86093
86455
  const dirs = [];
86094
86456
  let entries = 0;
86095
86457
  for (const relative of moduleDirs(main)) {
86096
- const target = path63.join(worktree, relative);
86097
- if (!fs31.existsSync(path63.dirname(target)) || fs31.existsSync(target))
86458
+ const target = path64.join(worktree, relative);
86459
+ if (!fs31.existsSync(path64.dirname(target)) || fs31.existsSync(target))
86098
86460
  continue;
86099
- if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(path63.sep).join("/")}/`]).ok) {
86100
- 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`);
86461
+ if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(path64.sep).join("/")}/`]).ok) {
86462
+ 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`);
86101
86463
  continue;
86102
86464
  }
86103
86465
  try {
86104
- entries += mirror(main, worktree, path63.join(main, relative), target, true);
86105
- dirs.push(relative.split(path63.sep).join("/"));
86466
+ entries += mirror(main, worktree, path64.join(main, relative), target, true);
86467
+ dirs.push(relative.split(path64.sep).join("/"));
86106
86468
  } catch (error) {
86107
86469
  fs31.rmSync(target, { recursive: true, force: true });
86108
86470
  notes.push(`could not link ${relative} from ${main} (${error.message}); install dependencies in the worktree yourself`);
@@ -86115,8 +86477,8 @@ function linkWorktreeDependencies(main, worktree) {
86115
86477
  return { linked: { from: main, dirs, entries, ms }, notes };
86116
86478
  }
86117
86479
  var MODULES = "node_modules", MAX_DEPTH2 = 2, within = (child, parent) => {
86118
- const relative = path63.relative(parent, child);
86119
- return relative === "" || !relative.startsWith("..") && !path63.isAbsolute(relative);
86480
+ const relative = path64.relative(parent, child);
86481
+ return relative === "" || !relative.startsWith("..") && !path64.isAbsolute(relative);
86120
86482
  };
86121
86483
  var init_worktree_deps = __esm(() => {
86122
86484
  init_fanout();
@@ -86125,7 +86487,7 @@ var init_worktree_deps = __esm(() => {
86125
86487
  // packages/workit-core/src/fanout-worktree.ts
86126
86488
  import { randomBytes as randomBytes5 } from "node:crypto";
86127
86489
  import fs32 from "node:fs";
86128
- import path64 from "node:path";
86490
+ import path65 from "node:path";
86129
86491
  function rowSample(lines) {
86130
86492
  const out = [];
86131
86493
  let bytes = 0;
@@ -86185,7 +86547,7 @@ function adminDir(worktree) {
86185
86547
  const file = dir.stdout.trim();
86186
86548
  let token = null;
86187
86549
  try {
86188
- token = fs32.readFileSync(path64.join(file, FANOUT_TOKEN_FILE), "utf8").trim() || null;
86550
+ token = fs32.readFileSync(path65.join(file, FANOUT_TOKEN_FILE), "utf8").trim() || null;
86189
86551
  } catch {
86190
86552
  token = null;
86191
86553
  }
@@ -86193,7 +86555,7 @@ function adminDir(worktree) {
86193
86555
  const stat = worktreeDeps.stat(file);
86194
86556
  return {
86195
86557
  path: file,
86196
- id: path64.basename(file),
86558
+ id: path65.basename(file),
86197
86559
  ino: stat.ino.toString(),
86198
86560
  token,
86199
86561
  birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
@@ -86209,7 +86571,7 @@ function markAdminDir(worktree) {
86209
86571
  return null;
86210
86572
  const token = randomBytes5(16).toString("hex");
86211
86573
  try {
86212
- fs32.writeFileSync(path64.join(admin.path, FANOUT_TOKEN_FILE), `${token}
86574
+ fs32.writeFileSync(path65.join(admin.path, FANOUT_TOKEN_FILE), `${token}
86213
86575
  `);
86214
86576
  } catch {
86215
86577
  return null;
@@ -86224,7 +86586,7 @@ function excludeScratch(cwd) {
86224
86586
  const common = gitCommonDir(cwd);
86225
86587
  if (!common)
86226
86588
  return;
86227
- const file = path64.join(common, "info", "exclude");
86589
+ const file = path65.join(common, "info", "exclude");
86228
86590
  let text = "";
86229
86591
  try {
86230
86592
  text = fs32.readFileSync(file, "utf8");
@@ -86233,7 +86595,7 @@ function excludeScratch(cwd) {
86233
86595
  }
86234
86596
  if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
86235
86597
  return;
86236
- fs32.mkdirSync(path64.dirname(file), { recursive: true });
86598
+ fs32.mkdirSync(path65.dirname(file), { recursive: true });
86237
86599
  fs32.appendFileSync(file, `${text && !text.endsWith(`
86238
86600
  `) ? `
86239
86601
  ` : ""}# workit fanout: per-worker scratch dirs
@@ -86242,13 +86604,13 @@ ${EXCLUDE_LINE}
86242
86604
  }
86243
86605
  function worktreeDependencies(main, worktree) {
86244
86606
  for (const [name, install] of LOCKFILES2) {
86245
- const ours = readBytes(path64.join(main, name));
86246
- const theirs = readBytes(path64.join(worktree, name));
86607
+ const ours = readBytes(path65.join(main, name));
86608
+ const theirs = readBytes(path65.join(worktree, name));
86247
86609
  if (ours === null && theirs === null)
86248
86610
  continue;
86249
86611
  if (ours !== null && theirs !== null && ours.equals(theirs))
86250
86612
  continue;
86251
- if (fs32.existsSync(path64.join(worktree, "node_modules")))
86613
+ if (fs32.existsSync(path65.join(worktree, "node_modules")))
86252
86614
  break;
86253
86615
  const command = install(worktree);
86254
86616
  return {
@@ -86260,7 +86622,7 @@ function worktreeDependencies(main, worktree) {
86260
86622
  };
86261
86623
  }
86262
86624
  const stale = staleBunInstall(main);
86263
- if (stale && !fs32.existsSync(path64.join(worktree, "node_modules"))) {
86625
+ if (stale && !fs32.existsSync(path65.join(worktree, "node_modules"))) {
86264
86626
  const command = `bun install --frozen-lockfile --cwd ${worktree}`;
86265
86627
  return {
86266
86628
  linked: null,
@@ -86273,9 +86635,9 @@ function worktreeDependencies(main, worktree) {
86273
86635
  return { ...linkWorktreeDependencies(main, worktree), install: null };
86274
86636
  }
86275
86637
  function staleBunInstall(main) {
86276
- if (!fs32.existsSync(path64.join(main, "node_modules")))
86638
+ if (!fs32.existsSync(path65.join(main, "node_modules")))
86277
86639
  return null;
86278
- const text = readBytes(path64.join(main, "bun.lock"))?.toString("utf8");
86640
+ const text = readBytes(path65.join(main, "bun.lock"))?.toString("utf8");
86279
86641
  if (!text)
86280
86642
  return null;
86281
86643
  let packages;
@@ -86302,7 +86664,7 @@ function staleBunInstall(main) {
86302
86664
  const version = spec.slice(at + 1);
86303
86665
  if (name !== key || version.includes(":"))
86304
86666
  continue;
86305
- const manifest = readBytes(path64.join(main, "node_modules", key, "package.json"));
86667
+ const manifest = readBytes(path65.join(main, "node_modules", key, "package.json"));
86306
86668
  if (!manifest) {
86307
86669
  problems.push(`${key} missing`);
86308
86670
  continue;
@@ -86319,7 +86681,7 @@ function staleBunInstall(main) {
86319
86681
  return problems.length ? problems.join("; ") : null;
86320
86682
  }
86321
86683
  function ensureScratch(worktree) {
86322
- const scratch = path64.join(worktree, SCRATCH_DIR);
86684
+ const scratch = path65.join(worktree, SCRATCH_DIR);
86323
86685
  fs32.mkdirSync(scratch, { recursive: true });
86324
86686
  return scratch;
86325
86687
  }
@@ -86593,7 +86955,7 @@ function unpushedCount(cwd, branch) {
86593
86955
  return count.ok ? Number(count.stdout.trim()) : null;
86594
86956
  }
86595
86957
  function removeScratch(worktree) {
86596
- const scratch = path64.join(worktree, SCRATCH_DIR);
86958
+ const scratch = path65.join(worktree, SCRATCH_DIR);
86597
86959
  let stat;
86598
86960
  try {
86599
86961
  stat = fs32.lstatSync(scratch);
@@ -86609,16 +86971,16 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
86609
86971
  try {
86610
86972
  return fs32.realpathSync.native(target);
86611
86973
  } catch {
86612
- return path64.resolve(target);
86974
+ return path65.resolve(target);
86613
86975
  }
86614
86976
  }, samePath = (a, b) => {
86615
86977
  const left = canonical2(a);
86616
86978
  const right = canonical2(b);
86617
86979
  return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
86618
86980
  }, inside3 = (child, parent) => {
86619
- const relative = path64.relative(canonical2(parent), canonical2(child));
86620
- return relative === "" || !relative.startsWith("..") && !path64.isAbsolute(relative);
86621
- }, slicePath = (cwd, slice) => path64.isAbsolute(slice.worktree) ? slice.worktree : path64.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps, LOCKFILES2, readBytes = (file) => {
86981
+ const relative = path65.relative(canonical2(parent), canonical2(child));
86982
+ return relative === "" || !relative.startsWith("..") && !path65.isAbsolute(relative);
86983
+ }, slicePath = (cwd, slice) => path65.isAbsolute(slice.worktree) ? slice.worktree : path65.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps, LOCKFILES2, readBytes = (file) => {
86622
86984
  try {
86623
86985
  return fs32.readFileSync(file);
86624
86986
  } catch {
@@ -86650,7 +87012,7 @@ var init_fanout_worktree = __esm(() => {
86650
87012
 
86651
87013
  // packages/workit-core/src/forge/merge-cleanup.ts
86652
87014
  import fs33 from "node:fs";
86653
- import path65 from "node:path";
87015
+ import path66 from "node:path";
86654
87016
  function cleanupMergedBranch(cwd, branch, mergedHead) {
86655
87017
  const out = { branchDeleted: false, worktreeRemoved: null, notes: [] };
86656
87018
  if (!branch || branch.startsWith("-"))
@@ -86710,13 +87072,13 @@ var SLOW2, isFanoutWorktree = (worktree) => {
86710
87072
  if (!dir.ok)
86711
87073
  return false;
86712
87074
  try {
86713
- return fs33.readFileSync(path65.join(dir.stdout.trim(), FANOUT_TOKEN_FILE), "utf8").trim() !== "";
87075
+ return fs33.readFileSync(path66.join(dir.stdout.trim(), FANOUT_TOKEN_FILE), "utf8").trim() !== "";
86714
87076
  } catch {
86715
87077
  return false;
86716
87078
  }
86717
87079
  }, inside4 = (child, parent) => {
86718
- const relative = path65.relative(fs33.realpathSync.native(parent), fs33.realpathSync.native(child));
86719
- return relative === "" || !relative.startsWith("..") && !path65.isAbsolute(relative);
87080
+ const relative = path66.relative(fs33.realpathSync.native(parent), fs33.realpathSync.native(child));
87081
+ return relative === "" || !relative.startsWith("..") && !path66.isAbsolute(relative);
86720
87082
  };
86721
87083
  var init_merge_cleanup = __esm(() => {
86722
87084
  init_fanout();
@@ -87168,7 +87530,7 @@ __export(exports_pr, {
87168
87530
  run: () => run15
87169
87531
  });
87170
87532
  import { existsSync as existsSync27, readFileSync as readFileSync27 } from "node:fs";
87171
- import path66 from "node:path";
87533
+ import path67 from "node:path";
87172
87534
  function titleRules(cwd) {
87173
87535
  let root;
87174
87536
  try {
@@ -87179,7 +87541,7 @@ function titleRules(cwd) {
87179
87541
  let text = null;
87180
87542
  let name = "";
87181
87543
  for (const candidate of COMMITLINT_FILES) {
87182
- const full = path66.join(root, candidate);
87544
+ const full = path67.join(root, candidate);
87183
87545
  if (!existsSync27(full))
87184
87546
  continue;
87185
87547
  text = readFileSync27(full, "utf8");
@@ -87188,7 +87550,7 @@ function titleRules(cwd) {
87188
87550
  }
87189
87551
  if (text === null) {
87190
87552
  try {
87191
- const pkg = JSON.parse(readFileSync27(path66.join(root, "package.json"), "utf8"));
87553
+ const pkg = JSON.parse(readFileSync27(path67.join(root, "package.json"), "utf8"));
87192
87554
  if (pkg.commitlint === undefined)
87193
87555
  return { rules: null, note: null };
87194
87556
  text = JSON.stringify(pkg.commitlint);
@@ -87285,7 +87647,7 @@ function refuseTitle(io, title, line) {
87285
87647
  function readBodyFile(io, file) {
87286
87648
  try {
87287
87649
  return {
87288
- body: file === "-" ? forgeDeps.readStdin() : readFileSync27(path66.resolve(io.cwd, file), "utf8")
87650
+ body: file === "-" ? forgeDeps.readStdin() : readFileSync27(path67.resolve(io.cwd, file), "utf8")
87289
87651
  };
87290
87652
  } catch {
87291
87653
  return `cannot read --body-file ${file}`;
@@ -87930,6 +88292,11 @@ async function wait2(argv, io) {
87930
88292
  let verdict = { state: "waiting", reason: "not_polled" };
87931
88293
  let baseContexts = null;
87932
88294
  let expectedMissing = [];
88295
+ const waiting = createProgress({ stream: process.stderr, json: io.json }).start("Waiting for CI");
88296
+ const abort = (...args) => {
88297
+ waiting.end("failed");
88298
+ return forgeFail(io, ...args);
88299
+ };
87933
88300
  for (;; ) {
87934
88301
  const read = resolved.forge.prStatus(number.data);
87935
88302
  polls += 1;
@@ -87939,7 +88306,7 @@ async function wait2(argv, io) {
87939
88306
  status = read.data;
87940
88307
  const doc = buildStatusDoc(io.cwd, resolved, status, { logLines: 0, behind: false });
87941
88308
  if (!doc.ok)
87942
- return forgeFail(io, doc);
88309
+ return abort(doc);
87943
88310
  recordPrStatus(io.cwd, doc.data, actor);
87944
88311
  if (status.requiredContexts === null && baseContexts === null) {
87945
88312
  const base = resolved.forge.branchChecks(status.base);
@@ -87950,12 +88317,14 @@ async function wait2(argv, io) {
87950
88317
  verdict = waitVerdict(doc.data, { head, elapsedMs, expectedMissing });
87951
88318
  if (verdict.state !== "waiting")
87952
88319
  break;
88320
+ const pending = doc.data.checks.pending;
88321
+ waiting.label(`Waiting for CI: ${pending.length} check${pending.length === 1 ? "" : "s"} pending${pending.length ? ` (${pending.slice(0, 3).join(", ")}${pending.length > 3 ? ", …" : ""})` : ""}`);
87953
88322
  } else {
87954
88323
  errors += 1;
87955
88324
  if (read.code !== "unavailable" && read.code !== "failed")
87956
- return forgeFail(io, read);
88325
+ return abort(read);
87957
88326
  if (errors >= MAX_POLL_ERRORS)
87958
- return forgeFail(io, read, { polls });
88327
+ return abort(read, { polls });
87959
88328
  }
87960
88329
  const remaining = deadline - forgeDeps.now();
87961
88330
  if (remaining <= 0)
@@ -87963,6 +88332,7 @@ async function wait2(argv, io) {
87963
88332
  await forgeDeps.sleep(Math.min(pollDelay(intervalMs, polls - 1), remaining));
87964
88333
  }
87965
88334
  const elapsedMs = forgeDeps.now() - started;
88335
+ waiting.end(verdict.state === "ready" ? "done" : verdict.state === "waiting" ? "skipped" : "failed");
87966
88336
  if (!status)
87967
88337
  return emit(io, fail2("unavailable", "no successful poll before the timeout", { data: { polls } }));
87968
88338
  const left = deadline - forgeDeps.now();
@@ -88129,6 +88499,7 @@ var init_ci = __esm(() => {
88129
88499
  init_ledger();
88130
88500
  init_autonomy();
88131
88501
  init_output();
88502
+ init_progress();
88132
88503
  init_forge_common();
88133
88504
  });
88134
88505
 
@@ -88165,7 +88536,7 @@ __export(exports_git, {
88165
88536
  run: () => run17
88166
88537
  });
88167
88538
  import { readFileSync as readFileSync28 } from "node:fs";
88168
- import path67 from "node:path";
88539
+ import path68 from "node:path";
88169
88540
  function kindHint(cwd, kind) {
88170
88541
  let kinds = [...BRANCH_KINDS];
88171
88542
  try {
@@ -88269,7 +88640,7 @@ function commitMessage(parsed, io) {
88269
88640
 
88270
88641
  `);
88271
88642
  try {
88272
- return file === "-" ? readFileSync28(0, "utf8") : readFileSync28(path67.resolve(io.cwd, file), "utf8");
88643
+ return file === "-" ? readFileSync28(0, "utf8") : readFileSync28(path68.resolve(io.cwd, file), "utf8");
88273
88644
  } catch (error) {
88274
88645
  return {
88275
88646
  error: `cannot read -F ${file}: ${error instanceof Error ? error.message : String(error)}`
@@ -89727,7 +90098,7 @@ var init_stack2 = __esm(() => {
89727
90098
  // packages/workit-core/src/fanout-brief.ts
89728
90099
  import { createHash as createHash20 } from "node:crypto";
89729
90100
  import fs35 from "node:fs";
89730
- import path68 from "node:path";
90101
+ import path69 from "node:path";
89731
90102
  function workerSession(lead, slice, attempt) {
89732
90103
  const tail = attempt === null ? "" : `+try${attempt}`;
89733
90104
  const full = `${lead}-w-${slice}${tail}`;
@@ -89810,7 +90181,7 @@ function renderBrief(cwd, plan, input) {
89810
90181
  "STANDING:",
89811
90182
  ...standing.length ? standing.map((order) => ` - ${order.what}`) : [" - none recorded beyond this brief"],
89812
90183
  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)`,
89813
- ...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`] : [],
90184
+ ...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`] : [],
89814
90185
  ...identityLines(identity, minted),
89815
90186
  ...rules(mode, branch, sliceBase, exists ? planned : null)
89816
90187
  ];
@@ -90352,7 +90723,7 @@ __export(exports_fanout, {
90352
90723
  run: () => run21
90353
90724
  });
90354
90725
  import fs36 from "node:fs";
90355
- import path69 from "node:path";
90726
+ import path70 from "node:path";
90356
90727
  function forgeFor(io, offline) {
90357
90728
  if (offline)
90358
90729
  return { forge: null, error: "--offline" };
@@ -90413,7 +90784,7 @@ function plan2(argv, io) {
90413
90784
  return usage4(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
90414
90785
  if (flags.positionals.length !== 1)
90415
90786
  return usage4(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
90416
- const file = path69.resolve(io.cwd, flags.positionals[0]);
90787
+ const file = path70.resolve(io.cwd, flags.positionals[0]);
90417
90788
  let raw;
90418
90789
  try {
90419
90790
  raw = JSON.parse(fs36.readFileSync(file, "utf8"));
@@ -105988,7 +106359,7 @@ var init_ast = __esm(() => {
105988
106359
 
105989
106360
  // packages/workit-cli/src/test-audit/rules.ts
105990
106361
  import { builtinModules } from "node:module";
105991
- import path70 from "node:path";
106362
+ import path71 from "node:path";
105992
106363
  function testCallee(call) {
105993
106364
  let callee = call.callee;
105994
106365
  if (callee.type === "CallExpression")
@@ -106481,12 +106852,12 @@ function checkConstantsOnly(ctx, emit) {
106481
106852
  }
106482
106853
  function checkOverMocking(ctx, emit) {
106483
106854
  const { program } = ctx.parsed;
106484
- const unit = path70.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
106855
+ const unit = path71.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
106485
106856
  const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
106486
106857
  const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
106487
106858
  for (const call of mocked) {
106488
106859
  const spec = call.arguments[0].value;
106489
- const base = path70.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
106860
+ const base = path71.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
106490
106861
  if (base === unit)
106491
106862
  emit({
106492
106863
  rule: "over-mocking",
@@ -106876,7 +107247,7 @@ var init_rules = __esm(() => {
106876
107247
  // packages/workit-cli/src/test-audit/audit.ts
106877
107248
  import { spawnSync as spawnSync29 } from "node:child_process";
106878
107249
  import { existsSync as existsSync28, readdirSync as readdirSync14, readFileSync as readFileSync29, statSync as statSync10 } from "node:fs";
106879
- import path71 from "node:path";
107250
+ import path72 from "node:path";
106880
107251
  function git7(cwd, args) {
106881
107252
  const run = spawnSync29("git", ["-c", "core.quotepath=off", ...args], {
106882
107253
  cwd,
@@ -106889,7 +107260,7 @@ function walkTests(dir, out) {
106889
107260
  for (const entry of readdirSync14(dir, { withFileTypes: true })) {
106890
107261
  if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
106891
107262
  continue;
106892
- const full = path71.join(dir, entry.name);
107263
+ const full = path72.join(dir, entry.name);
106893
107264
  if (entry.isDirectory()) {
106894
107265
  if (!SKIP_DIRS.has(entry.name))
106895
107266
  walkTests(full, out);
@@ -106901,7 +107272,7 @@ function expandPaths(cwd, inputs) {
106901
107272
  const files = [];
106902
107273
  const missing = [];
106903
107274
  for (const input of inputs.length > 0 ? inputs : ["."]) {
106904
- const full = path71.resolve(cwd, input);
107275
+ const full = path72.resolve(cwd, input);
106905
107276
  if (!existsSync28(full))
106906
107277
  missing.push(input);
106907
107278
  else if (statSync10(full).isDirectory())
@@ -106938,11 +107309,11 @@ function changedLines(cwd, base) {
106938
107309
  for (let offset = 0;offset < count; offset += 1)
106939
107310
  lines.add(start + offset);
106940
107311
  }
106941
- changed.set(path71.join(root, file), lines);
107312
+ changed.set(path72.join(root, file), lines);
106942
107313
  }
106943
107314
  const untracked = git7(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
106944
107315
  for (const file of untracked.stdout.split("\x00").filter(Boolean))
106945
- changed.set(path71.join(root, file), "all");
107316
+ changed.set(path72.join(root, file), "all");
106946
107317
  return changed;
106947
107318
  }
106948
107319
  function auditFiles(files, display) {
@@ -107004,7 +107375,7 @@ function auditFiles(files, display) {
107004
107375
  durationMs: Math.round(performance.now() - started)
107005
107376
  };
107006
107377
  }
107007
- var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path71.sep).join("/"), SEVERITY_ORDER, ruleIds;
107378
+ var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path72.sep).join("/"), SEVERITY_ORDER, ruleIds;
107008
107379
  var init_audit = __esm(() => {
107009
107380
  init_ast();
107010
107381
  init_rules();
@@ -107016,7 +107387,7 @@ var init_audit = __esm(() => {
107016
107387
  });
107017
107388
 
107018
107389
  // packages/workit-cli/src/test-audit/mutate.ts
107019
- import { spawn as spawn2 } from "node:child_process";
107390
+ import { spawn as spawn4 } from "node:child_process";
107020
107391
  import {
107021
107392
  existsSync as existsSync29,
107022
107393
  lstatSync as lstatSync9,
@@ -107034,7 +107405,7 @@ import {
107034
107405
  copyFileSync as copyFileSync8
107035
107406
  } from "node:fs";
107036
107407
  import os23 from "node:os";
107037
- import path72 from "node:path";
107408
+ import path73 from "node:path";
107038
107409
  function mutantsFor(source, file, lines) {
107039
107410
  const parsed = parseSource(source, file);
107040
107411
  const out = [];
@@ -107107,7 +107478,7 @@ function relatedTests(source, testFiles) {
107107
107478
  for (const match of text.matchAll(SPECIFIER)) {
107108
107479
  const spec = match[1];
107109
107480
  if (spec.startsWith(".")) {
107110
- if (stripExt(path72.posix.join(path72.posix.dirname(file), spec)) === target)
107481
+ if (stripExt(path73.posix.join(path73.posix.dirname(file), spec)) === target)
107111
107482
  return true;
107112
107483
  } else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
107113
107484
  return true;
@@ -107127,12 +107498,12 @@ function removeStaleCopies(tmp = os23.tmpdir()) {
107127
107498
  for (const name of names) {
107128
107499
  if (!name.startsWith(TEMP_PREFIX))
107129
107500
  continue;
107130
- const dir = path72.join(tmp, name);
107501
+ const dir = path73.join(tmp, name);
107131
107502
  try {
107132
107503
  const stat = lstatSync9(dir);
107133
107504
  if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
107134
107505
  continue;
107135
- const pid = Number(readFileSync30(path72.join(dir, PID_FILE), "utf8"));
107506
+ const pid = Number(readFileSync30(path73.join(dir, PID_FILE), "utf8"));
107136
107507
  if (Number.isInteger(pid) && pid > 0 && alive(pid))
107137
107508
  continue;
107138
107509
  } catch (error) {
@@ -107149,8 +107520,8 @@ function removeStaleCopies(tmp = os23.tmpdir()) {
107149
107520
  function linkNodeModules(origin, target, repo, copy) {
107150
107521
  mkdirSync12(target, { recursive: true });
107151
107522
  for (const entry of readdirSync15(origin, { withFileTypes: true })) {
107152
- const from = path72.join(origin, entry.name);
107153
- const to = path72.join(target, entry.name);
107523
+ const from = path73.join(origin, entry.name);
107524
+ const to = path73.join(target, entry.name);
107154
107525
  if (entry.name.startsWith("@") && entry.isDirectory()) {
107155
107526
  linkNodeModules(from, to, repo, copy);
107156
107527
  continue;
@@ -107166,9 +107537,9 @@ function linkNodeModules(origin, target, repo, copy) {
107166
107537
  } catch {
107167
107538
  continue;
107168
107539
  }
107169
- const relative = path72.relative(repo, real);
107170
- if (!relative.startsWith("..") && !path72.isAbsolute(relative) && !relative.split(path72.sep).includes("node_modules")) {
107171
- symlinkSync(path72.join(copy, relative), to, "junction");
107540
+ const relative = path73.relative(repo, real);
107541
+ if (!relative.startsWith("..") && !path73.isAbsolute(relative) && !relative.split(path73.sep).includes("node_modules")) {
107542
+ symlinkSync(path73.join(copy, relative), to, "junction");
107172
107543
  continue;
107173
107544
  }
107174
107545
  }
@@ -107184,7 +107555,7 @@ function copySymlink(repo, tree, from, to) {
107184
107555
  }
107185
107556
  const realRepo = realpathSync11(repo);
107186
107557
  if (real && inside5(realRepo, real)) {
107187
- symlinkSync(path72.relative(path72.dirname(to), path72.join(tree, path72.relative(realRepo, real))), to);
107558
+ symlinkSync(path73.relative(path73.dirname(to), path73.join(tree, path73.relative(realRepo, real))), to);
107188
107559
  return;
107189
107560
  }
107190
107561
  if (real && statSync11(real).isFile())
@@ -107193,10 +107564,10 @@ function copySymlink(repo, tree, from, to) {
107193
107564
  symlinkSync(readlinkSync3(from), to);
107194
107565
  }
107195
107566
  function writeInside(copy, file, content) {
107196
- const target = path72.join(copy, file);
107567
+ const target = path73.join(copy, file);
107197
107568
  try {
107198
107569
  const stat = lstatSync9(target);
107199
- if (!stat.isFile() || !inside5(realpathSync11(copy), realpathSync11(path72.dirname(target))))
107570
+ if (!stat.isFile() || !inside5(realpathSync11(copy), realpathSync11(path73.dirname(target))))
107200
107571
  return false;
107201
107572
  } catch {
107202
107573
  return false;
@@ -107207,9 +107578,9 @@ function writeInside(copy, file, content) {
107207
107578
  return true;
107208
107579
  }
107209
107580
  function copyWorkingTree(repo) {
107210
- const dir = mkdtempSync4(path72.join(os23.tmpdir(), TEMP_PREFIX));
107211
- writeFileSync13(path72.join(dir, PID_FILE), String(process.pid));
107212
- const tree = path72.join(dir, "tree");
107581
+ const dir = mkdtempSync4(path73.join(os23.tmpdir(), TEMP_PREFIX));
107582
+ writeFileSync13(path73.join(dir, PID_FILE), String(process.pid));
107583
+ const tree = path73.join(dir, "tree");
107213
107584
  const head = git7(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
107214
107585
  if (head && git7(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
107215
107586
  const branch = git7(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
@@ -107226,36 +107597,36 @@ function copyWorkingTree(repo) {
107226
107597
  for (const relative of listed) {
107227
107598
  if (!relative)
107228
107599
  continue;
107229
- const from = path72.join(repo, relative);
107600
+ const from = path73.join(repo, relative);
107230
107601
  let stat;
107231
107602
  try {
107232
107603
  stat = lstatSync9(from);
107233
107604
  } catch {
107234
107605
  continue;
107235
107606
  }
107236
- const to = path72.join(tree, relative);
107237
- mkdirSync12(path72.dirname(to), { recursive: true });
107607
+ const to = path73.join(tree, relative);
107608
+ mkdirSync12(path73.dirname(to), { recursive: true });
107238
107609
  if (stat.isSymbolicLink())
107239
107610
  copySymlink(repo, tree, from, to);
107240
107611
  else if (stat.isFile())
107241
107612
  copyFileSync8(from, to);
107242
- let parent = path72.dirname(relative);
107613
+ let parent = path73.dirname(relative);
107243
107614
  while (parent !== "." && !dirs.has(parent)) {
107244
107615
  dirs.add(parent);
107245
- parent = path72.dirname(parent);
107616
+ parent = path73.dirname(parent);
107246
107617
  }
107247
107618
  }
107248
107619
  for (const parent of dirs) {
107249
- const modules = path72.join(repo, parent, "node_modules");
107250
- if (existsSync29(modules) && !existsSync29(path72.join(tree, parent, "node_modules")))
107251
- linkNodeModules(modules, path72.join(tree, parent, "node_modules"), repo, tree);
107620
+ const modules = path73.join(repo, parent, "node_modules");
107621
+ if (existsSync29(modules) && !existsSync29(path73.join(tree, parent, "node_modules")))
107622
+ linkNodeModules(modules, path73.join(tree, parent, "node_modules"), repo, tree);
107252
107623
  }
107253
107624
  return { dir, tree };
107254
107625
  }
107255
107626
  function runCommand(command, cwd, timeoutMs, env) {
107256
107627
  const started = performance.now();
107257
107628
  return new Promise((resolve) => {
107258
- const child = spawn2(command, {
107629
+ const child = spawn4(command, {
107259
107630
  cwd,
107260
107631
  env,
107261
107632
  shell: true,
@@ -107287,14 +107658,14 @@ async function runMutation(options) {
107287
107658
  const tracked = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
107288
107659
  const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
107289
107660
  try {
107290
- return { file, text: readFileSync30(path72.join(repo, file), "utf8") };
107661
+ return { file, text: readFileSync30(path73.join(repo, file), "utf8") };
107291
107662
  } catch {
107292
107663
  return { file, text: "" };
107293
107664
  }
107294
107665
  });
107295
107666
  const candidates = [];
107296
107667
  for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
107297
- const relative = toPosix(path72.relative(repo, absolute));
107668
+ const relative = toPosix(path73.relative(repo, absolute));
107298
107669
  if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
107299
107670
  continue;
107300
107671
  if (NOT_SOURCE.test(relative) || !existsSync29(absolute))
@@ -107308,9 +107679,9 @@ async function runMutation(options) {
107308
107679
  for (const mutant of mutants)
107309
107680
  if (!related.has(mutant.file))
107310
107681
  related.set(mutant.file, relatedTests(mutant.file, testFiles));
107311
- const cwdRelative = path72.relative(repo, options.cwd);
107682
+ const cwdRelative = path73.relative(repo, options.cwd);
107312
107683
  const asArg = (file) => {
107313
- const relative = toPosix(path72.relative(cwdRelative, file));
107684
+ const relative = toPosix(path73.relative(cwdRelative, file));
107314
107685
  return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
107315
107686
  };
107316
107687
  const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
@@ -107346,7 +107717,7 @@ async function runMutation(options) {
107346
107717
  return finish3(options, 0, results, counts, started);
107347
107718
  removeStaleCopies();
107348
107719
  const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
107349
- const copyCwd = path72.join(copy, cwdRelative);
107720
+ const copyCwd = path73.join(copy, cwdRelative);
107350
107721
  let current = null;
107351
107722
  const restore = () => {
107352
107723
  if (current)
@@ -107381,7 +107752,7 @@ async function runMutation(options) {
107381
107752
  record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
107382
107753
  continue;
107383
107754
  }
107384
- const original = readFileSync30(path72.join(copy, mutant.file), "utf8");
107755
+ const original = readFileSync30(path73.join(copy, mutant.file), "utf8");
107385
107756
  const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
107386
107757
  current = { file: mutant.file, original };
107387
107758
  if (!writeInside(copy, mutant.file, mutated)) {
@@ -107438,8 +107809,8 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
107438
107809
  return error.code === "EPERM";
107439
107810
  }
107440
107811
  }, inside5 = (root, file) => {
107441
- const relative = path72.relative(root, file);
107442
- return relative === "" || !relative.startsWith("..") && !path72.isAbsolute(relative);
107812
+ const relative = path73.relative(root, file);
107813
+ return relative === "" || !relative.startsWith("..") && !path73.isAbsolute(relative);
107443
107814
  }, active, killTree = (child) => {
107444
107815
  try {
107445
107816
  if (child.pid && process.platform !== "win32")
@@ -107488,7 +107859,7 @@ __export(exports_test_audit, {
107488
107859
  run: () => run23
107489
107860
  });
107490
107861
  import { existsSync as existsSync30 } from "node:fs";
107491
- import path73 from "node:path";
107862
+ import path74 from "node:path";
107492
107863
  function parse8(argv) {
107493
107864
  const options = {
107494
107865
  paths: [],
@@ -107593,8 +107964,8 @@ async function run23(argv, io) {
107593
107964
  return emit(io, fail2("invalid_input", `${options}
107594
107965
  usage: ${USAGE16}`));
107595
107966
  const top = git7(io.cwd, ["rev-parse", "--show-toplevel"]);
107596
- const repo = top.ok ? path73.resolve(top.stdout.trim()) : null;
107597
- const display = (file) => toPosix(path73.relative(io.cwd, file) || file);
107967
+ const repo = top.ok ? path74.resolve(top.stdout.trim()) : null;
107968
+ const display = (file) => toPosix(path74.relative(io.cwd, file) || file);
107598
107969
  let base = null;
107599
107970
  let changed = null;
107600
107971
  if (options.diff || options.mutate) {
@@ -107733,7 +108104,7 @@ __export(exports_youtrack, {
107733
108104
  run: () => run25
107734
108105
  });
107735
108106
  import { readFileSync as readFileSync31 } from "node:fs";
107736
- import path74 from "node:path";
108107
+ import path75 from "node:path";
107737
108108
  async function run25(argv, io) {
107738
108109
  const [sub, ...rest] = argv;
107739
108110
  if (sub !== "note" && sub !== "time" && sub !== "meeting")
@@ -107779,7 +108150,7 @@ async function run25(argv, io) {
107779
108150
  let markdown = flags.values.markdown ?? "";
107780
108151
  if (flags.values.file)
107781
108152
  try {
107782
- markdown = readFileSync31(path74.resolve(io.cwd, flags.values.file), "utf8");
108153
+ markdown = readFileSync31(path75.resolve(io.cwd, flags.values.file), "utf8");
107783
108154
  } catch (error) {
107784
108155
  return usage4(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE18);
107785
108156
  }
@@ -107848,7 +108219,7 @@ __export(exports_changelog, {
107848
108219
  run: () => run26
107849
108220
  });
107850
108221
  import { readFileSync as readFileSync32 } from "node:fs";
107851
- import path75 from "node:path";
108222
+ import path76 from "node:path";
107852
108223
  async function run26(argv, io) {
107853
108224
  const [sub, ...rest] = argv;
107854
108225
  if (sub !== "apply")
@@ -107894,7 +108265,7 @@ async function run26(argv, io) {
107894
108265
  ]);
107895
108266
  }
107896
108267
  var USAGE19 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
107897
- const text = raw === "-" ? readFileSync32(0, "utf8") : raw.startsWith("@") ? readFileSync32(path75.resolve(cwd, raw.slice(1)), "utf8") : raw;
108268
+ const text = raw === "-" ? readFileSync32(0, "utf8") : raw.startsWith("@") ? readFileSync32(path76.resolve(cwd, raw.slice(1)), "utf8") : raw;
107898
108269
  return JSON.parse(text);
107899
108270
  };
107900
108271
  var init_changelog2 = __esm(() => {
@@ -107910,7 +108281,7 @@ __export(exports_handoff, {
107910
108281
  run: () => run27
107911
108282
  });
107912
108283
  import fs37 from "node:fs";
107913
- import path76 from "node:path";
108284
+ import path77 from "node:path";
107914
108285
  import { parseArgs as parseArgs2 } from "node:util";
107915
108286
  function render3(brief) {
107916
108287
  const lines = [
@@ -107950,9 +108321,9 @@ function bounded(brief, cwd) {
107950
108321
  let file = null;
107951
108322
  if (store.ok)
107952
108323
  try {
107953
- const dir = path76.join(store.value.root, "handoff");
108324
+ const dir = path77.join(store.value.root, "handoff");
107954
108325
  fs37.mkdirSync(dir, { recursive: true });
107955
- file = path76.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
108326
+ file = path77.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
107956
108327
  fs37.writeFileSync(file, `${[...body, ...tail].join(`
107957
108328
  `)}
107958
108329
  `, {
@@ -108027,7 +108398,7 @@ var init_handoff = __esm(() => {
108027
108398
  });
108028
108399
 
108029
108400
  // packages/workit-cli/src/main.ts
108030
- import path77 from "node:path";
108401
+ import path78 from "node:path";
108031
108402
 
108032
108403
  // packages/workit-core/src/git/env-redirect.ts
108033
108404
  var GIT_REDIRECT_ENV = [
@@ -108976,7 +109347,7 @@ var defaultIo = (json) => ({
108976
109347
  });
108977
109348
  async function main(argv, overrides = {}, options = {}) {
108978
109349
  const parsed = parseGlobals(argv);
108979
- const cwd = path77.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
109350
+ const cwd = path78.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
108980
109351
  const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
108981
109352
  if (parsed.error)
108982
109353
  return emit(io, fail2("invalid_input", parsed.error));