@brainervirus/workit-cli 8.38.2 → 8.38.3

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 +928 -826
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -9317,7 +9317,7 @@ var package_default;
9317
9317
  var init_package = __esm(() => {
9318
9318
  package_default = {
9319
9319
  name: "@brainervirus/workit-cli",
9320
- version: "8.38.2",
9320
+ version: "8.38.3",
9321
9321
  private: false,
9322
9322
  description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
9323
9323
  keywords: [
@@ -9355,13 +9355,13 @@ var init_package = __esm(() => {
9355
9355
  },
9356
9356
  dependencies: {
9357
9357
  "@babel/parser": "7.29.9",
9358
- "@brainervirus/workit-cursor": "^8.38.2",
9358
+ "@brainervirus/workit-cursor": "^8.38.3",
9359
9359
  "@inkjs/ui": "2.0.0",
9360
9360
  ink: "7.1.1",
9361
9361
  react: "19.2.8"
9362
9362
  },
9363
9363
  devDependencies: {
9364
- "@brainervirus/workit-core": "^8.38.2"
9364
+ "@brainervirus/workit-core": "^8.38.3"
9365
9365
  },
9366
9366
  engines: {
9367
9367
  node: ">=24"
@@ -74838,171 +74838,156 @@ var init_setup2 = __esm(() => {
74838
74838
  ALL_HOSTS = ["claude-code", "codex", "cursor", "opencode", "pi"];
74839
74839
  });
74840
74840
 
74841
- // packages/workit-cli/src/upgrade.ts
74842
- import { spawnSync as spawnSync17 } from "node:child_process";
74843
- import {
74844
- existsSync as existsSync20,
74845
- mkdtempSync as mkdtempSync3,
74846
- rmSync as rmSync8,
74847
- readFileSync as readFileSync21,
74848
- readdirSync as readdirSync12,
74849
- mkdirSync as mkdirSync11,
74850
- copyFileSync as copyFileSync6,
74851
- chmodSync as chmodSync2,
74852
- cpSync as cpSync5,
74853
- lstatSync as lstatSync7
74854
- } from "node:fs";
74841
+ // packages/workit-cli/src/upgrade/shared.ts
74842
+ import { existsSync as existsSync20, readFileSync as readFileSync21 } from "node:fs";
74855
74843
  import path44 from "node:path";
74856
74844
  import os16 from "node:os";
74857
74845
  import { createHash as createHash15 } from "node:crypto";
74858
- function previewUpgrade(hosts = HOSTS2, deps = {}) {
74859
- const paths = upgradePaths(deps);
74860
- const { home, configDir } = paths;
74861
- const run = runner(deps);
74862
- const state = readSetupState(configDir);
74863
- const plan = {
74864
- ok: true,
74865
- blocked: [],
74866
- failed: [],
74867
- skipped: [],
74868
- entries: [],
74869
- configDigests: {},
74870
- migrations: []
74846
+ 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) => {
74847
+ const home = deps.home ?? deps.env?.HOME ?? os16.homedir();
74848
+ const env = {
74849
+ ...process.env,
74850
+ ...deps.home || deps.env?.HOME ? {
74851
+ HOME: home,
74852
+ CODEX_HOME: path44.join(home, ".codex"),
74853
+ CLAUDE_CONFIG_DIR: path44.join(home, ".claude"),
74854
+ PI_CODING_AGENT_DIR: path44.join(home, ".pi/agent"),
74855
+ XDG_CONFIG_HOME: path44.join(home, ".config"),
74856
+ WORKFLOW_TOOLKIT_CONFIG: undefined,
74857
+ WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
74858
+ } : {},
74859
+ ...deps.env,
74860
+ HOME: home
74871
74861
  };
74872
- for (const file of [state.config, state.workspaces, state.youtrack, state.vcs]) {
74873
- if (file.status === "malformed")
74874
- plan.blocked.push(file.error ?? file.file);
74875
- plan.configDigests[file.file] = digest2(file.file);
74862
+ const xdg = env.XDG_CONFIG_HOME || path44.join(home, ".config");
74863
+ const codexHome = env.CODEX_HOME ?? path44.join(home, ".codex");
74864
+ return {
74865
+ home,
74866
+ env,
74867
+ configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path44.join(xdg, "workit"),
74868
+ opencodeConfig: path44.join(xdg, "opencode/opencode.json"),
74869
+ piSettings: path44.join(env.PI_CODING_AGENT_DIR ?? path44.join(home, ".pi/agent"), "settings.json"),
74870
+ codexHome,
74871
+ codexConfig: path44.join(codexHome, "config.toml"),
74872
+ cursorRoot: path44.join(home, ".cursor/plugins/local/workit")
74873
+ };
74874
+ }, object2 = (file) => {
74875
+ if (!existsSync20(file))
74876
+ return null;
74877
+ let data;
74878
+ try {
74879
+ data = JSON.parse(readFileSync21(file, "utf8"));
74880
+ } catch {
74881
+ throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
74876
74882
  }
74877
- for (const file of [
74878
- paths.opencodeConfig,
74879
- paths.opencodeConfig + "c",
74880
- path44.join(home, ".cursor/settings.json"),
74881
- path44.join(home, ".cursor/mcp.json"),
74882
- path44.join(paths.cursorRoot, "package.json"),
74883
- paths.codexConfig,
74884
- paths.piSettings
74885
- ])
74886
- plan.configDigests[file] = digest2(file);
74883
+ if (!data || typeof data !== "object" || Array.isArray(data))
74884
+ throw new Error(`${file} is not a configuration object`);
74885
+ return data;
74886
+ }, objectOrNull = (file) => {
74887
74887
  try {
74888
- const config = object2(state.config.file);
74889
- if (config && Object.hasOwn(config, "trustedPaths"))
74890
- plan.migrations.push({
74891
- id: "2.0-remove-ignored-trusted-paths",
74892
- file: state.config.file,
74893
- description: "Remove ignored Workit trustedPaths; native host permissions remain unchanged"
74894
- });
74895
- } catch (error) {
74896
- plan.blocked.push(errorText(error));
74888
+ return object2(file);
74889
+ } catch {
74890
+ return null;
74897
74891
  }
74898
- const installedSources = sources(paths, run, hosts, plan.failed);
74899
- let opencodeHelp;
74900
- if (installedSources.some((source) => source.host === "opencode")) {
74901
- const probe = opencodeProbe(deps, ["--version"]);
74902
- const installed = probe.status === 0 ? probe.stdout.match(/\d+\.\d+\.\d+/)?.[0] : undefined;
74903
- if (installed && !versionAtLeast(installed, SUPPORT_MATRIX.opencode.minimum))
74904
- (plan.warnings ??= []).push(`opencode ${installed}: ${OPENCODE_V1_FIX}`);
74892
+ }, digest2 = (file) => existsSync20(file) ? createHash15("sha256").update(readFileSync21(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
74893
+ const { home, env } = upgradePaths(deps);
74894
+ let step;
74895
+ try {
74896
+ step = hostCommand(command, args, { home, env });
74897
+ } catch {
74898
+ return { status: 1, stdout: "" };
74905
74899
  }
74906
- for (const host of ["opencode", "pi"]) {
74907
- if (new Set(installedSources.filter((source) => source.host === host).map((source) => source.selector)).size > 1)
74908
- plan.failed.push({
74909
- host,
74910
- status: "failed",
74911
- reason: "conflicting Workit registrations; reconcile them in the native host before upgrading"
74912
- });
74900
+ const result = runHostCommand(step, { home, env });
74901
+ return { status: result.exitCode, stdout: result.stdout };
74902
+ }), errorText = (error) => error instanceof Error ? error.message : "installed source could not be read", piInstalledVersion = (listing, selector) => {
74903
+ const lines = listing.split(/\r?\n/).map((line) => line.trim());
74904
+ const index = lines.indexOf(selector);
74905
+ if (index < 0 || !lines[index + 1] || !path44.isAbsolute(lines[index + 1]))
74906
+ return;
74907
+ const found = objectOrNull(path44.join(lines[index + 1], "package.json"));
74908
+ return found?.name === "@brainervirus/workit-pi" ? found.version : undefined;
74909
+ }, versionAtLeast = (installed, latest) => {
74910
+ if (!/^\d+\.\d+\.\d+$/.test(installed))
74911
+ return false;
74912
+ const current = installed.split(".").map(Number);
74913
+ const target = latest.split(".").map(Number);
74914
+ for (let index = 0;index < 3; index++) {
74915
+ if (current[index] !== target[index])
74916
+ return current[index] > target[index];
74913
74917
  }
74914
- const conflicted = new Set(plan.failed.map((entry) => entry.host));
74915
- for (const source of installedSources.filter((candidate, index, list) => !conflicted.has(candidate.host) && list.findIndex((entry) => entry.host === candidate.host && entry.selector === candidate.selector) === index)) {
74916
- if (source.kind === "pinned" || source.kind === "local") {
74917
- plan.skipped.push({
74918
- host: source.host,
74919
- reason: `${source.kind} source preserved; change its source explicitly to upgrade`
74920
- });
74921
- continue;
74922
- }
74923
- if (source.host === "claude-code") {
74924
- const [market] = source.selector.split("@").slice(1);
74925
- plan.entries.push({
74926
- host: "claude-code",
74927
- selector: source.selector,
74928
- latest: "",
74929
- installedVersion: source.installedVersion,
74930
- commands: [
74931
- {
74932
- command: "claude",
74933
- args: ["plugin", "marketplace", "update", market ?? "workit"]
74934
- },
74935
- { command: "claude", args: ["plugin", "update", source.selector] }
74936
- ],
74937
- fix: `claude plugin marketplace update ${market ?? "workit"} && claude plugin update ${source.selector}`
74938
- });
74939
- continue;
74940
- }
74941
- if (source.host === "opencode") {
74942
- opencodeHelp ??= opencodeProbe(deps, ["plugin", "--help"]).stdout;
74943
- if (!/^\s*(?:opencode\s+plugin\s+)?update\b/m.test(opencodeHelp)) {
74944
- plan.skipped.push({
74945
- host: "opencode",
74946
- reason: "this OpenCode has no `opencode plugin update`; upgrade OpenCode, then run the fix. Workit never updates unrelated plugins",
74947
- fix: OPENCODE_UPDATE
74948
- });
74949
- continue;
74950
- }
74951
- plan.entries.push({
74952
- host: "opencode",
74953
- selector: source.selector,
74954
- latest: "",
74955
- commands: [{ command: "opencode", args: ["plugin", "update", OPENCODE_PACKAGE] }],
74956
- fix: OPENCODE_UPDATE
74957
- });
74958
- continue;
74959
- }
74960
- const latest = registryVersion(run, `@brainervirus/workit-${source.host}`);
74961
- if (!latest) {
74962
- plan.failed.push({
74963
- host: source.host,
74964
- status: "failed",
74965
- reason: "registry version unavailable; existing installation preserved",
74966
- fix: fixFor(source.host, source.selector)
74967
- });
74968
- continue;
74969
- }
74970
- if (source.installedVersion && versionAtLeast(source.installedVersion, latest)) {
74971
- plan.skipped.push({
74972
- host: source.host,
74973
- reason: `already current (${source.installedVersion})`
74974
- });
74975
- continue;
74976
- }
74977
- const commands = source.host === "pi" ? [{ command: "pi", args: ["update", "--extension", source.selector] }] : source.host === "codex" ? [
74978
- {
74979
- command: "codex",
74980
- args: ["plugin", "marketplace", "upgrade", CODEX_MARKETPLACE]
74981
- },
74982
- {
74983
- command: "codex",
74984
- args: ["plugin", "add", `workit@${CODEX_MARKETPLACE}`, "--json"]
74985
- }
74986
- ] : planHostInstall("cursor", {
74987
- home,
74988
- env: deps.env,
74989
- cwd: home,
74990
- packageVersion: latest,
74991
- targetDir: paths.cursorRoot
74992
- });
74993
- plan.entries.push({
74994
- host: source.host,
74995
- selector: source.selector,
74996
- latest,
74997
- commands,
74998
- installedVersion: source.installedVersion,
74999
- ...source.kind === "repair" ? { repair: true } : {},
75000
- fix: fixFor(source.host, source.selector)
74918
+ return true;
74919
+ }, registryVersion = (run, name) => {
74920
+ const latest = run("npm", ["view", name, "version"]);
74921
+ const version = latest.stdout.trim();
74922
+ return latest.status === 0 && /^\d+\.\d+\.\d+$/.test(version) ? version : undefined;
74923
+ };
74924
+ var init_shared = __esm(() => {
74925
+ init_host_install();
74926
+ LAUNCH_HOSTS = ["opencode", "cursor", "codex", "pi"];
74927
+ HOSTS2 = [...LAUNCH_HOSTS, "claude-code"];
74928
+ LIVE_HOSTS = new Set(["opencode", "claude-code"]);
74929
+ OPENCODE_UPDATE = `opencode plugin update ${OPENCODE_PACKAGE}`;
74930
+ });
74931
+
74932
+ // packages/workit-cli/src/upgrade/processes.ts
74933
+ import path45 from "node:path";
74934
+ var PROCESS_HOSTS, SCRIPT_RUNTIMES, classifyProcess = (proc) => {
74935
+ if (proc.state.startsWith("Z") || proc.args.includes("<defunct>"))
74936
+ return null;
74937
+ const argv0 = proc.args.trim().split(/\s+/)[0] ?? "";
74938
+ const baseName = (value) => path45.basename(value.replaceAll("\\", "/")).replace(/^\[|\]$/g, "").replace(/\.exe$/i, "").toLowerCase();
74939
+ let host = PROCESS_HOSTS[baseName(argv0)];
74940
+ if (!host && SCRIPT_RUNTIMES.has(baseName(argv0))) {
74941
+ const script = proc.args.trim().split(/\s+/).slice(1).find((arg) => !arg.startsWith("-"));
74942
+ if (script)
74943
+ host = PROCESS_HOSTS[baseName(script).replace(/\.(?:[cm]?js|ts)$/, "")];
74944
+ }
74945
+ if (!host)
74946
+ return null;
74947
+ if (host === "codex" && /\bapp-server\b/.test(proc.args))
74948
+ return /\bdaemon\s+pid-update-loop\b/.test(proc.args) ? null : { ...proc, host, kind: "daemon" };
74949
+ if (host === "opencode" && /\bserve\b/.test(proc.args))
74950
+ return { ...proc, host, kind: "daemon" };
74951
+ return { ...proc, host, kind: "session" };
74952
+ }, listProcesses = (deps) => {
74953
+ if (deps.processes)
74954
+ return deps.processes();
74955
+ if (deps.activeHosts)
74956
+ return deps.activeHosts().map((host) => ({ pid: 0, state: "S", args: host }));
74957
+ const run = runner(deps);
74958
+ if (process.platform === "win32") {
74959
+ const list = run("tasklist", ["/fo", "csv", "/nh"]);
74960
+ if (list.status !== 0)
74961
+ return null;
74962
+ return list.stdout.split(/\r?\n/).flatMap((line) => {
74963
+ const [image, pid] = line.split('","').map((cell) => cell.replaceAll('"', ""));
74964
+ return image && /^\d+$/.test(pid ?? "") ? [{ pid: Number(pid), state: "R", args: image }] : [];
75001
74965
  });
75002
74966
  }
75003
- plan.ok = plan.blocked.length === 0 && plan.failed.length === 0;
75004
- return plan;
75005
- }
74967
+ const list = run("ps", ["-eo", "pid=,stat=,args="]);
74968
+ if (list.status !== 0)
74969
+ return null;
74970
+ return list.stdout.split(/\r?\n/).flatMap((line) => {
74971
+ const match = /^\s*(\d+)\s+(\S+)\s+(.+)$/.exec(line);
74972
+ return match ? [{ pid: Number(match[1]), state: match[2], args: match[3] }] : [];
74973
+ });
74974
+ }, describe2 = (proc) => `pid ${proc.pid}: ${proc.args.length > 120 ? `${proc.args.slice(0, 117)}...` : proc.args}`;
74975
+ var init_processes = __esm(() => {
74976
+ init_shared();
74977
+ PROCESS_HOSTS = {
74978
+ claude: "claude-code",
74979
+ codex: "codex",
74980
+ cursor: "cursor",
74981
+ opencode: "opencode",
74982
+ pi: "pi"
74983
+ };
74984
+ SCRIPT_RUNTIMES = new Set(["node", "nodejs", "bun"]);
74985
+ });
74986
+
74987
+ // packages/workit-cli/src/upgrade/apply.ts
74988
+ import { existsSync as existsSync21, readdirSync as readdirSync12, mkdirSync as mkdirSync11, copyFileSync as copyFileSync6, chmodSync as chmodSync2, cpSync as cpSync5 } from "node:fs";
74989
+ import path46 from "node:path";
74990
+ import { createHash as createHash16 } from "node:crypto";
75006
74991
  function applyUpgrade(plan, deps = {}) {
75007
74992
  const hosts = [...plan.failed];
75008
74993
  const done = (backup) => {
@@ -75036,11 +75021,11 @@ function applyUpgrade(plan, deps = {}) {
75036
75021
  };
75037
75022
  const paths = upgradePaths(deps);
75038
75023
  const { home, configDir } = paths;
75039
- const backup = path44.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
75024
+ const backup = path46.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
75040
75025
  mkdirSync11(backup, { recursive: true, mode: 448 });
75041
75026
  for (const file of Object.keys(plan.configDigests))
75042
- if (existsSync20(file)) {
75043
- const target = path44.join(backup, createHash15("sha256").update(file).digest("hex").slice(0, 12) + "-" + path44.basename(file));
75027
+ if (existsSync21(file)) {
75028
+ const target = path46.join(backup, createHash16("sha256").update(file).digest("hex").slice(0, 12) + "-" + path46.basename(file));
75044
75029
  copyFileSync6(file, target);
75045
75030
  chmodSync2(target, 384);
75046
75031
  }
@@ -75059,9 +75044,11 @@ function applyUpgrade(plan, deps = {}) {
75059
75044
  }
75060
75045
  const run = runner(deps);
75061
75046
  let cursorBackupError = null;
75062
- if (plan.entries.some((entry) => entry.host === "cursor") && existsSync20(paths.cursorRoot))
75047
+ if (plan.entries.some((entry) => entry.host === "cursor") && existsSync21(paths.cursorRoot))
75063
75048
  try {
75064
- cpSync5(paths.cursorRoot, path44.join(backup, "cursor-package"), { recursive: true });
75049
+ cpSync5(paths.cursorRoot, path46.join(backup, "cursor-package"), {
75050
+ recursive: true
75051
+ });
75065
75052
  } catch (error) {
75066
75053
  cursorBackupError = `could not back up the Cursor plugin: ${errorText(error)}`;
75067
75054
  }
@@ -75069,7 +75056,12 @@ function applyUpgrade(plan, deps = {}) {
75069
75056
  const running = (listed ?? []).flatMap((entry) => classifyProcess(entry) ?? []);
75070
75057
  for (const entry of plan.entries) {
75071
75058
  if (entry.host === "cursor" && cursorBackupError) {
75072
- hosts.push({ host: "cursor", status: "failed", reason: cursorBackupError, fix: entry.fix });
75059
+ hosts.push({
75060
+ host: "cursor",
75061
+ status: "failed",
75062
+ reason: cursorBackupError,
75063
+ fix: entry.fix
75064
+ });
75073
75065
  continue;
75074
75066
  }
75075
75067
  if (!LIVE_HOSTS.has(entry.host)) {
@@ -75178,238 +75170,356 @@ function applyUpgrade(plan, deps = {}) {
75178
75170
  try {
75179
75171
  hosts.push(applyCli(plan.cli, run, backup));
75180
75172
  } catch (error) {
75181
- hosts.push({ host: "cli", status: "failed", reason: errorText(error), fix: CLI_FIX });
75173
+ hosts.push({
75174
+ host: "cli",
75175
+ status: "failed",
75176
+ reason: errorText(error),
75177
+ fix: CLI_FIX
75178
+ });
75182
75179
  }
75183
75180
  return done(backup);
75184
75181
  }
75185
- async function runUpgradeCommand(argv, deps = {}) {
75186
- const out = deps.out ?? process.stdout;
75187
- const flags = new Set(argv);
75188
- const unknown = argv.filter((arg) => !["--apply", "--confirm", "--json", "--cli", "--preview", "--yes"].includes(arg) && !arg.startsWith("--hosts="));
75189
- const hostFlag = argv.find((arg) => arg.startsWith("--hosts="))?.slice(8);
75190
- const raw = hostFlag === "none" ? [] : hostFlag?.split(",") ?? HOSTS2;
75191
- if (unknown.length || raw.some((host) => !HOSTS2.includes(host)) || flags.has("--preview") && (flags.has("--apply") || flags.has("--yes"))) {
75192
- out.write(USAGE3);
75193
- return 2;
75182
+ var codexPluginRoot = (codexHome) => {
75183
+ const dir = path46.join(codexHome, "plugins", "cache", CODEX_MARKETPLACE, "workit");
75184
+ let versions = [];
75185
+ try {
75186
+ versions = readdirSync12(dir).filter((version) => /^\d+\.\d+\.\d+$/.test(version));
75187
+ } catch {
75188
+ return null;
75194
75189
  }
75195
- if (flags.has("--apply") && !flags.has("--confirm")) {
75196
- out.write(`Apply requires --confirm after reviewing the upgrade preview.
75197
- `);
75198
- return 2;
75190
+ const newest = versions.reduce((best, version) => best && versionAtLeast(best, version) ? best : version, null);
75191
+ return newest ? path46.join(dir, newest) : null;
75192
+ }, opencodeVersion = (run) => {
75193
+ const listing = run("opencode", ["plugin", "list"]);
75194
+ if (listing.status !== 0)
75195
+ return;
75196
+ for (const line of listing.stdout.split(/\r?\n/)) {
75197
+ const fields = line.trim().split(/\s+/);
75198
+ if (fields.length < 3)
75199
+ continue;
75200
+ const source = fields[fields.length - 1].replace(/^file:\/\//, "");
75201
+ const version = fields[fields.length - 2];
75202
+ if (/^(?:npm:)?@brainervirus\/workit-opencode(?:@[^/\s]+)?$/.test(source) && /^\d+\.\d+\.\d+$/.test(version))
75203
+ return version;
75199
75204
  }
75200
- const legacy = flags.has("--apply");
75201
- const json = flags.has("--json") || legacy;
75202
- const run = runner(deps);
75203
- const plan = previewUpgrade(raw, deps);
75204
- if (hostFlag === undefined || flags.has("--cli"))
75205
- planCli(plan, run);
75206
- plan.ok = plan.blocked.length === 0 && plan.failed.length === 0;
75207
- const { home, env } = upgradePaths(deps);
75208
- const permissions = planHostPermissions({
75209
- hosts: raw,
75210
- refreshOnly: true,
75211
- shell: false,
75212
- home,
75213
- env
75205
+ return;
75206
+ }, applyEntry = (entry, context) => {
75207
+ const { run, paths, configDir } = context;
75208
+ const { home, env } = paths;
75209
+ const fail = (reason) => ({
75210
+ host: entry.host,
75211
+ status: "failed",
75212
+ reason,
75213
+ fix: entry.fix
75214
75214
  });
75215
- const permissionPreview = {
75216
- changes: permissions.changes.map((c) => ({
75217
- host: c.host,
75218
- file: c.file,
75219
- diff: permissionDiff(c)
75220
- })),
75221
- ...permissions.refused ? { refused: permissions.refused } : {}
75222
- };
75223
- const withPermissions = (value) => permissions.changes.length ? { ...value, permissions: permissionPreview } : value;
75224
- const applyCommand = `workit upgrade ${[...hostFlag === undefined ? [] : [`--hosts=${hostFlag}`], ...flags.has("--cli") ? ["--cli"] : [], "--yes"].join(" ")}`;
75225
- const nothingChanged = `preview only; nothing changed. Apply with: ${applyCommand}
75226
- `;
75227
- if (json && !legacy && !flags.has("--yes")) {
75228
- out.write(JSON.stringify(withPermissions(plan), null, 2) + `
75229
- `);
75230
- return plan.blocked.length ? 1 : 0;
75215
+ if (entry.host === "cursor") {
75216
+ const preview = {
75217
+ ok: true,
75218
+ blocked: [],
75219
+ preserved: [],
75220
+ overrides: [],
75221
+ platforms: ["cursor"],
75222
+ state: readSetupState(configDir),
75223
+ mutations: [
75224
+ {
75225
+ type: "install-host",
75226
+ platform: "cursor",
75227
+ path: path46.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
75228
+ commands: entry.commands.map((command) => ({
75229
+ ...command,
75230
+ purpose: command.purpose ?? "Upgrade Cursor"
75231
+ }))
75232
+ },
75233
+ { type: "install-adapter", platform: "cursor", path: paths.cursorRoot }
75234
+ ]
75235
+ };
75236
+ const result = applySetupPreview(preview, {
75237
+ home,
75238
+ env,
75239
+ cwd: home,
75240
+ preferInstalledAdapter: true,
75241
+ runHostCommand: (command) => {
75242
+ const outcome = run(command.command, command.args);
75243
+ return {
75244
+ exitCode: outcome.status ?? 1,
75245
+ stdout: outcome.stdout,
75246
+ stderr: ""
75247
+ };
75248
+ }
75249
+ });
75250
+ const installed = objectOrNull(path46.join(paths.cursorRoot, "package.json"));
75251
+ if (!result.ok || installed?.version !== entry.latest)
75252
+ return fail("Cursor install did not verify the requested package version; inspect the installer before retrying");
75253
+ return {
75254
+ host: "cursor",
75255
+ status: "updated",
75256
+ reason: entry.repair ? `reinstalled missing plugin files (${entry.latest})` : `${entry.installedVersion ?? "?"} -> ${entry.latest}`
75257
+ };
75231
75258
  }
75232
- if (!json)
75233
- out.write(summary(plan, permissions.changes));
75234
- if (flags.has("--preview")) {
75235
- out.write(nothingChanged);
75236
- return plan.blocked.length ? 1 : 0;
75259
+ const before = entry.host === "opencode" ? opencodeVersion(run) : undefined;
75260
+ for (const command of entry.commands)
75261
+ if (run(command.command, command.args).status !== 0)
75262
+ return fail(`\`${command.command} ${command.args.join(" ")}\` failed`);
75263
+ if (entry.host === "opencode") {
75264
+ const after = opencodeVersion(run);
75265
+ if (before && after)
75266
+ return after === before ? {
75267
+ host: "opencode",
75268
+ status: "current",
75269
+ reason: `already current (${after})`
75270
+ } : {
75271
+ host: "opencode",
75272
+ status: "updated",
75273
+ reason: `${before} -> ${after}; OpenCode V2 loads it live`
75274
+ };
75275
+ return {
75276
+ host: "opencode",
75277
+ status: "updated",
75278
+ reason: "scoped update ran; OpenCode V2 loads it live"
75279
+ };
75237
75280
  }
75238
- if (plan.blocked.length) {
75239
- out.write(`Upgrade blocked: ${plan.blocked.join("; ")}
75240
- Nothing changed.
75241
- `);
75242
- return 1;
75281
+ if (entry.host === "claude-code") {
75282
+ const after = claudeWorkitInstalls(home, env, null).find((install) => install.id === entry.selector)?.version;
75283
+ return after && after === entry.installedVersion ? {
75284
+ host: "claude-code",
75285
+ status: "current",
75286
+ reason: `already current (${after})`
75287
+ } : {
75288
+ host: "claude-code",
75289
+ status: "updated",
75290
+ reason: `${entry.installedVersion ?? "?"} -> ${after ?? "?"}; new sessions load it`
75291
+ };
75243
75292
  }
75244
- const work = plan.entries.length + plan.migrations.length + (plan.cli ? 1 : 0) + permissions.changes.length;
75245
- if (work > 0 && !flags.has("--yes") && !legacy) {
75246
- const confirmed = await (deps.confirm ?? ((q) => askConfirm(q, out)))("Apply this upgrade? [y/N] ");
75247
- if (!confirmed) {
75248
- out.write(nothingChanged);
75249
- return 0;
75250
- }
75293
+ const verify = entry.host === "codex" ? run("codex", ["plugin", "list", "--json"]) : run("pi", ["list"]);
75294
+ if (verify.status !== 0)
75295
+ return fail("update verification failed");
75296
+ if (entry.host === "codex") {
75297
+ let installed = [];
75298
+ try {
75299
+ installed = JSON.parse(verify.stdout).installed ?? [];
75300
+ } catch {}
75301
+ if (!installed.some((plugin) => plugin.name === "workit" && plugin.marketplaceName === CODEX_MARKETPLACE && plugin.version === entry.latest))
75302
+ return fail("Codex did not report the requested Workit version");
75251
75303
  }
75252
- if (json)
75253
- for (const warning of plan.warnings ?? [])
75254
- out.write(`warning: ${warning}
75255
- `);
75256
- const result = applyUpgrade(plan, deps);
75257
- let permissionsOk = true;
75258
- let written;
75259
- if (permissions.changes.length && !permissions.refused && !result.error?.startsWith("configuration changed")) {
75260
- written = applyHostPermissions(permissions, { home, env });
75261
- permissionsOk = written.every((entry) => entry.status === "written");
75262
- for (const entry of written)
75263
- result.hosts.push({
75264
- host: entry.host,
75265
- status: entry.status === "written" ? "updated" : "failed",
75266
- reason: `permission block ${entry.status === "written" ? "refreshed" : entry.status} in ${entry.file}`,
75267
- ...entry.status === "written" ? {} : { fix: `workit setup --hosts=${entry.host}` }
75304
+ if (entry.host === "pi" && piInstalledVersion(verify.stdout, entry.selector) !== entry.latest)
75305
+ return fail("Pi did not report the requested Workit package version");
75306
+ return {
75307
+ host: entry.host,
75308
+ status: "updated",
75309
+ reason: entry.repair ? `reinstalled missing plugin files (${entry.latest})` : `${entry.installedVersion ?? "?"} -> ${entry.latest}`
75310
+ };
75311
+ }, refreshCodexAgents = (run, codexHome) => {
75312
+ const root = codexPluginRoot(codexHome);
75313
+ const launcher = root && path46.join(root, "dist", "launch-mcp.js");
75314
+ if (!launcher || !existsSync21(launcher))
75315
+ return { ok: true, note: "" };
75316
+ const fix = `node ${JSON.stringify(launcher)} --install-agents`;
75317
+ return run("node", [launcher, "--install-agents"]).status === 0 ? { ok: true, note: "agents refreshed" } : { ok: false, note: "agent refresh failed", fix };
75318
+ }, applyCli = (cli, run, backup) => {
75319
+ const fail = (reason) => ({
75320
+ host: "cli",
75321
+ status: "failed",
75322
+ reason,
75323
+ fix: CLI_FIX
75324
+ });
75325
+ const currentRoot = run("npm", ["root", "--global"]);
75326
+ if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== cli.root)
75327
+ return fail("Global npm location changed; preview again");
75328
+ const cliBackup = path46.join(backup, "cli-package");
75329
+ cpSync5(path46.join(cli.root, "@brainervirus/workit-cli"), cliBackup, {
75330
+ recursive: true
75331
+ });
75332
+ if (run("npm", ["install", "--global", `@brainervirus/workit-cli@${cli.latest}`]).status !== 0)
75333
+ return fail(`CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path46.join(cliBackup, "dist/index.js")}`);
75334
+ const installed = objectOrNull(path46.join(cli.root, "@brainervirus/workit-cli/package.json"));
75335
+ if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== cli.latest)
75336
+ return fail(`CLI update did not verify the requested version; preserved package at ${cliBackup}`);
75337
+ return {
75338
+ host: "cli",
75339
+ status: "updated",
75340
+ reason: `${cli.installed} -> ${cli.latest}`
75341
+ };
75342
+ };
75343
+ var init_apply = __esm(() => {
75344
+ init_host_install();
75345
+ init_setup_state();
75346
+ init_setup();
75347
+ init_safe_write();
75348
+ init_processes();
75349
+ init_shared();
75350
+ });
75351
+
75352
+ // packages/workit-cli/src/upgrade/plan.ts
75353
+ import { existsSync as existsSync22, mkdtempSync as mkdtempSync3, rmSync as rmSync8, lstatSync as lstatSync7, readFileSync as readFileSync22 } from "node:fs";
75354
+ import path47 from "node:path";
75355
+ import os17 from "node:os";
75356
+ function previewUpgrade(hosts = HOSTS2, deps = {}) {
75357
+ const paths = upgradePaths(deps);
75358
+ const { home, configDir } = paths;
75359
+ const run = runner(deps);
75360
+ const state = readSetupState(configDir);
75361
+ const plan = {
75362
+ ok: true,
75363
+ blocked: [],
75364
+ failed: [],
75365
+ skipped: [],
75366
+ entries: [],
75367
+ configDigests: {},
75368
+ migrations: []
75369
+ };
75370
+ for (const file of [state.config, state.workspaces, state.youtrack, state.vcs]) {
75371
+ if (file.status === "malformed")
75372
+ plan.blocked.push(file.error ?? file.file);
75373
+ plan.configDigests[file.file] = digest2(file.file);
75374
+ }
75375
+ for (const file of [
75376
+ paths.opencodeConfig,
75377
+ paths.opencodeConfig + "c",
75378
+ path47.join(home, ".cursor/settings.json"),
75379
+ path47.join(home, ".cursor/mcp.json"),
75380
+ path47.join(paths.cursorRoot, "package.json"),
75381
+ paths.codexConfig,
75382
+ paths.piSettings
75383
+ ])
75384
+ plan.configDigests[file] = digest2(file);
75385
+ try {
75386
+ const config = object2(state.config.file);
75387
+ if (config && Object.hasOwn(config, "trustedPaths"))
75388
+ plan.migrations.push({
75389
+ id: "2.0-remove-ignored-trusted-paths",
75390
+ file: state.config.file,
75391
+ description: "Remove ignored Workit trustedPaths; native host permissions remain unchanged"
75268
75392
  });
75393
+ } catch (error) {
75394
+ plan.blocked.push(errorText(error));
75269
75395
  }
75270
- const failed = !result.ok || !permissionsOk;
75271
- const cliVersion = result.hosts.some((h) => h.host === "cli" && h.status === "updated") ? plan.cli.latest : package_default.version;
75272
- const report = (deps.doctor ?? ((version) => runDoctor({ home, env, cliVersion: version, only: "upgrade" })))(cliVersion);
75273
- const left = report.checks.filter((check) => check.status === "warn" || check.status === "fail");
75274
- if (json) {
75275
- out.write(JSON.stringify({
75276
- ...result,
75277
- ok: !failed,
75278
- ...written ? { permissions: { changes: permissionPreview.changes, written } } : permissions.refused ? { permissions: permissionPreview } : {},
75279
- doctor: { clean: left.length === 0, left }
75280
- }, null, 2) + `
75281
- `);
75282
- return failed ? 1 : 0;
75396
+ const installedSources = sources(paths, run, hosts, plan.failed);
75397
+ let opencodeHelp;
75398
+ if (installedSources.some((source) => source.host === "opencode")) {
75399
+ const probe = opencodeProbe(deps, ["--version"]);
75400
+ const installed = probe.status === 0 ? probe.stdout.match(/\d+\.\d+\.\d+/)?.[0] : undefined;
75401
+ if (installed && !versionAtLeast(installed, SUPPORT_MATRIX.opencode.minimum))
75402
+ (plan.warnings ??= []).push(`opencode ${installed}: ${OPENCODE_V1_FIX}`);
75283
75403
  }
75284
- if (result.error && result.hosts.every((h) => h.status !== "failed"))
75285
- out.write(`Upgrade stopped: ${result.error}
75286
- `);
75287
- out.write(table(result.hosts));
75288
- if (permissions.refused)
75289
- out.write(`permissions: not refreshed: ${permissions.refused}
75290
- `);
75291
- if (result.backup)
75292
- out.write(`Backup: ${result.backup}
75293
- `);
75294
- out.write(left.length === 0 ? `Verified: workit doctor is clean for versions, assets, agents and permissions.
75295
- ` : `Left after upgrade (workit doctor):
75296
- ${left.map((check) => ` ${check.id}: ${check.detail}${check.fix ? `
75297
- fix: ${check.fix}` : ""}`).join(`
75298
- `)}
75299
- `);
75300
- return failed ? 1 : 0;
75301
- }
75302
- async function runLaunchCommand(argv, deps = {}) {
75303
- const [host, ...args] = argv;
75304
- if (!LAUNCH_HOSTS.includes(host)) {
75305
- (deps.out ?? process.stdout).write(`Usage: workit launch <opencode|cursor|codex|pi> [--auto-upgrade] [-- host arguments]
75306
- `);
75307
- return 2;
75404
+ for (const host of ["opencode", "pi"]) {
75405
+ if (new Set(installedSources.filter((source) => source.host === host).map((source) => source.selector)).size > 1)
75406
+ plan.failed.push({
75407
+ host,
75408
+ status: "failed",
75409
+ reason: "conflicting Workit registrations; reconcile them in the native host before upgrading"
75410
+ });
75308
75411
  }
75309
- const auto = args[0] === "--auto-upgrade";
75310
- const rest = auto ? args.slice(1) : args;
75311
- const hostArgs = rest[0] === "--" ? rest.slice(1) : rest;
75312
- const { home, env } = upgradePaths(deps);
75313
- let launch;
75314
- if (!deps.run) {
75315
- try {
75316
- launch = hostCommand(host, hostArgs, { home, env });
75317
- } catch (error) {
75318
- (deps.out ?? process.stderr).write(`${error instanceof Error ? error.message : "Host executable unavailable"}
75319
- `);
75320
- return 1;
75412
+ const conflicted = new Set(plan.failed.map((entry) => entry.host));
75413
+ for (const source of installedSources.filter((candidate, index, list) => !conflicted.has(candidate.host) && list.findIndex((entry) => entry.host === candidate.host && entry.selector === candidate.selector) === index)) {
75414
+ if (source.kind === "pinned" || source.kind === "local") {
75415
+ plan.skipped.push({
75416
+ host: source.host,
75417
+ reason: `${source.kind} source preserved; change its source explicitly to upgrade`
75418
+ });
75419
+ continue;
75321
75420
  }
75322
- }
75323
- if (auto) {
75324
- const plan = previewUpgrade([host], deps);
75325
- const reasons = [...plan.blocked, ...plan.failed.map((entry) => entry.reason)];
75326
- if (plan.ok) {
75327
- for (const skipped of plan.skipped)
75328
- (deps.out ?? process.stderr).write(`${skipped.host}: ${skipped.reason}${skipped.fix ? ` (run: ${skipped.fix})` : ""}
75329
- `);
75330
- const result = applyUpgrade(plan, deps);
75331
- if (!result.ok) {
75332
- (deps.out ?? process.stdout).write(`${result.error}
75333
- `);
75334
- return 1;
75421
+ if (source.host === "claude-code") {
75422
+ const [market] = source.selector.split("@").slice(1);
75423
+ plan.entries.push({
75424
+ host: "claude-code",
75425
+ selector: source.selector,
75426
+ latest: "",
75427
+ installedVersion: source.installedVersion,
75428
+ commands: [
75429
+ {
75430
+ command: "claude",
75431
+ args: ["plugin", "marketplace", "update", market ?? "workit"]
75432
+ },
75433
+ { command: "claude", args: ["plugin", "update", source.selector] }
75434
+ ],
75435
+ fix: `claude plugin marketplace update ${market ?? "workit"} && claude plugin update ${source.selector}`
75436
+ });
75437
+ continue;
75438
+ }
75439
+ if (source.host === "opencode") {
75440
+ opencodeHelp ??= opencodeProbe(deps, ["plugin", "--help"]).stdout;
75441
+ if (!/^\s*(?:opencode\s+plugin\s+)?update\b/m.test(opencodeHelp)) {
75442
+ plan.skipped.push({
75443
+ host: "opencode",
75444
+ reason: "this OpenCode has no `opencode plugin update`; upgrade OpenCode, then run the fix. Workit never updates unrelated plugins",
75445
+ fix: OPENCODE_UPDATE
75446
+ });
75447
+ continue;
75335
75448
  }
75336
- } else if (plan.blocked.length === 0 && reasons.every((reason) => reason.includes("registry version unavailable"))) {
75337
- (deps.out ?? process.stderr).write(`Upgrade unavailable: ${reasons.join("; ")}. Starting the unchanged host.
75338
- `);
75339
- } else {
75340
- (deps.out ?? process.stderr).write(`Upgrade blocked: ${reasons.join("; ")}
75341
- `);
75342
- return 1;
75449
+ plan.entries.push({
75450
+ host: "opencode",
75451
+ selector: source.selector,
75452
+ latest: "",
75453
+ commands: [{ command: "opencode", args: ["plugin", "update", OPENCODE_PACKAGE] }],
75454
+ fix: OPENCODE_UPDATE
75455
+ });
75456
+ continue;
75343
75457
  }
75458
+ const latest = registryVersion(run, `@brainervirus/workit-${source.host}`);
75459
+ if (!latest) {
75460
+ plan.failed.push({
75461
+ host: source.host,
75462
+ status: "failed",
75463
+ reason: "registry version unavailable; existing installation preserved",
75464
+ fix: fixFor(source.host, source.selector)
75465
+ });
75466
+ continue;
75467
+ }
75468
+ if (source.installedVersion && versionAtLeast(source.installedVersion, latest)) {
75469
+ plan.skipped.push({
75470
+ host: source.host,
75471
+ reason: `already current (${source.installedVersion})`
75472
+ });
75473
+ continue;
75474
+ }
75475
+ const commands = source.host === "pi" ? [{ command: "pi", args: ["update", "--extension", source.selector] }] : source.host === "codex" ? [
75476
+ {
75477
+ command: "codex",
75478
+ args: ["plugin", "marketplace", "upgrade", CODEX_MARKETPLACE]
75479
+ },
75480
+ {
75481
+ command: "codex",
75482
+ args: ["plugin", "add", `workit@${CODEX_MARKETPLACE}`, "--json"]
75483
+ }
75484
+ ] : planHostInstall("cursor", {
75485
+ home,
75486
+ env: deps.env,
75487
+ cwd: home,
75488
+ packageVersion: latest,
75489
+ targetDir: paths.cursorRoot
75490
+ });
75491
+ plan.entries.push({
75492
+ host: source.host,
75493
+ selector: source.selector,
75494
+ latest,
75495
+ commands,
75496
+ installedVersion: source.installedVersion,
75497
+ ...source.kind === "repair" ? { repair: true } : {},
75498
+ fix: fixFor(source.host, source.selector)
75499
+ });
75344
75500
  }
75345
- if (deps.run)
75346
- return deps.run(host, hostArgs).status ?? 1;
75347
- return spawnSync17(launch.command, launch.args, {
75348
- stdio: "inherit",
75349
- env
75350
- }).status ?? 1;
75501
+ plan.ok = plan.blocked.length === 0 && plan.failed.length === 0;
75502
+ return plan;
75351
75503
  }
75352
- 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) => {
75353
- const home = deps.home ?? deps.env?.HOME ?? os16.homedir();
75354
- const env = {
75355
- ...process.env,
75356
- ...deps.home || deps.env?.HOME ? {
75357
- HOME: home,
75358
- CODEX_HOME: path44.join(home, ".codex"),
75359
- CLAUDE_CONFIG_DIR: path44.join(home, ".claude"),
75360
- PI_CODING_AGENT_DIR: path44.join(home, ".pi/agent"),
75361
- XDG_CONFIG_HOME: path44.join(home, ".config"),
75362
- WORKFLOW_TOOLKIT_CONFIG: undefined,
75363
- WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
75364
- } : {},
75365
- ...deps.env,
75366
- HOME: home
75367
- };
75368
- const xdg = env.XDG_CONFIG_HOME || path44.join(home, ".config");
75369
- const codexHome = env.CODEX_HOME ?? path44.join(home, ".codex");
75370
- return {
75371
- home,
75372
- env,
75373
- configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path44.join(xdg, "workit"),
75374
- opencodeConfig: path44.join(xdg, "opencode/opencode.json"),
75375
- piSettings: path44.join(env.PI_CODING_AGENT_DIR ?? path44.join(home, ".pi/agent"), "settings.json"),
75376
- codexHome,
75377
- codexConfig: path44.join(codexHome, "config.toml"),
75378
- cursorRoot: path44.join(home, ".cursor/plugins/local/workit")
75379
- };
75380
- }, object2 = (file) => {
75381
- if (!existsSync20(file))
75382
- return null;
75383
- let data;
75384
- try {
75385
- data = JSON.parse(readFileSync21(file, "utf8"));
75386
- } catch {
75387
- throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
75388
- }
75389
- if (!data || typeof data !== "object" || Array.isArray(data))
75390
- throw new Error(`${file} is not a configuration object`);
75391
- return data;
75392
- }, objectOrNull = (file) => {
75393
- try {
75394
- return object2(file);
75395
- } catch {
75396
- return null;
75397
- }
75398
- }, digest2 = (file) => existsSync20(file) ? createHash15("sha256").update(readFileSync21(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
75399
- const { home, env } = upgradePaths(deps);
75400
- let step;
75504
+ var codexRegistered = (configFile) => {
75505
+ let text;
75401
75506
  try {
75402
- step = hostCommand(command, args, { home, env });
75507
+ text = readFileSync22(configFile, "utf8");
75403
75508
  } catch {
75404
- return { status: 1, stdout: "" };
75509
+ return false;
75405
75510
  }
75406
- const result = runHostCommand(step, { home, env });
75407
- return { status: result.exitCode, stdout: result.stdout };
75408
- }), classify = (host, selector) => ({
75511
+ const header = `[plugins."workit@${CODEX_MARKETPLACE}"]`;
75512
+ const start = text.split(/\r?\n/).findIndex((line) => line.trim() === header);
75513
+ if (start < 0)
75514
+ return false;
75515
+ const body = text.split(/\r?\n/).slice(start + 1).join(`
75516
+ `).split(/^\s*\[/m)[0];
75517
+ return !/^\s*enabled\s*=\s*false\b/m.test(body);
75518
+ }, classify = (host, selector) => ({
75409
75519
  host,
75410
75520
  selector,
75411
75521
  kind: selector === `@brainervirus/workit-${host}` || selector === `@brainervirus/workit-${host}@latest` || selector === `npm:@brainervirus/workit-${host}` || selector === `npm:@brainervirus/workit-${host}@latest` ? "floating" : new RegExp(`^(?:npm:)?@brainervirus/workit-${host}@[^/]+$`).test(selector) ? "pinned" : "local"
75412
- }), errorText = (error) => error instanceof Error ? error.message : "installed source could not be read", sources = (paths, run, hosts, failed) => {
75522
+ }), sources = (paths, run, hosts, failed) => {
75413
75523
  const { home } = paths;
75414
75524
  const result = [];
75415
75525
  const guard = (host, read) => {
@@ -75427,7 +75537,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75427
75537
  }
75428
75538
  };
75429
75539
  guard("opencode", () => {
75430
- if (existsSync20(paths.opencodeConfig + "c"))
75540
+ if (existsSync22(paths.opencodeConfig + "c"))
75431
75541
  throw new Error("OpenCode JSONC config is present; inspect effective native configuration before updating");
75432
75542
  const oc = object2(paths.opencodeConfig);
75433
75543
  if (oc && [oc.plugins, oc.plugin].some((value) => value !== undefined && !Array.isArray(value)))
@@ -75437,8 +75547,8 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75437
75547
  result.push(classify("opencode", pin));
75438
75548
  });
75439
75549
  guard("cursor", () => {
75440
- const cursor = objectOrNull(path44.join(paths.cursorRoot, "package.json"));
75441
- const mcp = objectOrNull(path44.join(home, ".cursor/mcp.json"));
75550
+ const cursor = objectOrNull(path47.join(paths.cursorRoot, "package.json"));
75551
+ const mcp = objectOrNull(path47.join(home, ".cursor/mcp.json"));
75442
75552
  const args = mcp?.mcpServers?.workit?.args ?? [];
75443
75553
  const arg = args.find((value) => typeof value === "string" && value.startsWith("--package="));
75444
75554
  const selector = typeof arg === "string" ? arg.slice(10) : "local";
@@ -75449,7 +75559,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75449
75559
  });
75450
75560
  return;
75451
75561
  }
75452
- const settings = objectOrNull(path44.join(home, ".cursor/settings.json"));
75562
+ const settings = objectOrNull(path47.join(home, ".cursor/settings.json"));
75453
75563
  const dirs = Array.isArray(settings?.plugin_dirs) ? settings.plugin_dirs : [];
75454
75564
  const registered = mcp?.mcpServers?.workit !== undefined || dirs.some((dir) => String(dir).replaceAll("\\", "/").replace(/\/+$/, "").endsWith("local/workit"));
75455
75565
  if (registered)
@@ -75464,7 +75574,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75464
75574
  if (typeof source !== "string")
75465
75575
  continue;
75466
75576
  const npm = /^(?:npm:)?@brainervirus\/workit-pi(?:@[^/]+)?$/.test(source);
75467
- const local = path44.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path44.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
75577
+ const local = path47.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path47.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
75468
75578
  if (!npm && !local)
75469
75579
  continue;
75470
75580
  const found = classify("pi", source);
@@ -75484,7 +75594,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75484
75594
  hostCommand("codex", [], { home, env: paths.env });
75485
75595
  available = true;
75486
75596
  } catch {}
75487
- if (available || existsSync20(paths.codexConfig))
75597
+ if (available || existsSync22(paths.codexConfig))
75488
75598
  throw new Error("Codex plugin inventory failed; inspect the native host before upgrading");
75489
75599
  return;
75490
75600
  }
@@ -75506,6 +75616,12 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75506
75616
  installedVersion: plugin.version
75507
75617
  });
75508
75618
  }
75619
+ if (!result.some((found) => found.host === "codex") && codexRegistered(paths.codexConfig))
75620
+ result.push({
75621
+ host: "codex",
75622
+ selector: "@brainervirus/workit-codex",
75623
+ kind: "repair"
75624
+ });
75509
75625
  });
75510
75626
  guard("claude-code", () => {
75511
75627
  for (const install of claudeWorkitInstalls(home, paths.env, null))
@@ -75517,213 +75633,24 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75517
75633
  });
75518
75634
  });
75519
75635
  return result;
75520
- }, piInstalledVersion = (listing, selector) => {
75521
- const lines = listing.split(/\r?\n/).map((line) => line.trim());
75522
- const index = lines.indexOf(selector);
75523
- if (index < 0 || !lines[index + 1] || !path44.isAbsolute(lines[index + 1]))
75524
- return;
75525
- const found = objectOrNull(path44.join(lines[index + 1], "package.json"));
75526
- return found?.name === "@brainervirus/workit-pi" ? found.version : undefined;
75527
- }, versionAtLeast = (installed, latest) => {
75528
- if (!/^\d+\.\d+\.\d+$/.test(installed))
75529
- return false;
75530
- const current = installed.split(".").map(Number);
75531
- const target = latest.split(".").map(Number);
75532
- for (let index = 0;index < 3; index++) {
75533
- if (current[index] !== target[index])
75534
- return current[index] > target[index];
75535
- }
75536
- return true;
75537
75636
  }, opencodeProbe = (deps, args) => {
75538
- const scratch = mkdtempSync3(path44.join(os16.tmpdir(), "workit-upgrade-opencode-"));
75637
+ const scratch = mkdtempSync3(path47.join(os17.tmpdir(), "workit-upgrade-opencode-"));
75539
75638
  try {
75540
75639
  return runner({
75541
75640
  ...deps,
75542
75641
  env: {
75543
75642
  ...deps.env,
75544
- XDG_DATA_HOME: path44.join(scratch, "data"),
75545
- XDG_STATE_HOME: path44.join(scratch, "state"),
75546
- XDG_CACHE_HOME: path44.join(scratch, "cache")
75643
+ XDG_DATA_HOME: path47.join(scratch, "data"),
75644
+ XDG_STATE_HOME: path47.join(scratch, "state"),
75645
+ XDG_CACHE_HOME: path47.join(scratch, "cache")
75547
75646
  }
75548
75647
  })("opencode", args);
75549
75648
  } finally {
75550
75649
  rmSync8(scratch, { recursive: true, force: true });
75551
75650
  }
75552
- }, registryVersion = (run, name) => {
75553
- const latest = run("npm", ["view", name, "version"]);
75554
- const version = latest.stdout.trim();
75555
- return latest.status === 0 && /^\d+\.\d+\.\d+$/.test(version) ? version : undefined;
75556
- }, PROCESS_HOSTS, classifyProcess = (proc) => {
75557
- if (proc.state.startsWith("Z") || proc.args.includes("<defunct>"))
75558
- return null;
75559
- const argv0 = proc.args.trim().split(/\s+/)[0] ?? "";
75560
- const name = path44.basename(argv0.replaceAll("\\", "/")).replace(/^\[|\]$/g, "").replace(/\.exe$/i, "").toLowerCase();
75561
- const host = PROCESS_HOSTS[name];
75562
- if (!host)
75563
- return null;
75564
- if (host === "codex" && /\bapp-server\b/.test(proc.args))
75565
- return /\bdaemon\s+pid-update-loop\b/.test(proc.args) ? null : { ...proc, host, kind: "daemon" };
75566
- if (host === "opencode" && /\bserve\b/.test(proc.args))
75567
- return { ...proc, host, kind: "daemon" };
75568
- return { ...proc, host, kind: "session" };
75569
- }, listProcesses = (deps) => {
75570
- if (deps.processes)
75571
- return deps.processes();
75572
- if (deps.activeHosts)
75573
- return deps.activeHosts().map((host) => ({ pid: 0, state: "S", args: host }));
75574
- const run = runner(deps);
75575
- if (process.platform === "win32") {
75576
- const list = run("tasklist", ["/fo", "csv", "/nh"]);
75577
- if (list.status !== 0)
75578
- return null;
75579
- return list.stdout.split(/\r?\n/).flatMap((line) => {
75580
- const [image, pid] = line.split('","').map((cell) => cell.replaceAll('"', ""));
75581
- return image && /^\d+$/.test(pid ?? "") ? [{ pid: Number(pid), state: "R", args: image }] : [];
75582
- });
75583
- }
75584
- const list = run("ps", ["-eo", "pid=,stat=,args="]);
75585
- if (list.status !== 0)
75586
- return null;
75587
- return list.stdout.split(/\r?\n/).flatMap((line) => {
75588
- const match = /^\s*(\d+)\s+(\S+)\s+(.+)$/.exec(line);
75589
- return match ? [{ pid: Number(match[1]), state: match[2], args: match[3] }] : [];
75590
- });
75591
- }, describe2 = (proc) => `pid ${proc.pid}: ${proc.args.length > 120 ? `${proc.args.slice(0, 117)}...` : proc.args}`, codexPluginRoot = (codexHome) => {
75592
- const dir = path44.join(codexHome, "plugins", "cache", CODEX_MARKETPLACE, "workit");
75593
- let versions = [];
75594
- try {
75595
- versions = readdirSync12(dir).filter((version) => /^\d+\.\d+\.\d+$/.test(version));
75596
- } catch {
75597
- return null;
75598
- }
75599
- const newest = versions.reduce((best, version) => best && versionAtLeast(best, version) ? best : version, null);
75600
- return newest ? path44.join(dir, newest) : null;
75601
- }, applyEntry = (entry, context) => {
75602
- const { run, paths, configDir } = context;
75603
- const { home, env } = paths;
75604
- const fail = (reason) => ({
75605
- host: entry.host,
75606
- status: "failed",
75607
- reason,
75608
- fix: entry.fix
75609
- });
75610
- if (entry.host === "cursor") {
75611
- const preview = {
75612
- ok: true,
75613
- blocked: [],
75614
- preserved: [],
75615
- overrides: [],
75616
- platforms: ["cursor"],
75617
- state: readSetupState(configDir),
75618
- mutations: [
75619
- {
75620
- type: "install-host",
75621
- platform: "cursor",
75622
- path: path44.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
75623
- commands: entry.commands.map((command) => ({
75624
- ...command,
75625
- purpose: command.purpose ?? "Upgrade Cursor"
75626
- }))
75627
- },
75628
- { type: "install-adapter", platform: "cursor", path: paths.cursorRoot }
75629
- ]
75630
- };
75631
- const result = applySetupPreview(preview, {
75632
- home,
75633
- env,
75634
- cwd: home,
75635
- preferInstalledAdapter: true,
75636
- runHostCommand: (command) => {
75637
- const outcome = run(command.command, command.args);
75638
- return {
75639
- exitCode: outcome.status ?? 1,
75640
- stdout: outcome.stdout,
75641
- stderr: ""
75642
- };
75643
- }
75644
- });
75645
- const installed = objectOrNull(path44.join(paths.cursorRoot, "package.json"));
75646
- if (!result.ok || installed?.version !== entry.latest)
75647
- return fail("Cursor install did not verify the requested package version; inspect the installer before retrying");
75648
- return {
75649
- host: "cursor",
75650
- status: "updated",
75651
- reason: entry.repair ? `reinstalled missing plugin files (${entry.latest})` : `${entry.installedVersion ?? "?"} -> ${entry.latest}`
75652
- };
75653
- }
75654
- for (const command of entry.commands)
75655
- if (run(command.command, command.args).status !== 0)
75656
- return fail(`\`${command.command} ${command.args.join(" ")}\` failed`);
75657
- if (entry.host === "opencode")
75658
- return {
75659
- host: "opencode",
75660
- status: "updated",
75661
- reason: "scoped update ran; OpenCode V2 loads it live"
75662
- };
75663
- if (entry.host === "claude-code") {
75664
- const after = claudeWorkitInstalls(home, env, null).find((install) => install.id === entry.selector)?.version;
75665
- return after && after === entry.installedVersion ? {
75666
- host: "claude-code",
75667
- status: "current",
75668
- reason: `already current (${after})`
75669
- } : {
75670
- host: "claude-code",
75671
- status: "updated",
75672
- reason: `${entry.installedVersion ?? "?"} -> ${after ?? "?"}; new sessions load it`
75673
- };
75674
- }
75675
- const verify = entry.host === "codex" ? run("codex", ["plugin", "list", "--json"]) : run("pi", ["list"]);
75676
- if (verify.status !== 0)
75677
- return fail("update verification failed");
75678
- if (entry.host === "codex") {
75679
- let installed = [];
75680
- try {
75681
- installed = JSON.parse(verify.stdout).installed ?? [];
75682
- } catch {}
75683
- if (!installed.some((plugin) => plugin.name === "workit" && plugin.marketplaceName === CODEX_MARKETPLACE && plugin.version === entry.latest))
75684
- return fail("Codex did not report the requested Workit version");
75685
- }
75686
- if (entry.host === "pi" && piInstalledVersion(verify.stdout, entry.selector) !== entry.latest)
75687
- return fail("Pi did not report the requested Workit package version");
75688
- return {
75689
- host: entry.host,
75690
- status: "updated",
75691
- reason: `${entry.installedVersion ?? "?"} -> ${entry.latest}`
75692
- };
75693
- }, refreshCodexAgents = (run, codexHome) => {
75694
- const root = codexPluginRoot(codexHome);
75695
- const launcher = root && path44.join(root, "dist", "launch-mcp.js");
75696
- if (!launcher || !existsSync20(launcher))
75697
- return { ok: true, note: "" };
75698
- const fix = `node ${JSON.stringify(launcher)} --install-agents`;
75699
- return run("node", [launcher, "--install-agents"]).status === 0 ? { ok: true, note: "agents refreshed" } : { ok: false, note: "agent refresh failed", fix };
75700
- }, applyCli = (cli, run, backup) => {
75701
- const fail = (reason) => ({
75702
- host: "cli",
75703
- status: "failed",
75704
- reason,
75705
- fix: CLI_FIX
75706
- });
75707
- const currentRoot = run("npm", ["root", "--global"]);
75708
- if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== cli.root)
75709
- return fail("Global npm location changed; preview again");
75710
- const cliBackup = path44.join(backup, "cli-package");
75711
- cpSync5(path44.join(cli.root, "@brainervirus/workit-cli"), cliBackup, {
75712
- recursive: true
75713
- });
75714
- if (run("npm", ["install", "--global", `@brainervirus/workit-cli@${cli.latest}`]).status !== 0)
75715
- return fail(`CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path44.join(cliBackup, "dist/index.js")}`);
75716
- const installed = objectOrNull(path44.join(cli.root, "@brainervirus/workit-cli/package.json"));
75717
- if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== cli.latest)
75718
- return fail(`CLI update did not verify the requested version; preserved package at ${cliBackup}`);
75719
- return {
75720
- host: "cli",
75721
- status: "updated",
75722
- reason: `${cli.installed} -> ${cli.latest}`
75723
- };
75724
75651
  }, planCli = (plan, run) => {
75725
75652
  const root = run("npm", ["root", "--global"]);
75726
- if (root.status !== 0 || !path44.isAbsolute(root.stdout.trim())) {
75653
+ if (root.status !== 0 || !path47.isAbsolute(root.stdout.trim())) {
75727
75654
  plan.skipped.push({
75728
75655
  host: "cli",
75729
75656
  reason: "global npm location could not be verified",
@@ -75731,9 +75658,9 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75731
75658
  });
75732
75659
  return;
75733
75660
  }
75734
- const packageFile = path44.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
75661
+ const packageFile = path47.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
75735
75662
  const installed = objectOrNull(packageFile);
75736
- if (installed?.name !== "@brainervirus/workit-cli" || lstatSync7(path44.dirname(packageFile)).isSymbolicLink()) {
75663
+ if (installed?.name !== "@brainervirus/workit-cli" || lstatSync7(path47.dirname(packageFile)).isSymbolicLink()) {
75737
75664
  plan.skipped.push({
75738
75665
  host: "cli",
75739
75666
  reason: "no managed global CLI install (local links preserved); use npx @brainervirus/workit-cli@latest"
@@ -75760,7 +75687,18 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75760
75687
  host: "cli",
75761
75688
  reason: `already current (${installed.version})`
75762
75689
  });
75763
- }, pad2 = (text) => text.padEnd(12), summary = (plan, permissions) => {
75690
+ };
75691
+ var init_plan = __esm(() => {
75692
+ init_registration();
75693
+ init_setup_state();
75694
+ init_host_install();
75695
+ init_doctor();
75696
+ init_support_matrix();
75697
+ init_shared();
75698
+ });
75699
+
75700
+ // packages/workit-cli/src/upgrade/report.ts
75701
+ var pad2 = (text) => text.padEnd(12), summary = (plan, permissions) => {
75764
75702
  const lines = ["Workit upgrade plan:"];
75765
75703
  if (plan.cli)
75766
75704
  lines.push(` ${pad2("cli")}update ${plan.cli.installed} -> ${plan.cli.latest}`);
@@ -75797,29 +75735,8 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75797
75735
  }
75798
75736
  await Promise.resolve().then(() => init_prompt());
75799
75737
  return /^y(?:es)?$/i.test((await askLine(question)).trim());
75800
- }, USAGE3 = `Usage: workit upgrade [--hosts=opencode,cursor,codex,pi,claude-code|none] [--cli] [--preview | --yes | --apply --confirm] [--json]
75801
- `;
75802
- var init_upgrade = __esm(() => {
75803
- init_package();
75804
- init_registration();
75805
- init_setup_state();
75806
- init_host_install();
75807
- init_setup();
75808
- init_doctor();
75809
- init_support_matrix();
75810
- init_safe_write();
75811
- init_host_permissions();
75812
- LAUNCH_HOSTS = ["opencode", "cursor", "codex", "pi"];
75813
- HOSTS2 = [...LAUNCH_HOSTS, "claude-code"];
75814
- LIVE_HOSTS = new Set(["opencode", "claude-code"]);
75815
- OPENCODE_UPDATE = `opencode plugin update ${OPENCODE_PACKAGE}`;
75816
- PROCESS_HOSTS = {
75817
- claude: "claude-code",
75818
- codex: "codex",
75819
- cursor: "cursor",
75820
- opencode: "opencode",
75821
- pi: "pi"
75822
- };
75738
+ };
75739
+ var init_report = __esm(() => {
75823
75740
  LABEL = {
75824
75741
  updated: "updated",
75825
75742
  current: "already current",
@@ -75828,6 +75745,191 @@ var init_upgrade = __esm(() => {
75828
75745
  };
75829
75746
  });
75830
75747
 
75748
+ // packages/workit-cli/src/upgrade.ts
75749
+ import { spawnSync as spawnSync17 } from "node:child_process";
75750
+ async function runUpgradeCommand(argv, deps = {}) {
75751
+ const out = deps.out ?? process.stdout;
75752
+ const flags = new Set(argv);
75753
+ const unknown = argv.filter((arg) => !["--apply", "--confirm", "--json", "--cli", "--preview", "--yes"].includes(arg) && !arg.startsWith("--hosts="));
75754
+ const hostFlag = argv.find((arg) => arg.startsWith("--hosts="))?.slice(8);
75755
+ const raw = hostFlag === "none" ? [] : hostFlag?.split(",") ?? HOSTS2;
75756
+ if (unknown.length || raw.some((host) => !HOSTS2.includes(host)) || flags.has("--preview") && (flags.has("--apply") || flags.has("--yes"))) {
75757
+ out.write(USAGE3);
75758
+ return 2;
75759
+ }
75760
+ if (flags.has("--apply") && !flags.has("--confirm")) {
75761
+ out.write(`Apply requires --confirm after reviewing the upgrade preview.
75762
+ `);
75763
+ return 2;
75764
+ }
75765
+ const legacy = flags.has("--apply");
75766
+ const json = flags.has("--json") || legacy;
75767
+ const run = runner(deps);
75768
+ const plan = previewUpgrade(raw, deps);
75769
+ if (hostFlag === undefined || flags.has("--cli"))
75770
+ planCli(plan, run);
75771
+ plan.ok = plan.blocked.length === 0 && plan.failed.length === 0;
75772
+ const { home, env } = upgradePaths(deps);
75773
+ const permissions = planHostPermissions({
75774
+ hosts: raw,
75775
+ refreshOnly: true,
75776
+ shell: false,
75777
+ home,
75778
+ env
75779
+ });
75780
+ const permissionPreview = {
75781
+ changes: permissions.changes.map((c) => ({
75782
+ host: c.host,
75783
+ file: c.file,
75784
+ diff: permissionDiff(c)
75785
+ })),
75786
+ ...permissions.refused ? { refused: permissions.refused } : {}
75787
+ };
75788
+ const withPermissions = (value) => permissions.changes.length ? { ...value, permissions: permissionPreview } : value;
75789
+ const applyCommand = `workit upgrade ${[...hostFlag === undefined ? [] : [`--hosts=${hostFlag}`], ...flags.has("--cli") ? ["--cli"] : [], "--yes"].join(" ")}`;
75790
+ const nothingChanged = `preview only; nothing changed. Apply with: ${applyCommand}
75791
+ `;
75792
+ if (json && !legacy && !flags.has("--yes")) {
75793
+ out.write(JSON.stringify(withPermissions(plan), null, 2) + `
75794
+ `);
75795
+ return plan.blocked.length ? 1 : 0;
75796
+ }
75797
+ if (!json)
75798
+ out.write(summary(plan, permissions.changes));
75799
+ if (flags.has("--preview")) {
75800
+ out.write(nothingChanged);
75801
+ return plan.blocked.length ? 1 : 0;
75802
+ }
75803
+ if (plan.blocked.length) {
75804
+ out.write(`Upgrade blocked: ${plan.blocked.join("; ")}
75805
+ Nothing changed.
75806
+ `);
75807
+ return 1;
75808
+ }
75809
+ const work = plan.entries.length + plan.migrations.length + (plan.cli ? 1 : 0) + permissions.changes.length;
75810
+ if (work > 0 && !flags.has("--yes") && !legacy) {
75811
+ const confirmed = await (deps.confirm ?? ((q) => askConfirm(q, out)))("Apply this upgrade? [y/N] ");
75812
+ if (!confirmed) {
75813
+ out.write(nothingChanged);
75814
+ return 0;
75815
+ }
75816
+ }
75817
+ if (json)
75818
+ for (const warning of plan.warnings ?? [])
75819
+ out.write(`warning: ${warning}
75820
+ `);
75821
+ const result = applyUpgrade(plan, deps);
75822
+ let permissionsOk = true;
75823
+ let written;
75824
+ if (permissions.changes.length && !permissions.refused && !result.error?.startsWith("configuration changed")) {
75825
+ written = applyHostPermissions(permissions, { home, env });
75826
+ permissionsOk = written.every((entry) => entry.status === "written");
75827
+ for (const entry of written)
75828
+ result.hosts.push({
75829
+ host: entry.host,
75830
+ status: entry.status === "written" ? "updated" : "failed",
75831
+ reason: `permission block ${entry.status === "written" ? "refreshed" : entry.status} in ${entry.file}`,
75832
+ ...entry.status === "written" ? {} : { fix: `workit setup --hosts=${entry.host}` }
75833
+ });
75834
+ }
75835
+ const failed = !result.ok || !permissionsOk;
75836
+ const cliVersion = result.hosts.some((h) => h.host === "cli" && h.status === "updated") ? plan.cli.latest : package_default.version;
75837
+ const report = (deps.doctor ?? ((version) => runDoctor({ home, env, cliVersion: version, only: "upgrade" })))(cliVersion);
75838
+ const left = report.checks.filter((check) => check.status === "warn" || check.status === "fail");
75839
+ if (json) {
75840
+ out.write(JSON.stringify({
75841
+ ...result,
75842
+ ok: !failed,
75843
+ ...written ? { permissions: { changes: permissionPreview.changes, written } } : permissions.refused ? { permissions: permissionPreview } : {},
75844
+ doctor: { clean: left.length === 0, left }
75845
+ }, null, 2) + `
75846
+ `);
75847
+ return failed ? 1 : 0;
75848
+ }
75849
+ if (result.error && result.hosts.every((h) => h.status !== "failed"))
75850
+ out.write(`Upgrade stopped: ${result.error}
75851
+ `);
75852
+ out.write(table(result.hosts));
75853
+ if (permissions.refused)
75854
+ out.write(`permissions: not refreshed: ${permissions.refused}
75855
+ `);
75856
+ if (result.backup)
75857
+ out.write(`Backup: ${result.backup}
75858
+ `);
75859
+ out.write(left.length === 0 ? `Verified: workit doctor is clean for versions, assets, agents and permissions.
75860
+ ` : `Left after upgrade (workit doctor):
75861
+ ${left.map((check) => ` ${check.id}: ${check.detail}${check.fix ? `
75862
+ fix: ${check.fix}` : ""}`).join(`
75863
+ `)}
75864
+ `);
75865
+ return failed ? 1 : 0;
75866
+ }
75867
+ async function runLaunchCommand(argv, deps = {}) {
75868
+ const [host, ...args] = argv;
75869
+ if (!LAUNCH_HOSTS.includes(host)) {
75870
+ (deps.out ?? process.stdout).write(`Usage: workit launch <opencode|cursor|codex|pi> [--auto-upgrade] [-- host arguments]
75871
+ `);
75872
+ return 2;
75873
+ }
75874
+ const auto = args[0] === "--auto-upgrade";
75875
+ const rest = auto ? args.slice(1) : args;
75876
+ const hostArgs = rest[0] === "--" ? rest.slice(1) : rest;
75877
+ const { home, env } = upgradePaths(deps);
75878
+ let launch;
75879
+ if (!deps.run) {
75880
+ try {
75881
+ launch = hostCommand(host, hostArgs, { home, env });
75882
+ } catch (error) {
75883
+ (deps.out ?? process.stderr).write(`${error instanceof Error ? error.message : "Host executable unavailable"}
75884
+ `);
75885
+ return 1;
75886
+ }
75887
+ }
75888
+ if (auto) {
75889
+ const plan = previewUpgrade([host], deps);
75890
+ const reasons = [...plan.blocked, ...plan.failed.map((entry) => entry.reason)];
75891
+ if (plan.ok) {
75892
+ for (const skipped of plan.skipped)
75893
+ (deps.out ?? process.stderr).write(`${skipped.host}: ${skipped.reason}${skipped.fix ? ` (run: ${skipped.fix})` : ""}
75894
+ `);
75895
+ const result = applyUpgrade(plan, deps);
75896
+ if (!result.ok) {
75897
+ (deps.out ?? process.stdout).write(`${result.error}
75898
+ `);
75899
+ return 1;
75900
+ }
75901
+ } else if (plan.blocked.length === 0 && reasons.every((reason) => reason.includes("registry version unavailable"))) {
75902
+ (deps.out ?? process.stderr).write(`Upgrade unavailable: ${reasons.join("; ")}. Starting the unchanged host.
75903
+ `);
75904
+ } else {
75905
+ (deps.out ?? process.stderr).write(`Upgrade blocked: ${reasons.join("; ")}
75906
+ `);
75907
+ return 1;
75908
+ }
75909
+ }
75910
+ if (deps.run)
75911
+ return deps.run(host, hostArgs).status ?? 1;
75912
+ return spawnSync17(launch.command, launch.args, {
75913
+ stdio: "inherit",
75914
+ env
75915
+ }).status ?? 1;
75916
+ }
75917
+ var USAGE3 = `Usage: workit upgrade [--hosts=opencode,cursor,codex,pi,claude-code|none] [--cli] [--preview | --yes | --apply --confirm] [--json]
75918
+ `;
75919
+ var init_upgrade = __esm(() => {
75920
+ init_package();
75921
+ init_host_install();
75922
+ init_doctor();
75923
+ init_host_permissions();
75924
+ init_apply();
75925
+ init_plan();
75926
+ init_report();
75927
+ init_shared();
75928
+ init_apply();
75929
+ init_plan();
75930
+ init_processes();
75931
+ });
75932
+
75831
75933
  // packages/workit-cli/src/verbs/upgrade.ts
75832
75934
  var exports_upgrade = {};
75833
75935
  __export(exports_upgrade, {
@@ -75851,7 +75953,7 @@ var init_launch = __esm(() => {
75851
75953
  // packages/workit-core/src/knowledge.ts
75852
75954
  import { spawnSync as spawnSync18 } from "node:child_process";
75853
75955
  import fs20 from "node:fs";
75854
- import path45 from "node:path";
75956
+ import path48 from "node:path";
75855
75957
  function lintKnowledge(root) {
75856
75958
  const seen = new Set;
75857
75959
  const unreadable = [];
@@ -75955,7 +76057,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
75955
76057
  const end = lines.indexOf("---", 1);
75956
76058
  return end === -1 ? lines : [...lines.slice(0, end + 1).map(() => ""), ...lines.slice(end + 1)];
75957
76059
  }, read = (root, file) => {
75958
- const full = path45.join(root, file);
76060
+ const full = path48.join(root, file);
75959
76061
  try {
75960
76062
  fs20.lstatSync(full);
75961
76063
  } catch {
@@ -75996,7 +76098,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
75996
76098
  }
75997
76099
  }, brokenLinks = (root, doc, tracked) => {
75998
76100
  const findings = [];
75999
- const base = path45.dirname(path45.join(root, doc.file));
76101
+ const base = path48.dirname(path48.join(root, doc.file));
76000
76102
  const missing = (target, line, how) => findings.push({
76001
76103
  rule: "broken-link",
76002
76104
  file: doc.file,
@@ -76015,7 +76117,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76015
76117
  const local = localTarget(target);
76016
76118
  if (!local)
76017
76119
  continue;
76018
- const resolved = local.startsWith("/") ? path45.join(root, local) : path45.resolve(base, local);
76120
+ const resolved = local.startsWith("/") ? path48.join(root, local) : path48.resolve(base, local);
76019
76121
  if (!exists2(resolved))
76020
76122
  missing(target, index + 1, "link");
76021
76123
  }
@@ -76025,9 +76127,9 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76025
76127
  continue;
76026
76128
  const relative = /^\.\.?\//.test(candidate);
76027
76129
  const first = candidate.split("/")[0];
76028
- if (!relative && !(tracked ? tracked.has(first) : exists2(path45.join(root, first))))
76130
+ if (!relative && !(tracked ? tracked.has(first) : exists2(path48.join(root, first))))
76029
76131
  continue;
76030
- const resolved = relative ? path45.resolve(base, candidate) : path45.join(root, candidate);
76132
+ const resolved = relative ? path48.resolve(base, candidate) : path48.join(root, candidate);
76031
76133
  if (!exists2(resolved))
76032
76134
  missing(span, index + 1, "pointer");
76033
76135
  }
@@ -76350,10 +76452,10 @@ var init_redact = __esm(() => {
76350
76452
 
76351
76453
  // packages/workit-core/src/checks.ts
76352
76454
  import { spawn, spawnSync as spawnSync19 } from "node:child_process";
76353
- import { createHash as createHash16 } from "node:crypto";
76455
+ import { createHash as createHash17 } from "node:crypto";
76354
76456
  import fs21 from "node:fs";
76355
- import os17 from "node:os";
76356
- import path46 from "node:path";
76457
+ import os18 from "node:os";
76458
+ import path49 from "node:path";
76357
76459
  import { StringDecoder } from "node:string_decoder";
76358
76460
  function tailLines(text, lines = TAIL_LINES) {
76359
76461
  const all = text.replace(/\r\n?/gu, `
@@ -76473,7 +76575,7 @@ function planSpawn(argv, options) {
76473
76575
  return { file: argv[0], args: [], verbatim: false, shell: true };
76474
76576
  if (options.platform !== "win32")
76475
76577
  return { file: argv[0], args: argv.slice(1), verbatim: false, shell: false };
76476
- const win = path46.win32;
76578
+ const win = path49.win32;
76477
76579
  const isFile = options.isFile ?? ((file) => {
76478
76580
  try {
76479
76581
  return fs21.statSync(file).isFile();
@@ -76558,7 +76660,7 @@ function runCheckCommand(argv, options) {
76558
76660
  `);
76559
76661
  redactor.end();
76560
76662
  resolve({
76561
- exitCode: spawnError ? 127 : code !== null ? code : 128 + (signal ? os17.constants.signals[signal] ?? 1 : 1),
76663
+ exitCode: spawnError ? 127 : code !== null ? code : 128 + (signal ? os18.constants.signals[signal] ?? 1 : 1),
76562
76664
  signal: signal ?? null,
76563
76665
  timedOut,
76564
76666
  durationMs: Date.now() - started,
@@ -76635,10 +76737,10 @@ function runCheckCommand(argv, options) {
76635
76737
  function storeLog(storeRoot, log) {
76636
76738
  const digest = logDigest(log);
76637
76739
  const ref = `blobs/logs/${digest.slice("sha256:".length)}.log`;
76638
- const file = path46.join(storeRoot, ref);
76740
+ const file = path49.join(storeRoot, ref);
76639
76741
  try {
76640
76742
  if (!fs21.existsSync(file)) {
76641
- fs21.mkdirSync(path46.dirname(file), { recursive: true });
76743
+ fs21.mkdirSync(path49.dirname(file), { recursive: true });
76642
76744
  const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
76643
76745
  fs21.writeFileSync(temp, log, { mode: 384 });
76644
76746
  fs21.renameSync(temp, file);
@@ -76651,7 +76753,7 @@ function storeLog(storeRoot, log) {
76651
76753
  function pruneCheckLogs(storeRoot, options = {}) {
76652
76754
  const limits = { ...LOG_RETENTION, ...options.retention };
76653
76755
  const now = options.now ?? Date.now();
76654
- const dir = path46.join(storeRoot, "blobs", "logs");
76756
+ const dir = path49.join(storeRoot, "blobs", "logs");
76655
76757
  const report = { removed: 0, removedBytes: 0, kept: 0 };
76656
76758
  let names;
76657
76759
  try {
@@ -76661,7 +76763,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
76661
76763
  }
76662
76764
  const files = names.flatMap((name) => {
76663
76765
  try {
76664
- const stat = fs21.statSync(path46.join(dir, name));
76766
+ const stat = fs21.statSync(path49.join(dir, name));
76665
76767
  return stat.isFile() ? [{ name, size: stat.size, mtimeMs: stat.mtimeMs }] : [];
76666
76768
  } catch {
76667
76769
  return [];
@@ -76680,7 +76782,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
76680
76782
  continue;
76681
76783
  if (!options.dryRun)
76682
76784
  try {
76683
- fs21.rmSync(path46.join(dir, file.name), { force: true });
76785
+ fs21.rmSync(path49.join(dir, file.name), { force: true });
76684
76786
  } catch {
76685
76787
  continue;
76686
76788
  }
@@ -76689,7 +76791,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
76689
76791
  }
76690
76792
  return report;
76691
76793
  }
76692
- var MAX_LOG_BYTES, TAIL_LINES = 80, MAX_LINE_CHARS = 400, redactLog = (text) => redactText(text), PEM_BEGIN, PEM_END, BATCH_BYTES, MAX_PENDING, PEM_BODY, MAX_KEY_LINES = 4096, MAX_KEY_BYTES, CMD_META, DRAIN_MS = 250, FORWARDED_SIGNALS, logDigest = (log) => `sha256:${createHash16("sha256").update(log).digest("hex")}`, LOG_RETENTION;
76794
+ var MAX_LOG_BYTES, TAIL_LINES = 80, MAX_LINE_CHARS = 400, redactLog = (text) => redactText(text), PEM_BEGIN, PEM_END, BATCH_BYTES, MAX_PENDING, PEM_BODY, MAX_KEY_LINES = 4096, MAX_KEY_BYTES, CMD_META, DRAIN_MS = 250, FORWARDED_SIGNALS, logDigest = (log) => `sha256:${createHash17("sha256").update(log).digest("hex")}`, LOG_RETENTION;
76693
76795
  var init_checks3 = __esm(() => {
76694
76796
  init_redact();
76695
76797
  MAX_LOG_BYTES = 2 * 1024 * 1024;
@@ -76953,7 +77055,7 @@ __export(exports_workspace, {
76953
77055
  run: () => run11,
76954
77056
  runWorkspace: () => runWorkspace
76955
77057
  });
76956
- import { copyFileSync as copyFileSync7, existsSync as existsSync21 } from "node:fs";
77058
+ import { copyFileSync as copyFileSync7, existsSync as existsSync23 } from "node:fs";
76957
77059
  function list2(argv, io) {
76958
77060
  if (argv.length)
76959
77061
  return usage3(io, `unexpected argument ${argv[0]}`);
@@ -77163,7 +77265,7 @@ usage: ${USAGE5}`)), load = (io) => {
77163
77265
  return { ok: false, error: `${current.path} changed; retry` };
77164
77266
  let backup = null;
77165
77267
  try {
77166
- if (existsSync21(current.path)) {
77268
+ if (existsSync23(current.path)) {
77167
77269
  backup = `${current.path}.bak`;
77168
77270
  copyFileSync7(current.path, backup);
77169
77271
  }
@@ -77231,12 +77333,12 @@ var init_workspace = __esm(() => {
77231
77333
 
77232
77334
  // packages/workit-core/src/core/heavy-rules.ts
77233
77335
  import fs22 from "node:fs";
77234
- import path47 from "node:path";
77336
+ import path50 from "node:path";
77235
77337
  function gitTop(cwd) {
77236
- for (let dir = path47.resolve(cwd);; dir = path47.dirname(dir)) {
77237
- if (fs22.existsSync(path47.join(dir, ".git")))
77338
+ for (let dir = path50.resolve(cwd);; dir = path50.dirname(dir)) {
77339
+ if (fs22.existsSync(path50.join(dir, ".git")))
77238
77340
  return dir;
77239
- if (path47.dirname(dir) === dir)
77341
+ if (path50.dirname(dir) === dir)
77240
77342
  return null;
77241
77343
  }
77242
77344
  }
@@ -77277,19 +77379,19 @@ var init_heavy_rules = () => {};
77277
77379
 
77278
77380
  // packages/workit-core/src/core/heavy.ts
77279
77381
  import fs23 from "node:fs";
77280
- import os18 from "node:os";
77281
- import path48 from "node:path";
77382
+ import os19 from "node:os";
77383
+ import path51 from "node:path";
77282
77384
  function stateDir2(env, platform = process.platform) {
77283
77385
  if (env.WORKFLOW_TOOLKIT_STATE)
77284
77386
  return env.WORKFLOW_TOOLKIT_STATE;
77285
77387
  if (env.XDG_STATE_HOME)
77286
- return path48.join(env.XDG_STATE_HOME, "workit");
77287
- const home = env.HOME || os18.homedir();
77388
+ return path51.join(env.XDG_STATE_HOME, "workit");
77389
+ const home = env.HOME || os19.homedir();
77288
77390
  if (platform === "darwin")
77289
- return path48.join(home, "Library", "Application Support", "workit");
77391
+ return path51.join(home, "Library", "Application Support", "workit");
77290
77392
  if (platform === "win32")
77291
- return path48.join(env.LOCALAPPDATA ?? path48.join(home, "AppData", "Local"), "workit");
77292
- return path48.join(home, ".local", "state", "workit");
77393
+ return path51.join(env.LOCALAPPDATA ?? path51.join(home, "AppData", "Local"), "workit");
77394
+ return path51.join(home, ".local", "state", "workit");
77293
77395
  }
77294
77396
  function positional(words, from, values = PM_VALUES) {
77295
77397
  let index = from;
@@ -77429,7 +77531,7 @@ function machinePatterns(env) {
77429
77531
  return isRecord8(value) ? stringList2(value.patterns) : [];
77430
77532
  }
77431
77533
  function repoPatterns(cwd) {
77432
- return repoHeavyCommands(gitTop(cwd) ?? path48.resolve(cwd));
77534
+ return repoHeavyCommands(gitTop(cwd) ?? path51.resolve(cwd));
77433
77535
  }
77434
77536
  function heavyLines(lines, options) {
77435
77537
  const found = [];
@@ -77508,7 +77610,7 @@ function leaseRewrite(command) {
77508
77610
  return null;
77509
77611
  return `${prefix}workit check --heavy -- ${rest}`;
77510
77612
  }
77511
- var HEAVY_COMMANDS_FILE = "heavy-commands.json", heavyCommandsFile = (env) => path48.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) => {
77613
+ 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) => {
77512
77614
  try {
77513
77615
  return JSON.parse(fs23.readFileSync(file, "utf8"));
77514
77616
  } catch {
@@ -77654,8 +77756,8 @@ var init_heavy = __esm(() => {
77654
77756
  // packages/workit-core/src/core/resources.ts
77655
77757
  import { randomUUID as randomUUID5 } from "node:crypto";
77656
77758
  import fs24 from "node:fs";
77657
- import os19 from "node:os";
77658
- import path49 from "node:path";
77759
+ import os20 from "node:os";
77760
+ import path52 from "node:path";
77659
77761
  function memoryValue(value, host) {
77660
77762
  const text = typeof value === "number" ? String(value) : typeof value === "string" ? value : "";
77661
77763
  const percent = PERCENT.exec(text.trim());
@@ -77836,7 +77938,7 @@ function tryOnce(options, record, reclaimed) {
77836
77938
  const text = `${JSON.stringify(record)}
77837
77939
  `;
77838
77940
  for (let slot = 0;slot < options.slots; slot += 1) {
77839
- const file = path49.join(options.dir, `slot-${slot}.json`);
77941
+ const file = path52.join(options.dir, `slot-${slot}.json`);
77840
77942
  for (let attempt = 0;attempt < 2; attempt += 1) {
77841
77943
  try {
77842
77944
  const fd = fs24.openSync(file, "wx", 384);
@@ -77961,7 +78063,7 @@ function heldLease(dir, id, options = {}) {
77961
78063
  for (const name of names) {
77962
78064
  if (!/^slot-\d+\.json$/u.test(name))
77963
78065
  continue;
77964
- const lease = parseLease(readText5(path49.join(dir, name)));
78066
+ const lease = parseLease(readText5(path52.join(dir, name)));
77965
78067
  if (lease?.id === id && !staleReason(lease, options.probe) && (options.ancestor ?? isAncestor)(lease.pid))
77966
78068
  return lease;
77967
78069
  }
@@ -78016,10 +78118,10 @@ async function runScoped(run, wrapper, sinks) {
78016
78118
  }
78017
78119
  function firstNotice(env, session, key, now = Date.now()) {
78018
78120
  const id = (session ?? `ppid-${process.ppid}`).replace(/[^A-Za-z0-9_.-]/gu, "_").slice(0, 120);
78019
- const dir = path49.join(stateDir2(env), "notices");
78121
+ const dir = path52.join(stateDir2(env), "notices");
78020
78122
  try {
78021
78123
  fs24.mkdirSync(dir, { recursive: true, mode: 448 });
78022
- fs24.writeFileSync(path49.join(dir, `${key}-${id}`), `${new Date(now).toISOString()}
78124
+ fs24.writeFileSync(path52.join(dir, `${key}-${id}`), `${new Date(now).toISOString()}
78023
78125
  `, {
78024
78126
  flag: "wx",
78025
78127
  mode: 384
@@ -78029,7 +78131,7 @@ function firstNotice(env, session, key, now = Date.now()) {
78029
78131
  }
78030
78132
  try {
78031
78133
  for (const name of fs24.readdirSync(dir)) {
78032
- const file = path49.join(dir, name);
78134
+ const file = path52.join(dir, name);
78033
78135
  if (now - fs24.statSync(file).mtimeMs > NOTICE_TTL_MS)
78034
78136
  fs24.rmSync(file, { force: true });
78035
78137
  }
@@ -78039,7 +78141,7 @@ function firstNotice(env, session, key, now = Date.now()) {
78039
78141
  function leaseSlots(dir, slots, probe = {}) {
78040
78142
  const states = [];
78041
78143
  for (let slot = 0;slot < slots; slot += 1) {
78042
- const lease = parseLease(readText5(path49.join(dir, `slot-${slot}.json`)));
78144
+ const lease = parseLease(readText5(path52.join(dir, `slot-${slot}.json`)));
78043
78145
  states.push({
78044
78146
  slot,
78045
78147
  holder: lease ? holderOf(lease) : null,
@@ -78049,15 +78151,15 @@ function leaseSlots(dir, slots, probe = {}) {
78049
78151
  return states;
78050
78152
  }
78051
78153
  var DEFAULT_HEAVY_CHECKS, DEFAULT_SLOTS = 1, DEFAULT_WAIT_S = 600, DEFAULT_MEMORY_SHARE = 0.4, DEFAULT_CPU_SHARE = 0.7, MAX_SLOTS = 64, UNREADABLE_TTL_MS = 30000, GUARD_TTL_MS = 30000, hostShape = () => ({
78052
- totalMemBytes: os19.totalmem(),
78053
- cpus: Math.max(1, os19.availableParallelism?.() ?? os19.cpus().length)
78054
- }), isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SIZE, PERCENT, UNITS, leaseDir = (env) => path49.join(stateDir2(env), "leases"), readText5 = (file) => {
78154
+ totalMemBytes: os20.totalmem(),
78155
+ cpus: Math.max(1, os20.availableParallelism?.() ?? os20.cpus().length)
78156
+ }), isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SIZE, PERCENT, UNITS, leaseDir = (env) => path52.join(stateDir2(env), "leases"), readText5 = (file) => {
78055
78157
  try {
78056
78158
  return fs24.readFileSync(file, "utf8");
78057
78159
  } catch {
78058
78160
  return null;
78059
78161
  }
78060
- }, bootId = () => readText5("/proc/sys/kernel/random/boot_id")?.trim() || null, bootTime = () => Math.round((Date.now() - os19.uptime() * 1000) / 1000) * 1000, BOOT_SLACK_MS = 120000, statFields = (pid) => {
78162
+ }, bootId = () => readText5("/proc/sys/kernel/random/boot_id")?.trim() || null, bootTime = () => Math.round((Date.now() - os20.uptime() * 1000) / 1000) * 1000, BOOT_SLACK_MS = 120000, statFields = (pid) => {
78061
78163
  const stat = readText5(`/proc/${pid}/stat`);
78062
78164
  return stat ? stat.slice(stat.lastIndexOf(")") + 2).split(" ") : null;
78063
78165
  }, processStart = (pid) => statFields(pid)?.[19] ?? null, pidAlive2 = (pid) => {
@@ -78106,8 +78208,8 @@ __export(exports_check, {
78106
78208
  run: () => run12,
78107
78209
  workspaceResources: () => workspaceResources
78108
78210
  });
78109
- import os20 from "node:os";
78110
- import path50 from "node:path";
78211
+ import os21 from "node:os";
78212
+ import path53 from "node:path";
78111
78213
  function parse6(argv) {
78112
78214
  const split = argv.indexOf("--");
78113
78215
  const head = split >= 0 ? argv.slice(0, split) : [...argv];
@@ -78309,7 +78411,7 @@ function hostToolWaitCapMs(env) {
78309
78411
  }
78310
78412
  async function workspaceResources(io) {
78311
78413
  const env = io.env;
78312
- const dir = env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path50.join(env.XDG_CONFIG_HOME || path50.join(env.HOME || os20.homedir(), ".config"), "workit");
78414
+ 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");
78313
78415
  try {
78314
78416
  await Promise.resolve().then(() => init_workspaces());
78315
78417
  const workspace = resolveWorkspaceFrom(io.cwd, dir, env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined);
@@ -78428,7 +78530,7 @@ async function run12(argv, io) {
78428
78530
  if (options.shell && command.length !== 1)
78429
78531
  return emit(io, fail2("invalid_input", '--shell takes the command as one string: workit check --shell -- "<cmd>"'));
78430
78532
  }
78431
- const relCwd = posix(path50.relative(top, runCwd));
78533
+ const relCwd = posix(path53.relative(top, runCwd));
78432
78534
  const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
78433
78535
  const shadowed = !configured && name !== null ? config.checks.find((item) => item.name === name) : undefined;
78434
78536
  if (shadowed)
@@ -78490,7 +78592,7 @@ async function run12(argv, io) {
78490
78592
  const modifiedWorktree = key.tree !== null && treeAfter !== key.tree;
78491
78593
  const store = storeRoot(io.cwd);
78492
78594
  const blob = store.ok ? storeLog(store.value.root, result.log) : null;
78493
- const logPath = store.ok && blob ? path50.join(store.value.root, blob.ref) : null;
78595
+ const logPath = store.ok && blob ? path53.join(store.value.root, blob.ref) : null;
78494
78596
  const tail = tailLines(result.log, TAIL_LINES);
78495
78597
  const passed = result.exitCode === 0 && !result.timedOut;
78496
78598
  const bounded = boundedArgv(command);
@@ -78605,7 +78707,7 @@ async function run12(argv, io) {
78605
78707
  return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
78606
78708
  return 0;
78607
78709
  }
78608
- var USAGE6 = 'workit check <name> [--full] [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--heavy] [--full] [--wait <s>] [--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(path50.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS, ANSI_COLOR, WARNING_LINE, NO_WARNINGS, HOST_TOOL_WAIT_CAP_MS = 1e5;
78710
+ var USAGE6 = 'workit check <name> [--full] [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--heavy] [--full] [--wait <s>] [--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, HOST_TOOL_WAIT_CAP_MS = 1e5;
78609
78711
  var init_check = __esm(() => {
78610
78712
  init_check_config();
78611
78713
  init_checks3();
@@ -78634,7 +78736,7 @@ __export(exports_lock, {
78634
78736
  run: () => run13
78635
78737
  });
78636
78738
  import fs25 from "node:fs";
78637
- import path51 from "node:path";
78739
+ import path54 from "node:path";
78638
78740
  async function settingsFor(io) {
78639
78741
  const workspace = await workspaceResources(io);
78640
78742
  const config = loadCheckConfig(io.cwd);
@@ -78716,7 +78818,7 @@ function readPatterns(file) {
78716
78818
  return { patterns: [] };
78717
78819
  }
78718
78820
  function writePatterns(file, value) {
78719
- fs25.mkdirSync(path51.dirname(file), { recursive: true, mode: 448 });
78821
+ fs25.mkdirSync(path54.dirname(file), { recursive: true, mode: 448 });
78720
78822
  const temp = `${file}.${process.pid}.tmp`;
78721
78823
  fs25.writeFileSync(temp, `${JSON.stringify(value, null, 2)}
78722
78824
  `, { mode: 384 });
@@ -78802,9 +78904,9 @@ var exports_models = {};
78802
78904
  __export(exports_models, {
78803
78905
  run: () => run14
78804
78906
  });
78805
- import { existsSync as existsSync22, readdirSync as readdirSync13, readFileSync as readFileSync22, statSync as statSync9 } from "node:fs";
78806
- import os21 from "node:os";
78807
- import path52 from "node:path";
78907
+ import { existsSync as existsSync24, readdirSync as readdirSync13, readFileSync as readFileSync23, statSync as statSync9 } from "node:fs";
78908
+ import os22 from "node:os";
78909
+ import path55 from "node:path";
78808
78910
  async function run14(argv, io) {
78809
78911
  const [sub, ...args] = argv.filter((arg) => arg !== "--json");
78810
78912
  if (sub !== "show")
@@ -78865,7 +78967,7 @@ var USAGE8 = "workit models show [--role <role>] [--tier <tier>] [--host <host>]
78865
78967
  const found = new Set;
78866
78968
  let text = "";
78867
78969
  try {
78868
- text = readFileSync22(file, "utf8");
78970
+ text = readFileSync23(file, "utf8");
78869
78971
  } catch {
78870
78972
  return found;
78871
78973
  }
@@ -78879,26 +78981,26 @@ var USAGE8 = "workit models show [--role <role>] [--tier <tier>] [--host <host>]
78879
78981
  } catch {}
78880
78982
  return found;
78881
78983
  }, matches3 = (ran, configured) => ran.toLowerCase().includes(configured.toLowerCase()), usageReport = (cwd, env, days) => {
78882
- const projects = path52.join(env.CLAUDE_CONFIG_DIR || path52.join(env.HOME || os21.homedir(), ".claude"), "projects");
78984
+ const projects = path55.join(env.CLAUDE_CONFIG_DIR || path55.join(env.HOME || os22.homedir(), ".claude"), "projects");
78883
78985
  const since = Date.now() - days * 86400000;
78884
78986
  const types = {};
78885
78987
  let agents = 0;
78886
78988
  const dirs = (dir) => {
78887
78989
  try {
78888
- return readdirSync13(dir).map((name) => path52.join(dir, name));
78990
+ return readdirSync13(dir).map((name) => path55.join(dir, name));
78889
78991
  } catch {
78890
78992
  return [];
78891
78993
  }
78892
78994
  };
78893
78995
  for (const project of dirs(projects))
78894
78996
  for (const session of dirs(project))
78895
- for (const meta of dirs(path52.join(session, "subagents")).filter((f) => f.endsWith(".meta.json"))) {
78997
+ for (const meta of dirs(path55.join(session, "subagents")).filter((f) => f.endsWith(".meta.json"))) {
78896
78998
  try {
78897
78999
  if (statSync9(meta).mtimeMs < since)
78898
79000
  continue;
78899
- const agentType = JSON.parse(readFileSync22(meta, "utf8")).agentType;
79001
+ const agentType = JSON.parse(readFileSync23(meta, "utf8")).agentType;
78900
79002
  const transcript = meta.replace(/\.meta\.json$/, ".jsonl");
78901
- if (typeof agentType !== "string" || !existsSync22(transcript))
79003
+ if (typeof agentType !== "string" || !existsSync24(transcript))
78902
79004
  continue;
78903
79005
  const ran = modelsOf(transcript);
78904
79006
  if (!ran.size)
@@ -79037,8 +79139,8 @@ var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock)
79037
79139
 
79038
79140
  // packages/workit-core/src/git/ops.ts
79039
79141
  import { spawnSync as spawnSync20 } from "node:child_process";
79040
- import { existsSync as existsSync23, readFileSync as readFileSync23 } from "node:fs";
79041
- import path53 from "node:path";
79142
+ import { existsSync as existsSync25, readFileSync as readFileSync24 } from "node:fs";
79143
+ import path56 from "node:path";
79042
79144
  function operationInProgress(cwd) {
79043
79145
  const markers = [
79044
79146
  ["rebase-merge", "rebase"],
@@ -79051,18 +79153,18 @@ function operationInProgress(cwd) {
79051
79153
  if (!run.ok)
79052
79154
  return null;
79053
79155
  const found = run.stdout.split(`
79054
- `).map((line) => path53.resolve(cwd, line.trim()));
79156
+ `).map((line) => path56.resolve(cwd, line.trim()));
79055
79157
  const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
79056
79158
  for (const [index, [, operation]] of markers.entries()) {
79057
79159
  const marker = found[index];
79058
- if (!marker || !existsSync23(marker))
79160
+ if (!marker || !existsSync25(marker))
79059
79161
  continue;
79060
- if (index === 1 && existsSync23(path53.join(marker, "applying")))
79162
+ if (index === 1 && existsSync25(path56.join(marker, "applying")))
79061
79163
  return { operation: "am", commitAllowed: false, branch: null };
79062
- if (index === 0 && existsSync23(path53.join(marker, "amend")) && !conflicted()) {
79164
+ if (index === 0 && existsSync25(path56.join(marker, "amend")) && !conflicted()) {
79063
79165
  let headName = "";
79064
79166
  try {
79065
- headName = readFileSync23(path53.join(marker, "head-name"), "utf8").trim();
79167
+ headName = readFileSync24(path56.join(marker, "head-name"), "utf8").trim();
79066
79168
  } catch {}
79067
79169
  const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
79068
79170
  return { operation, commitAllowed: branch !== null, branch };
@@ -79390,7 +79492,7 @@ function gitCommit(cwd, input) {
79390
79492
  if (paths.some((value) => value.startsWith("-") || !value.trim()))
79391
79493
  return failure3("invalid_input", "paths must not be empty or start with -");
79392
79494
  const tracked = new Set(nulList(git5(cwd, ["ls-files", "-z", "--", ...paths]).stdout));
79393
- const addable = paths.filter((value) => existsSync23(path53.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
79495
+ const addable = paths.filter((value) => existsSync25(path56.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
79394
79496
  if (addable.length) {
79395
79497
  const added = git5(cwd, ["add", "-A", "--", ...addable]);
79396
79498
  if (!added.ok)
@@ -79929,12 +80031,12 @@ var init_ops = __esm(() => {
79929
80031
 
79930
80032
  // packages/workit-core/src/verdict-cover.ts
79931
80033
  import fs26 from "node:fs";
79932
- import path54 from "node:path";
80034
+ import path57 from "node:path";
79933
80035
  function chainsAbove(cwd, branch) {
79934
80036
  const root = storeRoot(cwd);
79935
80037
  if (!root.ok)
79936
80038
  return [];
79937
- const dir = path54.join(root.value.root, "stacks");
80039
+ const dir = path57.join(root.value.root, "stacks");
79938
80040
  let names = [];
79939
80041
  try {
79940
80042
  names = fs26.readdirSync(dir).filter((name) => name.endsWith(".json"));
@@ -79945,7 +80047,7 @@ function chainsAbove(cwd, branch) {
79945
80047
  for (const name of names.toSorted()) {
79946
80048
  let parsed;
79947
80049
  try {
79948
- parsed = JSON.parse(fs26.readFileSync(path54.join(dir, name), "utf8"));
80050
+ parsed = JSON.parse(fs26.readFileSync(path57.join(dir, name), "utf8"));
79949
80051
  } catch {
79950
80052
  continue;
79951
80053
  }
@@ -80040,10 +80142,10 @@ var init_pr_lane = __esm(() => {
80040
80142
 
80041
80143
  // packages/workit-core/src/forge/reruns.ts
80042
80144
  import fs27 from "node:fs";
80043
- import path55 from "node:path";
80145
+ import path58 from "node:path";
80044
80146
  function rerunLogPath(cwd) {
80045
80147
  const common = gitCommonDir(cwd);
80046
- return common ? path55.join(common, "workit", "ci-reruns.jsonl") : null;
80148
+ return common ? path58.join(common, "workit", "ci-reruns.jsonl") : null;
80047
80149
  }
80048
80150
  function rerunCounts(cwd, key) {
80049
80151
  const counts = new Map;
@@ -80078,7 +80180,7 @@ function recordReruns(cwd, rows) {
80078
80180
  if (!file)
80079
80181
  return false;
80080
80182
  try {
80081
- fs27.mkdirSync(path55.dirname(file), { recursive: true });
80183
+ fs27.mkdirSync(path58.dirname(file), { recursive: true });
80082
80184
  fs27.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
80083
80185
  `).join(""));
80084
80186
  return true;
@@ -80091,7 +80193,7 @@ function withRerunLock(cwd, fn) {
80091
80193
  if (!file)
80092
80194
  return fn();
80093
80195
  const lock = `${file.slice(0, -".jsonl".length)}.lock`;
80094
- fs27.mkdirSync(path55.dirname(lock), { recursive: true });
80196
+ fs27.mkdirSync(path58.dirname(lock), { recursive: true });
80095
80197
  const until = Date.now() + LOCK_WAIT_MS2;
80096
80198
  for (;; ) {
80097
80199
  try {
@@ -80508,7 +80610,7 @@ function recordAccepted(cwd, resolved, status, accepted, options) {
80508
80610
  return recordReruns(cwd, rows);
80509
80611
  }
80510
80612
  var MAX_LOG_TAILS = 5, GITLAB_MERGEABLE, GITHUB_MERGEABLE, NO_CHECKS_GRACE_MS = 90000;
80511
- var init_report = __esm(() => {
80613
+ var init_report2 = __esm(() => {
80512
80614
  init_rev();
80513
80615
  init_ledger();
80514
80616
  init_reruns();
@@ -81057,7 +81159,7 @@ var init_pr_ops = __esm(() => {
81057
81159
  init_ledger();
81058
81160
  init_verdict_cover();
81059
81161
  init_pr_lane();
81060
- init_report();
81162
+ init_report2();
81061
81163
  VERIFY_DELAYS_MS = [1000, 2000, 4000];
81062
81164
  AFTER_REVIEW = {
81063
81165
  commit: "stop here; review comes when the user asks",
@@ -81070,9 +81172,9 @@ var init_pr_ops = __esm(() => {
81070
81172
 
81071
81173
  // packages/workit-core/src/stack.ts
81072
81174
  import { spawnSync as spawnSync22 } from "node:child_process";
81073
- import { createHash as createHash17, randomBytes as randomBytes4 } from "node:crypto";
81175
+ import { createHash as createHash18, randomBytes as randomBytes4 } from "node:crypto";
81074
81176
  import fs28 from "node:fs";
81075
- import path56 from "node:path";
81177
+ import path59 from "node:path";
81076
81178
  function worktreeOf(cwd, branch) {
81077
81179
  const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
81078
81180
  if (!list.ok)
@@ -81121,7 +81223,7 @@ function gitRestack(cwd, input) {
81121
81223
  error: "no store root"
81122
81224
  };
81123
81225
  fs28.mkdirSync(scratch, { recursive: true });
81124
- dir = path56.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
81226
+ dir = path59.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
81125
81227
  const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
81126
81228
  if (!added.ok)
81127
81229
  return {
@@ -81177,7 +81279,7 @@ function pruneScratch(cwd) {
81177
81279
  if (!scratch || !fs28.existsSync(scratch))
81178
81280
  return;
81179
81281
  for (const name of fs28.readdirSync(scratch)) {
81180
- const dir = path56.join(scratch, name);
81282
+ const dir = path59.join(scratch, name);
81181
81283
  if (!rebaseInProgress(dir) && !trackedDirt(dir))
81182
81284
  gitRun3(cwd, ["worktree", "remove", "--force", dir]);
81183
81285
  }
@@ -81187,7 +81289,7 @@ function stacksDir(cwd) {
81187
81289
  const root = storeRoot(cwd);
81188
81290
  if (!root.ok)
81189
81291
  return stackFail(root.code, root.error, root.unblock);
81190
- return { ok: true, data: path56.join(root.value.root, "stacks") };
81292
+ return { ok: true, data: path59.join(root.value.root, "stacks") };
81191
81293
  }
81192
81294
  function parseStack(raw) {
81193
81295
  if (!isRecord12(raw) || !Array.isArray(raw.branches))
@@ -81239,7 +81341,7 @@ function readStack(cwd, name) {
81239
81341
  const dir = stacksDir(cwd);
81240
81342
  if (!dir.ok)
81241
81343
  return dir;
81242
- const file = path56.join(dir.data, fileFor(name));
81344
+ const file = path59.join(dir.data, fileFor(name));
81243
81345
  let text;
81244
81346
  try {
81245
81347
  text = fs28.readFileSync(file, "utf8");
@@ -81260,7 +81362,7 @@ function writeStack(cwd, stack, now = new Date) {
81260
81362
  const dir = stacksDir(cwd);
81261
81363
  if (!dir.ok)
81262
81364
  return dir;
81263
- const file = path56.join(dir.data, fileFor(stack.name));
81365
+ const file = path59.join(dir.data, fileFor(stack.name));
81264
81366
  const temp = `${file}.${process.pid}.tmp`;
81265
81367
  try {
81266
81368
  fs28.mkdirSync(dir.data, { recursive: true });
@@ -81288,7 +81390,7 @@ function listStacks(cwd) {
81288
81390
  for (const name of names) {
81289
81391
  let parsed = null;
81290
81392
  try {
81291
- parsed = parseStack(JSON.parse(fs28.readFileSync(path56.join(dir.data, name), "utf8")));
81393
+ parsed = parseStack(JSON.parse(fs28.readFileSync(path59.join(dir.data, name), "utf8")));
81292
81394
  } catch {
81293
81395
  parsed = null;
81294
81396
  }
@@ -81350,7 +81452,7 @@ function takeLock(lock) {
81350
81452
  host: localLockHost(),
81351
81453
  nonce: randomBytes4(8).toString("hex")
81352
81454
  };
81353
- fs28.writeFileSync(path56.join(lock, OWNER), JSON.stringify(owner));
81455
+ fs28.writeFileSync(path59.join(lock, OWNER), JSON.stringify(owner));
81354
81456
  return owner;
81355
81457
  }
81356
81458
  function reapLock(lock, observed) {
@@ -81387,7 +81489,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
81387
81489
  return dir;
81388
81490
  if (!validName(name))
81389
81491
  return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
81390
- const lock = path56.join(dir.data, `${fileFor(name)}.lock`);
81492
+ const lock = path59.join(dir.data, `${fileFor(name)}.lock`);
81391
81493
  try {
81392
81494
  fs28.mkdirSync(dir.data, { recursive: true });
81393
81495
  } catch (error) {
@@ -81417,7 +81519,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
81417
81519
  const touch = () => {
81418
81520
  try {
81419
81521
  const now = new Date;
81420
- fs28.utimesSync(path56.join(lock, OWNER), now, now);
81522
+ fs28.utimesSync(path59.join(lock, OWNER), now, now);
81421
81523
  } catch {}
81422
81524
  };
81423
81525
  const beat = setInterval(touch, HEARTBEAT_MS);
@@ -82318,10 +82420,10 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
82318
82420
  return !status.ok || status.stdout.trim() !== "";
82319
82421
  }, scratchDir = (cwd) => {
82320
82422
  const dir = stacksDir(cwd);
82321
- return dir.ok ? path56.join(dir.data, "worktrees") : null;
82423
+ return dir.ok ? path59.join(dir.data, "worktrees") : null;
82322
82424
  }, firstLine = (run) => (`${run.stderr}
82323
82425
  ${run.stdout}`.split(`
82324
- `).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()}-${createHash17("sha256").update(name).digest("hex").slice(0, 12)}.json`, fileFor, validName = (name) => {
82426
+ `).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) => {
82325
82427
  if (name.length === 0 || name.length > 200)
82326
82428
  return false;
82327
82429
  for (let index = 0;index < name.length; index += 1) {
@@ -82333,12 +82435,12 @@ ${run.stdout}`.split(`
82333
82435
  }, 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) => {
82334
82436
  let raw = null;
82335
82437
  try {
82336
- raw = fs28.readFileSync(path56.join(lock, OWNER), "utf8");
82438
+ raw = fs28.readFileSync(path59.join(lock, OWNER), "utf8");
82337
82439
  } catch {
82338
82440
  raw = null;
82339
82441
  }
82340
82442
  let age = null;
82341
- for (const target of [path56.join(lock, OWNER), lock])
82443
+ for (const target of [path59.join(lock, OWNER), lock])
82342
82444
  try {
82343
82445
  age = Date.now() - fs28.statSync(target).mtimeMs;
82344
82446
  break;
@@ -82362,7 +82464,7 @@ var init_stack = __esm(() => {
82362
82464
  init_autonomy();
82363
82465
  init_store_lock();
82364
82466
  init_pr_ops();
82365
- init_report();
82467
+ init_report2();
82366
82468
  init_ops();
82367
82469
  init_rev();
82368
82470
  init_ledger();
@@ -82379,9 +82481,9 @@ var init_stack = __esm(() => {
82379
82481
 
82380
82482
  // packages/workit-core/src/fanout.ts
82381
82483
  import { spawnSync as spawnSync23 } from "node:child_process";
82382
- import { createHash as createHash18 } from "node:crypto";
82484
+ import { createHash as createHash19 } from "node:crypto";
82383
82485
  import fs29 from "node:fs";
82384
- import path57 from "node:path";
82486
+ import path60 from "node:path";
82385
82487
  function expandBraces2(pattern, limit = 64) {
82386
82488
  for (let index = 0;index < pattern.length; index += 1) {
82387
82489
  if (pattern[index] === "\\") {
@@ -82627,7 +82729,7 @@ function parsePlan(raw, defaults, name) {
82627
82729
  id,
82628
82730
  branch,
82629
82731
  base: optional("base") ?? "",
82630
- worktree: path57.resolve(defaults.root, optional("worktree") ?? path57.join(defaults.worktreeRoot, id)),
82732
+ worktree: path60.resolve(defaults.root, optional("worktree") ?? path60.join(defaults.worktreeRoot, id)),
82631
82733
  tier,
82632
82734
  reason,
82633
82735
  dependsOn: [...new Set(dependsOn ?? [])],
@@ -82756,12 +82858,12 @@ function regeneratedFiles(root, tracked) {
82756
82858
  const found = new Map;
82757
82859
  let scripts;
82758
82860
  try {
82759
- const manifest = JSON.parse(fs29.readFileSync(path57.join(root, "package.json"), "utf8"));
82861
+ const manifest = JSON.parse(fs29.readFileSync(path60.join(root, "package.json"), "utf8"));
82760
82862
  scripts = manifest.scripts ?? {};
82761
82863
  } catch {
82762
82864
  return found;
82763
82865
  }
82764
- const runner = fs29.existsSync(path57.join(root, "bun.lock")) ? "bun run" : fs29.existsSync(path57.join(root, "pnpm-lock.yaml")) ? "pnpm run" : fs29.existsSync(path57.join(root, "yarn.lock")) ? "yarn run" : "npm run";
82866
+ 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";
82765
82867
  const outputs = tracked.filter((file) => !CODE.test(file));
82766
82868
  for (const [name, command] of Object.entries(scripts)) {
82767
82869
  if (!name.startsWith("write:") || typeof command !== "string")
@@ -82769,7 +82871,7 @@ function regeneratedFiles(root, tracked) {
82769
82871
  for (const file of command.match(/[\w./-]+\.[cm]?[jt]s\b/gu) ?? []) {
82770
82872
  let source;
82771
82873
  try {
82772
- source = fs29.readFileSync(path57.join(root, file), "utf8");
82874
+ source = fs29.readFileSync(path60.join(root, file), "utf8");
82773
82875
  } catch {
82774
82876
  continue;
82775
82877
  }
@@ -82891,11 +82993,11 @@ function defaultTrunk(cwd) {
82891
82993
  }
82892
82994
  function mainCheckout(cwd) {
82893
82995
  const common = gitCommonDir(cwd);
82894
- return common && path57.basename(common) === ".git" ? path57.dirname(common) : path57.resolve(cwd);
82996
+ return common && path60.basename(common) === ".git" ? path60.dirname(common) : path60.resolve(cwd);
82895
82997
  }
82896
82998
  function worktreeRoot(cwd) {
82897
82999
  const main = mainCheckout(cwd);
82898
- return path57.join(path57.dirname(main), `${path57.basename(main)}-wt`);
83000
+ return path60.join(path60.dirname(main), `${path60.basename(main)}-wt`);
82899
83001
  }
82900
83002
  function sliceHash(slice) {
82901
83003
  const {
@@ -82909,13 +83011,13 @@ function sliceHash(slice) {
82909
83011
  issues: _issues,
82910
83012
  ...definition
82911
83013
  } = slice;
82912
- return createHash18("sha256").update(JSON.stringify(definition)).digest("hex").slice(0, 16);
83014
+ return createHash19("sha256").update(JSON.stringify(definition)).digest("hex").slice(0, 16);
82913
83015
  }
82914
83016
  function fanoutsDir(cwd) {
82915
83017
  const root = storeRoot(cwd);
82916
83018
  if (!root.ok)
82917
83019
  return fanoutFail(root.code, root.error, root.unblock);
82918
- return { ok: true, data: path57.join(root.value.root, "fanouts") };
83020
+ return { ok: true, data: path60.join(root.value.root, "fanouts") };
82919
83021
  }
82920
83022
  function parseStored(raw) {
82921
83023
  if (!isRecord13(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
@@ -82983,7 +83085,7 @@ function readFanout(cwd, name) {
82983
83085
  const dir = fanoutsDir(cwd);
82984
83086
  if (!dir.ok)
82985
83087
  return dir;
82986
- const file = path57.join(dir.data, stackFileName(name));
83088
+ const file = path60.join(dir.data, stackFileName(name));
82987
83089
  let parsed = null;
82988
83090
  try {
82989
83091
  parsed = parseStored(JSON.parse(fs29.readFileSync(file, "utf8")));
@@ -83008,7 +83110,7 @@ function listFanouts(cwd) {
83008
83110
  for (const entry of names) {
83009
83111
  let parsed = null;
83010
83112
  try {
83011
- parsed = parseStored(JSON.parse(fs29.readFileSync(path57.join(dir.data, entry), "utf8")));
83113
+ parsed = parseStored(JSON.parse(fs29.readFileSync(path60.join(dir.data, entry), "utf8")));
83012
83114
  } catch {
83013
83115
  parsed = null;
83014
83116
  }
@@ -83047,7 +83149,7 @@ function writeFanout(cwd, plan) {
83047
83149
  const dir = fanoutsDir(cwd);
83048
83150
  if (!dir.ok)
83049
83151
  return dir;
83050
- const file = path57.join(dir.data, stackFileName(plan.name));
83152
+ const file = path60.join(dir.data, stackFileName(plan.name));
83051
83153
  const temp = `${file}.${process.pid}.tmp`;
83052
83154
  try {
83053
83155
  fs29.mkdirSync(dir.data, { recursive: true });
@@ -83258,13 +83360,13 @@ var init_fanout = __esm(() => {
83258
83360
  // packages/workit-core/src/forge/exec.ts
83259
83361
  import { spawnSync as spawnSync24 } from "node:child_process";
83260
83362
  import fs30 from "node:fs";
83261
- import path58 from "node:path";
83363
+ import path61 from "node:path";
83262
83364
  function findExecutable(bin, env) {
83263
- const dirs = (env.PATH ?? env.Path ?? "").split(path58.delimiter).filter(Boolean);
83365
+ const dirs = (env.PATH ?? env.Path ?? "").split(path61.delimiter).filter(Boolean);
83264
83366
  const exts = process.platform === "win32" ? [".exe"] : [""];
83265
83367
  for (const dir of dirs)
83266
83368
  for (const ext of exts) {
83267
- const candidate = path58.join(dir, `${bin}${ext}`);
83369
+ const candidate = path61.join(dir, `${bin}${ext}`);
83268
83370
  try {
83269
83371
  const stat = fs30.statSync(candidate);
83270
83372
  if (stat.isFile())
@@ -84807,7 +84909,7 @@ var init_pr_edit = __esm(() => {
84807
84909
  init_rev();
84808
84910
  init_stack();
84809
84911
  init_pr_ops();
84810
- init_report();
84912
+ init_report2();
84811
84913
  });
84812
84914
 
84813
84915
  // packages/workit-core/src/core/live-session.ts
@@ -84827,7 +84929,7 @@ var init_live_session = __esm(() => {
84827
84929
  });
84828
84930
 
84829
84931
  // packages/workit-core/src/hooks/write-gate.ts
84830
- import path59 from "node:path";
84932
+ import path62 from "node:path";
84831
84933
  var CASE_INSENSITIVE, PREFIXES2, SCRIPT_SHELLS, cache3, MUTATING_GIT, DRY_N, MUTATING_WORKIT_GIT, CD2, PUSHD2, POPD2, UNKNOWN_DIR;
84832
84934
  var init_write_gate = __esm(() => {
84833
84935
  init_task_store();
@@ -84867,7 +84969,7 @@ var init_write_gate = __esm(() => {
84867
84969
  CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
84868
84970
  PUSHD2 = new Set(["pushd", "push-location"]);
84869
84971
  POPD2 = new Set(["popd", "pop-location"]);
84870
- UNKNOWN_DIR = path59.resolve(path59.parse(process.cwd()).root, ".workit-unknown-dir");
84972
+ UNKNOWN_DIR = path62.resolve(path62.parse(process.cwd()).root, ".workit-unknown-dir");
84871
84973
  });
84872
84974
 
84873
84975
  // packages/workit-core/src/hooks/worktree-confine.ts
@@ -84892,20 +84994,20 @@ var init_worktree_confine = __esm(() => {
84892
84994
 
84893
84995
  // packages/workit-core/src/worktree-deps.ts
84894
84996
  import fs31 from "node:fs";
84895
- import path60 from "node:path";
84997
+ import path63 from "node:path";
84896
84998
  function moduleDirs(main) {
84897
84999
  const out = [];
84898
85000
  const walk = (relative, depth) => {
84899
85001
  let entries;
84900
85002
  try {
84901
- entries = fs31.readdirSync(path60.join(main, relative), { withFileTypes: true });
85003
+ entries = fs31.readdirSync(path63.join(main, relative), { withFileTypes: true });
84902
85004
  } catch {
84903
85005
  return;
84904
85006
  }
84905
85007
  for (const entry of entries) {
84906
85008
  if (!entry.isDirectory())
84907
85009
  continue;
84908
- const child = path60.join(relative, entry.name);
85010
+ const child = path63.join(relative, entry.name);
84909
85011
  if (entry.name === MODULES)
84910
85012
  out.push(child);
84911
85013
  else if (depth < MAX_DEPTH2 && !entry.name.startsWith("."))
@@ -84919,8 +85021,8 @@ function linkEntry(main, worktree, source, target) {
84919
85021
  const stat = fs31.lstatSync(source);
84920
85022
  if (stat.isSymbolicLink()) {
84921
85023
  const link = fs31.readlinkSync(source);
84922
- const outside = path60.isAbsolute(link) && within(link, main) && !path60.relative(main, link).split(path60.sep).includes(MODULES);
84923
- const to = outside ? path60.join(worktree, path60.relative(main, link)) : link;
85024
+ const outside = path63.isAbsolute(link) && within(link, main) && !path63.relative(main, link).split(path63.sep).includes(MODULES);
85025
+ const to = outside ? path63.join(worktree, path63.relative(main, link)) : link;
84924
85026
  fs31.symlinkSync(to, target, process.platform === "win32" ? "junction" : undefined);
84925
85027
  return;
84926
85028
  }
@@ -84930,8 +85032,8 @@ function mirror(main, worktree, source, target, top) {
84930
85032
  fs31.mkdirSync(target);
84931
85033
  let count = 0;
84932
85034
  for (const entry of fs31.readdirSync(source, { withFileTypes: true })) {
84933
- const from = path60.join(source, entry.name);
84934
- const to = path60.join(target, entry.name);
85035
+ const from = path63.join(source, entry.name);
85036
+ const to = path63.join(target, entry.name);
84935
85037
  if (top && entry.isDirectory() && (entry.name.startsWith("@") || entry.name === ".bin"))
84936
85038
  count += mirror(main, worktree, from, to, false);
84937
85039
  else {
@@ -84947,16 +85049,16 @@ function linkWorktreeDependencies(main, worktree) {
84947
85049
  const dirs = [];
84948
85050
  let entries = 0;
84949
85051
  for (const relative of moduleDirs(main)) {
84950
- const target = path60.join(worktree, relative);
84951
- if (!fs31.existsSync(path60.dirname(target)) || fs31.existsSync(target))
85052
+ const target = path63.join(worktree, relative);
85053
+ if (!fs31.existsSync(path63.dirname(target)) || fs31.existsSync(target))
84952
85054
  continue;
84953
- if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(path60.sep).join("/")}/`]).ok) {
84954
- notes.push(`${relative.split(path60.sep).join("/")} is not ignored by git, so it was not linked from ${main}; install dependencies in the worktree yourself`);
85055
+ if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(path63.sep).join("/")}/`]).ok) {
85056
+ 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`);
84955
85057
  continue;
84956
85058
  }
84957
85059
  try {
84958
- entries += mirror(main, worktree, path60.join(main, relative), target, true);
84959
- dirs.push(relative.split(path60.sep).join("/"));
85060
+ entries += mirror(main, worktree, path63.join(main, relative), target, true);
85061
+ dirs.push(relative.split(path63.sep).join("/"));
84960
85062
  } catch (error) {
84961
85063
  fs31.rmSync(target, { recursive: true, force: true });
84962
85064
  notes.push(`could not link ${relative} from ${main} (${error.message}); install dependencies in the worktree yourself`);
@@ -84969,8 +85071,8 @@ function linkWorktreeDependencies(main, worktree) {
84969
85071
  return { linked: { from: main, dirs, entries, ms }, notes };
84970
85072
  }
84971
85073
  var MODULES = "node_modules", MAX_DEPTH2 = 2, within = (child, parent) => {
84972
- const relative = path60.relative(parent, child);
84973
- return relative === "" || !relative.startsWith("..") && !path60.isAbsolute(relative);
85074
+ const relative = path63.relative(parent, child);
85075
+ return relative === "" || !relative.startsWith("..") && !path63.isAbsolute(relative);
84974
85076
  };
84975
85077
  var init_worktree_deps = __esm(() => {
84976
85078
  init_fanout();
@@ -84979,7 +85081,7 @@ var init_worktree_deps = __esm(() => {
84979
85081
  // packages/workit-core/src/fanout-worktree.ts
84980
85082
  import { randomBytes as randomBytes5 } from "node:crypto";
84981
85083
  import fs32 from "node:fs";
84982
- import path61 from "node:path";
85084
+ import path64 from "node:path";
84983
85085
  function rowSample(lines) {
84984
85086
  const out = [];
84985
85087
  let bytes = 0;
@@ -85039,7 +85141,7 @@ function adminDir(worktree) {
85039
85141
  const file = dir.stdout.trim();
85040
85142
  let token = null;
85041
85143
  try {
85042
- token = fs32.readFileSync(path61.join(file, FANOUT_TOKEN_FILE), "utf8").trim() || null;
85144
+ token = fs32.readFileSync(path64.join(file, FANOUT_TOKEN_FILE), "utf8").trim() || null;
85043
85145
  } catch {
85044
85146
  token = null;
85045
85147
  }
@@ -85047,7 +85149,7 @@ function adminDir(worktree) {
85047
85149
  const stat = worktreeDeps.stat(file);
85048
85150
  return {
85049
85151
  path: file,
85050
- id: path61.basename(file),
85152
+ id: path64.basename(file),
85051
85153
  ino: stat.ino.toString(),
85052
85154
  token,
85053
85155
  birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
@@ -85063,7 +85165,7 @@ function markAdminDir(worktree) {
85063
85165
  return null;
85064
85166
  const token = randomBytes5(16).toString("hex");
85065
85167
  try {
85066
- fs32.writeFileSync(path61.join(admin.path, FANOUT_TOKEN_FILE), `${token}
85168
+ fs32.writeFileSync(path64.join(admin.path, FANOUT_TOKEN_FILE), `${token}
85067
85169
  `);
85068
85170
  } catch {
85069
85171
  return null;
@@ -85078,7 +85180,7 @@ function excludeScratch(cwd) {
85078
85180
  const common = gitCommonDir(cwd);
85079
85181
  if (!common)
85080
85182
  return;
85081
- const file = path61.join(common, "info", "exclude");
85183
+ const file = path64.join(common, "info", "exclude");
85082
85184
  let text = "";
85083
85185
  try {
85084
85186
  text = fs32.readFileSync(file, "utf8");
@@ -85087,7 +85189,7 @@ function excludeScratch(cwd) {
85087
85189
  }
85088
85190
  if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
85089
85191
  return;
85090
- fs32.mkdirSync(path61.dirname(file), { recursive: true });
85192
+ fs32.mkdirSync(path64.dirname(file), { recursive: true });
85091
85193
  fs32.appendFileSync(file, `${text && !text.endsWith(`
85092
85194
  `) ? `
85093
85195
  ` : ""}# workit fanout: per-worker scratch dirs
@@ -85096,13 +85198,13 @@ ${EXCLUDE_LINE}
85096
85198
  }
85097
85199
  function worktreeDependencies(main, worktree) {
85098
85200
  for (const [name, install] of LOCKFILES2) {
85099
- const ours = readBytes(path61.join(main, name));
85100
- const theirs = readBytes(path61.join(worktree, name));
85201
+ const ours = readBytes(path64.join(main, name));
85202
+ const theirs = readBytes(path64.join(worktree, name));
85101
85203
  if (ours === null && theirs === null)
85102
85204
  continue;
85103
85205
  if (ours !== null && theirs !== null && ours.equals(theirs))
85104
85206
  continue;
85105
- if (fs32.existsSync(path61.join(worktree, "node_modules")))
85207
+ if (fs32.existsSync(path64.join(worktree, "node_modules")))
85106
85208
  break;
85107
85209
  const command = install(worktree);
85108
85210
  return {
@@ -85116,7 +85218,7 @@ function worktreeDependencies(main, worktree) {
85116
85218
  return { ...linkWorktreeDependencies(main, worktree), install: null };
85117
85219
  }
85118
85220
  function ensureScratch(worktree) {
85119
- const scratch = path61.join(worktree, SCRATCH_DIR);
85221
+ const scratch = path64.join(worktree, SCRATCH_DIR);
85120
85222
  fs32.mkdirSync(scratch, { recursive: true });
85121
85223
  return scratch;
85122
85224
  }
@@ -85355,7 +85457,7 @@ function unpushedCount(cwd, branch) {
85355
85457
  return count.ok ? Number(count.stdout.trim()) : null;
85356
85458
  }
85357
85459
  function removeScratch(worktree) {
85358
- const scratch = path61.join(worktree, SCRATCH_DIR);
85460
+ const scratch = path64.join(worktree, SCRATCH_DIR);
85359
85461
  let stat;
85360
85462
  try {
85361
85463
  stat = fs32.lstatSync(scratch);
@@ -85371,16 +85473,16 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
85371
85473
  try {
85372
85474
  return fs32.realpathSync.native(target);
85373
85475
  } catch {
85374
- return path61.resolve(target);
85476
+ return path64.resolve(target);
85375
85477
  }
85376
85478
  }, samePath = (a, b) => {
85377
85479
  const left = canonical2(a);
85378
85480
  const right = canonical2(b);
85379
85481
  return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
85380
85482
  }, inside3 = (child, parent) => {
85381
- const relative = path61.relative(canonical2(parent), canonical2(child));
85382
- return relative === "" || !relative.startsWith("..") && !path61.isAbsolute(relative);
85383
- }, slicePath = (cwd, slice) => path61.isAbsolute(slice.worktree) ? slice.worktree : path61.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps, LOCKFILES2, readBytes = (file) => {
85483
+ const relative = path64.relative(canonical2(parent), canonical2(child));
85484
+ return relative === "" || !relative.startsWith("..") && !path64.isAbsolute(relative);
85485
+ }, slicePath = (cwd, slice) => path64.isAbsolute(slice.worktree) ? slice.worktree : path64.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps, LOCKFILES2, readBytes = (file) => {
85384
85486
  try {
85385
85487
  return fs32.readFileSync(file);
85386
85488
  } catch {
@@ -85411,7 +85513,7 @@ var init_fanout_worktree = __esm(() => {
85411
85513
 
85412
85514
  // packages/workit-core/src/forge/merge-cleanup.ts
85413
85515
  import fs33 from "node:fs";
85414
- import path62 from "node:path";
85516
+ import path65 from "node:path";
85415
85517
  function cleanupMergedBranch(cwd, branch, mergedHead) {
85416
85518
  const out = { branchDeleted: false, worktreeRemoved: null, notes: [] };
85417
85519
  if (!branch || branch.startsWith("-"))
@@ -85471,13 +85573,13 @@ var SLOW2, isFanoutWorktree = (worktree) => {
85471
85573
  if (!dir.ok)
85472
85574
  return false;
85473
85575
  try {
85474
- return fs33.readFileSync(path62.join(dir.stdout.trim(), FANOUT_TOKEN_FILE), "utf8").trim() !== "";
85576
+ return fs33.readFileSync(path65.join(dir.stdout.trim(), FANOUT_TOKEN_FILE), "utf8").trim() !== "";
85475
85577
  } catch {
85476
85578
  return false;
85477
85579
  }
85478
85580
  }, inside4 = (child, parent) => {
85479
- const relative = path62.relative(fs33.realpathSync.native(parent), fs33.realpathSync.native(child));
85480
- return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
85581
+ const relative = path65.relative(fs33.realpathSync.native(parent), fs33.realpathSync.native(child));
85582
+ return relative === "" || !relative.startsWith("..") && !path65.isAbsolute(relative);
85481
85583
  };
85482
85584
  var init_merge_cleanup = __esm(() => {
85483
85585
  init_fanout();
@@ -85758,7 +85860,7 @@ var init_duration = __esm(() => {
85758
85860
  });
85759
85861
 
85760
85862
  // packages/workit-cli/src/verbs/forge-common.ts
85761
- import { readFileSync as readFileSync24 } from "node:fs";
85863
+ import { readFileSync as readFileSync25 } from "node:fs";
85762
85864
  function parseFlags(argv, spec) {
85763
85865
  const parsed = { values: {}, booleans: new Set, lists: {}, positionals: [] };
85764
85866
  for (let index = 0;index < argv.length; index += 1) {
@@ -85913,7 +86015,7 @@ var init_forge_common = __esm(() => {
85913
86015
  forgeDeps = {
85914
86016
  runner: undefined,
85915
86017
  npm: undefined,
85916
- readStdin: () => readFileSync24(0, "utf8"),
86018
+ readStdin: () => readFileSync25(0, "utf8"),
85917
86019
  sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
85918
86020
  now: () => Date.now()
85919
86021
  };
@@ -85924,12 +86026,12 @@ var exports_pr = {};
85924
86026
  __export(exports_pr, {
85925
86027
  run: () => run15
85926
86028
  });
85927
- import { readFileSync as readFileSync25 } from "node:fs";
85928
- import path63 from "node:path";
86029
+ import { readFileSync as readFileSync26 } from "node:fs";
86030
+ import path66 from "node:path";
85929
86031
  function readBodyFile(io, file) {
85930
86032
  try {
85931
86033
  return {
85932
- body: file === "-" ? forgeDeps.readStdin() : readFileSync25(path63.resolve(io.cwd, file), "utf8")
86034
+ body: file === "-" ? forgeDeps.readStdin() : readFileSync26(path66.resolve(io.cwd, file), "utf8")
85933
86035
  };
85934
86036
  } catch {
85935
86037
  return `cannot read --body-file ${file}`;
@@ -86440,7 +86542,7 @@ var init_pr = __esm(() => {
86440
86542
  init_issue_link();
86441
86543
  init_pr_edit();
86442
86544
  init_pr_ops();
86443
- init_report();
86545
+ init_report2();
86444
86546
  init_rev();
86445
86547
  init_workspaces();
86446
86548
  init_merge_cleanup();
@@ -86694,7 +86796,7 @@ async function run16(argv, io) {
86694
86796
  }
86695
86797
  var WAIT_USAGE = "workit ci wait [--pr <n> | --branch <b>] [--head <sha>] [--timeout 20m] [--interval 30s] [--json]", RERUN_USAGE = "workit ci rerun [--pr <n> | --branch <b>] [--check <name>… | --failed] --reason flake|infra [--force] [--json]", LOGS_USAGE = "workit ci logs --failed [--pr <n> | --branch <b>] [--json]", LOG_LINES = 60, ONE_POLL_MS = 20000, MAX_POLL_ERRORS = 3, seconds = (ms) => `${Math.round(ms / 1000)}s`;
86696
86798
  var init_ci = __esm(() => {
86697
- init_report();
86799
+ init_report2();
86698
86800
  init_ledger();
86699
86801
  init_autonomy();
86700
86802
  init_output();
@@ -86733,8 +86835,8 @@ var exports_git = {};
86733
86835
  __export(exports_git, {
86734
86836
  run: () => run17
86735
86837
  });
86736
- import { readFileSync as readFileSync26 } from "node:fs";
86737
- import path64 from "node:path";
86838
+ import { readFileSync as readFileSync27 } from "node:fs";
86839
+ import path67 from "node:path";
86738
86840
  function kindHint(cwd, kind) {
86739
86841
  let kinds = [...BRANCH_KINDS];
86740
86842
  try {
@@ -86838,7 +86940,7 @@ function commitMessage(parsed, io) {
86838
86940
 
86839
86941
  `);
86840
86942
  try {
86841
- return file === "-" ? readFileSync26(0, "utf8") : readFileSync26(path64.resolve(io.cwd, file), "utf8");
86943
+ return file === "-" ? readFileSync27(0, "utf8") : readFileSync27(path67.resolve(io.cwd, file), "utf8");
86842
86944
  } catch (error) {
86843
86945
  return {
86844
86946
  error: `cannot read -F ${file}: ${error instanceof Error ? error.message : String(error)}`
@@ -87252,7 +87354,7 @@ var init_verify = __esm(() => {
87252
87354
  init_exec();
87253
87355
  init_rev();
87254
87356
  init_ledger();
87255
- init_report();
87357
+ init_report2();
87256
87358
  init_redact();
87257
87359
  NPM_NAME = /^(?:@[A-Za-z0-9~][A-Za-z0-9-._~]*\/)?[A-Za-z0-9~][A-Za-z0-9-._~]*$/u;
87258
87360
  SEMVER2 = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u;
@@ -88271,15 +88373,15 @@ var init_stack2 = __esm(() => {
88271
88373
  });
88272
88374
 
88273
88375
  // packages/workit-core/src/fanout-brief.ts
88274
- import { createHash as createHash19 } from "node:crypto";
88376
+ import { createHash as createHash20 } from "node:crypto";
88275
88377
  import fs35 from "node:fs";
88276
- import path65 from "node:path";
88378
+ import path68 from "node:path";
88277
88379
  function workerSession(lead, slice, attempt) {
88278
88380
  const tail = attempt === null ? "" : `+try${attempt}`;
88279
88381
  const full = `${lead}-w-${slice}${tail}`;
88280
88382
  if (full.length <= SESSION_MAX)
88281
88383
  return full;
88282
- const digest = createHash19("sha256").update(slice).digest("hex").slice(0, 12);
88384
+ const digest = createHash20("sha256").update(slice).digest("hex").slice(0, 12);
88283
88385
  return `${lead.slice(0, SESSION_MAX - 3 - digest.length - tail.length)}-w-${digest}${tail}`;
88284
88386
  }
88285
88387
  function renderBrief(cwd, plan, input) {
@@ -88355,7 +88457,7 @@ function renderBrief(cwd, plan, input) {
88355
88457
  "STANDING:",
88356
88458
  ...standing.length ? standing.map((order) => ` - ${order.what}`) : [" - none recorded beyond this brief"],
88357
88459
  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)`,
88358
- ...exists && typeof made?.install === "string" && !fs35.existsSync(path65.join(planned, "node_modules")) ? [`INSTALL: \`${made.install}\` first: the main checkout's node_modules was not linked here`] : [],
88460
+ ...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`] : [],
88359
88461
  ...identityLines(identity, minted),
88360
88462
  ...rules(mode, branch, slice.base, exists ? planned : null)
88361
88463
  ];
@@ -89085,7 +89187,7 @@ var DEFAULT_STUCK_MS, isoOf = (seconds) => {
89085
89187
  }, newest = (...values) => values.filter((value) => Boolean(value) && !Number.isNaN(Date.parse(value ?? ""))).reduce((best, value) => best === null || Date.parse(value) > Date.parse(best) ? value : best, null);
89086
89188
  var init_fanout_status = __esm(() => {
89087
89189
  init_duration();
89088
- init_report();
89190
+ init_report2();
89089
89191
  init_role_models();
89090
89192
  init_ledger();
89091
89193
  init_fanout_check();
@@ -89100,7 +89202,7 @@ __export(exports_fanout, {
89100
89202
  run: () => run21
89101
89203
  });
89102
89204
  import fs36 from "node:fs";
89103
- import path66 from "node:path";
89205
+ import path69 from "node:path";
89104
89206
  function forgeFor(io, offline) {
89105
89207
  if (offline)
89106
89208
  return { forge: null, error: "--offline" };
@@ -89161,7 +89263,7 @@ function plan2(argv, io) {
89161
89263
  return usage4(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
89162
89264
  if (flags.positionals.length !== 1)
89163
89265
  return usage4(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
89164
- const file = path66.resolve(io.cwd, flags.positionals[0]);
89266
+ const file = path69.resolve(io.cwd, flags.positionals[0]);
89165
89267
  let raw;
89166
89268
  try {
89167
89269
  raw = JSON.parse(fs36.readFileSync(file, "utf8"));
@@ -104704,7 +104806,7 @@ var init_ast = __esm(() => {
104704
104806
 
104705
104807
  // packages/workit-cli/src/test-audit/rules.ts
104706
104808
  import { builtinModules } from "node:module";
104707
- import path67 from "node:path";
104809
+ import path70 from "node:path";
104708
104810
  function testCallee(call) {
104709
104811
  let callee = call.callee;
104710
104812
  if (callee.type === "CallExpression")
@@ -105197,12 +105299,12 @@ function checkConstantsOnly(ctx, emit) {
105197
105299
  }
105198
105300
  function checkOverMocking(ctx, emit) {
105199
105301
  const { program } = ctx.parsed;
105200
- const unit = path67.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
105302
+ const unit = path70.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
105201
105303
  const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
105202
105304
  const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
105203
105305
  for (const call of mocked) {
105204
105306
  const spec = call.arguments[0].value;
105205
- const base = path67.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
105307
+ const base = path70.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
105206
105308
  if (base === unit)
105207
105309
  emit({
105208
105310
  rule: "over-mocking",
@@ -105591,8 +105693,8 @@ var init_rules = __esm(() => {
105591
105693
 
105592
105694
  // packages/workit-cli/src/test-audit/audit.ts
105593
105695
  import { spawnSync as spawnSync29 } from "node:child_process";
105594
- import { existsSync as existsSync24, readdirSync as readdirSync14, readFileSync as readFileSync27, statSync as statSync10 } from "node:fs";
105595
- import path68 from "node:path";
105696
+ import { existsSync as existsSync26, readdirSync as readdirSync14, readFileSync as readFileSync28, statSync as statSync10 } from "node:fs";
105697
+ import path71 from "node:path";
105596
105698
  function git7(cwd, args) {
105597
105699
  const run = spawnSync29("git", ["-c", "core.quotepath=off", ...args], {
105598
105700
  cwd,
@@ -105605,7 +105707,7 @@ function walkTests(dir, out) {
105605
105707
  for (const entry of readdirSync14(dir, { withFileTypes: true })) {
105606
105708
  if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
105607
105709
  continue;
105608
- const full = path68.join(dir, entry.name);
105710
+ const full = path71.join(dir, entry.name);
105609
105711
  if (entry.isDirectory()) {
105610
105712
  if (!SKIP_DIRS.has(entry.name))
105611
105713
  walkTests(full, out);
@@ -105617,8 +105719,8 @@ function expandPaths(cwd, inputs) {
105617
105719
  const files = [];
105618
105720
  const missing = [];
105619
105721
  for (const input of inputs.length > 0 ? inputs : ["."]) {
105620
- const full = path68.resolve(cwd, input);
105621
- if (!existsSync24(full))
105722
+ const full = path71.resolve(cwd, input);
105723
+ if (!existsSync26(full))
105622
105724
  missing.push(input);
105623
105725
  else if (statSync10(full).isDirectory())
105624
105726
  walkTests(full, files);
@@ -105654,11 +105756,11 @@ function changedLines(cwd, base) {
105654
105756
  for (let offset = 0;offset < count; offset += 1)
105655
105757
  lines.add(start + offset);
105656
105758
  }
105657
- changed.set(path68.join(root, file), lines);
105759
+ changed.set(path71.join(root, file), lines);
105658
105760
  }
105659
105761
  const untracked = git7(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
105660
105762
  for (const file of untracked.stdout.split("\x00").filter(Boolean))
105661
- changed.set(path68.join(root, file), "all");
105763
+ changed.set(path71.join(root, file), "all");
105662
105764
  return changed;
105663
105765
  }
105664
105766
  function auditFiles(files, display) {
@@ -105671,7 +105773,7 @@ function auditFiles(files, display) {
105671
105773
  const shown = display(file);
105672
105774
  let parsed;
105673
105775
  try {
105674
- parsed = parseSource(readFileSync27(file, "utf8"), file);
105776
+ parsed = parseSource(readFileSync28(file, "utf8"), file);
105675
105777
  } catch (error) {
105676
105778
  parseErrors.push({
105677
105779
  file: shown,
@@ -105720,7 +105822,7 @@ function auditFiles(files, display) {
105720
105822
  durationMs: Math.round(performance.now() - started)
105721
105823
  };
105722
105824
  }
105723
- var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path68.sep).join("/"), SEVERITY_ORDER, ruleIds;
105825
+ var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path71.sep).join("/"), SEVERITY_ORDER, ruleIds;
105724
105826
  var init_audit = __esm(() => {
105725
105827
  init_ast();
105726
105828
  init_rules();
@@ -105734,12 +105836,12 @@ var init_audit = __esm(() => {
105734
105836
  // packages/workit-cli/src/test-audit/mutate.ts
105735
105837
  import { spawn as spawn2 } from "node:child_process";
105736
105838
  import {
105737
- existsSync as existsSync25,
105839
+ existsSync as existsSync27,
105738
105840
  lstatSync as lstatSync8,
105739
105841
  mkdirSync as mkdirSync12,
105740
105842
  mkdtempSync as mkdtempSync4,
105741
105843
  readdirSync as readdirSync15,
105742
- readFileSync as readFileSync28,
105844
+ readFileSync as readFileSync29,
105743
105845
  readlinkSync as readlinkSync3,
105744
105846
  realpathSync as realpathSync10,
105745
105847
  renameSync as renameSync7,
@@ -105749,8 +105851,8 @@ import {
105749
105851
  writeFileSync as writeFileSync12,
105750
105852
  copyFileSync as copyFileSync8
105751
105853
  } from "node:fs";
105752
- import os22 from "node:os";
105753
- import path69 from "node:path";
105854
+ import os23 from "node:os";
105855
+ import path72 from "node:path";
105754
105856
  function mutantsFor(source, file, lines) {
105755
105857
  const parsed = parseSource(source, file);
105756
105858
  const out = [];
@@ -105823,7 +105925,7 @@ function relatedTests(source, testFiles) {
105823
105925
  for (const match of text.matchAll(SPECIFIER)) {
105824
105926
  const spec = match[1];
105825
105927
  if (spec.startsWith(".")) {
105826
- if (stripExt(path69.posix.join(path69.posix.dirname(file), spec)) === target)
105928
+ if (stripExt(path72.posix.join(path72.posix.dirname(file), spec)) === target)
105827
105929
  return true;
105828
105930
  } else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
105829
105931
  return true;
@@ -105831,7 +105933,7 @@ function relatedTests(source, testFiles) {
105831
105933
  return false;
105832
105934
  }).map((entry) => entry.file);
105833
105935
  }
105834
- function removeStaleCopies(tmp = os22.tmpdir()) {
105936
+ function removeStaleCopies(tmp = os23.tmpdir()) {
105835
105937
  let removed = 0;
105836
105938
  let names = [];
105837
105939
  try {
@@ -105843,12 +105945,12 @@ function removeStaleCopies(tmp = os22.tmpdir()) {
105843
105945
  for (const name of names) {
105844
105946
  if (!name.startsWith(TEMP_PREFIX))
105845
105947
  continue;
105846
- const dir = path69.join(tmp, name);
105948
+ const dir = path72.join(tmp, name);
105847
105949
  try {
105848
105950
  const stat = lstatSync8(dir);
105849
105951
  if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
105850
105952
  continue;
105851
- const pid = Number(readFileSync28(path69.join(dir, PID_FILE), "utf8"));
105953
+ const pid = Number(readFileSync29(path72.join(dir, PID_FILE), "utf8"));
105852
105954
  if (Number.isInteger(pid) && pid > 0 && alive(pid))
105853
105955
  continue;
105854
105956
  } catch (error) {
@@ -105865,8 +105967,8 @@ function removeStaleCopies(tmp = os22.tmpdir()) {
105865
105967
  function linkNodeModules(origin, target, repo, copy) {
105866
105968
  mkdirSync12(target, { recursive: true });
105867
105969
  for (const entry of readdirSync15(origin, { withFileTypes: true })) {
105868
- const from = path69.join(origin, entry.name);
105869
- const to = path69.join(target, entry.name);
105970
+ const from = path72.join(origin, entry.name);
105971
+ const to = path72.join(target, entry.name);
105870
105972
  if (entry.name.startsWith("@") && entry.isDirectory()) {
105871
105973
  linkNodeModules(from, to, repo, copy);
105872
105974
  continue;
@@ -105882,9 +105984,9 @@ function linkNodeModules(origin, target, repo, copy) {
105882
105984
  } catch {
105883
105985
  continue;
105884
105986
  }
105885
- const relative = path69.relative(repo, real);
105886
- if (!relative.startsWith("..") && !path69.isAbsolute(relative) && !relative.split(path69.sep).includes("node_modules")) {
105887
- symlinkSync(path69.join(copy, relative), to, "junction");
105987
+ const relative = path72.relative(repo, real);
105988
+ if (!relative.startsWith("..") && !path72.isAbsolute(relative) && !relative.split(path72.sep).includes("node_modules")) {
105989
+ symlinkSync(path72.join(copy, relative), to, "junction");
105888
105990
  continue;
105889
105991
  }
105890
105992
  }
@@ -105900,7 +106002,7 @@ function copySymlink(repo, tree, from, to) {
105900
106002
  }
105901
106003
  const realRepo = realpathSync10(repo);
105902
106004
  if (real && inside5(realRepo, real)) {
105903
- symlinkSync(path69.relative(path69.dirname(to), path69.join(tree, path69.relative(realRepo, real))), to);
106005
+ symlinkSync(path72.relative(path72.dirname(to), path72.join(tree, path72.relative(realRepo, real))), to);
105904
106006
  return;
105905
106007
  }
105906
106008
  if (real && statSync11(real).isFile())
@@ -105909,10 +106011,10 @@ function copySymlink(repo, tree, from, to) {
105909
106011
  symlinkSync(readlinkSync3(from), to);
105910
106012
  }
105911
106013
  function writeInside(copy, file, content) {
105912
- const target = path69.join(copy, file);
106014
+ const target = path72.join(copy, file);
105913
106015
  try {
105914
106016
  const stat = lstatSync8(target);
105915
- if (!stat.isFile() || !inside5(realpathSync10(copy), realpathSync10(path69.dirname(target))))
106017
+ if (!stat.isFile() || !inside5(realpathSync10(copy), realpathSync10(path72.dirname(target))))
105916
106018
  return false;
105917
106019
  } catch {
105918
106020
  return false;
@@ -105923,9 +106025,9 @@ function writeInside(copy, file, content) {
105923
106025
  return true;
105924
106026
  }
105925
106027
  function copyWorkingTree(repo) {
105926
- const dir = mkdtempSync4(path69.join(os22.tmpdir(), TEMP_PREFIX));
105927
- writeFileSync12(path69.join(dir, PID_FILE), String(process.pid));
105928
- const tree = path69.join(dir, "tree");
106028
+ const dir = mkdtempSync4(path72.join(os23.tmpdir(), TEMP_PREFIX));
106029
+ writeFileSync12(path72.join(dir, PID_FILE), String(process.pid));
106030
+ const tree = path72.join(dir, "tree");
105929
106031
  const head = git7(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
105930
106032
  if (head && git7(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
105931
106033
  const branch = git7(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
@@ -105942,29 +106044,29 @@ function copyWorkingTree(repo) {
105942
106044
  for (const relative of listed) {
105943
106045
  if (!relative)
105944
106046
  continue;
105945
- const from = path69.join(repo, relative);
106047
+ const from = path72.join(repo, relative);
105946
106048
  let stat;
105947
106049
  try {
105948
106050
  stat = lstatSync8(from);
105949
106051
  } catch {
105950
106052
  continue;
105951
106053
  }
105952
- const to = path69.join(tree, relative);
105953
- mkdirSync12(path69.dirname(to), { recursive: true });
106054
+ const to = path72.join(tree, relative);
106055
+ mkdirSync12(path72.dirname(to), { recursive: true });
105954
106056
  if (stat.isSymbolicLink())
105955
106057
  copySymlink(repo, tree, from, to);
105956
106058
  else if (stat.isFile())
105957
106059
  copyFileSync8(from, to);
105958
- let parent = path69.dirname(relative);
106060
+ let parent = path72.dirname(relative);
105959
106061
  while (parent !== "." && !dirs.has(parent)) {
105960
106062
  dirs.add(parent);
105961
- parent = path69.dirname(parent);
106063
+ parent = path72.dirname(parent);
105962
106064
  }
105963
106065
  }
105964
106066
  for (const parent of dirs) {
105965
- const modules = path69.join(repo, parent, "node_modules");
105966
- if (existsSync25(modules) && !existsSync25(path69.join(tree, parent, "node_modules")))
105967
- linkNodeModules(modules, path69.join(tree, parent, "node_modules"), repo, tree);
106067
+ const modules = path72.join(repo, parent, "node_modules");
106068
+ if (existsSync27(modules) && !existsSync27(path72.join(tree, parent, "node_modules")))
106069
+ linkNodeModules(modules, path72.join(tree, parent, "node_modules"), repo, tree);
105968
106070
  }
105969
106071
  return { dir, tree };
105970
106072
  }
@@ -106003,20 +106105,20 @@ async function runMutation(options) {
106003
106105
  const tracked = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
106004
106106
  const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
106005
106107
  try {
106006
- return { file, text: readFileSync28(path69.join(repo, file), "utf8") };
106108
+ return { file, text: readFileSync29(path72.join(repo, file), "utf8") };
106007
106109
  } catch {
106008
106110
  return { file, text: "" };
106009
106111
  }
106010
106112
  });
106011
106113
  const candidates = [];
106012
106114
  for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
106013
- const relative = toPosix(path69.relative(repo, absolute));
106115
+ const relative = toPosix(path72.relative(repo, absolute));
106014
106116
  if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
106015
106117
  continue;
106016
- if (NOT_SOURCE.test(relative) || !existsSync25(absolute))
106118
+ if (NOT_SOURCE.test(relative) || !existsSync27(absolute))
106017
106119
  continue;
106018
106120
  try {
106019
- candidates.push(...mutantsFor(readFileSync28(absolute, "utf8"), relative, lines));
106121
+ candidates.push(...mutantsFor(readFileSync29(absolute, "utf8"), relative, lines));
106020
106122
  } catch {}
106021
106123
  }
106022
106124
  const mutants = candidates.map((mutant, index) => ({ ...mutant, id: index + 1 }));
@@ -106024,9 +106126,9 @@ async function runMutation(options) {
106024
106126
  for (const mutant of mutants)
106025
106127
  if (!related.has(mutant.file))
106026
106128
  related.set(mutant.file, relatedTests(mutant.file, testFiles));
106027
- const cwdRelative = path69.relative(repo, options.cwd);
106129
+ const cwdRelative = path72.relative(repo, options.cwd);
106028
106130
  const asArg = (file) => {
106029
- const relative = toPosix(path69.relative(cwdRelative, file));
106131
+ const relative = toPosix(path72.relative(cwdRelative, file));
106030
106132
  return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
106031
106133
  };
106032
106134
  const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
@@ -106062,7 +106164,7 @@ async function runMutation(options) {
106062
106164
  return finish3(options, 0, results, counts, started);
106063
106165
  removeStaleCopies();
106064
106166
  const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
106065
- const copyCwd = path69.join(copy, cwdRelative);
106167
+ const copyCwd = path72.join(copy, cwdRelative);
106066
106168
  let current = null;
106067
106169
  const restore = () => {
106068
106170
  if (current)
@@ -106097,7 +106199,7 @@ async function runMutation(options) {
106097
106199
  record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
106098
106200
  continue;
106099
106201
  }
106100
- const original = readFileSync28(path69.join(copy, mutant.file), "utf8");
106202
+ const original = readFileSync29(path72.join(copy, mutant.file), "utf8");
106101
106203
  const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
106102
106204
  current = { file: mutant.file, original };
106103
106205
  if (!writeInside(copy, mutant.file, mutated)) {
@@ -106154,8 +106256,8 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
106154
106256
  return error.code === "EPERM";
106155
106257
  }
106156
106258
  }, inside5 = (root, file) => {
106157
- const relative = path69.relative(root, file);
106158
- return relative === "" || !relative.startsWith("..") && !path69.isAbsolute(relative);
106259
+ const relative = path72.relative(root, file);
106260
+ return relative === "" || !relative.startsWith("..") && !path72.isAbsolute(relative);
106159
106261
  }, active, killTree = (child) => {
106160
106262
  try {
106161
106263
  if (child.pid && process.platform !== "win32")
@@ -106203,8 +106305,8 @@ var exports_test_audit = {};
106203
106305
  __export(exports_test_audit, {
106204
106306
  run: () => run23
106205
106307
  });
106206
- import { existsSync as existsSync26 } from "node:fs";
106207
- import path70 from "node:path";
106308
+ import { existsSync as existsSync28 } from "node:fs";
106309
+ import path73 from "node:path";
106208
106310
  function parse8(argv) {
106209
106311
  const options = {
106210
106312
  paths: [],
@@ -106309,8 +106411,8 @@ async function run23(argv, io) {
106309
106411
  return emit(io, fail2("invalid_input", `${options}
106310
106412
  usage: ${USAGE16}`));
106311
106413
  const top = git7(io.cwd, ["rev-parse", "--show-toplevel"]);
106312
- const repo = top.ok ? path70.resolve(top.stdout.trim()) : null;
106313
- const display = (file) => toPosix(path70.relative(io.cwd, file) || file);
106414
+ const repo = top.ok ? path73.resolve(top.stdout.trim()) : null;
106415
+ const display = (file) => toPosix(path73.relative(io.cwd, file) || file);
106314
106416
  let base = null;
106315
106417
  let changed = null;
106316
106418
  if (options.diff || options.mutate) {
@@ -106327,7 +106429,7 @@ usage: ${USAGE16}`));
106327
106429
  }
106328
106430
  let files;
106329
106431
  if (options.diff && changed)
106330
- files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) && existsSync26(file)).toSorted();
106432
+ files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) && existsSync28(file)).toSorted();
106331
106433
  else {
106332
106434
  const expanded = expandPaths(io.cwd, options.paths);
106333
106435
  if (expanded.missing.length > 0)
@@ -106448,8 +106550,8 @@ var exports_youtrack = {};
106448
106550
  __export(exports_youtrack, {
106449
106551
  run: () => run25
106450
106552
  });
106451
- import { readFileSync as readFileSync29 } from "node:fs";
106452
- import path71 from "node:path";
106553
+ import { readFileSync as readFileSync30 } from "node:fs";
106554
+ import path74 from "node:path";
106453
106555
  async function run25(argv, io) {
106454
106556
  const [sub, ...rest] = argv;
106455
106557
  if (sub !== "note" && sub !== "time" && sub !== "meeting")
@@ -106495,7 +106597,7 @@ async function run25(argv, io) {
106495
106597
  let markdown = flags.values.markdown ?? "";
106496
106598
  if (flags.values.file)
106497
106599
  try {
106498
- markdown = readFileSync29(path71.resolve(io.cwd, flags.values.file), "utf8");
106600
+ markdown = readFileSync30(path74.resolve(io.cwd, flags.values.file), "utf8");
106499
106601
  } catch (error) {
106500
106602
  return usage4(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE18);
106501
106603
  }
@@ -106563,8 +106665,8 @@ var exports_changelog = {};
106563
106665
  __export(exports_changelog, {
106564
106666
  run: () => run26
106565
106667
  });
106566
- import { readFileSync as readFileSync30 } from "node:fs";
106567
- import path72 from "node:path";
106668
+ import { readFileSync as readFileSync31 } from "node:fs";
106669
+ import path75 from "node:path";
106568
106670
  async function run26(argv, io) {
106569
106671
  const [sub, ...rest] = argv;
106570
106672
  if (sub !== "apply")
@@ -106610,7 +106712,7 @@ async function run26(argv, io) {
106610
106712
  ]);
106611
106713
  }
106612
106714
  var USAGE19 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
106613
- const text = raw === "-" ? readFileSync30(0, "utf8") : raw.startsWith("@") ? readFileSync30(path72.resolve(cwd, raw.slice(1)), "utf8") : raw;
106715
+ const text = raw === "-" ? readFileSync31(0, "utf8") : raw.startsWith("@") ? readFileSync31(path75.resolve(cwd, raw.slice(1)), "utf8") : raw;
106614
106716
  return JSON.parse(text);
106615
106717
  };
106616
106718
  var init_changelog2 = __esm(() => {
@@ -106626,7 +106728,7 @@ __export(exports_handoff, {
106626
106728
  run: () => run27
106627
106729
  });
106628
106730
  import fs37 from "node:fs";
106629
- import path73 from "node:path";
106731
+ import path76 from "node:path";
106630
106732
  import { parseArgs as parseArgs2 } from "node:util";
106631
106733
  function render3(brief) {
106632
106734
  const lines = [
@@ -106666,9 +106768,9 @@ function bounded(brief, cwd) {
106666
106768
  let file = null;
106667
106769
  if (store.ok)
106668
106770
  try {
106669
- const dir = path73.join(store.value.root, "handoff");
106771
+ const dir = path76.join(store.value.root, "handoff");
106670
106772
  fs37.mkdirSync(dir, { recursive: true });
106671
- file = path73.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
106773
+ file = path76.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
106672
106774
  fs37.writeFileSync(file, `${[...body, ...tail].join(`
106673
106775
  `)}
106674
106776
  `, {
@@ -106745,7 +106847,7 @@ var init_handoff = __esm(() => {
106745
106847
  // packages/workit-cli/src/main.ts
106746
106848
  init_host_session();
106747
106849
  init_package();
106748
- import path74 from "node:path";
106850
+ import path77 from "node:path";
106749
106851
 
106750
106852
  // packages/workit-cli/src/verbs/registry.ts
106751
106853
  var TASK_FAMILY_NAMES = [
@@ -107657,7 +107759,7 @@ var defaultIo = (json) => ({
107657
107759
  });
107658
107760
  async function main(argv, overrides = {}, options = {}) {
107659
107761
  const parsed = parseGlobals(argv);
107660
- const cwd = path74.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
107762
+ const cwd = path77.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
107661
107763
  const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
107662
107764
  if (parsed.error)
107663
107765
  return emit(io, fail2("invalid_input", parsed.error));