@brainervirus/workit-claude-code 8.38.2 → 8.38.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/workit.js CHANGED
@@ -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.4",
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.4",
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.4"
9365
9365
  },
9366
9366
  engines: {
9367
9367
  node: ">=24"
@@ -16832,6 +16832,79 @@ var init_workers = __esm(() => {
16832
16832
  UNCERTAIN_WORKER_STATES = ["dispatching", "running", "cancelling", "unknown"];
16833
16833
  });
16834
16834
 
16835
+ // packages/workit-core/src/core/task-delivery.ts
16836
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
16837
+ function closeDeliveredTasks(store, now, options = {}) {
16838
+ let closedCount = 0;
16839
+ const index = store.listStoreIndex();
16840
+ if (!index.ok)
16841
+ return 0;
16842
+ const open = index.data.filter((entry) => entry.status !== "closed" && entry.branch !== null);
16843
+ if (open.length === 0)
16844
+ return 0;
16845
+ const file = options.cached ? ledgerPath(store.root) : null;
16846
+ const signature = file?.ok ? `${fileSignature(file.value) ?? "-"}|${open.map((entry) => entry.id).join(",")}` : null;
16847
+ const marker = file?.ok ? `${file.value}.delivery-sweep` : null;
16848
+ if (signature && marker) {
16849
+ try {
16850
+ if (readFileSync6(marker, "utf8") === signature)
16851
+ return 0;
16852
+ } catch {}
16853
+ }
16854
+ const ledger = readLedger(store.root);
16855
+ if (!ledger.ok)
16856
+ return 0;
16857
+ const rows = ledger.value.rows;
16858
+ const after = (row, since) => Date.parse(row.at) >= Date.parse(since);
16859
+ for (const entry of open) {
16860
+ const merged = rows.findLast((row) => row.type === "pr.merged" && row.branch === entry.branch && typeof row.pr === "number" && after(row, entry.createdAt));
16861
+ if (!merged)
16862
+ continue;
16863
+ const pr = merged.pr;
16864
+ const verified = rows.findLast((row) => row.type === "delivery.verified" && row.expect === "merged" && row.branch === entry.branch && (row.pr === undefined || row.pr === pr));
16865
+ if (!verified) {
16866
+ const next = `PR #${pr} is merged but delivery is not verified: run \`workit verify-delivery merged\``;
16867
+ if (entry.progress.nextAction !== next) {
16868
+ store.mutateTask(entry.id, entry.revision, (task, context) => success(context.revision, null, {
16869
+ ...task,
16870
+ progress: { ...task.progress, nextAction: next }
16871
+ }));
16872
+ }
16873
+ continue;
16874
+ }
16875
+ const task = store.readTask(entry.id);
16876
+ if (!task.ok || task.data.status === "closed")
16877
+ continue;
16878
+ if (task.data.workers.some((worker) => workerBlocksTransition("close", worker.data.state)))
16879
+ continue;
16880
+ const closed = store.mutateTask(entry.id, task.data.revision, (value, context) => success(context.revision, null, {
16881
+ ...value,
16882
+ status: "closed",
16883
+ closure: {
16884
+ outcome: "verified",
16885
+ at: context.now,
16886
+ summary: `delivered: PR #${pr} merged (pr.merged ${String(merged.id)}) and delivery verified (delivery.verified ${String(verified.id)})`,
16887
+ decisionIds: [],
16888
+ evidenceIds: []
16889
+ }
16890
+ }), now);
16891
+ if (closed.ok)
16892
+ closedCount++;
16893
+ }
16894
+ if (signature && marker && closedCount === 0 && !racySignature(signature.split("|")[0] ?? "")) {
16895
+ try {
16896
+ writeFileSync4(marker, signature);
16897
+ } catch {}
16898
+ }
16899
+ return closedCount;
16900
+ }
16901
+ var init_task_delivery = __esm(() => {
16902
+ init_ledger();
16903
+ init_task_store();
16904
+ init_task_contract();
16905
+ init_workers();
16906
+ });
16907
+
16835
16908
  // packages/workit-core/src/core/task-evaluation.ts
16836
16909
  import { createHash as createHash11 } from "node:crypto";
16837
16910
  import * as fs14 from "node:fs";
@@ -18804,10 +18877,10 @@ var init_route_intent = __esm(() => {
18804
18877
 
18805
18878
  // packages/workit-core/src/core/runtime-identity.ts
18806
18879
  import { createHash as createHash12 } from "node:crypto";
18807
- import { readFileSync as readFileSync7 } from "node:fs";
18880
+ import { readFileSync as readFileSync8 } from "node:fs";
18808
18881
  var sha256Hex = (bytes) => createHash12("sha256").update(bytes).digest("hex"), bundleHashOfFile = (file) => {
18809
18882
  try {
18810
- return sha256Hex(readFileSync7(file));
18883
+ return sha256Hex(readFileSync8(file));
18811
18884
  } catch {
18812
18885
  return null;
18813
18886
  }
@@ -21199,7 +21272,7 @@ var init_core3 = __esm(() => {
21199
21272
  });
21200
21273
 
21201
21274
  // packages/workit-cli/src/task.ts
21202
- import { readFileSync as readFileSync8 } from "node:fs";
21275
+ import { readFileSync as readFileSync9 } from "node:fs";
21203
21276
  import path27 from "node:path";
21204
21277
  async function readInput(input) {
21205
21278
  if (typeof input === "string")
@@ -21216,7 +21289,7 @@ async function payloadValue(raw, deps) {
21216
21289
  return { ok: true, value: {} };
21217
21290
  let source;
21218
21291
  try {
21219
- source = raw === "-" ? await readInput(deps.stdin ?? process.stdin) : raw.startsWith("@") ? decodeUtf8(readFileSync8(raw.slice(1))) : raw;
21292
+ source = raw === "-" ? await readInput(deps.stdin ?? process.stdin) : raw.startsWith("@") ? decodeUtf8(readFileSync9(raw.slice(1))) : raw;
21220
21293
  } catch (error) {
21221
21294
  return {
21222
21295
  ok: false,
@@ -21504,7 +21577,12 @@ async function runTaskCommand(argv, deps = {}) {
21504
21577
  return parsed.usage ? 2 : 1;
21505
21578
  }
21506
21579
  const root = workspaceRootFor(deps);
21507
- const core = new WorkitCore(new TaskStore(root), contextFor(root, parsed.parsed.actor !== undefined ? { ...deps, actor: parsed.parsed.actor } : deps));
21580
+ const store = new TaskStore(root);
21581
+ try {
21582
+ const now = new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
21583
+ closeDeliveredTasks(store, now, { cached: parsed.parsed.action !== "list" });
21584
+ } catch {}
21585
+ const core = new WorkitCore(store, contextFor(root, parsed.parsed.actor !== undefined ? { ...deps, actor: parsed.parsed.actor } : deps));
21508
21586
  let result;
21509
21587
  if (parsed.parsed.handoff) {
21510
21588
  const exported = dispatch(core, "state", parsed.parsed.request);
@@ -21600,6 +21678,7 @@ var init_task = __esm(() => {
21600
21678
  init_current_judgment();
21601
21679
  init_judgment();
21602
21680
  init_lane();
21681
+ init_task_delivery();
21603
21682
  init_task_store();
21604
21683
  init_core3();
21605
21684
  init_task_contract();
@@ -65285,13 +65364,13 @@ var init_changelog = __esm(() => {
65285
65364
 
65286
65365
  // packages/workit-core/src/core/hygiene.ts
65287
65366
  import { spawnSync as spawnSync12 } from "node:child_process";
65288
- import { existsSync as existsSync10, readFileSync as readFileSync10, readdirSync as readdirSync5, writeFileSync as writeFileSync4 } from "node:fs";
65367
+ import { existsSync as existsSync10, readFileSync as readFileSync11, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
65289
65368
  import path29 from "node:path";
65290
65369
  var repoRoot2, templatesDir = () => path29.join(repoRoot2, "templates", "hygiene"), packageJson = (root) => {
65291
65370
  if (!existsSync10(path29.join(root, "package.json")))
65292
65371
  return null;
65293
65372
  try {
65294
- return JSON.parse(readFileSync10(path29.join(root, "package.json"), "utf8"));
65373
+ return JSON.parse(readFileSync11(path29.join(root, "package.json"), "utf8"));
65295
65374
  } catch {
65296
65375
  return null;
65297
65376
  }
@@ -65344,7 +65423,7 @@ var repoRoot2, templatesDir = () => path29.join(repoRoot2, "templates", "hygiene
65344
65423
  const tpl = path29.join(templatesDir(), file);
65345
65424
  if (!existsSync10(tpl))
65346
65425
  continue;
65347
- const content = readFileSync10(tpl, "utf8").replace(/<PROJECT>/g, path29.basename(root)).replace(/<YEAR>/g, String(new Date().getFullYear())).replace(/<HOLDER>\s*/g, licenseHolder(root));
65426
+ const content = readFileSync11(tpl, "utf8").replace(/<PROJECT>/g, path29.basename(root)).replace(/<YEAR>/g, String(new Date().getFullYear())).replace(/<HOLDER>\s*/g, licenseHolder(root));
65348
65427
  planned.push({ path: path29.join(root, file), content });
65349
65428
  }
65350
65429
  return planned;
@@ -65356,13 +65435,13 @@ var init_hygiene = __esm(() => {
65356
65435
  });
65357
65436
 
65358
65437
  // packages/workit-cli/src/admin/setup-state.ts
65359
- import { existsSync as existsSync11, readFileSync as readFileSync11 } from "node:fs";
65438
+ import { existsSync as existsSync11, readFileSync as readFileSync12 } from "node:fs";
65360
65439
  import path30 from "node:path";
65361
65440
  var classifySetupFile = (dir, name) => {
65362
65441
  const file = path30.join(dir, name);
65363
65442
  let raw;
65364
65443
  try {
65365
- raw = readFileSync11(file, "utf8");
65444
+ raw = readFileSync12(file, "utf8");
65366
65445
  } catch {
65367
65446
  if (existsSync11(file)) {
65368
65447
  return { file, status: "malformed", error: `${file} is not readable` };
@@ -65803,7 +65882,7 @@ import {
65803
65882
  accessSync,
65804
65883
  constants as constants2,
65805
65884
  existsSync as existsSync12,
65806
- readFileSync as readFileSync12,
65885
+ readFileSync as readFileSync13,
65807
65886
  readdirSync as readdirSync6,
65808
65887
  realpathSync as realpathSync6,
65809
65888
  statSync as statSync2
@@ -66093,7 +66172,7 @@ function runHostCommand(step, context = {}) {
66093
66172
  }
66094
66173
  var resolveWindowsShimScript = (shim) => {
66095
66174
  try {
66096
- const contents = readFileSync12(shim, "utf8");
66175
+ const contents = readFileSync13(shim, "utf8");
66097
66176
  return resolveWindowsShimEntry(contents, shim);
66098
66177
  } catch {
66099
66178
  return null;
@@ -66114,7 +66193,7 @@ var resolveWindowsShimScript = (shim) => {
66114
66193
  }, isPiWorkitInstalled = (home, env = process.env) => {
66115
66194
  const settings = path33.join(env.PI_CODING_AGENT_DIR ?? path33.join(home, ".pi", "agent"), "settings.json");
66116
66195
  try {
66117
- const document2 = JSON.parse(readFileSync12(settings, "utf8"));
66196
+ const document2 = JSON.parse(readFileSync13(settings, "utf8"));
66118
66197
  return (document2.packages ?? []).some((entry) => {
66119
66198
  const source = entry && typeof entry === "object" && !Array.isArray(entry) ? entry.source : entry;
66120
66199
  const value = String(source).replaceAll("\\", "/").replace(/\/+$/, "");
@@ -66125,7 +66204,7 @@ var resolveWindowsShimScript = (shim) => {
66125
66204
  }
66126
66205
  }, OPENCODE_PLUGIN_SCOPE = "@brainervirus", OPENCODE_PLUGIN_NAME = "workit-opencode", packageVersionAt = (root, name) => {
66127
66206
  try {
66128
- const pkg = JSON.parse(readFileSync12(path33.join(root, "package.json"), "utf8"));
66207
+ const pkg = JSON.parse(readFileSync13(path33.join(root, "package.json"), "utf8"));
66129
66208
  return pkg.name === name && typeof pkg.version === "string" ? pkg.version : null;
66130
66209
  } catch {
66131
66210
  return null;
@@ -66163,7 +66242,7 @@ var resolveWindowsShimScript = (shim) => {
66163
66242
  path33.join(root, "package.json")
66164
66243
  ]) {
66165
66244
  try {
66166
- const manifest = JSON.parse(readFileSync12(file, "utf8"));
66245
+ const manifest = JSON.parse(readFileSync13(file, "utf8"));
66167
66246
  const repository = typeof manifest.repository === "string" ? manifest.repository : manifest.repository?.url;
66168
66247
  if ((manifest.name === "workit" || manifest.name === "@brainervirus/workit-codex") && repository?.replace(/\.git$/, "").toLowerCase() === "https://github.com/brainervirus/workit")
66169
66248
  return true;
@@ -66204,7 +66283,7 @@ var resolveWindowsShimScript = (shim) => {
66204
66283
  return relative === "" || !relative.startsWith("..") && !path33.isAbsolute(relative);
66205
66284
  }, isCanonicalClaudePlugin = (root) => {
66206
66285
  try {
66207
- const manifest = JSON.parse(readFileSync12(path33.join(root, ".claude-plugin", "plugin.json"), "utf8"));
66286
+ const manifest = JSON.parse(readFileSync13(path33.join(root, ".claude-plugin", "plugin.json"), "utf8"));
66208
66287
  const repository = typeof manifest.repository === "string" ? manifest.repository : manifest.repository?.url;
66209
66288
  return manifest.name === "workit" && repository?.replace(/\.git$/, "").toLowerCase() === "https://github.com/brainervirus/workit";
66210
66289
  } catch {
@@ -66214,7 +66293,7 @@ var resolveWindowsShimScript = (shim) => {
66214
66293
  const file = path33.join(claudeConfigDir(home, env), "plugins", "installed_plugins.json");
66215
66294
  let registry;
66216
66295
  try {
66217
- registry = JSON.parse(readFileSync12(file, "utf8"));
66296
+ registry = JSON.parse(readFileSync13(file, "utf8"));
66218
66297
  } catch {
66219
66298
  return [];
66220
66299
  }
@@ -66263,7 +66342,7 @@ var init_host_install = __esm(() => {
66263
66342
  });
66264
66343
 
66265
66344
  // packages/workit-core/src/core/skill-manifests.ts
66266
- import { cpSync as cpSync3, existsSync as existsSync13, readFileSync as readFileSync13, readdirSync as readdirSync7, statSync as statSync3, writeFileSync as writeFileSync5 } from "node:fs";
66345
+ import { cpSync as cpSync3, existsSync as existsSync13, readFileSync as readFileSync14, readdirSync as readdirSync7, statSync as statSync3, writeFileSync as writeFileSync6 } from "node:fs";
66267
66346
  import path34 from "node:path";
66268
66347
  var WORKIT_METHOD_SKILLS, skillManifestNames = (root) => existsSync13(root) ? readdirSync7(root).filter((name) => existsSync13(path34.join(root, name, "SKILL.md"))).toSorted() : [], validateSkillManifests = (root, expected, label) => {
66269
66348
  const actual = skillManifestNames(root);
@@ -66281,7 +66360,7 @@ var WORKIT_METHOD_SKILLS, skillManifestNames = (root) => existsSync13(root) ? re
66281
66360
  const file = path34.join(dir, entry.name);
66282
66361
  if (entry.isDirectory())
66283
66362
  pending.push(file);
66284
- else if ((statSync3(file).mode & 73) !== 0 || readFileSync13(file).subarray(0, 2).toString("latin1") === "#!") {
66363
+ else if ((statSync3(file).mode & 73) !== 0 || readFileSync14(file).subarray(0, 2).toString("latin1") === "#!") {
66285
66364
  return `Cursor vendor contains active file: ${file}`;
66286
66365
  }
66287
66366
  }
@@ -66314,11 +66393,11 @@ import {
66314
66393
  existsSync as existsSync14,
66315
66394
  lstatSync as lstatSync4,
66316
66395
  mkdirSync as mkdirSync5,
66317
- readFileSync as readFileSync14,
66396
+ readFileSync as readFileSync15,
66318
66397
  renameSync as renameSync3,
66319
66398
  rmSync as rmSync2,
66320
66399
  statSync as statSync4,
66321
- writeFileSync as writeFileSync6
66400
+ writeFileSync as writeFileSync7
66322
66401
  } from "node:fs";
66323
66402
  import path35 from "node:path";
66324
66403
  function inspectSessionHook(cwd, env = process.env) {
@@ -66517,7 +66596,7 @@ exit 0
66517
66596
  return rel === "" || !rel.startsWith("..") && !path35.isAbsolute(rel);
66518
66597
  }, readText3 = (file) => {
66519
66598
  try {
66520
- return readFileSync14(file, "utf8");
66599
+ return readFileSync15(file, "utf8");
66521
66600
  } catch {
66522
66601
  return null;
66523
66602
  }
@@ -66621,7 +66700,7 @@ exit 0
66621
66700
  mkdirSync5(path35.dirname(file), { recursive: true });
66622
66701
  const staged = `${file}.workit-new`;
66623
66702
  try {
66624
- writeFileSync6(staged, content, { mode: 493 });
66703
+ writeFileSync7(staged, content, { mode: 493 });
66625
66704
  chmodSync(staged, 493);
66626
66705
  renameSync3(staged, file);
66627
66706
  } finally {
@@ -66684,7 +66763,7 @@ var init_heavy_words = __esm(() => {
66684
66763
  });
66685
66764
 
66686
66765
  // packages/workit-core/src/hooks/hook-runs.ts
66687
- import { mkdirSync as mkdirSync6, readdirSync as readdirSync8, readFileSync as readFileSync15, writeFileSync as writeFileSync7 } from "node:fs";
66766
+ import { mkdirSync as mkdirSync6, readdirSync as readdirSync8, readFileSync as readFileSync16, writeFileSync as writeFileSync8 } from "node:fs";
66688
66767
  import path37 from "node:path";
66689
66768
  var HOOK_RUNS_DIR = "hook-runs", readHookRuns = (dir) => {
66690
66769
  const runs = [];
@@ -66696,7 +66775,7 @@ var HOOK_RUNS_DIR = "hook-runs", readHookRuns = (dir) => {
66696
66775
  }
66697
66776
  for (const name of names) {
66698
66777
  try {
66699
- const row = JSON.parse(readFileSync15(path37.join(dir, HOOK_RUNS_DIR, name), "utf8"));
66778
+ const row = JSON.parse(readFileSync16(path37.join(dir, HOOK_RUNS_DIR, name), "utf8"));
66700
66779
  if (typeof row.host === "string" && typeof row.event === "string" && typeof row.at === "string" && typeof row.count === "number")
66701
66780
  runs.push({
66702
66781
  host: row.host,
@@ -66742,7 +66821,7 @@ import {
66742
66821
  existsSync as existsSync15,
66743
66822
  readdirSync as readdirSync9,
66744
66823
  mkdirSync as mkdirSync7,
66745
- readFileSync as readFileSync16,
66824
+ readFileSync as readFileSync17,
66746
66825
  realpathSync as realpathSync7,
66747
66826
  rmSync as rmSync3,
66748
66827
  statSync as statSync5
@@ -67170,7 +67249,7 @@ ${[...rules, ...lease, grant].join(`
67170
67249
  }, AGENT_SESSION_VARS, agentSessionVar = (env) => AGENT_SESSION_VARS.find((name) => (env[name] ?? "") !== "") ?? null, RECORD_FILE = "host-permissions.json", readOwnership = (options = {}) => {
67171
67250
  const { stateDir } = resolvePaths(options);
67172
67251
  try {
67173
- const value = JSON.parse(readFileSync16(path38.join(stateDir, RECORD_FILE), "utf8"));
67252
+ const value = JSON.parse(readFileSync17(path38.join(stateDir, RECORD_FILE), "utf8"));
67174
67253
  if (isRecord5(value) && isRecord5(value.hosts))
67175
67254
  return { version: 1, hosts: value.hosts };
67176
67255
  } catch {}
@@ -67199,7 +67278,7 @@ ${[...rules, ...lease, grant].join(`
67199
67278
  writeOwnership(record, paths.stateDir);
67200
67279
  }, readText4 = (file) => {
67201
67280
  try {
67202
- return readFileSync16(file, "utf8");
67281
+ return readFileSync17(file, "utf8");
67203
67282
  } catch {
67204
67283
  return null;
67205
67284
  }
@@ -67361,13 +67440,13 @@ import {
67361
67440
  mkdirSync as mkdirSync8,
67362
67441
  mkdtempSync,
67363
67442
  readdirSync as readdirSync10,
67364
- readFileSync as readFileSync17,
67443
+ readFileSync as readFileSync18,
67365
67444
  readlinkSync as readlinkSync2,
67366
67445
  renameSync as renameSync4,
67367
67446
  rmSync as rmSync4,
67368
67447
  statSync as statSync6,
67369
67448
  unlinkSync as unlinkSync3,
67370
- writeFileSync as writeFileSync8
67449
+ writeFileSync as writeFileSync9
67371
67450
  } from "node:fs";
67372
67451
  import os12 from "node:os";
67373
67452
  import path39 from "node:path";
@@ -67431,14 +67510,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67431
67510
  };
67432
67511
  }, readJson = (p) => {
67433
67512
  try {
67434
- const parsed = JSON.parse(readFileSync17(p, "utf8"));
67513
+ const parsed = JSON.parse(readFileSync18(p, "utf8"));
67435
67514
  return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
67436
67515
  } catch {
67437
67516
  return null;
67438
67517
  }
67439
67518
  }, parsesAsConfigObject = (p) => {
67440
67519
  try {
67441
- return isConfigObject(JSON.parse(readFileSync17(p, "utf8")));
67520
+ return isConfigObject(JSON.parse(readFileSync18(p, "utf8")));
67442
67521
  } catch {
67443
67522
  return false;
67444
67523
  }
@@ -67661,7 +67740,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67661
67740
  const tables = new Map;
67662
67741
  let text;
67663
67742
  try {
67664
- text = readFileSync17(file, "utf8");
67743
+ text = readFileSync18(file, "utf8");
67665
67744
  } catch {
67666
67745
  return tables;
67667
67746
  }
@@ -67832,7 +67911,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67832
67911
  let stale = false;
67833
67912
  for (const file of files) {
67834
67913
  const dest = path39.join(agentsDir, file);
67835
- const want = stampCodexAgent(readFileSync17(path39.join(source, file), "utf8"), version);
67914
+ const want = stampCodexAgent(readFileSync18(path39.join(source, file), "utf8"), version);
67836
67915
  let link = false;
67837
67916
  try {
67838
67917
  link = lstatSync5(dest).isSymbolicLink();
@@ -67846,7 +67925,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67846
67925
  }
67847
67926
  let have = null;
67848
67927
  try {
67849
- have = readFileSync17(dest, "utf8");
67928
+ have = readFileSync18(dest, "utf8");
67850
67929
  } catch {
67851
67930
  have = null;
67852
67931
  }
@@ -68095,7 +68174,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
68095
68174
  }, validNodeEntry = (entry, runtime, env) => {
68096
68175
  try {
68097
68176
  const stat = statSync6(entry);
68098
- if (!stat.isFile() || stat.size === 0 || !readFileSync17(entry, "utf8").startsWith(`#!/usr/bin/env node
68177
+ if (!stat.isFile() || stat.size === 0 || !readFileSync18(entry, "utf8").startsWith(`#!/usr/bin/env node
68099
68178
  `)) {
68100
68179
  return false;
68101
68180
  }
@@ -68951,7 +69030,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
68951
69030
  return { ...installSessionHook(res.cwd, res.env), workspace: workspace.name };
68952
69031
  }, isPlaceholder = (p) => {
68953
69032
  try {
68954
- return readFileSync17(p, "utf8").trim() === TOKEN_PLACEHOLDER2;
69033
+ return readFileSync18(p, "utf8").trim() === TOKEN_PLACEHOLDER2;
68955
69034
  } catch {
68956
69035
  return false;
68957
69036
  }
@@ -69165,7 +69244,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
69165
69244
  const probe = path39.join(logsDir, "doctor-probe.tmp");
69166
69245
  try {
69167
69246
  mkdirSync8(logsDir, { recursive: true, mode: 448 });
69168
- writeFileSync8(probe, `{"probe":true}
69247
+ writeFileSync9(probe, `{"probe":true}
69169
69248
  `, { mode: 384 });
69170
69249
  return {
69171
69250
  id: "log_writable",
@@ -69244,7 +69323,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
69244
69323
  const counts = { skip: 0, late: 0 };
69245
69324
  let text = "";
69246
69325
  try {
69247
- text = readFileSync17(path39.join(stateDir, HOOK_SKIPS_FILE), "utf8");
69326
+ text = readFileSync18(path39.join(stateDir, HOOK_SKIPS_FILE), "utf8");
69248
69327
  } catch {
69249
69328
  return counts;
69250
69329
  }
@@ -69435,7 +69514,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
69435
69514
  return null;
69436
69515
  return files.some((file) => {
69437
69516
  try {
69438
- return readFileSync17(path39.join(root, "dist", file), "utf8").includes(HOOK_ISSUED_MARKER);
69517
+ return readFileSync18(path39.join(root, "dist", file), "utf8").includes(HOOK_ISSUED_MARKER);
69439
69518
  } catch {
69440
69519
  return false;
69441
69520
  }
@@ -69779,13 +69858,13 @@ import {
69779
69858
  lstatSync as lstatSync6,
69780
69859
  mkdirSync as mkdirSync9,
69781
69860
  mkdtempSync as mkdtempSync2,
69782
- readFileSync as readFileSync18,
69861
+ readFileSync as readFileSync19,
69783
69862
  readdirSync as readdirSync11,
69784
69863
  realpathSync as realpathSync8,
69785
69864
  renameSync as renameSync5,
69786
69865
  rmSync as rmSync5,
69787
69866
  statSync as statSync7,
69788
- writeFileSync as writeFileSync9
69867
+ writeFileSync as writeFileSync10
69789
69868
  } from "node:fs";
69790
69869
  import { createRequire as createRequire2 } from "node:module";
69791
69870
  import os13 from "node:os";
@@ -69953,7 +70032,7 @@ function buildSetupPreview(values, opts = {}) {
69953
70032
  if (target?.ok) {
69954
70033
  const root = target.root;
69955
70034
  const gitignorePath = path40.join(root, ".gitignore");
69956
- const existing = existsSync17(gitignorePath) ? readFileSync18(gitignorePath, "utf8") : "";
70035
+ const existing = existsSync17(gitignorePath) ? readFileSync19(gitignorePath, "utf8") : "";
69957
70036
  const existingLines = new Set(existing.split(`
69958
70037
  `).map((l) => l.trim()).filter(Boolean));
69959
70038
  const entries = GITIGNORE_ENTRIES.filter((e) => e.trim() !== "" && !existingLines.has(e.trim()));
@@ -70017,7 +70096,7 @@ function applyMutation(m) {
70017
70096
  return { platform: "core", file: m.path, status: "Skipped", detail: "already configured" };
70018
70097
  }
70019
70098
  mkdirSync9(dir, { recursive: true });
70020
- writeFileSync9(m.path, JSON.stringify(merged, null, 2) + `
70099
+ writeFileSync10(m.path, JSON.stringify(merged, null, 2) + `
70021
70100
  `, "utf8");
70022
70101
  return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
70023
70102
  }
@@ -70061,7 +70140,7 @@ function applyMutation(m) {
70061
70140
  mkdirSync9(dir, { recursive: true });
70062
70141
  const tmp = `${m.path}.${process.pid}.tmp`;
70063
70142
  try {
70064
- writeFileSync9(tmp, next, "utf8");
70143
+ writeFileSync10(tmp, next, "utf8");
70065
70144
  if (workspacesRevision(readFileSafe(m.path)) !== m.expectedRevision) {
70066
70145
  rmSync5(tmp, { force: true });
70067
70146
  return {
@@ -70100,7 +70179,7 @@ function applyMutation(m) {
70100
70179
  const separator = existing && !existing.endsWith(`
70101
70180
  `) ? `
70102
70181
  ` : "";
70103
- writeFileSync9(m.path, existing + separator + (existing ? `
70182
+ writeFileSync10(m.path, existing + separator + (existing ? `
70104
70183
  ` : "") + add.join(`
70105
70184
  `) + `
70106
70185
  `, "utf8");
@@ -70140,7 +70219,7 @@ function applyMutation(m) {
70140
70219
  };
70141
70220
  }
70142
70221
  mkdirSync9(path40.dirname(m.path), { recursive: true });
70143
- writeFileSync9(m.path, JSON.stringify(merged, null, 2) + `
70222
+ writeFileSync10(m.path, JSON.stringify(merged, null, 2) + `
70144
70223
  `, "utf8");
70145
70224
  return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
70146
70225
  }
@@ -70212,7 +70291,7 @@ function applyOpenCode(root, res) {
70212
70291
  detail: "already registered"
70213
70292
  };
70214
70293
  }
70215
- writeFileSync9(res.opencodeConfig, JSON.stringify(merged.config, null, 2) + `
70294
+ writeFileSync10(res.opencodeConfig, JSON.stringify(merged.config, null, 2) + `
70216
70295
  `, "utf8");
70217
70296
  return existing.kind === "record" ? {
70218
70297
  platform: "opencode",
@@ -70247,12 +70326,12 @@ function copyPluginDir(src, dest) {
70247
70326
  });
70248
70327
  const stagedHooks = path40.join(stage, CURSOR_HOOKS_FILE);
70249
70328
  if (existsSync17(stagedHooks))
70250
- writeFileSync9(stagedHooks, localizedCursorHooks(readFileSync18(stagedHooks), dest));
70329
+ writeFileSync10(stagedHooks, localizedCursorHooks(readFileSync19(stagedHooks), dest));
70251
70330
  for (const [name, content] of rules) {
70252
70331
  mkdirSync9(path40.join(stage, "rules"), { recursive: true });
70253
- writeFileSync9(path40.join(stage, "rules", name), content);
70332
+ writeFileSync10(path40.join(stage, "rules", name), content);
70254
70333
  }
70255
- writeFileSync9(path40.join(stage, ".workit-root"), realSrc + `
70334
+ writeFileSync10(path40.join(stage, ".workit-root"), realSrc + `
70256
70335
  `, "utf8");
70257
70336
  if (!samePluginContent(realSrc, stage, dest))
70258
70337
  throw new Error("staged adapter content is incomplete");
@@ -70294,7 +70373,7 @@ function applyCursorSettings(root, res) {
70294
70373
  detail: "already registered"
70295
70374
  };
70296
70375
  }
70297
- writeFileSync9(res.cursorSettings, JSON.stringify(settings.config, null, 2) + `
70376
+ writeFileSync10(res.cursorSettings, JSON.stringify(settings.config, null, 2) + `
70298
70377
  `, "utf8");
70299
70378
  return {
70300
70379
  platform: "cursor",
@@ -70333,7 +70412,7 @@ function applyCursorMcp(root, res) {
70333
70412
  detail: "already registered"
70334
70413
  };
70335
70414
  }
70336
- writeFileSync9(res.cursorMcp, JSON.stringify(mcp.config, null, 2) + `
70415
+ writeFileSync10(res.cursorMcp, JSON.stringify(mcp.config, null, 2) + `
70337
70416
  `, "utf8");
70338
70417
  return {
70339
70418
  platform: "cursor",
@@ -70602,7 +70681,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
70602
70681
  return configured ?? fallback;
70603
70682
  }, readConfigRecord = (file) => {
70604
70683
  try {
70605
- const value = JSON.parse(readFileSync18(file, "utf8"));
70684
+ const value = JSON.parse(readFileSync19(file, "utf8"));
70606
70685
  return isRecord6(value) ? value : null;
70607
70686
  } catch {
70608
70687
  return null;
@@ -70623,7 +70702,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
70623
70702
  }, isRecord6 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readExisting = (p) => {
70624
70703
  let raw;
70625
70704
  try {
70626
- raw = readFileSync18(p, "utf8");
70705
+ raw = readFileSync19(p, "utf8");
70627
70706
  } catch {
70628
70707
  if (existsSync17(p))
70629
70708
  return { kind: "malformed", error: `${p} is not readable` };
@@ -70640,7 +70719,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
70640
70719
  return { kind: "malformed", error: `${p} is not a JSON object` };
70641
70720
  }, readFileSafe = (p) => {
70642
70721
  try {
70643
- return readFileSync18(p, "utf8");
70722
+ return readFileSync19(p, "utf8");
70644
70723
  } catch {
70645
70724
  return null;
70646
70725
  }
@@ -70655,7 +70734,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
70655
70734
  }
70656
70735
  }, isAdapter = (root, platform) => {
70657
70736
  try {
70658
- const pkg = JSON.parse(readFileSync18(path40.join(root, "package.json"), "utf8"));
70737
+ const pkg = JSON.parse(readFileSync19(path40.join(root, "package.json"), "utf8"));
70659
70738
  return pkg.name === `@brainervirus/workit-${platform}`;
70660
70739
  } catch {
70661
70740
  return false;
@@ -70704,8 +70783,8 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
70704
70783
  if (!statSync7(installed).isDirectory() || !samePluginContent(source, installed, pluginDir, rel))
70705
70784
  return false;
70706
70785
  } else {
70707
- const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(readFileSync18(source), pluginDir) : readFileSync18(source);
70708
- if (!expected.equals(readFileSync18(installed)))
70786
+ const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(readFileSync19(source), pluginDir) : readFileSync19(source);
70787
+ if (!expected.equals(readFileSync19(installed)))
70709
70788
  return false;
70710
70789
  }
70711
70790
  }
@@ -70733,7 +70812,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
70733
70812
  continue;
70734
70813
  if (existsSync17(path40.join(sourceRules, entry.name)))
70735
70814
  continue;
70736
- preserved.set(entry.name, readFileSync18(path40.join(installedRules, entry.name)));
70815
+ preserved.set(entry.name, readFileSync19(path40.join(installedRules, entry.name)));
70737
70816
  }
70738
70817
  } catch {}
70739
70818
  return preserved;
@@ -70788,7 +70867,7 @@ var init_setup = __esm(() => {
70788
70867
  });
70789
70868
 
70790
70869
  // packages/workit-core/src/core/workspace-branch-policy.ts
70791
- import { mkdirSync as mkdirSync10, readFileSync as readFileSync19, renameSync as renameSync6, rmSync as rmSync6, writeFileSync as writeFileSync10 } from "node:fs";
70870
+ import { mkdirSync as mkdirSync10, readFileSync as readFileSync20, renameSync as renameSync6, rmSync as rmSync6, writeFileSync as writeFileSync11 } from "node:fs";
70792
70871
  import path41 from "node:path";
70793
70872
  import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
70794
70873
  function applyWorkspaceBranchPolicy(opts) {
@@ -70857,7 +70936,7 @@ function applyWorkspaceBranchPolicy(opts) {
70857
70936
  mkdirSync10(path41.dirname(wsPath), { recursive: true });
70858
70937
  const tmp = `${wsPath}.${process.pid}.tmp`;
70859
70938
  try {
70860
- writeFileSync10(tmp, JSON.stringify({ ...document2, workspaces: next }, null, 2) + `
70939
+ writeFileSync11(tmp, JSON.stringify({ ...document2, workspaces: next }, null, 2) + `
70861
70940
  `, "utf8");
70862
70941
  if (workspacesRevision(readFileSafe2(wsPath)) !== revision) {
70863
70942
  rmSync6(tmp, { force: true });
@@ -70886,7 +70965,7 @@ function applyWorkspaceBranchPolicy(opts) {
70886
70965
  }
70887
70966
  var readFileSafe2 = (p) => {
70888
70967
  try {
70889
- return readFileSync19(p, "utf8");
70968
+ return readFileSync20(p, "utf8");
70890
70969
  } catch {
70891
70970
  return null;
70892
70971
  }
@@ -71726,7 +71805,7 @@ var init_wizard_state = __esm(() => {
71726
71805
  });
71727
71806
 
71728
71807
  // packages/workit-cli/src/admin/uninstall.ts
71729
- import { existsSync as existsSync19, readFileSync as readFileSync20, realpathSync as realpathSync9, rmSync as rmSync7, writeFileSync as writeFileSync11 } from "node:fs";
71808
+ import { existsSync as existsSync19, readFileSync as readFileSync21, realpathSync as realpathSync9, rmSync as rmSync7, writeFileSync as writeFileSync12 } from "node:fs";
71730
71809
  import os14 from "node:os";
71731
71810
  import path43 from "node:path";
71732
71811
  function cleanCursorSettings(settings, pluginDir) {
@@ -71988,7 +72067,7 @@ var resolveUninstallPaths = (options = {}) => {
71988
72067
  }, isRecord7 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readJsonRecord = (file) => {
71989
72068
  let raw;
71990
72069
  try {
71991
- raw = readFileSync20(file, "utf8");
72070
+ raw = readFileSync21(file, "utf8");
71992
72071
  } catch {
71993
72072
  if (existsSync19(file))
71994
72073
  return { kind: "malformed", error: `${file} is not readable` };
@@ -72053,7 +72132,7 @@ var resolveUninstallPaths = (options = {}) => {
72053
72132
  `;
72054
72133
  let current;
72055
72134
  try {
72056
- current = readFileSync20(target, "utf8");
72135
+ current = readFileSync21(target, "utf8");
72057
72136
  } catch (error) {
72058
72137
  return {
72059
72138
  status: "failed",
@@ -72064,7 +72143,7 @@ var resolveUninstallPaths = (options = {}) => {
72064
72143
  return { status: "skipped", detail: "already clean" };
72065
72144
  }
72066
72145
  try {
72067
- writeFileSync11(target, serialized, "utf8");
72146
+ writeFileSync12(target, serialized, "utf8");
72068
72147
  } catch (error) {
72069
72148
  return {
72070
72149
  status: "failed",
@@ -74838,171 +74917,156 @@ var init_setup2 = __esm(() => {
74838
74917
  ALL_HOSTS = ["claude-code", "codex", "cursor", "opencode", "pi"];
74839
74918
  });
74840
74919
 
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";
74920
+ // packages/workit-cli/src/upgrade/shared.ts
74921
+ import { existsSync as existsSync20, readFileSync as readFileSync22 } from "node:fs";
74855
74922
  import path44 from "node:path";
74856
74923
  import os16 from "node:os";
74857
74924
  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: []
74925
+ 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) => {
74926
+ const home = deps.home ?? deps.env?.HOME ?? os16.homedir();
74927
+ const env = {
74928
+ ...process.env,
74929
+ ...deps.home || deps.env?.HOME ? {
74930
+ HOME: home,
74931
+ CODEX_HOME: path44.join(home, ".codex"),
74932
+ CLAUDE_CONFIG_DIR: path44.join(home, ".claude"),
74933
+ PI_CODING_AGENT_DIR: path44.join(home, ".pi/agent"),
74934
+ XDG_CONFIG_HOME: path44.join(home, ".config"),
74935
+ WORKFLOW_TOOLKIT_CONFIG: undefined,
74936
+ WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
74937
+ } : {},
74938
+ ...deps.env,
74939
+ HOME: home
74871
74940
  };
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);
74941
+ const xdg = env.XDG_CONFIG_HOME || path44.join(home, ".config");
74942
+ const codexHome = env.CODEX_HOME ?? path44.join(home, ".codex");
74943
+ return {
74944
+ home,
74945
+ env,
74946
+ configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path44.join(xdg, "workit"),
74947
+ opencodeConfig: path44.join(xdg, "opencode/opencode.json"),
74948
+ piSettings: path44.join(env.PI_CODING_AGENT_DIR ?? path44.join(home, ".pi/agent"), "settings.json"),
74949
+ codexHome,
74950
+ codexConfig: path44.join(codexHome, "config.toml"),
74951
+ cursorRoot: path44.join(home, ".cursor/plugins/local/workit")
74952
+ };
74953
+ }, object2 = (file) => {
74954
+ if (!existsSync20(file))
74955
+ return null;
74956
+ let data;
74957
+ try {
74958
+ data = JSON.parse(readFileSync22(file, "utf8"));
74959
+ } catch {
74960
+ throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
74876
74961
  }
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);
74962
+ if (!data || typeof data !== "object" || Array.isArray(data))
74963
+ throw new Error(`${file} is not a configuration object`);
74964
+ return data;
74965
+ }, objectOrNull = (file) => {
74887
74966
  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));
74967
+ return object2(file);
74968
+ } catch {
74969
+ return null;
74897
74970
  }
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}`);
74971
+ }, digest2 = (file) => existsSync20(file) ? createHash15("sha256").update(readFileSync22(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
74972
+ const { home, env } = upgradePaths(deps);
74973
+ let step;
74974
+ try {
74975
+ step = hostCommand(command, args, { home, env });
74976
+ } catch {
74977
+ return { status: 1, stdout: "" };
74905
74978
  }
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
- });
74979
+ const result = runHostCommand(step, { home, env });
74980
+ return { status: result.exitCode, stdout: result.stdout };
74981
+ }), errorText = (error) => error instanceof Error ? error.message : "installed source could not be read", piInstalledVersion = (listing, selector) => {
74982
+ const lines = listing.split(/\r?\n/).map((line) => line.trim());
74983
+ const index = lines.indexOf(selector);
74984
+ if (index < 0 || !lines[index + 1] || !path44.isAbsolute(lines[index + 1]))
74985
+ return;
74986
+ const found = objectOrNull(path44.join(lines[index + 1], "package.json"));
74987
+ return found?.name === "@brainervirus/workit-pi" ? found.version : undefined;
74988
+ }, versionAtLeast = (installed, latest) => {
74989
+ if (!/^\d+\.\d+\.\d+$/.test(installed))
74990
+ return false;
74991
+ const current = installed.split(".").map(Number);
74992
+ const target = latest.split(".").map(Number);
74993
+ for (let index = 0;index < 3; index++) {
74994
+ if (current[index] !== target[index])
74995
+ return current[index] > target[index];
74913
74996
  }
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)
74997
+ return true;
74998
+ }, registryVersion = (run, name) => {
74999
+ const latest = run("npm", ["view", name, "version"]);
75000
+ const version = latest.stdout.trim();
75001
+ return latest.status === 0 && /^\d+\.\d+\.\d+$/.test(version) ? version : undefined;
75002
+ };
75003
+ var init_shared = __esm(() => {
75004
+ init_host_install();
75005
+ LAUNCH_HOSTS = ["opencode", "cursor", "codex", "pi"];
75006
+ HOSTS2 = [...LAUNCH_HOSTS, "claude-code"];
75007
+ LIVE_HOSTS = new Set(["opencode", "claude-code"]);
75008
+ OPENCODE_UPDATE = `opencode plugin update ${OPENCODE_PACKAGE}`;
75009
+ });
75010
+
75011
+ // packages/workit-cli/src/upgrade/processes.ts
75012
+ import path45 from "node:path";
75013
+ var PROCESS_HOSTS, SCRIPT_RUNTIMES, classifyProcess = (proc) => {
75014
+ if (proc.state.startsWith("Z") || proc.args.includes("<defunct>"))
75015
+ return null;
75016
+ const argv0 = proc.args.trim().split(/\s+/)[0] ?? "";
75017
+ const baseName = (value) => path45.basename(value.replaceAll("\\", "/")).replace(/^\[|\]$/g, "").replace(/\.exe$/i, "").toLowerCase();
75018
+ let host = PROCESS_HOSTS[baseName(argv0)];
75019
+ if (!host && SCRIPT_RUNTIMES.has(baseName(argv0))) {
75020
+ const script = proc.args.trim().split(/\s+/).slice(1).find((arg) => !arg.startsWith("-"));
75021
+ if (script)
75022
+ host = PROCESS_HOSTS[baseName(script).replace(/\.(?:[cm]?js|ts)$/, "")];
75023
+ }
75024
+ if (!host)
75025
+ return null;
75026
+ if (host === "codex" && /\bapp-server\b/.test(proc.args))
75027
+ return /\bdaemon\s+pid-update-loop\b/.test(proc.args) ? null : { ...proc, host, kind: "daemon" };
75028
+ if (host === "opencode" && /\bserve\b/.test(proc.args))
75029
+ return { ...proc, host, kind: "daemon" };
75030
+ return { ...proc, host, kind: "session" };
75031
+ }, listProcesses = (deps) => {
75032
+ if (deps.processes)
75033
+ return deps.processes();
75034
+ if (deps.activeHosts)
75035
+ return deps.activeHosts().map((host) => ({ pid: 0, state: "S", args: host }));
75036
+ const run = runner(deps);
75037
+ if (process.platform === "win32") {
75038
+ const list = run("tasklist", ["/fo", "csv", "/nh"]);
75039
+ if (list.status !== 0)
75040
+ return null;
75041
+ return list.stdout.split(/\r?\n/).flatMap((line) => {
75042
+ const [image, pid] = line.split('","').map((cell) => cell.replaceAll('"', ""));
75043
+ return image && /^\d+$/.test(pid ?? "") ? [{ pid: Number(pid), state: "R", args: image }] : [];
75001
75044
  });
75002
75045
  }
75003
- plan.ok = plan.blocked.length === 0 && plan.failed.length === 0;
75004
- return plan;
75005
- }
75046
+ const list = run("ps", ["-eo", "pid=,stat=,args="]);
75047
+ if (list.status !== 0)
75048
+ return null;
75049
+ return list.stdout.split(/\r?\n/).flatMap((line) => {
75050
+ const match = /^\s*(\d+)\s+(\S+)\s+(.+)$/.exec(line);
75051
+ return match ? [{ pid: Number(match[1]), state: match[2], args: match[3] }] : [];
75052
+ });
75053
+ }, describe2 = (proc) => `pid ${proc.pid}: ${proc.args.length > 120 ? `${proc.args.slice(0, 117)}...` : proc.args}`;
75054
+ var init_processes = __esm(() => {
75055
+ init_shared();
75056
+ PROCESS_HOSTS = {
75057
+ claude: "claude-code",
75058
+ codex: "codex",
75059
+ cursor: "cursor",
75060
+ opencode: "opencode",
75061
+ pi: "pi"
75062
+ };
75063
+ SCRIPT_RUNTIMES = new Set(["node", "nodejs", "bun"]);
75064
+ });
75065
+
75066
+ // packages/workit-cli/src/upgrade/apply.ts
75067
+ import { existsSync as existsSync21, readdirSync as readdirSync12, mkdirSync as mkdirSync11, copyFileSync as copyFileSync6, chmodSync as chmodSync2, cpSync as cpSync5 } from "node:fs";
75068
+ import path46 from "node:path";
75069
+ import { createHash as createHash16 } from "node:crypto";
75006
75070
  function applyUpgrade(plan, deps = {}) {
75007
75071
  const hosts = [...plan.failed];
75008
75072
  const done = (backup) => {
@@ -75036,11 +75100,11 @@ function applyUpgrade(plan, deps = {}) {
75036
75100
  };
75037
75101
  const paths = upgradePaths(deps);
75038
75102
  const { home, configDir } = paths;
75039
- const backup = path44.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
75103
+ const backup = path46.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
75040
75104
  mkdirSync11(backup, { recursive: true, mode: 448 });
75041
75105
  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));
75106
+ if (existsSync21(file)) {
75107
+ const target = path46.join(backup, createHash16("sha256").update(file).digest("hex").slice(0, 12) + "-" + path46.basename(file));
75044
75108
  copyFileSync6(file, target);
75045
75109
  chmodSync2(target, 384);
75046
75110
  }
@@ -75059,9 +75123,11 @@ function applyUpgrade(plan, deps = {}) {
75059
75123
  }
75060
75124
  const run = runner(deps);
75061
75125
  let cursorBackupError = null;
75062
- if (plan.entries.some((entry) => entry.host === "cursor") && existsSync20(paths.cursorRoot))
75126
+ if (plan.entries.some((entry) => entry.host === "cursor") && existsSync21(paths.cursorRoot))
75063
75127
  try {
75064
- cpSync5(paths.cursorRoot, path44.join(backup, "cursor-package"), { recursive: true });
75128
+ cpSync5(paths.cursorRoot, path46.join(backup, "cursor-package"), {
75129
+ recursive: true
75130
+ });
75065
75131
  } catch (error) {
75066
75132
  cursorBackupError = `could not back up the Cursor plugin: ${errorText(error)}`;
75067
75133
  }
@@ -75069,7 +75135,12 @@ function applyUpgrade(plan, deps = {}) {
75069
75135
  const running = (listed ?? []).flatMap((entry) => classifyProcess(entry) ?? []);
75070
75136
  for (const entry of plan.entries) {
75071
75137
  if (entry.host === "cursor" && cursorBackupError) {
75072
- hosts.push({ host: "cursor", status: "failed", reason: cursorBackupError, fix: entry.fix });
75138
+ hosts.push({
75139
+ host: "cursor",
75140
+ status: "failed",
75141
+ reason: cursorBackupError,
75142
+ fix: entry.fix
75143
+ });
75073
75144
  continue;
75074
75145
  }
75075
75146
  if (!LIVE_HOSTS.has(entry.host)) {
@@ -75178,238 +75249,356 @@ function applyUpgrade(plan, deps = {}) {
75178
75249
  try {
75179
75250
  hosts.push(applyCli(plan.cli, run, backup));
75180
75251
  } catch (error) {
75181
- hosts.push({ host: "cli", status: "failed", reason: errorText(error), fix: CLI_FIX });
75252
+ hosts.push({
75253
+ host: "cli",
75254
+ status: "failed",
75255
+ reason: errorText(error),
75256
+ fix: CLI_FIX
75257
+ });
75182
75258
  }
75183
75259
  return done(backup);
75184
75260
  }
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;
75261
+ var codexPluginRoot = (codexHome) => {
75262
+ const dir = path46.join(codexHome, "plugins", "cache", CODEX_MARKETPLACE, "workit");
75263
+ let versions = [];
75264
+ try {
75265
+ versions = readdirSync12(dir).filter((version) => /^\d+\.\d+\.\d+$/.test(version));
75266
+ } catch {
75267
+ return null;
75194
75268
  }
75195
- if (flags.has("--apply") && !flags.has("--confirm")) {
75196
- out.write(`Apply requires --confirm after reviewing the upgrade preview.
75197
- `);
75198
- return 2;
75269
+ const newest = versions.reduce((best, version) => best && versionAtLeast(best, version) ? best : version, null);
75270
+ return newest ? path46.join(dir, newest) : null;
75271
+ }, opencodeVersion = (run) => {
75272
+ const listing = run("opencode", ["plugin", "list"]);
75273
+ if (listing.status !== 0)
75274
+ return;
75275
+ for (const line of listing.stdout.split(/\r?\n/)) {
75276
+ const fields = line.trim().split(/\s+/);
75277
+ if (fields.length < 3)
75278
+ continue;
75279
+ const source = fields[fields.length - 1].replace(/^file:\/\//, "");
75280
+ const version = fields[fields.length - 2];
75281
+ if (/^(?:npm:)?@brainervirus\/workit-opencode(?:@[^/\s]+)?$/.test(source) && /^\d+\.\d+\.\d+$/.test(version))
75282
+ return version;
75199
75283
  }
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
75284
+ return;
75285
+ }, applyEntry = (entry, context) => {
75286
+ const { run, paths, configDir } = context;
75287
+ const { home, env } = paths;
75288
+ const fail = (reason) => ({
75289
+ host: entry.host,
75290
+ status: "failed",
75291
+ reason,
75292
+ fix: entry.fix
75214
75293
  });
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;
75294
+ if (entry.host === "cursor") {
75295
+ const preview = {
75296
+ ok: true,
75297
+ blocked: [],
75298
+ preserved: [],
75299
+ overrides: [],
75300
+ platforms: ["cursor"],
75301
+ state: readSetupState(configDir),
75302
+ mutations: [
75303
+ {
75304
+ type: "install-host",
75305
+ platform: "cursor",
75306
+ path: path46.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
75307
+ commands: entry.commands.map((command) => ({
75308
+ ...command,
75309
+ purpose: command.purpose ?? "Upgrade Cursor"
75310
+ }))
75311
+ },
75312
+ { type: "install-adapter", platform: "cursor", path: paths.cursorRoot }
75313
+ ]
75314
+ };
75315
+ const result = applySetupPreview(preview, {
75316
+ home,
75317
+ env,
75318
+ cwd: home,
75319
+ preferInstalledAdapter: true,
75320
+ runHostCommand: (command) => {
75321
+ const outcome = run(command.command, command.args);
75322
+ return {
75323
+ exitCode: outcome.status ?? 1,
75324
+ stdout: outcome.stdout,
75325
+ stderr: ""
75326
+ };
75327
+ }
75328
+ });
75329
+ const installed = objectOrNull(path46.join(paths.cursorRoot, "package.json"));
75330
+ if (!result.ok || installed?.version !== entry.latest)
75331
+ return fail("Cursor install did not verify the requested package version; inspect the installer before retrying");
75332
+ return {
75333
+ host: "cursor",
75334
+ status: "updated",
75335
+ reason: entry.repair ? `reinstalled missing plugin files (${entry.latest})` : `${entry.installedVersion ?? "?"} -> ${entry.latest}`
75336
+ };
75231
75337
  }
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;
75338
+ const before = entry.host === "opencode" ? opencodeVersion(run) : undefined;
75339
+ for (const command of entry.commands)
75340
+ if (run(command.command, command.args).status !== 0)
75341
+ return fail(`\`${command.command} ${command.args.join(" ")}\` failed`);
75342
+ if (entry.host === "opencode") {
75343
+ const after = opencodeVersion(run);
75344
+ if (before && after)
75345
+ return after === before ? {
75346
+ host: "opencode",
75347
+ status: "current",
75348
+ reason: `already current (${after})`
75349
+ } : {
75350
+ host: "opencode",
75351
+ status: "updated",
75352
+ reason: `${before} -> ${after}; OpenCode V2 loads it live`
75353
+ };
75354
+ return {
75355
+ host: "opencode",
75356
+ status: "updated",
75357
+ reason: "scoped update ran; OpenCode V2 loads it live"
75358
+ };
75237
75359
  }
75238
- if (plan.blocked.length) {
75239
- out.write(`Upgrade blocked: ${plan.blocked.join("; ")}
75240
- Nothing changed.
75241
- `);
75242
- return 1;
75360
+ if (entry.host === "claude-code") {
75361
+ const after = claudeWorkitInstalls(home, env, null).find((install) => install.id === entry.selector)?.version;
75362
+ return after && after === entry.installedVersion ? {
75363
+ host: "claude-code",
75364
+ status: "current",
75365
+ reason: `already current (${after})`
75366
+ } : {
75367
+ host: "claude-code",
75368
+ status: "updated",
75369
+ reason: `${entry.installedVersion ?? "?"} -> ${after ?? "?"}; new sessions load it`
75370
+ };
75243
75371
  }
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
- }
75372
+ const verify = entry.host === "codex" ? run("codex", ["plugin", "list", "--json"]) : run("pi", ["list"]);
75373
+ if (verify.status !== 0)
75374
+ return fail("update verification failed");
75375
+ if (entry.host === "codex") {
75376
+ let installed = [];
75377
+ try {
75378
+ installed = JSON.parse(verify.stdout).installed ?? [];
75379
+ } catch {}
75380
+ if (!installed.some((plugin) => plugin.name === "workit" && plugin.marketplaceName === CODEX_MARKETPLACE && plugin.version === entry.latest))
75381
+ return fail("Codex did not report the requested Workit version");
75251
75382
  }
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}` }
75383
+ if (entry.host === "pi" && piInstalledVersion(verify.stdout, entry.selector) !== entry.latest)
75384
+ return fail("Pi did not report the requested Workit package version");
75385
+ return {
75386
+ host: entry.host,
75387
+ status: "updated",
75388
+ reason: entry.repair ? `reinstalled missing plugin files (${entry.latest})` : `${entry.installedVersion ?? "?"} -> ${entry.latest}`
75389
+ };
75390
+ }, refreshCodexAgents = (run, codexHome) => {
75391
+ const root = codexPluginRoot(codexHome);
75392
+ const launcher = root && path46.join(root, "dist", "launch-mcp.js");
75393
+ if (!launcher || !existsSync21(launcher))
75394
+ return { ok: true, note: "" };
75395
+ const fix = `node ${JSON.stringify(launcher)} --install-agents`;
75396
+ return run("node", [launcher, "--install-agents"]).status === 0 ? { ok: true, note: "agents refreshed" } : { ok: false, note: "agent refresh failed", fix };
75397
+ }, applyCli = (cli, run, backup) => {
75398
+ const fail = (reason) => ({
75399
+ host: "cli",
75400
+ status: "failed",
75401
+ reason,
75402
+ fix: CLI_FIX
75403
+ });
75404
+ const currentRoot = run("npm", ["root", "--global"]);
75405
+ if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== cli.root)
75406
+ return fail("Global npm location changed; preview again");
75407
+ const cliBackup = path46.join(backup, "cli-package");
75408
+ cpSync5(path46.join(cli.root, "@brainervirus/workit-cli"), cliBackup, {
75409
+ recursive: true
75410
+ });
75411
+ if (run("npm", ["install", "--global", `@brainervirus/workit-cli@${cli.latest}`]).status !== 0)
75412
+ return fail(`CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path46.join(cliBackup, "dist/index.js")}`);
75413
+ const installed = objectOrNull(path46.join(cli.root, "@brainervirus/workit-cli/package.json"));
75414
+ if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== cli.latest)
75415
+ return fail(`CLI update did not verify the requested version; preserved package at ${cliBackup}`);
75416
+ return {
75417
+ host: "cli",
75418
+ status: "updated",
75419
+ reason: `${cli.installed} -> ${cli.latest}`
75420
+ };
75421
+ };
75422
+ var init_apply = __esm(() => {
75423
+ init_host_install();
75424
+ init_setup_state();
75425
+ init_setup();
75426
+ init_safe_write();
75427
+ init_processes();
75428
+ init_shared();
75429
+ });
75430
+
75431
+ // packages/workit-cli/src/upgrade/plan.ts
75432
+ import { existsSync as existsSync22, mkdtempSync as mkdtempSync3, rmSync as rmSync8, lstatSync as lstatSync7, readFileSync as readFileSync23 } from "node:fs";
75433
+ import path47 from "node:path";
75434
+ import os17 from "node:os";
75435
+ function previewUpgrade(hosts = HOSTS2, deps = {}) {
75436
+ const paths = upgradePaths(deps);
75437
+ const { home, configDir } = paths;
75438
+ const run = runner(deps);
75439
+ const state = readSetupState(configDir);
75440
+ const plan = {
75441
+ ok: true,
75442
+ blocked: [],
75443
+ failed: [],
75444
+ skipped: [],
75445
+ entries: [],
75446
+ configDigests: {},
75447
+ migrations: []
75448
+ };
75449
+ for (const file of [state.config, state.workspaces, state.youtrack, state.vcs]) {
75450
+ if (file.status === "malformed")
75451
+ plan.blocked.push(file.error ?? file.file);
75452
+ plan.configDigests[file.file] = digest2(file.file);
75453
+ }
75454
+ for (const file of [
75455
+ paths.opencodeConfig,
75456
+ paths.opencodeConfig + "c",
75457
+ path47.join(home, ".cursor/settings.json"),
75458
+ path47.join(home, ".cursor/mcp.json"),
75459
+ path47.join(paths.cursorRoot, "package.json"),
75460
+ paths.codexConfig,
75461
+ paths.piSettings
75462
+ ])
75463
+ plan.configDigests[file] = digest2(file);
75464
+ try {
75465
+ const config = object2(state.config.file);
75466
+ if (config && Object.hasOwn(config, "trustedPaths"))
75467
+ plan.migrations.push({
75468
+ id: "2.0-remove-ignored-trusted-paths",
75469
+ file: state.config.file,
75470
+ description: "Remove ignored Workit trustedPaths; native host permissions remain unchanged"
75268
75471
  });
75472
+ } catch (error) {
75473
+ plan.blocked.push(errorText(error));
75269
75474
  }
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;
75475
+ const installedSources = sources(paths, run, hosts, plan.failed);
75476
+ let opencodeHelp;
75477
+ if (installedSources.some((source) => source.host === "opencode")) {
75478
+ const probe = opencodeProbe(deps, ["--version"]);
75479
+ const installed = probe.status === 0 ? probe.stdout.match(/\d+\.\d+\.\d+/)?.[0] : undefined;
75480
+ if (installed && !versionAtLeast(installed, SUPPORT_MATRIX.opencode.minimum))
75481
+ (plan.warnings ??= []).push(`opencode ${installed}: ${OPENCODE_V1_FIX}`);
75283
75482
  }
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;
75483
+ for (const host of ["opencode", "pi"]) {
75484
+ if (new Set(installedSources.filter((source) => source.host === host).map((source) => source.selector)).size > 1)
75485
+ plan.failed.push({
75486
+ host,
75487
+ status: "failed",
75488
+ reason: "conflicting Workit registrations; reconcile them in the native host before upgrading"
75489
+ });
75308
75490
  }
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;
75491
+ const conflicted = new Set(plan.failed.map((entry) => entry.host));
75492
+ 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)) {
75493
+ if (source.kind === "pinned" || source.kind === "local") {
75494
+ plan.skipped.push({
75495
+ host: source.host,
75496
+ reason: `${source.kind} source preserved; change its source explicitly to upgrade`
75497
+ });
75498
+ continue;
75321
75499
  }
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;
75500
+ if (source.host === "claude-code") {
75501
+ const [market] = source.selector.split("@").slice(1);
75502
+ plan.entries.push({
75503
+ host: "claude-code",
75504
+ selector: source.selector,
75505
+ latest: "",
75506
+ installedVersion: source.installedVersion,
75507
+ commands: [
75508
+ {
75509
+ command: "claude",
75510
+ args: ["plugin", "marketplace", "update", market ?? "workit"]
75511
+ },
75512
+ { command: "claude", args: ["plugin", "update", source.selector] }
75513
+ ],
75514
+ fix: `claude plugin marketplace update ${market ?? "workit"} && claude plugin update ${source.selector}`
75515
+ });
75516
+ continue;
75517
+ }
75518
+ if (source.host === "opencode") {
75519
+ opencodeHelp ??= opencodeProbe(deps, ["plugin", "--help"]).stdout;
75520
+ if (!/^\s*(?:opencode\s+plugin\s+)?update\b/m.test(opencodeHelp)) {
75521
+ plan.skipped.push({
75522
+ host: "opencode",
75523
+ reason: "this OpenCode has no `opencode plugin update`; upgrade OpenCode, then run the fix. Workit never updates unrelated plugins",
75524
+ fix: OPENCODE_UPDATE
75525
+ });
75526
+ continue;
75335
75527
  }
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;
75528
+ plan.entries.push({
75529
+ host: "opencode",
75530
+ selector: source.selector,
75531
+ latest: "",
75532
+ commands: [{ command: "opencode", args: ["plugin", "update", OPENCODE_PACKAGE] }],
75533
+ fix: OPENCODE_UPDATE
75534
+ });
75535
+ continue;
75343
75536
  }
75537
+ const latest = registryVersion(run, `@brainervirus/workit-${source.host}`);
75538
+ if (!latest) {
75539
+ plan.failed.push({
75540
+ host: source.host,
75541
+ status: "failed",
75542
+ reason: "registry version unavailable; existing installation preserved",
75543
+ fix: fixFor(source.host, source.selector)
75544
+ });
75545
+ continue;
75546
+ }
75547
+ if (source.installedVersion && versionAtLeast(source.installedVersion, latest)) {
75548
+ plan.skipped.push({
75549
+ host: source.host,
75550
+ reason: `already current (${source.installedVersion})`
75551
+ });
75552
+ continue;
75553
+ }
75554
+ const commands = source.host === "pi" ? [{ command: "pi", args: ["update", "--extension", source.selector] }] : source.host === "codex" ? [
75555
+ {
75556
+ command: "codex",
75557
+ args: ["plugin", "marketplace", "upgrade", CODEX_MARKETPLACE]
75558
+ },
75559
+ {
75560
+ command: "codex",
75561
+ args: ["plugin", "add", `workit@${CODEX_MARKETPLACE}`, "--json"]
75562
+ }
75563
+ ] : planHostInstall("cursor", {
75564
+ home,
75565
+ env: deps.env,
75566
+ cwd: home,
75567
+ packageVersion: latest,
75568
+ targetDir: paths.cursorRoot
75569
+ });
75570
+ plan.entries.push({
75571
+ host: source.host,
75572
+ selector: source.selector,
75573
+ latest,
75574
+ commands,
75575
+ installedVersion: source.installedVersion,
75576
+ ...source.kind === "repair" ? { repair: true } : {},
75577
+ fix: fixFor(source.host, source.selector)
75578
+ });
75344
75579
  }
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;
75580
+ plan.ok = plan.blocked.length === 0 && plan.failed.length === 0;
75581
+ return plan;
75351
75582
  }
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;
75583
+ var codexRegistered = (configFile) => {
75584
+ let text;
75401
75585
  try {
75402
- step = hostCommand(command, args, { home, env });
75586
+ text = readFileSync23(configFile, "utf8");
75403
75587
  } catch {
75404
- return { status: 1, stdout: "" };
75588
+ return false;
75405
75589
  }
75406
- const result = runHostCommand(step, { home, env });
75407
- return { status: result.exitCode, stdout: result.stdout };
75408
- }), classify = (host, selector) => ({
75590
+ const header = `[plugins."workit@${CODEX_MARKETPLACE}"]`;
75591
+ const start = text.split(/\r?\n/).findIndex((line) => line.trim() === header);
75592
+ if (start < 0)
75593
+ return false;
75594
+ const body = text.split(/\r?\n/).slice(start + 1).join(`
75595
+ `).split(/^\s*\[/m)[0];
75596
+ return !/^\s*enabled\s*=\s*false\b/m.test(body);
75597
+ }, classify = (host, selector) => ({
75409
75598
  host,
75410
75599
  selector,
75411
75600
  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) => {
75601
+ }), sources = (paths, run, hosts, failed) => {
75413
75602
  const { home } = paths;
75414
75603
  const result = [];
75415
75604
  const guard = (host, read) => {
@@ -75427,7 +75616,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75427
75616
  }
75428
75617
  };
75429
75618
  guard("opencode", () => {
75430
- if (existsSync20(paths.opencodeConfig + "c"))
75619
+ if (existsSync22(paths.opencodeConfig + "c"))
75431
75620
  throw new Error("OpenCode JSONC config is present; inspect effective native configuration before updating");
75432
75621
  const oc = object2(paths.opencodeConfig);
75433
75622
  if (oc && [oc.plugins, oc.plugin].some((value) => value !== undefined && !Array.isArray(value)))
@@ -75437,8 +75626,8 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75437
75626
  result.push(classify("opencode", pin));
75438
75627
  });
75439
75628
  guard("cursor", () => {
75440
- const cursor = objectOrNull(path44.join(paths.cursorRoot, "package.json"));
75441
- const mcp = objectOrNull(path44.join(home, ".cursor/mcp.json"));
75629
+ const cursor = objectOrNull(path47.join(paths.cursorRoot, "package.json"));
75630
+ const mcp = objectOrNull(path47.join(home, ".cursor/mcp.json"));
75442
75631
  const args = mcp?.mcpServers?.workit?.args ?? [];
75443
75632
  const arg = args.find((value) => typeof value === "string" && value.startsWith("--package="));
75444
75633
  const selector = typeof arg === "string" ? arg.slice(10) : "local";
@@ -75449,7 +75638,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75449
75638
  });
75450
75639
  return;
75451
75640
  }
75452
- const settings = objectOrNull(path44.join(home, ".cursor/settings.json"));
75641
+ const settings = objectOrNull(path47.join(home, ".cursor/settings.json"));
75453
75642
  const dirs = Array.isArray(settings?.plugin_dirs) ? settings.plugin_dirs : [];
75454
75643
  const registered = mcp?.mcpServers?.workit !== undefined || dirs.some((dir) => String(dir).replaceAll("\\", "/").replace(/\/+$/, "").endsWith("local/workit"));
75455
75644
  if (registered)
@@ -75464,7 +75653,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75464
75653
  if (typeof source !== "string")
75465
75654
  continue;
75466
75655
  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";
75656
+ const local = path47.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path47.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
75468
75657
  if (!npm && !local)
75469
75658
  continue;
75470
75659
  const found = classify("pi", source);
@@ -75484,7 +75673,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75484
75673
  hostCommand("codex", [], { home, env: paths.env });
75485
75674
  available = true;
75486
75675
  } catch {}
75487
- if (available || existsSync20(paths.codexConfig))
75676
+ if (available || existsSync22(paths.codexConfig))
75488
75677
  throw new Error("Codex plugin inventory failed; inspect the native host before upgrading");
75489
75678
  return;
75490
75679
  }
@@ -75506,6 +75695,12 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75506
75695
  installedVersion: plugin.version
75507
75696
  });
75508
75697
  }
75698
+ if (!result.some((found) => found.host === "codex") && codexRegistered(paths.codexConfig))
75699
+ result.push({
75700
+ host: "codex",
75701
+ selector: "@brainervirus/workit-codex",
75702
+ kind: "repair"
75703
+ });
75509
75704
  });
75510
75705
  guard("claude-code", () => {
75511
75706
  for (const install of claudeWorkitInstalls(home, paths.env, null))
@@ -75517,213 +75712,24 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75517
75712
  });
75518
75713
  });
75519
75714
  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
75715
  }, opencodeProbe = (deps, args) => {
75538
- const scratch = mkdtempSync3(path44.join(os16.tmpdir(), "workit-upgrade-opencode-"));
75716
+ const scratch = mkdtempSync3(path47.join(os17.tmpdir(), "workit-upgrade-opencode-"));
75539
75717
  try {
75540
75718
  return runner({
75541
75719
  ...deps,
75542
75720
  env: {
75543
75721
  ...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")
75722
+ XDG_DATA_HOME: path47.join(scratch, "data"),
75723
+ XDG_STATE_HOME: path47.join(scratch, "state"),
75724
+ XDG_CACHE_HOME: path47.join(scratch, "cache")
75547
75725
  }
75548
75726
  })("opencode", args);
75549
75727
  } finally {
75550
75728
  rmSync8(scratch, { recursive: true, force: true });
75551
75729
  }
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
75730
  }, planCli = (plan, run) => {
75725
75731
  const root = run("npm", ["root", "--global"]);
75726
- if (root.status !== 0 || !path44.isAbsolute(root.stdout.trim())) {
75732
+ if (root.status !== 0 || !path47.isAbsolute(root.stdout.trim())) {
75727
75733
  plan.skipped.push({
75728
75734
  host: "cli",
75729
75735
  reason: "global npm location could not be verified",
@@ -75731,9 +75737,9 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75731
75737
  });
75732
75738
  return;
75733
75739
  }
75734
- const packageFile = path44.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
75740
+ const packageFile = path47.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
75735
75741
  const installed = objectOrNull(packageFile);
75736
- if (installed?.name !== "@brainervirus/workit-cli" || lstatSync7(path44.dirname(packageFile)).isSymbolicLink()) {
75742
+ if (installed?.name !== "@brainervirus/workit-cli" || lstatSync7(path47.dirname(packageFile)).isSymbolicLink()) {
75737
75743
  plan.skipped.push({
75738
75744
  host: "cli",
75739
75745
  reason: "no managed global CLI install (local links preserved); use npx @brainervirus/workit-cli@latest"
@@ -75760,7 +75766,18 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75760
75766
  host: "cli",
75761
75767
  reason: `already current (${installed.version})`
75762
75768
  });
75763
- }, pad2 = (text) => text.padEnd(12), summary = (plan, permissions) => {
75769
+ };
75770
+ var init_plan = __esm(() => {
75771
+ init_registration();
75772
+ init_setup_state();
75773
+ init_host_install();
75774
+ init_doctor();
75775
+ init_support_matrix();
75776
+ init_shared();
75777
+ });
75778
+
75779
+ // packages/workit-cli/src/upgrade/report.ts
75780
+ var pad2 = (text) => text.padEnd(12), summary = (plan, permissions) => {
75764
75781
  const lines = ["Workit upgrade plan:"];
75765
75782
  if (plan.cli)
75766
75783
  lines.push(` ${pad2("cli")}update ${plan.cli.installed} -> ${plan.cli.latest}`);
@@ -75797,29 +75814,8 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
75797
75814
  }
75798
75815
  await Promise.resolve().then(() => init_prompt());
75799
75816
  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
- };
75817
+ };
75818
+ var init_report = __esm(() => {
75823
75819
  LABEL = {
75824
75820
  updated: "updated",
75825
75821
  current: "already current",
@@ -75828,6 +75824,191 @@ var init_upgrade = __esm(() => {
75828
75824
  };
75829
75825
  });
75830
75826
 
75827
+ // packages/workit-cli/src/upgrade.ts
75828
+ import { spawnSync as spawnSync17 } from "node:child_process";
75829
+ async function runUpgradeCommand(argv, deps = {}) {
75830
+ const out = deps.out ?? process.stdout;
75831
+ const flags = new Set(argv);
75832
+ const unknown = argv.filter((arg) => !["--apply", "--confirm", "--json", "--cli", "--preview", "--yes"].includes(arg) && !arg.startsWith("--hosts="));
75833
+ const hostFlag = argv.find((arg) => arg.startsWith("--hosts="))?.slice(8);
75834
+ const raw = hostFlag === "none" ? [] : hostFlag?.split(",") ?? HOSTS2;
75835
+ if (unknown.length || raw.some((host) => !HOSTS2.includes(host)) || flags.has("--preview") && (flags.has("--apply") || flags.has("--yes"))) {
75836
+ out.write(USAGE3);
75837
+ return 2;
75838
+ }
75839
+ if (flags.has("--apply") && !flags.has("--confirm")) {
75840
+ out.write(`Apply requires --confirm after reviewing the upgrade preview.
75841
+ `);
75842
+ return 2;
75843
+ }
75844
+ const legacy = flags.has("--apply");
75845
+ const json = flags.has("--json") || legacy;
75846
+ const run = runner(deps);
75847
+ const plan = previewUpgrade(raw, deps);
75848
+ if (hostFlag === undefined || flags.has("--cli"))
75849
+ planCli(plan, run);
75850
+ plan.ok = plan.blocked.length === 0 && plan.failed.length === 0;
75851
+ const { home, env } = upgradePaths(deps);
75852
+ const permissions = planHostPermissions({
75853
+ hosts: raw,
75854
+ refreshOnly: true,
75855
+ shell: false,
75856
+ home,
75857
+ env
75858
+ });
75859
+ const permissionPreview = {
75860
+ changes: permissions.changes.map((c) => ({
75861
+ host: c.host,
75862
+ file: c.file,
75863
+ diff: permissionDiff(c)
75864
+ })),
75865
+ ...permissions.refused ? { refused: permissions.refused } : {}
75866
+ };
75867
+ const withPermissions = (value) => permissions.changes.length ? { ...value, permissions: permissionPreview } : value;
75868
+ const applyCommand = `workit upgrade ${[...hostFlag === undefined ? [] : [`--hosts=${hostFlag}`], ...flags.has("--cli") ? ["--cli"] : [], "--yes"].join(" ")}`;
75869
+ const nothingChanged = `preview only; nothing changed. Apply with: ${applyCommand}
75870
+ `;
75871
+ if (json && !legacy && !flags.has("--yes")) {
75872
+ out.write(JSON.stringify(withPermissions(plan), null, 2) + `
75873
+ `);
75874
+ return plan.blocked.length ? 1 : 0;
75875
+ }
75876
+ if (!json)
75877
+ out.write(summary(plan, permissions.changes));
75878
+ if (flags.has("--preview")) {
75879
+ out.write(nothingChanged);
75880
+ return plan.blocked.length ? 1 : 0;
75881
+ }
75882
+ if (plan.blocked.length) {
75883
+ out.write(`Upgrade blocked: ${plan.blocked.join("; ")}
75884
+ Nothing changed.
75885
+ `);
75886
+ return 1;
75887
+ }
75888
+ const work = plan.entries.length + plan.migrations.length + (plan.cli ? 1 : 0) + permissions.changes.length;
75889
+ if (work > 0 && !flags.has("--yes") && !legacy) {
75890
+ const confirmed = await (deps.confirm ?? ((q) => askConfirm(q, out)))("Apply this upgrade? [y/N] ");
75891
+ if (!confirmed) {
75892
+ out.write(nothingChanged);
75893
+ return 0;
75894
+ }
75895
+ }
75896
+ if (json)
75897
+ for (const warning of plan.warnings ?? [])
75898
+ out.write(`warning: ${warning}
75899
+ `);
75900
+ const result = applyUpgrade(plan, deps);
75901
+ let permissionsOk = true;
75902
+ let written;
75903
+ if (permissions.changes.length && !permissions.refused && !result.error?.startsWith("configuration changed")) {
75904
+ written = applyHostPermissions(permissions, { home, env });
75905
+ permissionsOk = written.every((entry) => entry.status === "written");
75906
+ for (const entry of written)
75907
+ result.hosts.push({
75908
+ host: entry.host,
75909
+ status: entry.status === "written" ? "updated" : "failed",
75910
+ reason: `permission block ${entry.status === "written" ? "refreshed" : entry.status} in ${entry.file}`,
75911
+ ...entry.status === "written" ? {} : { fix: `workit setup --hosts=${entry.host}` }
75912
+ });
75913
+ }
75914
+ const failed = !result.ok || !permissionsOk;
75915
+ const cliVersion = result.hosts.some((h) => h.host === "cli" && h.status === "updated") ? plan.cli.latest : package_default.version;
75916
+ const report = (deps.doctor ?? ((version) => runDoctor({ home, env, cliVersion: version, only: "upgrade" })))(cliVersion);
75917
+ const left = report.checks.filter((check) => check.status === "warn" || check.status === "fail");
75918
+ if (json) {
75919
+ out.write(JSON.stringify({
75920
+ ...result,
75921
+ ok: !failed,
75922
+ ...written ? { permissions: { changes: permissionPreview.changes, written } } : permissions.refused ? { permissions: permissionPreview } : {},
75923
+ doctor: { clean: left.length === 0, left }
75924
+ }, null, 2) + `
75925
+ `);
75926
+ return failed ? 1 : 0;
75927
+ }
75928
+ if (result.error && result.hosts.every((h) => h.status !== "failed"))
75929
+ out.write(`Upgrade stopped: ${result.error}
75930
+ `);
75931
+ out.write(table(result.hosts));
75932
+ if (permissions.refused)
75933
+ out.write(`permissions: not refreshed: ${permissions.refused}
75934
+ `);
75935
+ if (result.backup)
75936
+ out.write(`Backup: ${result.backup}
75937
+ `);
75938
+ out.write(left.length === 0 ? `Verified: workit doctor is clean for versions, assets, agents and permissions.
75939
+ ` : `Left after upgrade (workit doctor):
75940
+ ${left.map((check) => ` ${check.id}: ${check.detail}${check.fix ? `
75941
+ fix: ${check.fix}` : ""}`).join(`
75942
+ `)}
75943
+ `);
75944
+ return failed ? 1 : 0;
75945
+ }
75946
+ async function runLaunchCommand(argv, deps = {}) {
75947
+ const [host, ...args] = argv;
75948
+ if (!LAUNCH_HOSTS.includes(host)) {
75949
+ (deps.out ?? process.stdout).write(`Usage: workit launch <opencode|cursor|codex|pi> [--auto-upgrade] [-- host arguments]
75950
+ `);
75951
+ return 2;
75952
+ }
75953
+ const auto = args[0] === "--auto-upgrade";
75954
+ const rest = auto ? args.slice(1) : args;
75955
+ const hostArgs = rest[0] === "--" ? rest.slice(1) : rest;
75956
+ const { home, env } = upgradePaths(deps);
75957
+ let launch;
75958
+ if (!deps.run) {
75959
+ try {
75960
+ launch = hostCommand(host, hostArgs, { home, env });
75961
+ } catch (error) {
75962
+ (deps.out ?? process.stderr).write(`${error instanceof Error ? error.message : "Host executable unavailable"}
75963
+ `);
75964
+ return 1;
75965
+ }
75966
+ }
75967
+ if (auto) {
75968
+ const plan = previewUpgrade([host], deps);
75969
+ const reasons = [...plan.blocked, ...plan.failed.map((entry) => entry.reason)];
75970
+ if (plan.ok) {
75971
+ for (const skipped of plan.skipped)
75972
+ (deps.out ?? process.stderr).write(`${skipped.host}: ${skipped.reason}${skipped.fix ? ` (run: ${skipped.fix})` : ""}
75973
+ `);
75974
+ const result = applyUpgrade(plan, deps);
75975
+ if (!result.ok) {
75976
+ (deps.out ?? process.stdout).write(`${result.error}
75977
+ `);
75978
+ return 1;
75979
+ }
75980
+ } else if (plan.blocked.length === 0 && reasons.every((reason) => reason.includes("registry version unavailable"))) {
75981
+ (deps.out ?? process.stderr).write(`Upgrade unavailable: ${reasons.join("; ")}. Starting the unchanged host.
75982
+ `);
75983
+ } else {
75984
+ (deps.out ?? process.stderr).write(`Upgrade blocked: ${reasons.join("; ")}
75985
+ `);
75986
+ return 1;
75987
+ }
75988
+ }
75989
+ if (deps.run)
75990
+ return deps.run(host, hostArgs).status ?? 1;
75991
+ return spawnSync17(launch.command, launch.args, {
75992
+ stdio: "inherit",
75993
+ env
75994
+ }).status ?? 1;
75995
+ }
75996
+ var USAGE3 = `Usage: workit upgrade [--hosts=opencode,cursor,codex,pi,claude-code|none] [--cli] [--preview | --yes | --apply --confirm] [--json]
75997
+ `;
75998
+ var init_upgrade = __esm(() => {
75999
+ init_package();
76000
+ init_host_install();
76001
+ init_doctor();
76002
+ init_host_permissions();
76003
+ init_apply();
76004
+ init_plan();
76005
+ init_report();
76006
+ init_shared();
76007
+ init_apply();
76008
+ init_plan();
76009
+ init_processes();
76010
+ });
76011
+
75831
76012
  // packages/workit-cli/src/verbs/upgrade.ts
75832
76013
  var exports_upgrade = {};
75833
76014
  __export(exports_upgrade, {
@@ -75851,7 +76032,7 @@ var init_launch = __esm(() => {
75851
76032
  // packages/workit-core/src/knowledge.ts
75852
76033
  import { spawnSync as spawnSync18 } from "node:child_process";
75853
76034
  import fs20 from "node:fs";
75854
- import path45 from "node:path";
76035
+ import path48 from "node:path";
75855
76036
  function lintKnowledge(root) {
75856
76037
  const seen = new Set;
75857
76038
  const unreadable = [];
@@ -75955,7 +76136,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
75955
76136
  const end = lines.indexOf("---", 1);
75956
76137
  return end === -1 ? lines : [...lines.slice(0, end + 1).map(() => ""), ...lines.slice(end + 1)];
75957
76138
  }, read = (root, file) => {
75958
- const full = path45.join(root, file);
76139
+ const full = path48.join(root, file);
75959
76140
  try {
75960
76141
  fs20.lstatSync(full);
75961
76142
  } catch {
@@ -75996,7 +76177,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
75996
76177
  }
75997
76178
  }, brokenLinks = (root, doc, tracked) => {
75998
76179
  const findings = [];
75999
- const base = path45.dirname(path45.join(root, doc.file));
76180
+ const base = path48.dirname(path48.join(root, doc.file));
76000
76181
  const missing = (target, line, how) => findings.push({
76001
76182
  rule: "broken-link",
76002
76183
  file: doc.file,
@@ -76015,7 +76196,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76015
76196
  const local = localTarget(target);
76016
76197
  if (!local)
76017
76198
  continue;
76018
- const resolved = local.startsWith("/") ? path45.join(root, local) : path45.resolve(base, local);
76199
+ const resolved = local.startsWith("/") ? path48.join(root, local) : path48.resolve(base, local);
76019
76200
  if (!exists2(resolved))
76020
76201
  missing(target, index + 1, "link");
76021
76202
  }
@@ -76025,9 +76206,9 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
76025
76206
  continue;
76026
76207
  const relative = /^\.\.?\//.test(candidate);
76027
76208
  const first = candidate.split("/")[0];
76028
- if (!relative && !(tracked ? tracked.has(first) : exists2(path45.join(root, first))))
76209
+ if (!relative && !(tracked ? tracked.has(first) : exists2(path48.join(root, first))))
76029
76210
  continue;
76030
- const resolved = relative ? path45.resolve(base, candidate) : path45.join(root, candidate);
76211
+ const resolved = relative ? path48.resolve(base, candidate) : path48.join(root, candidate);
76031
76212
  if (!exists2(resolved))
76032
76213
  missing(span, index + 1, "pointer");
76033
76214
  }
@@ -76350,10 +76531,10 @@ var init_redact = __esm(() => {
76350
76531
 
76351
76532
  // packages/workit-core/src/checks.ts
76352
76533
  import { spawn, spawnSync as spawnSync19 } from "node:child_process";
76353
- import { createHash as createHash16 } from "node:crypto";
76534
+ import { createHash as createHash17 } from "node:crypto";
76354
76535
  import fs21 from "node:fs";
76355
- import os17 from "node:os";
76356
- import path46 from "node:path";
76536
+ import os18 from "node:os";
76537
+ import path49 from "node:path";
76357
76538
  import { StringDecoder } from "node:string_decoder";
76358
76539
  function tailLines(text, lines = TAIL_LINES) {
76359
76540
  const all = text.replace(/\r\n?/gu, `
@@ -76473,7 +76654,7 @@ function planSpawn(argv, options) {
76473
76654
  return { file: argv[0], args: [], verbatim: false, shell: true };
76474
76655
  if (options.platform !== "win32")
76475
76656
  return { file: argv[0], args: argv.slice(1), verbatim: false, shell: false };
76476
- const win = path46.win32;
76657
+ const win = path49.win32;
76477
76658
  const isFile = options.isFile ?? ((file) => {
76478
76659
  try {
76479
76660
  return fs21.statSync(file).isFile();
@@ -76558,7 +76739,7 @@ function runCheckCommand(argv, options) {
76558
76739
  `);
76559
76740
  redactor.end();
76560
76741
  resolve({
76561
- exitCode: spawnError ? 127 : code !== null ? code : 128 + (signal ? os17.constants.signals[signal] ?? 1 : 1),
76742
+ exitCode: spawnError ? 127 : code !== null ? code : 128 + (signal ? os18.constants.signals[signal] ?? 1 : 1),
76562
76743
  signal: signal ?? null,
76563
76744
  timedOut,
76564
76745
  durationMs: Date.now() - started,
@@ -76635,10 +76816,10 @@ function runCheckCommand(argv, options) {
76635
76816
  function storeLog(storeRoot, log) {
76636
76817
  const digest = logDigest(log);
76637
76818
  const ref = `blobs/logs/${digest.slice("sha256:".length)}.log`;
76638
- const file = path46.join(storeRoot, ref);
76819
+ const file = path49.join(storeRoot, ref);
76639
76820
  try {
76640
76821
  if (!fs21.existsSync(file)) {
76641
- fs21.mkdirSync(path46.dirname(file), { recursive: true });
76822
+ fs21.mkdirSync(path49.dirname(file), { recursive: true });
76642
76823
  const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
76643
76824
  fs21.writeFileSync(temp, log, { mode: 384 });
76644
76825
  fs21.renameSync(temp, file);
@@ -76651,7 +76832,7 @@ function storeLog(storeRoot, log) {
76651
76832
  function pruneCheckLogs(storeRoot, options = {}) {
76652
76833
  const limits = { ...LOG_RETENTION, ...options.retention };
76653
76834
  const now = options.now ?? Date.now();
76654
- const dir = path46.join(storeRoot, "blobs", "logs");
76835
+ const dir = path49.join(storeRoot, "blobs", "logs");
76655
76836
  const report = { removed: 0, removedBytes: 0, kept: 0 };
76656
76837
  let names;
76657
76838
  try {
@@ -76661,7 +76842,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
76661
76842
  }
76662
76843
  const files = names.flatMap((name) => {
76663
76844
  try {
76664
- const stat = fs21.statSync(path46.join(dir, name));
76845
+ const stat = fs21.statSync(path49.join(dir, name));
76665
76846
  return stat.isFile() ? [{ name, size: stat.size, mtimeMs: stat.mtimeMs }] : [];
76666
76847
  } catch {
76667
76848
  return [];
@@ -76680,7 +76861,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
76680
76861
  continue;
76681
76862
  if (!options.dryRun)
76682
76863
  try {
76683
- fs21.rmSync(path46.join(dir, file.name), { force: true });
76864
+ fs21.rmSync(path49.join(dir, file.name), { force: true });
76684
76865
  } catch {
76685
76866
  continue;
76686
76867
  }
@@ -76689,7 +76870,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
76689
76870
  }
76690
76871
  return report;
76691
76872
  }
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;
76873
+ 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
76874
  var init_checks3 = __esm(() => {
76694
76875
  init_redact();
76695
76876
  MAX_LOG_BYTES = 2 * 1024 * 1024;
@@ -76953,7 +77134,7 @@ __export(exports_workspace, {
76953
77134
  run: () => run11,
76954
77135
  runWorkspace: () => runWorkspace
76955
77136
  });
76956
- import { copyFileSync as copyFileSync7, existsSync as existsSync21 } from "node:fs";
77137
+ import { copyFileSync as copyFileSync7, existsSync as existsSync23 } from "node:fs";
76957
77138
  function list2(argv, io) {
76958
77139
  if (argv.length)
76959
77140
  return usage3(io, `unexpected argument ${argv[0]}`);
@@ -77163,7 +77344,7 @@ usage: ${USAGE5}`)), load = (io) => {
77163
77344
  return { ok: false, error: `${current.path} changed; retry` };
77164
77345
  let backup = null;
77165
77346
  try {
77166
- if (existsSync21(current.path)) {
77347
+ if (existsSync23(current.path)) {
77167
77348
  backup = `${current.path}.bak`;
77168
77349
  copyFileSync7(current.path, backup);
77169
77350
  }
@@ -77231,12 +77412,12 @@ var init_workspace = __esm(() => {
77231
77412
 
77232
77413
  // packages/workit-core/src/core/heavy-rules.ts
77233
77414
  import fs22 from "node:fs";
77234
- import path47 from "node:path";
77415
+ import path50 from "node:path";
77235
77416
  function gitTop(cwd) {
77236
- for (let dir = path47.resolve(cwd);; dir = path47.dirname(dir)) {
77237
- if (fs22.existsSync(path47.join(dir, ".git")))
77417
+ for (let dir = path50.resolve(cwd);; dir = path50.dirname(dir)) {
77418
+ if (fs22.existsSync(path50.join(dir, ".git")))
77238
77419
  return dir;
77239
- if (path47.dirname(dir) === dir)
77420
+ if (path50.dirname(dir) === dir)
77240
77421
  return null;
77241
77422
  }
77242
77423
  }
@@ -77277,19 +77458,19 @@ var init_heavy_rules = () => {};
77277
77458
 
77278
77459
  // packages/workit-core/src/core/heavy.ts
77279
77460
  import fs23 from "node:fs";
77280
- import os18 from "node:os";
77281
- import path48 from "node:path";
77461
+ import os19 from "node:os";
77462
+ import path51 from "node:path";
77282
77463
  function stateDir2(env, platform = process.platform) {
77283
77464
  if (env.WORKFLOW_TOOLKIT_STATE)
77284
77465
  return env.WORKFLOW_TOOLKIT_STATE;
77285
77466
  if (env.XDG_STATE_HOME)
77286
- return path48.join(env.XDG_STATE_HOME, "workit");
77287
- const home = env.HOME || os18.homedir();
77467
+ return path51.join(env.XDG_STATE_HOME, "workit");
77468
+ const home = env.HOME || os19.homedir();
77288
77469
  if (platform === "darwin")
77289
- return path48.join(home, "Library", "Application Support", "workit");
77470
+ return path51.join(home, "Library", "Application Support", "workit");
77290
77471
  if (platform === "win32")
77291
- return path48.join(env.LOCALAPPDATA ?? path48.join(home, "AppData", "Local"), "workit");
77292
- return path48.join(home, ".local", "state", "workit");
77472
+ return path51.join(env.LOCALAPPDATA ?? path51.join(home, "AppData", "Local"), "workit");
77473
+ return path51.join(home, ".local", "state", "workit");
77293
77474
  }
77294
77475
  function positional(words, from, values = PM_VALUES) {
77295
77476
  let index = from;
@@ -77429,7 +77610,7 @@ function machinePatterns(env) {
77429
77610
  return isRecord8(value) ? stringList2(value.patterns) : [];
77430
77611
  }
77431
77612
  function repoPatterns(cwd) {
77432
- return repoHeavyCommands(gitTop(cwd) ?? path48.resolve(cwd));
77613
+ return repoHeavyCommands(gitTop(cwd) ?? path51.resolve(cwd));
77433
77614
  }
77434
77615
  function heavyLines(lines, options) {
77435
77616
  const found = [];
@@ -77508,7 +77689,7 @@ function leaseRewrite(command) {
77508
77689
  return null;
77509
77690
  return `${prefix}workit check --heavy -- ${rest}`;
77510
77691
  }
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) => {
77692
+ 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
77693
  try {
77513
77694
  return JSON.parse(fs23.readFileSync(file, "utf8"));
77514
77695
  } catch {
@@ -77654,8 +77835,8 @@ var init_heavy = __esm(() => {
77654
77835
  // packages/workit-core/src/core/resources.ts
77655
77836
  import { randomUUID as randomUUID5 } from "node:crypto";
77656
77837
  import fs24 from "node:fs";
77657
- import os19 from "node:os";
77658
- import path49 from "node:path";
77838
+ import os20 from "node:os";
77839
+ import path52 from "node:path";
77659
77840
  function memoryValue(value, host) {
77660
77841
  const text = typeof value === "number" ? String(value) : typeof value === "string" ? value : "";
77661
77842
  const percent = PERCENT.exec(text.trim());
@@ -77836,7 +78017,7 @@ function tryOnce(options, record, reclaimed) {
77836
78017
  const text = `${JSON.stringify(record)}
77837
78018
  `;
77838
78019
  for (let slot = 0;slot < options.slots; slot += 1) {
77839
- const file = path49.join(options.dir, `slot-${slot}.json`);
78020
+ const file = path52.join(options.dir, `slot-${slot}.json`);
77840
78021
  for (let attempt = 0;attempt < 2; attempt += 1) {
77841
78022
  try {
77842
78023
  const fd = fs24.openSync(file, "wx", 384);
@@ -77961,7 +78142,7 @@ function heldLease(dir, id, options = {}) {
77961
78142
  for (const name of names) {
77962
78143
  if (!/^slot-\d+\.json$/u.test(name))
77963
78144
  continue;
77964
- const lease = parseLease(readText5(path49.join(dir, name)));
78145
+ const lease = parseLease(readText5(path52.join(dir, name)));
77965
78146
  if (lease?.id === id && !staleReason(lease, options.probe) && (options.ancestor ?? isAncestor)(lease.pid))
77966
78147
  return lease;
77967
78148
  }
@@ -78016,10 +78197,10 @@ async function runScoped(run, wrapper, sinks) {
78016
78197
  }
78017
78198
  function firstNotice(env, session, key, now = Date.now()) {
78018
78199
  const id = (session ?? `ppid-${process.ppid}`).replace(/[^A-Za-z0-9_.-]/gu, "_").slice(0, 120);
78019
- const dir = path49.join(stateDir2(env), "notices");
78200
+ const dir = path52.join(stateDir2(env), "notices");
78020
78201
  try {
78021
78202
  fs24.mkdirSync(dir, { recursive: true, mode: 448 });
78022
- fs24.writeFileSync(path49.join(dir, `${key}-${id}`), `${new Date(now).toISOString()}
78203
+ fs24.writeFileSync(path52.join(dir, `${key}-${id}`), `${new Date(now).toISOString()}
78023
78204
  `, {
78024
78205
  flag: "wx",
78025
78206
  mode: 384
@@ -78029,7 +78210,7 @@ function firstNotice(env, session, key, now = Date.now()) {
78029
78210
  }
78030
78211
  try {
78031
78212
  for (const name of fs24.readdirSync(dir)) {
78032
- const file = path49.join(dir, name);
78213
+ const file = path52.join(dir, name);
78033
78214
  if (now - fs24.statSync(file).mtimeMs > NOTICE_TTL_MS)
78034
78215
  fs24.rmSync(file, { force: true });
78035
78216
  }
@@ -78039,7 +78220,7 @@ function firstNotice(env, session, key, now = Date.now()) {
78039
78220
  function leaseSlots(dir, slots, probe = {}) {
78040
78221
  const states = [];
78041
78222
  for (let slot = 0;slot < slots; slot += 1) {
78042
- const lease = parseLease(readText5(path49.join(dir, `slot-${slot}.json`)));
78223
+ const lease = parseLease(readText5(path52.join(dir, `slot-${slot}.json`)));
78043
78224
  states.push({
78044
78225
  slot,
78045
78226
  holder: lease ? holderOf(lease) : null,
@@ -78049,15 +78230,15 @@ function leaseSlots(dir, slots, probe = {}) {
78049
78230
  return states;
78050
78231
  }
78051
78232
  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) => {
78233
+ totalMemBytes: os20.totalmem(),
78234
+ cpus: Math.max(1, os20.availableParallelism?.() ?? os20.cpus().length)
78235
+ }), isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SIZE, PERCENT, UNITS, leaseDir = (env) => path52.join(stateDir2(env), "leases"), readText5 = (file) => {
78055
78236
  try {
78056
78237
  return fs24.readFileSync(file, "utf8");
78057
78238
  } catch {
78058
78239
  return null;
78059
78240
  }
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) => {
78241
+ }, 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
78242
  const stat = readText5(`/proc/${pid}/stat`);
78062
78243
  return stat ? stat.slice(stat.lastIndexOf(")") + 2).split(" ") : null;
78063
78244
  }, processStart = (pid) => statFields(pid)?.[19] ?? null, pidAlive2 = (pid) => {
@@ -78106,8 +78287,8 @@ __export(exports_check, {
78106
78287
  run: () => run12,
78107
78288
  workspaceResources: () => workspaceResources
78108
78289
  });
78109
- import os20 from "node:os";
78110
- import path50 from "node:path";
78290
+ import os21 from "node:os";
78291
+ import path53 from "node:path";
78111
78292
  function parse6(argv) {
78112
78293
  const split = argv.indexOf("--");
78113
78294
  const head = split >= 0 ? argv.slice(0, split) : [...argv];
@@ -78309,7 +78490,7 @@ function hostToolWaitCapMs(env) {
78309
78490
  }
78310
78491
  async function workspaceResources(io) {
78311
78492
  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");
78493
+ 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
78494
  try {
78314
78495
  await Promise.resolve().then(() => init_workspaces());
78315
78496
  const workspace = resolveWorkspaceFrom(io.cwd, dir, env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined);
@@ -78428,7 +78609,7 @@ async function run12(argv, io) {
78428
78609
  if (options.shell && command.length !== 1)
78429
78610
  return emit(io, fail2("invalid_input", '--shell takes the command as one string: workit check --shell -- "<cmd>"'));
78430
78611
  }
78431
- const relCwd = posix(path50.relative(top, runCwd));
78612
+ const relCwd = posix(path53.relative(top, runCwd));
78432
78613
  const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
78433
78614
  const shadowed = !configured && name !== null ? config.checks.find((item) => item.name === name) : undefined;
78434
78615
  if (shadowed)
@@ -78490,7 +78671,7 @@ async function run12(argv, io) {
78490
78671
  const modifiedWorktree = key.tree !== null && treeAfter !== key.tree;
78491
78672
  const store = storeRoot(io.cwd);
78492
78673
  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;
78674
+ const logPath = store.ok && blob ? path53.join(store.value.root, blob.ref) : null;
78494
78675
  const tail = tailLines(result.log, TAIL_LINES);
78495
78676
  const passed = result.exitCode === 0 && !result.timedOut;
78496
78677
  const bounded = boundedArgv(command);
@@ -78605,7 +78786,7 @@ async function run12(argv, io) {
78605
78786
  return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
78606
78787
  return 0;
78607
78788
  }
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;
78789
+ 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
78790
  var init_check = __esm(() => {
78610
78791
  init_check_config();
78611
78792
  init_checks3();
@@ -78634,7 +78815,7 @@ __export(exports_lock, {
78634
78815
  run: () => run13
78635
78816
  });
78636
78817
  import fs25 from "node:fs";
78637
- import path51 from "node:path";
78818
+ import path54 from "node:path";
78638
78819
  async function settingsFor(io) {
78639
78820
  const workspace = await workspaceResources(io);
78640
78821
  const config = loadCheckConfig(io.cwd);
@@ -78716,7 +78897,7 @@ function readPatterns(file) {
78716
78897
  return { patterns: [] };
78717
78898
  }
78718
78899
  function writePatterns(file, value) {
78719
- fs25.mkdirSync(path51.dirname(file), { recursive: true, mode: 448 });
78900
+ fs25.mkdirSync(path54.dirname(file), { recursive: true, mode: 448 });
78720
78901
  const temp = `${file}.${process.pid}.tmp`;
78721
78902
  fs25.writeFileSync(temp, `${JSON.stringify(value, null, 2)}
78722
78903
  `, { mode: 384 });
@@ -78802,9 +78983,9 @@ var exports_models = {};
78802
78983
  __export(exports_models, {
78803
78984
  run: () => run14
78804
78985
  });
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";
78986
+ import { existsSync as existsSync24, readdirSync as readdirSync13, readFileSync as readFileSync24, statSync as statSync9 } from "node:fs";
78987
+ import os22 from "node:os";
78988
+ import path55 from "node:path";
78808
78989
  async function run14(argv, io) {
78809
78990
  const [sub, ...args] = argv.filter((arg) => arg !== "--json");
78810
78991
  if (sub !== "show")
@@ -78865,7 +79046,7 @@ var USAGE8 = "workit models show [--role <role>] [--tier <tier>] [--host <host>]
78865
79046
  const found = new Set;
78866
79047
  let text = "";
78867
79048
  try {
78868
- text = readFileSync22(file, "utf8");
79049
+ text = readFileSync24(file, "utf8");
78869
79050
  } catch {
78870
79051
  return found;
78871
79052
  }
@@ -78879,26 +79060,26 @@ var USAGE8 = "workit models show [--role <role>] [--tier <tier>] [--host <host>]
78879
79060
  } catch {}
78880
79061
  return found;
78881
79062
  }, 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");
79063
+ const projects = path55.join(env.CLAUDE_CONFIG_DIR || path55.join(env.HOME || os22.homedir(), ".claude"), "projects");
78883
79064
  const since = Date.now() - days * 86400000;
78884
79065
  const types = {};
78885
79066
  let agents = 0;
78886
79067
  const dirs = (dir) => {
78887
79068
  try {
78888
- return readdirSync13(dir).map((name) => path52.join(dir, name));
79069
+ return readdirSync13(dir).map((name) => path55.join(dir, name));
78889
79070
  } catch {
78890
79071
  return [];
78891
79072
  }
78892
79073
  };
78893
79074
  for (const project of dirs(projects))
78894
79075
  for (const session of dirs(project))
78895
- for (const meta of dirs(path52.join(session, "subagents")).filter((f) => f.endsWith(".meta.json"))) {
79076
+ for (const meta of dirs(path55.join(session, "subagents")).filter((f) => f.endsWith(".meta.json"))) {
78896
79077
  try {
78897
79078
  if (statSync9(meta).mtimeMs < since)
78898
79079
  continue;
78899
- const agentType = JSON.parse(readFileSync22(meta, "utf8")).agentType;
79080
+ const agentType = JSON.parse(readFileSync24(meta, "utf8")).agentType;
78900
79081
  const transcript = meta.replace(/\.meta\.json$/, ".jsonl");
78901
- if (typeof agentType !== "string" || !existsSync22(transcript))
79082
+ if (typeof agentType !== "string" || !existsSync24(transcript))
78902
79083
  continue;
78903
79084
  const ran = modelsOf(transcript);
78904
79085
  if (!ran.size)
@@ -79037,8 +79218,8 @@ var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock)
79037
79218
 
79038
79219
  // packages/workit-core/src/git/ops.ts
79039
79220
  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";
79221
+ import { existsSync as existsSync25, readFileSync as readFileSync25 } from "node:fs";
79222
+ import path56 from "node:path";
79042
79223
  function operationInProgress(cwd) {
79043
79224
  const markers = [
79044
79225
  ["rebase-merge", "rebase"],
@@ -79051,18 +79232,18 @@ function operationInProgress(cwd) {
79051
79232
  if (!run.ok)
79052
79233
  return null;
79053
79234
  const found = run.stdout.split(`
79054
- `).map((line) => path53.resolve(cwd, line.trim()));
79235
+ `).map((line) => path56.resolve(cwd, line.trim()));
79055
79236
  const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
79056
79237
  for (const [index, [, operation]] of markers.entries()) {
79057
79238
  const marker = found[index];
79058
- if (!marker || !existsSync23(marker))
79239
+ if (!marker || !existsSync25(marker))
79059
79240
  continue;
79060
- if (index === 1 && existsSync23(path53.join(marker, "applying")))
79241
+ if (index === 1 && existsSync25(path56.join(marker, "applying")))
79061
79242
  return { operation: "am", commitAllowed: false, branch: null };
79062
- if (index === 0 && existsSync23(path53.join(marker, "amend")) && !conflicted()) {
79243
+ if (index === 0 && existsSync25(path56.join(marker, "amend")) && !conflicted()) {
79063
79244
  let headName = "";
79064
79245
  try {
79065
- headName = readFileSync23(path53.join(marker, "head-name"), "utf8").trim();
79246
+ headName = readFileSync25(path56.join(marker, "head-name"), "utf8").trim();
79066
79247
  } catch {}
79067
79248
  const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
79068
79249
  return { operation, commitAllowed: branch !== null, branch };
@@ -79390,7 +79571,7 @@ function gitCommit(cwd, input) {
79390
79571
  if (paths.some((value) => value.startsWith("-") || !value.trim()))
79391
79572
  return failure3("invalid_input", "paths must not be empty or start with -");
79392
79573
  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}/`)));
79574
+ const addable = paths.filter((value) => existsSync25(path56.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
79394
79575
  if (addable.length) {
79395
79576
  const added = git5(cwd, ["add", "-A", "--", ...addable]);
79396
79577
  if (!added.ok)
@@ -79929,12 +80110,12 @@ var init_ops = __esm(() => {
79929
80110
 
79930
80111
  // packages/workit-core/src/verdict-cover.ts
79931
80112
  import fs26 from "node:fs";
79932
- import path54 from "node:path";
80113
+ import path57 from "node:path";
79933
80114
  function chainsAbove(cwd, branch) {
79934
80115
  const root = storeRoot(cwd);
79935
80116
  if (!root.ok)
79936
80117
  return [];
79937
- const dir = path54.join(root.value.root, "stacks");
80118
+ const dir = path57.join(root.value.root, "stacks");
79938
80119
  let names = [];
79939
80120
  try {
79940
80121
  names = fs26.readdirSync(dir).filter((name) => name.endsWith(".json"));
@@ -79945,7 +80126,7 @@ function chainsAbove(cwd, branch) {
79945
80126
  for (const name of names.toSorted()) {
79946
80127
  let parsed;
79947
80128
  try {
79948
- parsed = JSON.parse(fs26.readFileSync(path54.join(dir, name), "utf8"));
80129
+ parsed = JSON.parse(fs26.readFileSync(path57.join(dir, name), "utf8"));
79949
80130
  } catch {
79950
80131
  continue;
79951
80132
  }
@@ -80040,10 +80221,10 @@ var init_pr_lane = __esm(() => {
80040
80221
 
80041
80222
  // packages/workit-core/src/forge/reruns.ts
80042
80223
  import fs27 from "node:fs";
80043
- import path55 from "node:path";
80224
+ import path58 from "node:path";
80044
80225
  function rerunLogPath(cwd) {
80045
80226
  const common = gitCommonDir(cwd);
80046
- return common ? path55.join(common, "workit", "ci-reruns.jsonl") : null;
80227
+ return common ? path58.join(common, "workit", "ci-reruns.jsonl") : null;
80047
80228
  }
80048
80229
  function rerunCounts(cwd, key) {
80049
80230
  const counts = new Map;
@@ -80078,7 +80259,7 @@ function recordReruns(cwd, rows) {
80078
80259
  if (!file)
80079
80260
  return false;
80080
80261
  try {
80081
- fs27.mkdirSync(path55.dirname(file), { recursive: true });
80262
+ fs27.mkdirSync(path58.dirname(file), { recursive: true });
80082
80263
  fs27.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
80083
80264
  `).join(""));
80084
80265
  return true;
@@ -80091,7 +80272,7 @@ function withRerunLock(cwd, fn) {
80091
80272
  if (!file)
80092
80273
  return fn();
80093
80274
  const lock = `${file.slice(0, -".jsonl".length)}.lock`;
80094
- fs27.mkdirSync(path55.dirname(lock), { recursive: true });
80275
+ fs27.mkdirSync(path58.dirname(lock), { recursive: true });
80095
80276
  const until = Date.now() + LOCK_WAIT_MS2;
80096
80277
  for (;; ) {
80097
80278
  try {
@@ -80508,7 +80689,7 @@ function recordAccepted(cwd, resolved, status, accepted, options) {
80508
80689
  return recordReruns(cwd, rows);
80509
80690
  }
80510
80691
  var MAX_LOG_TAILS = 5, GITLAB_MERGEABLE, GITHUB_MERGEABLE, NO_CHECKS_GRACE_MS = 90000;
80511
- var init_report = __esm(() => {
80692
+ var init_report2 = __esm(() => {
80512
80693
  init_rev();
80513
80694
  init_ledger();
80514
80695
  init_reruns();
@@ -81057,7 +81238,7 @@ var init_pr_ops = __esm(() => {
81057
81238
  init_ledger();
81058
81239
  init_verdict_cover();
81059
81240
  init_pr_lane();
81060
- init_report();
81241
+ init_report2();
81061
81242
  VERIFY_DELAYS_MS = [1000, 2000, 4000];
81062
81243
  AFTER_REVIEW = {
81063
81244
  commit: "stop here; review comes when the user asks",
@@ -81070,9 +81251,9 @@ var init_pr_ops = __esm(() => {
81070
81251
 
81071
81252
  // packages/workit-core/src/stack.ts
81072
81253
  import { spawnSync as spawnSync22 } from "node:child_process";
81073
- import { createHash as createHash17, randomBytes as randomBytes4 } from "node:crypto";
81254
+ import { createHash as createHash18, randomBytes as randomBytes4 } from "node:crypto";
81074
81255
  import fs28 from "node:fs";
81075
- import path56 from "node:path";
81256
+ import path59 from "node:path";
81076
81257
  function worktreeOf(cwd, branch) {
81077
81258
  const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
81078
81259
  if (!list.ok)
@@ -81121,7 +81302,7 @@ function gitRestack(cwd, input) {
81121
81302
  error: "no store root"
81122
81303
  };
81123
81304
  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")}`);
81305
+ dir = path59.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
81125
81306
  const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
81126
81307
  if (!added.ok)
81127
81308
  return {
@@ -81177,7 +81358,7 @@ function pruneScratch(cwd) {
81177
81358
  if (!scratch || !fs28.existsSync(scratch))
81178
81359
  return;
81179
81360
  for (const name of fs28.readdirSync(scratch)) {
81180
- const dir = path56.join(scratch, name);
81361
+ const dir = path59.join(scratch, name);
81181
81362
  if (!rebaseInProgress(dir) && !trackedDirt(dir))
81182
81363
  gitRun3(cwd, ["worktree", "remove", "--force", dir]);
81183
81364
  }
@@ -81187,7 +81368,7 @@ function stacksDir(cwd) {
81187
81368
  const root = storeRoot(cwd);
81188
81369
  if (!root.ok)
81189
81370
  return stackFail(root.code, root.error, root.unblock);
81190
- return { ok: true, data: path56.join(root.value.root, "stacks") };
81371
+ return { ok: true, data: path59.join(root.value.root, "stacks") };
81191
81372
  }
81192
81373
  function parseStack(raw) {
81193
81374
  if (!isRecord12(raw) || !Array.isArray(raw.branches))
@@ -81239,7 +81420,7 @@ function readStack(cwd, name) {
81239
81420
  const dir = stacksDir(cwd);
81240
81421
  if (!dir.ok)
81241
81422
  return dir;
81242
- const file = path56.join(dir.data, fileFor(name));
81423
+ const file = path59.join(dir.data, fileFor(name));
81243
81424
  let text;
81244
81425
  try {
81245
81426
  text = fs28.readFileSync(file, "utf8");
@@ -81260,7 +81441,7 @@ function writeStack(cwd, stack, now = new Date) {
81260
81441
  const dir = stacksDir(cwd);
81261
81442
  if (!dir.ok)
81262
81443
  return dir;
81263
- const file = path56.join(dir.data, fileFor(stack.name));
81444
+ const file = path59.join(dir.data, fileFor(stack.name));
81264
81445
  const temp = `${file}.${process.pid}.tmp`;
81265
81446
  try {
81266
81447
  fs28.mkdirSync(dir.data, { recursive: true });
@@ -81288,7 +81469,7 @@ function listStacks(cwd) {
81288
81469
  for (const name of names) {
81289
81470
  let parsed = null;
81290
81471
  try {
81291
- parsed = parseStack(JSON.parse(fs28.readFileSync(path56.join(dir.data, name), "utf8")));
81472
+ parsed = parseStack(JSON.parse(fs28.readFileSync(path59.join(dir.data, name), "utf8")));
81292
81473
  } catch {
81293
81474
  parsed = null;
81294
81475
  }
@@ -81350,7 +81531,7 @@ function takeLock(lock) {
81350
81531
  host: localLockHost(),
81351
81532
  nonce: randomBytes4(8).toString("hex")
81352
81533
  };
81353
- fs28.writeFileSync(path56.join(lock, OWNER), JSON.stringify(owner));
81534
+ fs28.writeFileSync(path59.join(lock, OWNER), JSON.stringify(owner));
81354
81535
  return owner;
81355
81536
  }
81356
81537
  function reapLock(lock, observed) {
@@ -81387,7 +81568,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
81387
81568
  return dir;
81388
81569
  if (!validName(name))
81389
81570
  return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
81390
- const lock = path56.join(dir.data, `${fileFor(name)}.lock`);
81571
+ const lock = path59.join(dir.data, `${fileFor(name)}.lock`);
81391
81572
  try {
81392
81573
  fs28.mkdirSync(dir.data, { recursive: true });
81393
81574
  } catch (error) {
@@ -81417,7 +81598,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
81417
81598
  const touch = () => {
81418
81599
  try {
81419
81600
  const now = new Date;
81420
- fs28.utimesSync(path56.join(lock, OWNER), now, now);
81601
+ fs28.utimesSync(path59.join(lock, OWNER), now, now);
81421
81602
  } catch {}
81422
81603
  };
81423
81604
  const beat = setInterval(touch, HEARTBEAT_MS);
@@ -82318,10 +82499,10 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
82318
82499
  return !status.ok || status.stdout.trim() !== "";
82319
82500
  }, scratchDir = (cwd) => {
82320
82501
  const dir = stacksDir(cwd);
82321
- return dir.ok ? path56.join(dir.data, "worktrees") : null;
82502
+ return dir.ok ? path59.join(dir.data, "worktrees") : null;
82322
82503
  }, firstLine = (run) => (`${run.stderr}
82323
82504
  ${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) => {
82505
+ `).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
82506
  if (name.length === 0 || name.length > 200)
82326
82507
  return false;
82327
82508
  for (let index = 0;index < name.length; index += 1) {
@@ -82333,12 +82514,12 @@ ${run.stdout}`.split(`
82333
82514
  }, 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
82515
  let raw = null;
82335
82516
  try {
82336
- raw = fs28.readFileSync(path56.join(lock, OWNER), "utf8");
82517
+ raw = fs28.readFileSync(path59.join(lock, OWNER), "utf8");
82337
82518
  } catch {
82338
82519
  raw = null;
82339
82520
  }
82340
82521
  let age = null;
82341
- for (const target of [path56.join(lock, OWNER), lock])
82522
+ for (const target of [path59.join(lock, OWNER), lock])
82342
82523
  try {
82343
82524
  age = Date.now() - fs28.statSync(target).mtimeMs;
82344
82525
  break;
@@ -82362,7 +82543,7 @@ var init_stack = __esm(() => {
82362
82543
  init_autonomy();
82363
82544
  init_store_lock();
82364
82545
  init_pr_ops();
82365
- init_report();
82546
+ init_report2();
82366
82547
  init_ops();
82367
82548
  init_rev();
82368
82549
  init_ledger();
@@ -82379,9 +82560,9 @@ var init_stack = __esm(() => {
82379
82560
 
82380
82561
  // packages/workit-core/src/fanout.ts
82381
82562
  import { spawnSync as spawnSync23 } from "node:child_process";
82382
- import { createHash as createHash18 } from "node:crypto";
82563
+ import { createHash as createHash19 } from "node:crypto";
82383
82564
  import fs29 from "node:fs";
82384
- import path57 from "node:path";
82565
+ import path60 from "node:path";
82385
82566
  function expandBraces2(pattern, limit = 64) {
82386
82567
  for (let index = 0;index < pattern.length; index += 1) {
82387
82568
  if (pattern[index] === "\\") {
@@ -82627,7 +82808,7 @@ function parsePlan(raw, defaults, name) {
82627
82808
  id,
82628
82809
  branch,
82629
82810
  base: optional("base") ?? "",
82630
- worktree: path57.resolve(defaults.root, optional("worktree") ?? path57.join(defaults.worktreeRoot, id)),
82811
+ worktree: path60.resolve(defaults.root, optional("worktree") ?? path60.join(defaults.worktreeRoot, id)),
82631
82812
  tier,
82632
82813
  reason,
82633
82814
  dependsOn: [...new Set(dependsOn ?? [])],
@@ -82756,12 +82937,12 @@ function regeneratedFiles(root, tracked) {
82756
82937
  const found = new Map;
82757
82938
  let scripts;
82758
82939
  try {
82759
- const manifest = JSON.parse(fs29.readFileSync(path57.join(root, "package.json"), "utf8"));
82940
+ const manifest = JSON.parse(fs29.readFileSync(path60.join(root, "package.json"), "utf8"));
82760
82941
  scripts = manifest.scripts ?? {};
82761
82942
  } catch {
82762
82943
  return found;
82763
82944
  }
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";
82945
+ 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
82946
  const outputs = tracked.filter((file) => !CODE.test(file));
82766
82947
  for (const [name, command] of Object.entries(scripts)) {
82767
82948
  if (!name.startsWith("write:") || typeof command !== "string")
@@ -82769,7 +82950,7 @@ function regeneratedFiles(root, tracked) {
82769
82950
  for (const file of command.match(/[\w./-]+\.[cm]?[jt]s\b/gu) ?? []) {
82770
82951
  let source;
82771
82952
  try {
82772
- source = fs29.readFileSync(path57.join(root, file), "utf8");
82953
+ source = fs29.readFileSync(path60.join(root, file), "utf8");
82773
82954
  } catch {
82774
82955
  continue;
82775
82956
  }
@@ -82891,11 +83072,11 @@ function defaultTrunk(cwd) {
82891
83072
  }
82892
83073
  function mainCheckout(cwd) {
82893
83074
  const common = gitCommonDir(cwd);
82894
- return common && path57.basename(common) === ".git" ? path57.dirname(common) : path57.resolve(cwd);
83075
+ return common && path60.basename(common) === ".git" ? path60.dirname(common) : path60.resolve(cwd);
82895
83076
  }
82896
83077
  function worktreeRoot(cwd) {
82897
83078
  const main = mainCheckout(cwd);
82898
- return path57.join(path57.dirname(main), `${path57.basename(main)}-wt`);
83079
+ return path60.join(path60.dirname(main), `${path60.basename(main)}-wt`);
82899
83080
  }
82900
83081
  function sliceHash(slice) {
82901
83082
  const {
@@ -82909,13 +83090,13 @@ function sliceHash(slice) {
82909
83090
  issues: _issues,
82910
83091
  ...definition
82911
83092
  } = slice;
82912
- return createHash18("sha256").update(JSON.stringify(definition)).digest("hex").slice(0, 16);
83093
+ return createHash19("sha256").update(JSON.stringify(definition)).digest("hex").slice(0, 16);
82913
83094
  }
82914
83095
  function fanoutsDir(cwd) {
82915
83096
  const root = storeRoot(cwd);
82916
83097
  if (!root.ok)
82917
83098
  return fanoutFail(root.code, root.error, root.unblock);
82918
- return { ok: true, data: path57.join(root.value.root, "fanouts") };
83099
+ return { ok: true, data: path60.join(root.value.root, "fanouts") };
82919
83100
  }
82920
83101
  function parseStored(raw) {
82921
83102
  if (!isRecord13(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
@@ -82983,7 +83164,7 @@ function readFanout(cwd, name) {
82983
83164
  const dir = fanoutsDir(cwd);
82984
83165
  if (!dir.ok)
82985
83166
  return dir;
82986
- const file = path57.join(dir.data, stackFileName(name));
83167
+ const file = path60.join(dir.data, stackFileName(name));
82987
83168
  let parsed = null;
82988
83169
  try {
82989
83170
  parsed = parseStored(JSON.parse(fs29.readFileSync(file, "utf8")));
@@ -83008,7 +83189,7 @@ function listFanouts(cwd) {
83008
83189
  for (const entry of names) {
83009
83190
  let parsed = null;
83010
83191
  try {
83011
- parsed = parseStored(JSON.parse(fs29.readFileSync(path57.join(dir.data, entry), "utf8")));
83192
+ parsed = parseStored(JSON.parse(fs29.readFileSync(path60.join(dir.data, entry), "utf8")));
83012
83193
  } catch {
83013
83194
  parsed = null;
83014
83195
  }
@@ -83047,7 +83228,7 @@ function writeFanout(cwd, plan) {
83047
83228
  const dir = fanoutsDir(cwd);
83048
83229
  if (!dir.ok)
83049
83230
  return dir;
83050
- const file = path57.join(dir.data, stackFileName(plan.name));
83231
+ const file = path60.join(dir.data, stackFileName(plan.name));
83051
83232
  const temp = `${file}.${process.pid}.tmp`;
83052
83233
  try {
83053
83234
  fs29.mkdirSync(dir.data, { recursive: true });
@@ -83258,13 +83439,13 @@ var init_fanout = __esm(() => {
83258
83439
  // packages/workit-core/src/forge/exec.ts
83259
83440
  import { spawnSync as spawnSync24 } from "node:child_process";
83260
83441
  import fs30 from "node:fs";
83261
- import path58 from "node:path";
83442
+ import path61 from "node:path";
83262
83443
  function findExecutable(bin, env) {
83263
- const dirs = (env.PATH ?? env.Path ?? "").split(path58.delimiter).filter(Boolean);
83444
+ const dirs = (env.PATH ?? env.Path ?? "").split(path61.delimiter).filter(Boolean);
83264
83445
  const exts = process.platform === "win32" ? [".exe"] : [""];
83265
83446
  for (const dir of dirs)
83266
83447
  for (const ext of exts) {
83267
- const candidate = path58.join(dir, `${bin}${ext}`);
83448
+ const candidate = path61.join(dir, `${bin}${ext}`);
83268
83449
  try {
83269
83450
  const stat = fs30.statSync(candidate);
83270
83451
  if (stat.isFile())
@@ -84807,7 +84988,7 @@ var init_pr_edit = __esm(() => {
84807
84988
  init_rev();
84808
84989
  init_stack();
84809
84990
  init_pr_ops();
84810
- init_report();
84991
+ init_report2();
84811
84992
  });
84812
84993
 
84813
84994
  // packages/workit-core/src/core/live-session.ts
@@ -84827,7 +85008,7 @@ var init_live_session = __esm(() => {
84827
85008
  });
84828
85009
 
84829
85010
  // packages/workit-core/src/hooks/write-gate.ts
84830
- import path59 from "node:path";
85011
+ import path62 from "node:path";
84831
85012
  var CASE_INSENSITIVE, PREFIXES2, SCRIPT_SHELLS, cache3, MUTATING_GIT, DRY_N, MUTATING_WORKIT_GIT, CD2, PUSHD2, POPD2, UNKNOWN_DIR;
84832
85013
  var init_write_gate = __esm(() => {
84833
85014
  init_task_store();
@@ -84867,7 +85048,7 @@ var init_write_gate = __esm(() => {
84867
85048
  CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
84868
85049
  PUSHD2 = new Set(["pushd", "push-location"]);
84869
85050
  POPD2 = new Set(["popd", "pop-location"]);
84870
- UNKNOWN_DIR = path59.resolve(path59.parse(process.cwd()).root, ".workit-unknown-dir");
85051
+ UNKNOWN_DIR = path62.resolve(path62.parse(process.cwd()).root, ".workit-unknown-dir");
84871
85052
  });
84872
85053
 
84873
85054
  // packages/workit-core/src/hooks/worktree-confine.ts
@@ -84892,20 +85073,20 @@ var init_worktree_confine = __esm(() => {
84892
85073
 
84893
85074
  // packages/workit-core/src/worktree-deps.ts
84894
85075
  import fs31 from "node:fs";
84895
- import path60 from "node:path";
85076
+ import path63 from "node:path";
84896
85077
  function moduleDirs(main) {
84897
85078
  const out = [];
84898
85079
  const walk = (relative, depth) => {
84899
85080
  let entries;
84900
85081
  try {
84901
- entries = fs31.readdirSync(path60.join(main, relative), { withFileTypes: true });
85082
+ entries = fs31.readdirSync(path63.join(main, relative), { withFileTypes: true });
84902
85083
  } catch {
84903
85084
  return;
84904
85085
  }
84905
85086
  for (const entry of entries) {
84906
85087
  if (!entry.isDirectory())
84907
85088
  continue;
84908
- const child = path60.join(relative, entry.name);
85089
+ const child = path63.join(relative, entry.name);
84909
85090
  if (entry.name === MODULES)
84910
85091
  out.push(child);
84911
85092
  else if (depth < MAX_DEPTH2 && !entry.name.startsWith("."))
@@ -84919,8 +85100,8 @@ function linkEntry(main, worktree, source, target) {
84919
85100
  const stat = fs31.lstatSync(source);
84920
85101
  if (stat.isSymbolicLink()) {
84921
85102
  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;
85103
+ const outside = path63.isAbsolute(link) && within(link, main) && !path63.relative(main, link).split(path63.sep).includes(MODULES);
85104
+ const to = outside ? path63.join(worktree, path63.relative(main, link)) : link;
84924
85105
  fs31.symlinkSync(to, target, process.platform === "win32" ? "junction" : undefined);
84925
85106
  return;
84926
85107
  }
@@ -84930,8 +85111,8 @@ function mirror(main, worktree, source, target, top) {
84930
85111
  fs31.mkdirSync(target);
84931
85112
  let count = 0;
84932
85113
  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);
85114
+ const from = path63.join(source, entry.name);
85115
+ const to = path63.join(target, entry.name);
84935
85116
  if (top && entry.isDirectory() && (entry.name.startsWith("@") || entry.name === ".bin"))
84936
85117
  count += mirror(main, worktree, from, to, false);
84937
85118
  else {
@@ -84947,16 +85128,16 @@ function linkWorktreeDependencies(main, worktree) {
84947
85128
  const dirs = [];
84948
85129
  let entries = 0;
84949
85130
  for (const relative of moduleDirs(main)) {
84950
- const target = path60.join(worktree, relative);
84951
- if (!fs31.existsSync(path60.dirname(target)) || fs31.existsSync(target))
85131
+ const target = path63.join(worktree, relative);
85132
+ if (!fs31.existsSync(path63.dirname(target)) || fs31.existsSync(target))
84952
85133
  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`);
85134
+ if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(path63.sep).join("/")}/`]).ok) {
85135
+ 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
85136
  continue;
84956
85137
  }
84957
85138
  try {
84958
- entries += mirror(main, worktree, path60.join(main, relative), target, true);
84959
- dirs.push(relative.split(path60.sep).join("/"));
85139
+ entries += mirror(main, worktree, path63.join(main, relative), target, true);
85140
+ dirs.push(relative.split(path63.sep).join("/"));
84960
85141
  } catch (error) {
84961
85142
  fs31.rmSync(target, { recursive: true, force: true });
84962
85143
  notes.push(`could not link ${relative} from ${main} (${error.message}); install dependencies in the worktree yourself`);
@@ -84969,8 +85150,8 @@ function linkWorktreeDependencies(main, worktree) {
84969
85150
  return { linked: { from: main, dirs, entries, ms }, notes };
84970
85151
  }
84971
85152
  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);
85153
+ const relative = path63.relative(parent, child);
85154
+ return relative === "" || !relative.startsWith("..") && !path63.isAbsolute(relative);
84974
85155
  };
84975
85156
  var init_worktree_deps = __esm(() => {
84976
85157
  init_fanout();
@@ -84979,7 +85160,7 @@ var init_worktree_deps = __esm(() => {
84979
85160
  // packages/workit-core/src/fanout-worktree.ts
84980
85161
  import { randomBytes as randomBytes5 } from "node:crypto";
84981
85162
  import fs32 from "node:fs";
84982
- import path61 from "node:path";
85163
+ import path64 from "node:path";
84983
85164
  function rowSample(lines) {
84984
85165
  const out = [];
84985
85166
  let bytes = 0;
@@ -85039,7 +85220,7 @@ function adminDir(worktree) {
85039
85220
  const file = dir.stdout.trim();
85040
85221
  let token = null;
85041
85222
  try {
85042
- token = fs32.readFileSync(path61.join(file, FANOUT_TOKEN_FILE), "utf8").trim() || null;
85223
+ token = fs32.readFileSync(path64.join(file, FANOUT_TOKEN_FILE), "utf8").trim() || null;
85043
85224
  } catch {
85044
85225
  token = null;
85045
85226
  }
@@ -85047,7 +85228,7 @@ function adminDir(worktree) {
85047
85228
  const stat = worktreeDeps.stat(file);
85048
85229
  return {
85049
85230
  path: file,
85050
- id: path61.basename(file),
85231
+ id: path64.basename(file),
85051
85232
  ino: stat.ino.toString(),
85052
85233
  token,
85053
85234
  birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
@@ -85063,7 +85244,7 @@ function markAdminDir(worktree) {
85063
85244
  return null;
85064
85245
  const token = randomBytes5(16).toString("hex");
85065
85246
  try {
85066
- fs32.writeFileSync(path61.join(admin.path, FANOUT_TOKEN_FILE), `${token}
85247
+ fs32.writeFileSync(path64.join(admin.path, FANOUT_TOKEN_FILE), `${token}
85067
85248
  `);
85068
85249
  } catch {
85069
85250
  return null;
@@ -85078,7 +85259,7 @@ function excludeScratch(cwd) {
85078
85259
  const common = gitCommonDir(cwd);
85079
85260
  if (!common)
85080
85261
  return;
85081
- const file = path61.join(common, "info", "exclude");
85262
+ const file = path64.join(common, "info", "exclude");
85082
85263
  let text = "";
85083
85264
  try {
85084
85265
  text = fs32.readFileSync(file, "utf8");
@@ -85087,7 +85268,7 @@ function excludeScratch(cwd) {
85087
85268
  }
85088
85269
  if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
85089
85270
  return;
85090
- fs32.mkdirSync(path61.dirname(file), { recursive: true });
85271
+ fs32.mkdirSync(path64.dirname(file), { recursive: true });
85091
85272
  fs32.appendFileSync(file, `${text && !text.endsWith(`
85092
85273
  `) ? `
85093
85274
  ` : ""}# workit fanout: per-worker scratch dirs
@@ -85096,13 +85277,13 @@ ${EXCLUDE_LINE}
85096
85277
  }
85097
85278
  function worktreeDependencies(main, worktree) {
85098
85279
  for (const [name, install] of LOCKFILES2) {
85099
- const ours = readBytes(path61.join(main, name));
85100
- const theirs = readBytes(path61.join(worktree, name));
85280
+ const ours = readBytes(path64.join(main, name));
85281
+ const theirs = readBytes(path64.join(worktree, name));
85101
85282
  if (ours === null && theirs === null)
85102
85283
  continue;
85103
85284
  if (ours !== null && theirs !== null && ours.equals(theirs))
85104
85285
  continue;
85105
- if (fs32.existsSync(path61.join(worktree, "node_modules")))
85286
+ if (fs32.existsSync(path64.join(worktree, "node_modules")))
85106
85287
  break;
85107
85288
  const command = install(worktree);
85108
85289
  return {
@@ -85116,7 +85297,7 @@ function worktreeDependencies(main, worktree) {
85116
85297
  return { ...linkWorktreeDependencies(main, worktree), install: null };
85117
85298
  }
85118
85299
  function ensureScratch(worktree) {
85119
- const scratch = path61.join(worktree, SCRATCH_DIR);
85300
+ const scratch = path64.join(worktree, SCRATCH_DIR);
85120
85301
  fs32.mkdirSync(scratch, { recursive: true });
85121
85302
  return scratch;
85122
85303
  }
@@ -85355,7 +85536,7 @@ function unpushedCount(cwd, branch) {
85355
85536
  return count.ok ? Number(count.stdout.trim()) : null;
85356
85537
  }
85357
85538
  function removeScratch(worktree) {
85358
- const scratch = path61.join(worktree, SCRATCH_DIR);
85539
+ const scratch = path64.join(worktree, SCRATCH_DIR);
85359
85540
  let stat;
85360
85541
  try {
85361
85542
  stat = fs32.lstatSync(scratch);
@@ -85371,16 +85552,16 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
85371
85552
  try {
85372
85553
  return fs32.realpathSync.native(target);
85373
85554
  } catch {
85374
- return path61.resolve(target);
85555
+ return path64.resolve(target);
85375
85556
  }
85376
85557
  }, samePath = (a, b) => {
85377
85558
  const left = canonical2(a);
85378
85559
  const right = canonical2(b);
85379
85560
  return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
85380
85561
  }, 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) => {
85562
+ const relative = path64.relative(canonical2(parent), canonical2(child));
85563
+ return relative === "" || !relative.startsWith("..") && !path64.isAbsolute(relative);
85564
+ }, slicePath = (cwd, slice) => path64.isAbsolute(slice.worktree) ? slice.worktree : path64.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps, LOCKFILES2, readBytes = (file) => {
85384
85565
  try {
85385
85566
  return fs32.readFileSync(file);
85386
85567
  } catch {
@@ -85411,7 +85592,7 @@ var init_fanout_worktree = __esm(() => {
85411
85592
 
85412
85593
  // packages/workit-core/src/forge/merge-cleanup.ts
85413
85594
  import fs33 from "node:fs";
85414
- import path62 from "node:path";
85595
+ import path65 from "node:path";
85415
85596
  function cleanupMergedBranch(cwd, branch, mergedHead) {
85416
85597
  const out = { branchDeleted: false, worktreeRemoved: null, notes: [] };
85417
85598
  if (!branch || branch.startsWith("-"))
@@ -85471,13 +85652,13 @@ var SLOW2, isFanoutWorktree = (worktree) => {
85471
85652
  if (!dir.ok)
85472
85653
  return false;
85473
85654
  try {
85474
- return fs33.readFileSync(path62.join(dir.stdout.trim(), FANOUT_TOKEN_FILE), "utf8").trim() !== "";
85655
+ return fs33.readFileSync(path65.join(dir.stdout.trim(), FANOUT_TOKEN_FILE), "utf8").trim() !== "";
85475
85656
  } catch {
85476
85657
  return false;
85477
85658
  }
85478
85659
  }, inside4 = (child, parent) => {
85479
- const relative = path62.relative(fs33.realpathSync.native(parent), fs33.realpathSync.native(child));
85480
- return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
85660
+ const relative = path65.relative(fs33.realpathSync.native(parent), fs33.realpathSync.native(child));
85661
+ return relative === "" || !relative.startsWith("..") && !path65.isAbsolute(relative);
85481
85662
  };
85482
85663
  var init_merge_cleanup = __esm(() => {
85483
85664
  init_fanout();
@@ -85758,7 +85939,7 @@ var init_duration = __esm(() => {
85758
85939
  });
85759
85940
 
85760
85941
  // packages/workit-cli/src/verbs/forge-common.ts
85761
- import { readFileSync as readFileSync24 } from "node:fs";
85942
+ import { readFileSync as readFileSync26 } from "node:fs";
85762
85943
  function parseFlags(argv, spec) {
85763
85944
  const parsed = { values: {}, booleans: new Set, lists: {}, positionals: [] };
85764
85945
  for (let index = 0;index < argv.length; index += 1) {
@@ -85913,7 +86094,7 @@ var init_forge_common = __esm(() => {
85913
86094
  forgeDeps = {
85914
86095
  runner: undefined,
85915
86096
  npm: undefined,
85916
- readStdin: () => readFileSync24(0, "utf8"),
86097
+ readStdin: () => readFileSync26(0, "utf8"),
85917
86098
  sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
85918
86099
  now: () => Date.now()
85919
86100
  };
@@ -85924,12 +86105,12 @@ var exports_pr = {};
85924
86105
  __export(exports_pr, {
85925
86106
  run: () => run15
85926
86107
  });
85927
- import { readFileSync as readFileSync25 } from "node:fs";
85928
- import path63 from "node:path";
86108
+ import { readFileSync as readFileSync27 } from "node:fs";
86109
+ import path66 from "node:path";
85929
86110
  function readBodyFile(io, file) {
85930
86111
  try {
85931
86112
  return {
85932
- body: file === "-" ? forgeDeps.readStdin() : readFileSync25(path63.resolve(io.cwd, file), "utf8")
86113
+ body: file === "-" ? forgeDeps.readStdin() : readFileSync27(path66.resolve(io.cwd, file), "utf8")
85933
86114
  };
85934
86115
  } catch {
85935
86116
  return `cannot read --body-file ${file}`;
@@ -86440,7 +86621,7 @@ var init_pr = __esm(() => {
86440
86621
  init_issue_link();
86441
86622
  init_pr_edit();
86442
86623
  init_pr_ops();
86443
- init_report();
86624
+ init_report2();
86444
86625
  init_rev();
86445
86626
  init_workspaces();
86446
86627
  init_merge_cleanup();
@@ -86694,7 +86875,7 @@ async function run16(argv, io) {
86694
86875
  }
86695
86876
  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
86877
  var init_ci = __esm(() => {
86697
- init_report();
86878
+ init_report2();
86698
86879
  init_ledger();
86699
86880
  init_autonomy();
86700
86881
  init_output();
@@ -86733,8 +86914,8 @@ var exports_git = {};
86733
86914
  __export(exports_git, {
86734
86915
  run: () => run17
86735
86916
  });
86736
- import { readFileSync as readFileSync26 } from "node:fs";
86737
- import path64 from "node:path";
86917
+ import { readFileSync as readFileSync28 } from "node:fs";
86918
+ import path67 from "node:path";
86738
86919
  function kindHint(cwd, kind) {
86739
86920
  let kinds = [...BRANCH_KINDS];
86740
86921
  try {
@@ -86838,7 +87019,7 @@ function commitMessage(parsed, io) {
86838
87019
 
86839
87020
  `);
86840
87021
  try {
86841
- return file === "-" ? readFileSync26(0, "utf8") : readFileSync26(path64.resolve(io.cwd, file), "utf8");
87022
+ return file === "-" ? readFileSync28(0, "utf8") : readFileSync28(path67.resolve(io.cwd, file), "utf8");
86842
87023
  } catch (error) {
86843
87024
  return {
86844
87025
  error: `cannot read -F ${file}: ${error instanceof Error ? error.message : String(error)}`
@@ -87252,7 +87433,7 @@ var init_verify = __esm(() => {
87252
87433
  init_exec();
87253
87434
  init_rev();
87254
87435
  init_ledger();
87255
- init_report();
87436
+ init_report2();
87256
87437
  init_redact();
87257
87438
  NPM_NAME = /^(?:@[A-Za-z0-9~][A-Za-z0-9-._~]*\/)?[A-Za-z0-9~][A-Za-z0-9-._~]*$/u;
87258
87439
  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;
@@ -87999,6 +88180,11 @@ async function run19(argv, io) {
87999
88180
  if (!result.ok)
88000
88181
  return forgeFail(io, result);
88001
88182
  const report = result.data;
88183
+ if (report.delivered && expect === "merged") {
88184
+ try {
88185
+ closeDeliveredTasks(new TaskStore(io.cwd), new Date().toISOString().replace(/\.\d{3}Z$/, "Z"));
88186
+ } catch {}
88187
+ }
88002
88188
  if (report.delivered)
88003
88189
  return emit(io, ok2(report), render2);
88004
88190
  const failed = report.observations.filter((entry) => !entry.ok);
@@ -88017,6 +88203,8 @@ var USAGE12 = "workit verify-delivery [push|pr|merge|release] [--expect pushed|p
88017
88203
  ];
88018
88204
  var init_verify_delivery = __esm(() => {
88019
88205
  init_verify();
88206
+ init_task_store();
88207
+ init_task_delivery();
88020
88208
  init_ledger();
88021
88209
  init_output();
88022
88210
  init_forge_common();
@@ -88271,15 +88459,15 @@ var init_stack2 = __esm(() => {
88271
88459
  });
88272
88460
 
88273
88461
  // packages/workit-core/src/fanout-brief.ts
88274
- import { createHash as createHash19 } from "node:crypto";
88462
+ import { createHash as createHash20 } from "node:crypto";
88275
88463
  import fs35 from "node:fs";
88276
- import path65 from "node:path";
88464
+ import path68 from "node:path";
88277
88465
  function workerSession(lead, slice, attempt) {
88278
88466
  const tail = attempt === null ? "" : `+try${attempt}`;
88279
88467
  const full = `${lead}-w-${slice}${tail}`;
88280
88468
  if (full.length <= SESSION_MAX)
88281
88469
  return full;
88282
- const digest = createHash19("sha256").update(slice).digest("hex").slice(0, 12);
88470
+ const digest = createHash20("sha256").update(slice).digest("hex").slice(0, 12);
88283
88471
  return `${lead.slice(0, SESSION_MAX - 3 - digest.length - tail.length)}-w-${digest}${tail}`;
88284
88472
  }
88285
88473
  function renderBrief(cwd, plan, input) {
@@ -88355,7 +88543,7 @@ function renderBrief(cwd, plan, input) {
88355
88543
  "STANDING:",
88356
88544
  ...standing.length ? standing.map((order) => ` - ${order.what}`) : [" - none recorded beyond this brief"],
88357
88545
  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`] : [],
88546
+ ...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
88547
  ...identityLines(identity, minted),
88360
88548
  ...rules(mode, branch, slice.base, exists ? planned : null)
88361
88549
  ];
@@ -89085,7 +89273,7 @@ var DEFAULT_STUCK_MS, isoOf = (seconds) => {
89085
89273
  }, 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
89274
  var init_fanout_status = __esm(() => {
89087
89275
  init_duration();
89088
- init_report();
89276
+ init_report2();
89089
89277
  init_role_models();
89090
89278
  init_ledger();
89091
89279
  init_fanout_check();
@@ -89100,7 +89288,7 @@ __export(exports_fanout, {
89100
89288
  run: () => run21
89101
89289
  });
89102
89290
  import fs36 from "node:fs";
89103
- import path66 from "node:path";
89291
+ import path69 from "node:path";
89104
89292
  function forgeFor(io, offline) {
89105
89293
  if (offline)
89106
89294
  return { forge: null, error: "--offline" };
@@ -89161,7 +89349,7 @@ function plan2(argv, io) {
89161
89349
  return usage4(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
89162
89350
  if (flags.positionals.length !== 1)
89163
89351
  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]);
89352
+ const file = path69.resolve(io.cwd, flags.positionals[0]);
89165
89353
  let raw;
89166
89354
  try {
89167
89355
  raw = JSON.parse(fs36.readFileSync(file, "utf8"));
@@ -104704,7 +104892,7 @@ var init_ast = __esm(() => {
104704
104892
 
104705
104893
  // packages/workit-cli/src/test-audit/rules.ts
104706
104894
  import { builtinModules } from "node:module";
104707
- import path67 from "node:path";
104895
+ import path70 from "node:path";
104708
104896
  function testCallee(call) {
104709
104897
  let callee = call.callee;
104710
104898
  if (callee.type === "CallExpression")
@@ -105197,12 +105385,12 @@ function checkConstantsOnly(ctx, emit) {
105197
105385
  }
105198
105386
  function checkOverMocking(ctx, emit) {
105199
105387
  const { program } = ctx.parsed;
105200
- const unit = path67.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
105388
+ const unit = path70.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
105201
105389
  const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
105202
105390
  const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
105203
105391
  for (const call of mocked) {
105204
105392
  const spec = call.arguments[0].value;
105205
- const base = path67.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
105393
+ const base = path70.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
105206
105394
  if (base === unit)
105207
105395
  emit({
105208
105396
  rule: "over-mocking",
@@ -105591,8 +105779,8 @@ var init_rules = __esm(() => {
105591
105779
 
105592
105780
  // packages/workit-cli/src/test-audit/audit.ts
105593
105781
  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";
105782
+ import { existsSync as existsSync26, readdirSync as readdirSync14, readFileSync as readFileSync29, statSync as statSync10 } from "node:fs";
105783
+ import path71 from "node:path";
105596
105784
  function git7(cwd, args) {
105597
105785
  const run = spawnSync29("git", ["-c", "core.quotepath=off", ...args], {
105598
105786
  cwd,
@@ -105605,7 +105793,7 @@ function walkTests(dir, out) {
105605
105793
  for (const entry of readdirSync14(dir, { withFileTypes: true })) {
105606
105794
  if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
105607
105795
  continue;
105608
- const full = path68.join(dir, entry.name);
105796
+ const full = path71.join(dir, entry.name);
105609
105797
  if (entry.isDirectory()) {
105610
105798
  if (!SKIP_DIRS.has(entry.name))
105611
105799
  walkTests(full, out);
@@ -105617,8 +105805,8 @@ function expandPaths(cwd, inputs) {
105617
105805
  const files = [];
105618
105806
  const missing = [];
105619
105807
  for (const input of inputs.length > 0 ? inputs : ["."]) {
105620
- const full = path68.resolve(cwd, input);
105621
- if (!existsSync24(full))
105808
+ const full = path71.resolve(cwd, input);
105809
+ if (!existsSync26(full))
105622
105810
  missing.push(input);
105623
105811
  else if (statSync10(full).isDirectory())
105624
105812
  walkTests(full, files);
@@ -105654,11 +105842,11 @@ function changedLines(cwd, base) {
105654
105842
  for (let offset = 0;offset < count; offset += 1)
105655
105843
  lines.add(start + offset);
105656
105844
  }
105657
- changed.set(path68.join(root, file), lines);
105845
+ changed.set(path71.join(root, file), lines);
105658
105846
  }
105659
105847
  const untracked = git7(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
105660
105848
  for (const file of untracked.stdout.split("\x00").filter(Boolean))
105661
- changed.set(path68.join(root, file), "all");
105849
+ changed.set(path71.join(root, file), "all");
105662
105850
  return changed;
105663
105851
  }
105664
105852
  function auditFiles(files, display) {
@@ -105671,7 +105859,7 @@ function auditFiles(files, display) {
105671
105859
  const shown = display(file);
105672
105860
  let parsed;
105673
105861
  try {
105674
- parsed = parseSource(readFileSync27(file, "utf8"), file);
105862
+ parsed = parseSource(readFileSync29(file, "utf8"), file);
105675
105863
  } catch (error) {
105676
105864
  parseErrors.push({
105677
105865
  file: shown,
@@ -105720,7 +105908,7 @@ function auditFiles(files, display) {
105720
105908
  durationMs: Math.round(performance.now() - started)
105721
105909
  };
105722
105910
  }
105723
- var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path68.sep).join("/"), SEVERITY_ORDER, ruleIds;
105911
+ var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path71.sep).join("/"), SEVERITY_ORDER, ruleIds;
105724
105912
  var init_audit = __esm(() => {
105725
105913
  init_ast();
105726
105914
  init_rules();
@@ -105734,23 +105922,23 @@ var init_audit = __esm(() => {
105734
105922
  // packages/workit-cli/src/test-audit/mutate.ts
105735
105923
  import { spawn as spawn2 } from "node:child_process";
105736
105924
  import {
105737
- existsSync as existsSync25,
105925
+ existsSync as existsSync27,
105738
105926
  lstatSync as lstatSync8,
105739
105927
  mkdirSync as mkdirSync12,
105740
105928
  mkdtempSync as mkdtempSync4,
105741
105929
  readdirSync as readdirSync15,
105742
- readFileSync as readFileSync28,
105930
+ readFileSync as readFileSync30,
105743
105931
  readlinkSync as readlinkSync3,
105744
105932
  realpathSync as realpathSync10,
105745
105933
  renameSync as renameSync7,
105746
105934
  rmSync as rmSync9,
105747
105935
  statSync as statSync11,
105748
105936
  symlinkSync,
105749
- writeFileSync as writeFileSync12,
105937
+ writeFileSync as writeFileSync13,
105750
105938
  copyFileSync as copyFileSync8
105751
105939
  } from "node:fs";
105752
- import os22 from "node:os";
105753
- import path69 from "node:path";
105940
+ import os23 from "node:os";
105941
+ import path72 from "node:path";
105754
105942
  function mutantsFor(source, file, lines) {
105755
105943
  const parsed = parseSource(source, file);
105756
105944
  const out = [];
@@ -105823,7 +106011,7 @@ function relatedTests(source, testFiles) {
105823
106011
  for (const match of text.matchAll(SPECIFIER)) {
105824
106012
  const spec = match[1];
105825
106013
  if (spec.startsWith(".")) {
105826
- if (stripExt(path69.posix.join(path69.posix.dirname(file), spec)) === target)
106014
+ if (stripExt(path72.posix.join(path72.posix.dirname(file), spec)) === target)
105827
106015
  return true;
105828
106016
  } else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
105829
106017
  return true;
@@ -105831,7 +106019,7 @@ function relatedTests(source, testFiles) {
105831
106019
  return false;
105832
106020
  }).map((entry) => entry.file);
105833
106021
  }
105834
- function removeStaleCopies(tmp = os22.tmpdir()) {
106022
+ function removeStaleCopies(tmp = os23.tmpdir()) {
105835
106023
  let removed = 0;
105836
106024
  let names = [];
105837
106025
  try {
@@ -105843,12 +106031,12 @@ function removeStaleCopies(tmp = os22.tmpdir()) {
105843
106031
  for (const name of names) {
105844
106032
  if (!name.startsWith(TEMP_PREFIX))
105845
106033
  continue;
105846
- const dir = path69.join(tmp, name);
106034
+ const dir = path72.join(tmp, name);
105847
106035
  try {
105848
106036
  const stat = lstatSync8(dir);
105849
106037
  if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
105850
106038
  continue;
105851
- const pid = Number(readFileSync28(path69.join(dir, PID_FILE), "utf8"));
106039
+ const pid = Number(readFileSync30(path72.join(dir, PID_FILE), "utf8"));
105852
106040
  if (Number.isInteger(pid) && pid > 0 && alive(pid))
105853
106041
  continue;
105854
106042
  } catch (error) {
@@ -105865,8 +106053,8 @@ function removeStaleCopies(tmp = os22.tmpdir()) {
105865
106053
  function linkNodeModules(origin, target, repo, copy) {
105866
106054
  mkdirSync12(target, { recursive: true });
105867
106055
  for (const entry of readdirSync15(origin, { withFileTypes: true })) {
105868
- const from = path69.join(origin, entry.name);
105869
- const to = path69.join(target, entry.name);
106056
+ const from = path72.join(origin, entry.name);
106057
+ const to = path72.join(target, entry.name);
105870
106058
  if (entry.name.startsWith("@") && entry.isDirectory()) {
105871
106059
  linkNodeModules(from, to, repo, copy);
105872
106060
  continue;
@@ -105882,9 +106070,9 @@ function linkNodeModules(origin, target, repo, copy) {
105882
106070
  } catch {
105883
106071
  continue;
105884
106072
  }
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");
106073
+ const relative = path72.relative(repo, real);
106074
+ if (!relative.startsWith("..") && !path72.isAbsolute(relative) && !relative.split(path72.sep).includes("node_modules")) {
106075
+ symlinkSync(path72.join(copy, relative), to, "junction");
105888
106076
  continue;
105889
106077
  }
105890
106078
  }
@@ -105900,7 +106088,7 @@ function copySymlink(repo, tree, from, to) {
105900
106088
  }
105901
106089
  const realRepo = realpathSync10(repo);
105902
106090
  if (real && inside5(realRepo, real)) {
105903
- symlinkSync(path69.relative(path69.dirname(to), path69.join(tree, path69.relative(realRepo, real))), to);
106091
+ symlinkSync(path72.relative(path72.dirname(to), path72.join(tree, path72.relative(realRepo, real))), to);
105904
106092
  return;
105905
106093
  }
105906
106094
  if (real && statSync11(real).isFile())
@@ -105909,23 +106097,23 @@ function copySymlink(repo, tree, from, to) {
105909
106097
  symlinkSync(readlinkSync3(from), to);
105910
106098
  }
105911
106099
  function writeInside(copy, file, content) {
105912
- const target = path69.join(copy, file);
106100
+ const target = path72.join(copy, file);
105913
106101
  try {
105914
106102
  const stat = lstatSync8(target);
105915
- if (!stat.isFile() || !inside5(realpathSync10(copy), realpathSync10(path69.dirname(target))))
106103
+ if (!stat.isFile() || !inside5(realpathSync10(copy), realpathSync10(path72.dirname(target))))
105916
106104
  return false;
105917
106105
  } catch {
105918
106106
  return false;
105919
106107
  }
105920
106108
  const temp = `${target}.workit-mutant-${process.pid}`;
105921
- writeFileSync12(temp, content);
106109
+ writeFileSync13(temp, content);
105922
106110
  renameSync7(temp, target);
105923
106111
  return true;
105924
106112
  }
105925
106113
  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");
106114
+ const dir = mkdtempSync4(path72.join(os23.tmpdir(), TEMP_PREFIX));
106115
+ writeFileSync13(path72.join(dir, PID_FILE), String(process.pid));
106116
+ const tree = path72.join(dir, "tree");
105929
106117
  const head = git7(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
105930
106118
  if (head && git7(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
105931
106119
  const branch = git7(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
@@ -105942,29 +106130,29 @@ function copyWorkingTree(repo) {
105942
106130
  for (const relative of listed) {
105943
106131
  if (!relative)
105944
106132
  continue;
105945
- const from = path69.join(repo, relative);
106133
+ const from = path72.join(repo, relative);
105946
106134
  let stat;
105947
106135
  try {
105948
106136
  stat = lstatSync8(from);
105949
106137
  } catch {
105950
106138
  continue;
105951
106139
  }
105952
- const to = path69.join(tree, relative);
105953
- mkdirSync12(path69.dirname(to), { recursive: true });
106140
+ const to = path72.join(tree, relative);
106141
+ mkdirSync12(path72.dirname(to), { recursive: true });
105954
106142
  if (stat.isSymbolicLink())
105955
106143
  copySymlink(repo, tree, from, to);
105956
106144
  else if (stat.isFile())
105957
106145
  copyFileSync8(from, to);
105958
- let parent = path69.dirname(relative);
106146
+ let parent = path72.dirname(relative);
105959
106147
  while (parent !== "." && !dirs.has(parent)) {
105960
106148
  dirs.add(parent);
105961
- parent = path69.dirname(parent);
106149
+ parent = path72.dirname(parent);
105962
106150
  }
105963
106151
  }
105964
106152
  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);
106153
+ const modules = path72.join(repo, parent, "node_modules");
106154
+ if (existsSync27(modules) && !existsSync27(path72.join(tree, parent, "node_modules")))
106155
+ linkNodeModules(modules, path72.join(tree, parent, "node_modules"), repo, tree);
105968
106156
  }
105969
106157
  return { dir, tree };
105970
106158
  }
@@ -106003,20 +106191,20 @@ async function runMutation(options) {
106003
106191
  const tracked = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
106004
106192
  const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
106005
106193
  try {
106006
- return { file, text: readFileSync28(path69.join(repo, file), "utf8") };
106194
+ return { file, text: readFileSync30(path72.join(repo, file), "utf8") };
106007
106195
  } catch {
106008
106196
  return { file, text: "" };
106009
106197
  }
106010
106198
  });
106011
106199
  const candidates = [];
106012
106200
  for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
106013
- const relative = toPosix(path69.relative(repo, absolute));
106201
+ const relative = toPosix(path72.relative(repo, absolute));
106014
106202
  if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
106015
106203
  continue;
106016
- if (NOT_SOURCE.test(relative) || !existsSync25(absolute))
106204
+ if (NOT_SOURCE.test(relative) || !existsSync27(absolute))
106017
106205
  continue;
106018
106206
  try {
106019
- candidates.push(...mutantsFor(readFileSync28(absolute, "utf8"), relative, lines));
106207
+ candidates.push(...mutantsFor(readFileSync30(absolute, "utf8"), relative, lines));
106020
106208
  } catch {}
106021
106209
  }
106022
106210
  const mutants = candidates.map((mutant, index) => ({ ...mutant, id: index + 1 }));
@@ -106024,9 +106212,9 @@ async function runMutation(options) {
106024
106212
  for (const mutant of mutants)
106025
106213
  if (!related.has(mutant.file))
106026
106214
  related.set(mutant.file, relatedTests(mutant.file, testFiles));
106027
- const cwdRelative = path69.relative(repo, options.cwd);
106215
+ const cwdRelative = path72.relative(repo, options.cwd);
106028
106216
  const asArg = (file) => {
106029
- const relative = toPosix(path69.relative(cwdRelative, file));
106217
+ const relative = toPosix(path72.relative(cwdRelative, file));
106030
106218
  return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
106031
106219
  };
106032
106220
  const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
@@ -106062,7 +106250,7 @@ async function runMutation(options) {
106062
106250
  return finish3(options, 0, results, counts, started);
106063
106251
  removeStaleCopies();
106064
106252
  const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
106065
- const copyCwd = path69.join(copy, cwdRelative);
106253
+ const copyCwd = path72.join(copy, cwdRelative);
106066
106254
  let current = null;
106067
106255
  const restore = () => {
106068
106256
  if (current)
@@ -106097,7 +106285,7 @@ async function runMutation(options) {
106097
106285
  record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
106098
106286
  continue;
106099
106287
  }
106100
- const original = readFileSync28(path69.join(copy, mutant.file), "utf8");
106288
+ const original = readFileSync30(path72.join(copy, mutant.file), "utf8");
106101
106289
  const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
106102
106290
  current = { file: mutant.file, original };
106103
106291
  if (!writeInside(copy, mutant.file, mutated)) {
@@ -106154,8 +106342,8 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
106154
106342
  return error.code === "EPERM";
106155
106343
  }
106156
106344
  }, inside5 = (root, file) => {
106157
- const relative = path69.relative(root, file);
106158
- return relative === "" || !relative.startsWith("..") && !path69.isAbsolute(relative);
106345
+ const relative = path72.relative(root, file);
106346
+ return relative === "" || !relative.startsWith("..") && !path72.isAbsolute(relative);
106159
106347
  }, active, killTree = (child) => {
106160
106348
  try {
106161
106349
  if (child.pid && process.platform !== "win32")
@@ -106203,8 +106391,8 @@ var exports_test_audit = {};
106203
106391
  __export(exports_test_audit, {
106204
106392
  run: () => run23
106205
106393
  });
106206
- import { existsSync as existsSync26 } from "node:fs";
106207
- import path70 from "node:path";
106394
+ import { existsSync as existsSync28 } from "node:fs";
106395
+ import path73 from "node:path";
106208
106396
  function parse8(argv) {
106209
106397
  const options = {
106210
106398
  paths: [],
@@ -106309,8 +106497,8 @@ async function run23(argv, io) {
106309
106497
  return emit(io, fail2("invalid_input", `${options}
106310
106498
  usage: ${USAGE16}`));
106311
106499
  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);
106500
+ const repo = top.ok ? path73.resolve(top.stdout.trim()) : null;
106501
+ const display = (file) => toPosix(path73.relative(io.cwd, file) || file);
106314
106502
  let base = null;
106315
106503
  let changed = null;
106316
106504
  if (options.diff || options.mutate) {
@@ -106327,7 +106515,7 @@ usage: ${USAGE16}`));
106327
106515
  }
106328
106516
  let files;
106329
106517
  if (options.diff && changed)
106330
- files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) && existsSync26(file)).toSorted();
106518
+ files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) && existsSync28(file)).toSorted();
106331
106519
  else {
106332
106520
  const expanded = expandPaths(io.cwd, options.paths);
106333
106521
  if (expanded.missing.length > 0)
@@ -106448,8 +106636,8 @@ var exports_youtrack = {};
106448
106636
  __export(exports_youtrack, {
106449
106637
  run: () => run25
106450
106638
  });
106451
- import { readFileSync as readFileSync29 } from "node:fs";
106452
- import path71 from "node:path";
106639
+ import { readFileSync as readFileSync31 } from "node:fs";
106640
+ import path74 from "node:path";
106453
106641
  async function run25(argv, io) {
106454
106642
  const [sub, ...rest] = argv;
106455
106643
  if (sub !== "note" && sub !== "time" && sub !== "meeting")
@@ -106495,7 +106683,7 @@ async function run25(argv, io) {
106495
106683
  let markdown = flags.values.markdown ?? "";
106496
106684
  if (flags.values.file)
106497
106685
  try {
106498
- markdown = readFileSync29(path71.resolve(io.cwd, flags.values.file), "utf8");
106686
+ markdown = readFileSync31(path74.resolve(io.cwd, flags.values.file), "utf8");
106499
106687
  } catch (error) {
106500
106688
  return usage4(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE18);
106501
106689
  }
@@ -106563,8 +106751,8 @@ var exports_changelog = {};
106563
106751
  __export(exports_changelog, {
106564
106752
  run: () => run26
106565
106753
  });
106566
- import { readFileSync as readFileSync30 } from "node:fs";
106567
- import path72 from "node:path";
106754
+ import { readFileSync as readFileSync32 } from "node:fs";
106755
+ import path75 from "node:path";
106568
106756
  async function run26(argv, io) {
106569
106757
  const [sub, ...rest] = argv;
106570
106758
  if (sub !== "apply")
@@ -106610,7 +106798,7 @@ async function run26(argv, io) {
106610
106798
  ]);
106611
106799
  }
106612
106800
  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;
106801
+ const text = raw === "-" ? readFileSync32(0, "utf8") : raw.startsWith("@") ? readFileSync32(path75.resolve(cwd, raw.slice(1)), "utf8") : raw;
106614
106802
  return JSON.parse(text);
106615
106803
  };
106616
106804
  var init_changelog2 = __esm(() => {
@@ -106626,7 +106814,7 @@ __export(exports_handoff, {
106626
106814
  run: () => run27
106627
106815
  });
106628
106816
  import fs37 from "node:fs";
106629
- import path73 from "node:path";
106817
+ import path76 from "node:path";
106630
106818
  import { parseArgs as parseArgs2 } from "node:util";
106631
106819
  function render3(brief) {
106632
106820
  const lines = [
@@ -106666,9 +106854,9 @@ function bounded(brief, cwd) {
106666
106854
  let file = null;
106667
106855
  if (store.ok)
106668
106856
  try {
106669
- const dir = path73.join(store.value.root, "handoff");
106857
+ const dir = path76.join(store.value.root, "handoff");
106670
106858
  fs37.mkdirSync(dir, { recursive: true });
106671
- file = path73.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
106859
+ file = path76.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
106672
106860
  fs37.writeFileSync(file, `${[...body, ...tail].join(`
106673
106861
  `)}
106674
106862
  `, {
@@ -106745,7 +106933,7 @@ var init_handoff = __esm(() => {
106745
106933
  // packages/workit-cli/src/main.ts
106746
106934
  init_host_session();
106747
106935
  init_package();
106748
- import path74 from "node:path";
106936
+ import path77 from "node:path";
106749
106937
 
106750
106938
  // packages/workit-cli/src/verbs/registry.ts
106751
106939
  var TASK_FAMILY_NAMES = [
@@ -107657,7 +107845,7 @@ var defaultIo = (json) => ({
107657
107845
  });
107658
107846
  async function main(argv, overrides = {}, options = {}) {
107659
107847
  const parsed = parseGlobals(argv);
107660
- const cwd = path74.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
107848
+ const cwd = path77.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
107661
107849
  const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
107662
107850
  if (parsed.error)
107663
107851
  return emit(io, fail2("invalid_input", parsed.error));