@brainervirus/workit-cli 8.13.1 → 8.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +152 -23
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -65,7 +65,7 @@ var package_default;
65
65
  var init_package = __esm(() => {
66
66
  package_default = {
67
67
  name: "@brainervirus/workit-cli",
68
- version: "8.13.1",
68
+ version: "8.14.1",
69
69
  private: false,
70
70
  description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
71
71
  keywords: [
@@ -103,13 +103,13 @@ var init_package = __esm(() => {
103
103
  },
104
104
  dependencies: {
105
105
  "@babel/parser": "7.29.9",
106
- "@brainervirus/workit-cursor": "^8.13.1",
106
+ "@brainervirus/workit-cursor": "^8.14.1",
107
107
  "@inkjs/ui": "2.0.0",
108
108
  ink: "7.1.1",
109
109
  react: "19.2.8"
110
110
  },
111
111
  devDependencies: {
112
- "@brainervirus/workit-core": "^8.13.1"
112
+ "@brainervirus/workit-core": "^8.14.1"
113
113
  },
114
114
  engines: {
115
115
  node: ">=24"
@@ -7977,6 +7977,16 @@ var init_zod = __esm(() => {
7977
7977
 
7978
7978
  // packages/workit-core/src/core/task-contract.ts
7979
7979
  import { createHash, randomUUID } from "node:crypto";
7980
+ function resolveIdRef(kind, ref, ids) {
7981
+ if (ids.includes(ref))
7982
+ return success(null, null, ref);
7983
+ const matches = ids.filter((candidate) => candidate.startsWith(ref));
7984
+ if (matches.length === 1)
7985
+ return success(null, null, matches[0]);
7986
+ if (matches.length === 0)
7987
+ return failure2("not_found", `${kind} not found`);
7988
+ return failure2("invalid_input", `${kind} prefix ${ref} is ambiguous; candidates: ${matches.join(", ")}`);
7989
+ }
7980
7990
  function parseOperation(family, input) {
7981
7991
  if (typeof input === "object" && input !== null && "schemaVersion" in input && input.schemaVersion !== SCHEMA_VERSION)
7982
7992
  return failure2("unsupported_version", "unsupported schema version", { operation: family });
@@ -8079,7 +8089,7 @@ var SCHEMA_VERSION = 1, POLICY_VERSION = "1.0.0", OPERATION_FAMILIES, uuidPatter
8079
8089
  return true;
8080
8090
  }
8081
8091
  return false;
8082
- }, text, id, digest, revision, validUtc = (value) => {
8092
+ }, text, id, idRefPattern, idRef, digest, revision, validUtc = (value) => {
8083
8093
  const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9}))?Z$/.exec(value);
8084
8094
  if (!match)
8085
8095
  return false;
@@ -8262,6 +8272,8 @@ var init_task_contract = __esm(() => {
8262
8272
  ctx.issues.push({ code: "custom", input: ctx.value, message: "invalid Unicode", path: [] });
8263
8273
  });
8264
8274
  id = text.regex(uuidPattern, "expected lowercase UUID");
8275
+ idRefPattern = /^[0-9a-f][0-9a-f-]{7,35}$/;
8276
+ idRef = text.regex(idRefPattern, "expected a UUID or an id prefix of 8+ characters");
8265
8277
  digest = text.regex(digestPattern, "expected lowercase SHA-256 digest");
8266
8278
  revision = text.regex(uuidPattern, "expected UUID revision");
8267
8279
  utcSchema = text.check((ctx) => {
@@ -8530,7 +8542,7 @@ var init_task_contract = __esm(() => {
8530
8542
  outcome: _enum(["completed", "failed", "cancelled"]),
8531
8543
  summary: text,
8532
8544
  evidenceIds: array(id),
8533
- findingIds: array(id)
8545
+ findingIds: array(idRef)
8534
8546
  }).strict();
8535
8547
  workerSchema = object({
8536
8548
  assignment: assignmentSchema,
@@ -8722,7 +8734,7 @@ var init_task_contract = __esm(() => {
8722
8734
  action: literal("resolve"),
8723
8735
  ...taskId,
8724
8736
  expectedRevision: revision.optional(),
8725
- findingId: id,
8737
+ findingId: idRef,
8726
8738
  disposition: _enum(["open", "fixed", "dismissed", "deferred"]),
8727
8739
  reason: text,
8728
8740
  evidenceIds: array(id),
@@ -8763,7 +8775,7 @@ var init_task_contract = __esm(() => {
8763
8775
  ...taskId,
8764
8776
  expectedRevision: revision.optional(),
8765
8777
  expectedWorkspaceRevision: revision.optional(),
8766
- workerId: id,
8778
+ workerId: idRef,
8767
8779
  report: workerReportSchema
8768
8780
  }),
8769
8781
  cancel: operation({
@@ -8771,7 +8783,7 @@ var init_task_contract = __esm(() => {
8771
8783
  ...taskId,
8772
8784
  ...revisions,
8773
8785
  expectedWorkspaceRevision: revision.optional(),
8774
- workerId: id,
8786
+ workerId: idRef,
8775
8787
  reason: text
8776
8788
  })
8777
8789
  };
@@ -11453,20 +11465,26 @@ class TaskStore {
11453
11465
  return success(null, null, { key: key.data, bound: bound.data });
11454
11466
  }
11455
11467
  taskForWorker(workerId) {
11456
- if (typeof workerId !== "string" || !validId(workerId))
11468
+ if (typeof workerId !== "string" || !idRefPattern.test(workerId))
11457
11469
  return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
11458
11470
  const listed = this.listTaskIndex();
11459
11471
  if (!listed.ok)
11460
11472
  return listed;
11473
+ const owners = new Map;
11461
11474
  for (const entry of listed.data) {
11462
11475
  if (entry.status === "closed")
11463
11476
  continue;
11464
11477
  const loaded = this.load(entry.id);
11465
11478
  if (!loaded.ok)
11466
11479
  return loaded;
11467
- if (loaded.data?.record.workers.some((worker) => worker.id === workerId))
11468
- return success(null, null, entry.id);
11480
+ for (const worker of loaded.data?.record.workers ?? [])
11481
+ owners.set(worker.id, entry.id);
11469
11482
  }
11483
+ const resolved = resolveIdRef("worker", workerId, [...owners.keys()]);
11484
+ if (resolved.ok)
11485
+ return success(null, null, owners.get(resolved.data) ?? null);
11486
+ if (resolved.code !== "not_found")
11487
+ return resolved;
11470
11488
  return success(null, null, null);
11471
11489
  }
11472
11490
  originTaskEntry() {
@@ -14022,23 +14040,79 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
14022
14040
  }, resolveRuntimeReleaseTracks = (cwd) => {
14023
14041
  const matched = matchRuntimeWorkspace(cwd);
14024
14042
  return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
14025
- }, workspaceTrailers = (cwd, dir) => {
14043
+ }, inheritedSetting = (cwd, dir, has) => {
14026
14044
  let matched;
14027
14045
  try {
14028
14046
  matched = matchRuntimeWorkspace(cwd, dir);
14029
14047
  } catch {
14030
- return { enabled: true, workspace: null, from: null };
14048
+ return null;
14031
14049
  }
14032
14050
  if (!matched)
14033
- return { enabled: true, workspace: null, from: null };
14051
+ return null;
14034
14052
  const { selected, matches } = matched;
14035
14053
  const enclosing = matches.filter((entry) => entry !== selected).toSorted((a, b) => globSpecificity(b.glob) - globSpecificity(a.glob));
14036
- const source = [selected, ...enclosing].find((entry) => typeof entry.trailers === "boolean");
14054
+ return { workspace: selected.name, source: [selected, ...enclosing].find(has) ?? null };
14055
+ }, workspaceTrailers = (cwd, dir) => {
14056
+ const found = inheritedSetting(cwd, dir, (entry) => typeof entry.trailers === "boolean");
14037
14057
  return {
14038
- enabled: source?.trailers !== false,
14039
- workspace: selected.name,
14040
- from: source?.name ?? null
14058
+ enabled: found?.source?.trailers !== false,
14059
+ workspace: found?.workspace ?? null,
14060
+ from: found?.source?.name ?? null
14041
14061
  };
14062
+ }, hostFamily = (host) => host.replace(/_(?:cli|desktop)$/u, ""), TIER_KEYS, TIER_HOSTS, workspaceTierModelIssues = (cwd, dir) => {
14063
+ let matched;
14064
+ try {
14065
+ matched = matchRuntimeWorkspace(cwd, dir);
14066
+ } catch {
14067
+ return [];
14068
+ }
14069
+ const issues = [];
14070
+ for (const entry of matched?.matches ?? []) {
14071
+ const models = entry.fanout?.tierModels;
14072
+ if (models === undefined)
14073
+ continue;
14074
+ const where = `workspace ${entry.name} fanout.tierModels`;
14075
+ if (!models || typeof models !== "object" || Array.isArray(models)) {
14076
+ issues.push(`${where} is not an object; ignored`);
14077
+ continue;
14078
+ }
14079
+ for (const [tier, value] of Object.entries(models)) {
14080
+ if (!TIER_KEYS.has(tier))
14081
+ issues.push(`${where}.${tier}: unknown tier; ignored`);
14082
+ else if (typeof value === "string") {
14083
+ if (!value.trim())
14084
+ issues.push(`${where}.${tier}: empty model name; ignored`);
14085
+ } else if (!value || typeof value !== "object" || Array.isArray(value))
14086
+ issues.push(`${where}.${tier}: not a model name or a per-host object; ignored`);
14087
+ else
14088
+ for (const [host, model] of Object.entries(value)) {
14089
+ if (!TIER_HOSTS.has(host))
14090
+ issues.push(`${where}.${tier}.${host}: unknown host; ignored`);
14091
+ else if (typeof model !== "string" || !model.trim())
14092
+ issues.push(`${where}.${tier}.${host}: not a model name; ignored`);
14093
+ }
14094
+ }
14095
+ }
14096
+ return issues;
14097
+ }, workspaceTierModel = (cwd, tier, host, dir) => {
14098
+ const pick = (entry) => {
14099
+ const fanout = entry.fanout;
14100
+ const models = fanout?.tierModels;
14101
+ if (!models || typeof models !== "object" || !Object.hasOwn(models, tier))
14102
+ return null;
14103
+ const value = models[tier];
14104
+ if (typeof value === "string")
14105
+ return value.trim() || null;
14106
+ if (!value || typeof value !== "object")
14107
+ return null;
14108
+ const byHost = value;
14109
+ const family = host ? hostFamily(host) : null;
14110
+ const named = (family && Object.hasOwn(byHost, family) ? byHost[family] : undefined) ?? (host && Object.hasOwn(byHost, host) ? byHost[host] : undefined) ?? (Object.hasOwn(byHost, "default") ? byHost.default : undefined);
14111
+ return typeof named === "string" && named.trim() ? named.trim() : null;
14112
+ };
14113
+ const found = inheritedSetting(cwd, dir, (entry) => pick(entry) !== null);
14114
+ const model = found?.source ? pick(found.source) : null;
14115
+ return model && found?.source ? { model, workspace: found.source.name } : null;
14042
14116
  }, resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
14043
14117
  const matched = matchRuntimeWorkspace(cwd);
14044
14118
  if (!matched)
@@ -14190,6 +14264,8 @@ var init_workspaces = __esm(() => {
14190
14264
  defaultEndpoint: unknown().optional(),
14191
14265
  verification: _enum(["self", "independent"]).optional(),
14192
14266
  trailers: boolean2().optional(),
14267
+ liveSessionGuard: boolean2().optional(),
14268
+ fanout: object({ tierModels: unknown().optional() }).passthrough().optional(),
14193
14269
  autonomy: object(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
14194
14270
  kind,
14195
14271
  union([boolean2(), literal("verified")]).optional()
@@ -14239,6 +14315,17 @@ var init_workspaces = __esm(() => {
14239
14315
  runtimeWorkspaceIndexSchema = object({
14240
14316
  workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
14241
14317
  }).passthrough();
14318
+ TIER_KEYS = new Set(["mundane", "standard", "hard"]);
14319
+ TIER_HOSTS = new Set([
14320
+ "claude_code",
14321
+ "opencode",
14322
+ "codex",
14323
+ "codex_cli",
14324
+ "codex_desktop",
14325
+ "cursor",
14326
+ "pi",
14327
+ "default"
14328
+ ]);
14242
14329
  });
14243
14330
 
14244
14331
  // packages/workit-core/src/core/release-tracks.ts
@@ -18749,6 +18836,10 @@ class WorkitCore {
18749
18836
  }
18750
18837
  if (helper?.ok)
18751
18838
  return failure2("permission_denied", "helpers cannot resolve findings");
18839
+ const findingRef = resolveIdRef("finding", input.findingId, task.data.findings.map((entry) => entry.id));
18840
+ if (!findingRef.ok)
18841
+ return findingRef;
18842
+ input.findingId = findingRef.data;
18752
18843
  const finding = task.data.findings.find((entry) => entry.id === input.findingId);
18753
18844
  if (!finding)
18754
18845
  return failure2("not_found", "finding not found");
@@ -18900,15 +18991,31 @@ class WorkitCore {
18900
18991
  return changed;
18901
18992
  return success(changed.data.task.revision, changed.data.workspace.revision, changed.data.task.workers.at(-1));
18902
18993
  }
18994
+ const workerRef = resolveIdRef("worker", input.workerId, helperId === null ? task.data.workers.map((candidate) => candidate.id) : [helperId]);
18995
+ if (!workerRef.ok)
18996
+ return helperId === null ? workerRef : failure2("permission_denied", input.action === "report" ? ONLY_OWN_REPORT : NO_HELPER_CONTROL);
18997
+ input.workerId = workerRef.data;
18903
18998
  const entry = task.data.workers.find((candidate) => candidate.id === input.workerId);
18904
18999
  if (!entry)
18905
19000
  return failure2("not_found", "worker not found");
18906
19001
  if (input.action === "report") {
18907
19002
  if (helperId === null || helperId !== input.workerId)
18908
- return failure2("permission_denied", "workers can submit only their own report");
19003
+ return failure2("permission_denied", ONLY_OWN_REPORT);
18909
19004
  const helper = this.helperEntry(task.data, true, true);
18910
19005
  if (!helper.ok)
18911
19006
  return helper;
19007
+ const ownFindings = task.data.findings.filter((candidate) => candidate.provenance.workerId === helperId).map((candidate) => candidate.id);
19008
+ const reported = [];
19009
+ for (const findingRef of input.report.findingIds) {
19010
+ const found = resolveIdRef("finding", findingRef, ownFindings);
19011
+ if (found.ok)
19012
+ reported.push(found.data);
19013
+ else if (found.code === "not_found")
19014
+ reported.push(findingRef);
19015
+ else
19016
+ return found;
19017
+ }
19018
+ input.report.findingIds = reported;
18912
19019
  const evidence = task.data.evidence.filter((candidate) => input.report.evidenceIds.includes(candidate.id));
18913
19020
  const findings = task.data.findings.filter((candidate) => input.report.findingIds.includes(candidate.id));
18914
19021
  if (evidence.length !== input.report.evidenceIds.length || findings.length !== input.report.findingIds.length)
@@ -18936,7 +19043,7 @@ class WorkitCore {
18936
19043
  return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during report");
18937
19044
  }
18938
19045
  if (helperId !== null)
18939
- return failure2("permission_denied", "helpers cannot cancel or control workers");
19046
+ return failure2("permission_denied", NO_HELPER_CONTROL);
18940
19047
  if (task.data.status === "closed")
18941
19048
  return failure2("invalid_transition", "closed task cannot cancel workers");
18942
19049
  if (entry.data.state === "stopped") {
@@ -19465,7 +19572,7 @@ var MAX_JUDGED_REFS = 5, workspaceVerification = (root) => {
19465
19572
  return changed;
19466
19573
  const updated = changed.data.task.workers.find((candidate) => candidate.id === input.workerId);
19467
19574
  return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during lifecycle observation");
19468
- }, refsWithinScope = (refs, scope) => refs.every((ref) => ref.kind !== "file" || scopeCovers(scope, { description: "", paths: [ref.path], exclusions: [] })), TASK_SCOPED_ACTIONS, WORKER_ADDRESSED_ACTIONS, workerCommand = (taskId, request) => {
19575
+ }, refsWithinScope = (refs, scope) => refs.every((ref) => ref.kind !== "file" || scopeCovers(scope, { description: "", paths: [ref.path], exclusions: [] })), TASK_SCOPED_ACTIONS, ONLY_OWN_REPORT = "workers can submit only their own report", NO_HELPER_CONTROL = "helpers cannot cancel or control workers", WORKER_ADDRESSED_ACTIONS, workerCommand = (taskId, request) => {
19469
19576
  const { action, workerId, reason, report } = request;
19470
19577
  const rest = JSON.stringify({ reason, report });
19471
19578
  const payload = rest === "{}" ? "" : ` --payload '${rest.replace(/'/gu, "'\\''")}'`;
@@ -73303,9 +73410,15 @@ function show(argv, io) {
73303
73410
  return emit(io, fail("invalid_input", error instanceof Error ? error.message : String(error)));
73304
73411
  }
73305
73412
  const tracks = releaseTracksReport(io.cwd);
73306
- const shown = tracks.tracks.length || tracks.error ? { ...autonomy, releaseTracks: tracks } : autonomy;
73413
+ const tierModelIssues = workspaceTierModelIssues(io.cwd);
73414
+ const shown = {
73415
+ ...autonomy,
73416
+ ...tracks.tracks.length || tracks.error ? { releaseTracks: tracks } : {},
73417
+ ...tierModelIssues.length ? { tierModelIssues } : {}
73418
+ };
73307
73419
  return emit(io, ok(shown), (data) => [
73308
73420
  ...data.note ? [`note: ${data.note}`] : [],
73421
+ ...tierModelIssues.map((issue) => `note: ${issue}`),
73309
73422
  data.workspace ? `workspace ${data.workspace} (${data.source === "default" ? "D4 defaults" : `from ${data.source}`})` : "no workspace matches this checkout: D4 defaults apply",
73310
73423
  ...describe2(data.grants, data.configured, data, data.verification),
73311
73424
  ...describeReleaseTracks(tracks).map((line) => ` ${line}`),
@@ -73401,6 +73514,7 @@ usage: ${USAGE2}`)), run9 = (argv, io) => runGrant(argv, io);
73401
73514
  var init_grant = __esm(() => {
73402
73515
  init_autonomy();
73403
73516
  init_release_tracks();
73517
+ init_workspaces();
73404
73518
  init_output();
73405
73519
  init_prompt();
73406
73520
  AGENT_ENV = [
@@ -82374,6 +82488,7 @@ function renderBrief(cwd, plan, input) {
82374
82488
  what: String(row.what)
82375
82489
  }));
82376
82490
  const identity = identityOf(input.actor.host);
82491
+ const model = workspaceTierModel(cwd, slice.tier, input.actor.host);
82377
82492
  const minted = workerSession(sessionSafe(input.actor.session), slice.id, input.attempt);
82378
82493
  const session = identity === "declared" ? minted : null;
82379
82494
  const fanIn = plan.fanIn === "integration" ? [
@@ -82397,6 +82512,7 @@ function renderBrief(cwd, plan, input) {
82397
82512
  ...slice.acceptance.map((line) => ` - ${line}`),
82398
82513
  `VERIFY: ${slice.verify.join("; ")}`,
82399
82514
  `TIER: ${slice.tier}`,
82515
+ ...model ? [` model: ${model.model} (fanout.tierModels in workspace ${model.workspace})`] : [],
82400
82516
  `TIMEBOX: ${slice.timebox ?? DEFAULT_TIMEBOX}; past it without a new commit you will be replaced`,
82401
82517
  scratchLine,
82402
82518
  `FORBIDDEN: ${slice.forbidden.join("; ")}`,
@@ -82417,6 +82533,7 @@ function renderBrief(cwd, plan, input) {
82417
82533
  branch,
82418
82534
  base: slice.base,
82419
82535
  tier: slice.tier,
82536
+ model: model?.model ?? null,
82420
82537
  scratch,
82421
82538
  session,
82422
82539
  standing,
@@ -82459,6 +82576,7 @@ var DEFAULT_TIMEBOX = "30 minutes", REPORT, identityOf = (host) => {
82459
82576
  ];
82460
82577
  }, sessionSafe = (text) => text.replace(/[^A-Za-z0-9_.:@/+-]/gu, "-"), SESSION_MAX = 128;
82461
82578
  var init_fanout_brief = __esm(() => {
82579
+ init_workspaces();
82462
82580
  init_ledger();
82463
82581
  init_fanout();
82464
82582
  init_fanout_worktree();
@@ -83076,6 +83194,15 @@ function fanoutStatus(cwd, plan, options) {
83076
83194
  if (row.waitsFor.length && !suggested.includes(id))
83077
83195
  row.reasons.push(`waits for ${row.waitsFor.join(", ")}`);
83078
83196
  }
83197
+ const host = options.host === undefined ? actorFromEnv(process.env).host : options.host;
83198
+ const spawnModels = {};
83199
+ for (const id of spawnable) {
83200
+ const tier = plan.slices.find((slice) => slice.id === id)?.tier;
83201
+ const model = tier ? workspaceTierModel(cwd, tier, host) : null;
83202
+ if (model)
83203
+ spawnModels[id] = model.model;
83204
+ }
83205
+ const spawnList = spawnable.map((id) => spawnModels[id] ? `${id} (model ${spawnModels[id]})` : id).join(", ");
83079
83206
  const stuck = order.filter((id) => out.get(id)?.stuck);
83080
83207
  const down = breaker.down();
83081
83208
  if (down)
@@ -83085,7 +83212,7 @@ function fanoutStatus(cwd, plan, options) {
83085
83212
  const row = out.get(id);
83086
83213
  return !row.landed && row.reasons.length === 1 && row.reasons[0] === "no PR";
83087
83214
  });
83088
- const next = stuck.length ? `replace ${stuck.join(", ")}: stop the worker, then workit fanout worktree release ${stuck[0]} (records git status first) and respawn it in MODE: resume` : suggested.length ? online ? `land in this order: ${suggested.join(", ")} (workit fanout check first; workit pr merge each)` : `land in this order: ${suggested.join(", ")} once each has a PR (offline: PRs unchecked; open a missing one with workit git push && workit pr create --fill, then workit fanout status online)` : noPr.length ? `open PRs for ${noPr.join(", ")}: workit git push && workit pr create --fill on each branch` : spawnable.length ? `spawn ${spawnable.join(", ")} (workit fanout worktree create <slice> on hosts without native worktrees)` : order.every((id) => out.get(id)?.landed) ? "every slice has landed" : "wait for workers, then workit fanout status again";
83215
+ const next = stuck.length ? `replace ${stuck.join(", ")}: stop the worker, then workit fanout worktree release ${stuck[0]} (records git status first) and respawn it in MODE: resume` : suggested.length ? online ? `land in this order: ${suggested.join(", ")} (workit fanout check first; workit pr merge each)` : `land in this order: ${suggested.join(", ")} once each has a PR (offline: PRs unchecked; open a missing one with workit git push && workit pr create --fill, then workit fanout status online)` : noPr.length ? `open PRs for ${noPr.join(", ")}: workit git push && workit pr create --fill on each branch` : spawnable.length ? `spawn ${spawnList} (workit fanout worktree create <slice> on hosts without native worktrees)` : order.every((id) => out.get(id)?.landed) ? "every slice has landed" : "wait for workers, then workit fanout status again";
83089
83216
  return {
83090
83217
  ok: true,
83091
83218
  data: {
@@ -83099,6 +83226,7 @@ function fanoutStatus(cwd, plan, options) {
83099
83226
  slices: order.map((id) => out.get(id)),
83100
83227
  landingOrder: suggested,
83101
83228
  spawnable,
83229
+ spawnModels,
83102
83230
  stuck,
83103
83231
  next,
83104
83232
  notes
@@ -83112,6 +83240,7 @@ var DEFAULT_STUCK_MS, isoOf = (seconds) => {
83112
83240
  var init_fanout_status = __esm(() => {
83113
83241
  init_duration();
83114
83242
  init_report();
83243
+ init_workspaces();
83115
83244
  init_ledger();
83116
83245
  init_fanout_check();
83117
83246
  init_fanout_landed();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cli",
3
- "version": "8.13.1",
3
+ "version": "8.14.1",
4
4
  "private": false,
5
5
  "description": "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
6
6
  "keywords": [
@@ -38,13 +38,13 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@babel/parser": "7.29.9",
41
- "@brainervirus/workit-cursor": "^8.13.1",
41
+ "@brainervirus/workit-cursor": "^8.14.1",
42
42
  "@inkjs/ui": "2.0.0",
43
43
  "ink": "7.1.1",
44
44
  "react": "19.2.8"
45
45
  },
46
46
  "devDependencies": {
47
- "@brainervirus/workit-core": "^8.13.1"
47
+ "@brainervirus/workit-core": "^8.14.1"
48
48
  },
49
49
  "engines": {
50
50
  "node": ">=24"