@brainervirus/workit-cli 8.25.0 → 8.26.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 +330 -102
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -6670,6 +6670,32 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
6670
6670
  }, DELEGATION_MODES, isDelegation = (value) => DELEGATION_MODES.includes(value), workspaceDelegation = (cwd, dir) => {
6671
6671
  const source = inheritedSetting(cwd, dir, (entry) => isDelegation(entry.delegation))?.source;
6672
6672
  return isDelegation(source?.delegation) ? source.delegation : "inline-first";
6673
+ }, modelSources = (cwd, dir) => {
6674
+ const out = [];
6675
+ try {
6676
+ const matched = matchRuntimeWorkspace(cwd, dir);
6677
+ if (matched) {
6678
+ const enclosing = matched.matches.filter((entry) => entry !== matched.selected).toSorted((a, b) => globSpecificity(b.glob) - globSpecificity(a.glob));
6679
+ for (const entry of [matched.selected, ...enclosing])
6680
+ out.push({
6681
+ name: entry.name,
6682
+ global: false,
6683
+ models: entry.models,
6684
+ tierModels: entry.fanout?.tierModels
6685
+ });
6686
+ }
6687
+ } catch {}
6688
+ try {
6689
+ const document2 = JSON.parse(readFileSync2(path2.join(dir ?? configDir(), "workspaces.json"), "utf8"));
6690
+ if (document2 && typeof document2 === "object" && !Array.isArray(document2))
6691
+ out.push({
6692
+ name: "global",
6693
+ global: true,
6694
+ models: document2.models,
6695
+ tierModels: undefined
6696
+ });
6697
+ } catch {}
6698
+ return out;
6673
6699
  }, hostFamily = (host) => host.replace(/_(?:cli|desktop)$/u, ""), TIER_KEYS, TIER_HOSTS, workspaceTierModelIssues = (cwd, dir) => {
6674
6700
  let matched;
6675
6701
  try {
@@ -6705,25 +6731,6 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
6705
6731
  }
6706
6732
  }
6707
6733
  return issues;
6708
- }, workspaceTierModel = (cwd, tier, host, dir) => {
6709
- const pick = (entry) => {
6710
- const fanout = entry.fanout;
6711
- const models = fanout?.tierModels;
6712
- if (!models || typeof models !== "object" || !Object.hasOwn(models, tier))
6713
- return null;
6714
- const value = models[tier];
6715
- if (typeof value === "string")
6716
- return value.trim() || null;
6717
- if (!value || typeof value !== "object")
6718
- return null;
6719
- const byHost = value;
6720
- const family = host ? hostFamily(host) : null;
6721
- 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);
6722
- return typeof named === "string" && named.trim() ? named.trim() : null;
6723
- };
6724
- const found = inheritedSetting(cwd, dir, (entry) => pick(entry) !== null);
6725
- const model = found?.source ? pick(found.source) : null;
6726
- return model && found?.source ? { model, workspace: found.source.name } : null;
6727
6734
  }, resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
6728
6735
  const matched = matchRuntimeWorkspace(cwd);
6729
6736
  if (!matched)
@@ -6878,6 +6885,7 @@ var init_workspaces = __esm(() => {
6878
6885
  trailers: boolean2().optional(),
6879
6886
  liveSessionGuard: boolean2().optional(),
6880
6887
  fanout: object({ tierModels: unknown().optional() }).passthrough().optional(),
6888
+ models: object({ roles: unknown().optional() }).passthrough().optional(),
6881
6889
  autonomy: object(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
6882
6890
  kind,
6883
6891
  union([boolean2(), literal("verified")]).optional()
@@ -6904,7 +6912,10 @@ var init_workspaces = __esm(() => {
6904
6912
  });
6905
6913
  }
6906
6914
  });
6907
- workspacesFileSchema = object({ workspaces: array(workspaceConfigSchema).optional() }).passthrough().superRefine((file, context) => {
6915
+ workspacesFileSchema = object({
6916
+ workspaces: array(workspaceConfigSchema).optional(),
6917
+ models: object({ roles: unknown().optional() }).passthrough().optional()
6918
+ }).passthrough().superRefine((file, context) => {
6908
6919
  const names = new Set;
6909
6920
  for (const [index, workspace] of (file.workspaces ?? []).entries()) {
6910
6921
  if (names.has(workspace.name)) {
@@ -9229,7 +9240,7 @@ var package_default;
9229
9240
  var init_package = __esm(() => {
9230
9241
  package_default = {
9231
9242
  name: "@brainervirus/workit-cli",
9232
- version: "8.25.0",
9243
+ version: "8.26.1",
9233
9244
  private: false,
9234
9245
  description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
9235
9246
  keywords: [
@@ -9267,13 +9278,13 @@ var init_package = __esm(() => {
9267
9278
  },
9268
9279
  dependencies: {
9269
9280
  "@babel/parser": "7.29.9",
9270
- "@brainervirus/workit-cursor": "^8.25.0",
9281
+ "@brainervirus/workit-cursor": "^8.26.1",
9271
9282
  "@inkjs/ui": "2.0.0",
9272
9283
  ink: "7.1.1",
9273
9284
  react: "19.2.8"
9274
9285
  },
9275
9286
  devDependencies: {
9276
- "@brainervirus/workit-core": "^8.25.0"
9287
+ "@brainervirus/workit-core": "^8.26.1"
9277
9288
  },
9278
9289
  engines: {
9279
9290
  node: ">=24"
@@ -64958,6 +64969,134 @@ var readText2 = (file) => {
64958
64969
  }), PROBE_MEMORY = "268435456", PROBE_CPU = "50%", PROBE_SCRIPT = 'cg=$(sed -n "s/^0:://p" /proc/self/cgroup); cat "/sys/fs/cgroup$cg/memory.max" "/sys/fs/cgroup$cg/cpu.max"';
64959
64970
  var init_heavy_scope = () => {};
64960
64971
 
64972
+ // packages/workit-core/src/core/role-models.ts
64973
+ var MODEL_ROLES, MODEL_TIERS, HOST_KEYS, BUILT_IN_CLAUDE_CODE, isObject9 = (value) => !!value && typeof value === "object" && !Array.isArray(value), name = (value) => typeof value === "string" && value.trim() ? value.trim() : null, leaf = (value) => {
64974
+ const text = name(value);
64975
+ if (text)
64976
+ return { model: text, effort: null };
64977
+ if (!isObject9(value))
64978
+ return null;
64979
+ const model = name(value.model);
64980
+ return model ? { model, effort: name(value.effort) } : null;
64981
+ }, isFlat = (value) => typeof value === "string" || isObject9(value) && Object.hasOwn(value, "model"), forHost = (value, host) => {
64982
+ if (isFlat(value))
64983
+ return leaf(value);
64984
+ if (!isObject9(value))
64985
+ return null;
64986
+ const family = host ? hostFamily(host) : null;
64987
+ for (const key of [family, host, "default"])
64988
+ if (key && Object.hasOwn(value, key)) {
64989
+ const found = leaf(value[key]);
64990
+ if (found)
64991
+ return found;
64992
+ }
64993
+ return null;
64994
+ }, rolesOf = (models) => isObject9(models) && isObject9(models.roles) ? models.roles : null, resolveRoleModel = (cwd, selector, host, dir) => {
64995
+ const { role, tier } = selector;
64996
+ for (const source of modelSources(cwd, dir)) {
64997
+ const where = source.global ? "the global default" : `workspace ${source.name}`;
64998
+ const roles = rolesOf(source.models);
64999
+ const configured = roles && Object.hasOwn(roles, role) ? roles[role] : undefined;
65000
+ const fromRoles = role === "implementer" ? tier && isObject9(configured) && Object.hasOwn(configured, tier) ? forHost(configured[tier], host) : null : forHost(configured, host);
65001
+ if (fromRoles)
65002
+ return { ...fromRoles, source: `models.roles in ${where}` };
65003
+ if (role === "implementer" && tier && isObject9(source.tierModels)) {
65004
+ const fromTiers = Object.hasOwn(source.tierModels, tier) ? forHost(source.tierModels[tier], host) : null;
65005
+ if (fromTiers)
65006
+ return { model: fromTiers.model, effort: null, source: `fanout.tierModels in ${where}` };
65007
+ }
65008
+ }
65009
+ if (host && hostFamily(host) === "claude_code") {
65010
+ const builtIn = BUILT_IN_CLAUDE_CODE[tier ? `${role}.${tier}` : role];
65011
+ if (builtIn)
65012
+ return { model: builtIn.model, effort: builtIn.effort ?? null, source: "built-in" };
65013
+ }
65014
+ return null;
65015
+ }, ROLE_SELECTORS, valueIssues = (where, value, out) => {
65016
+ if (isFlat(value)) {
65017
+ if (!leaf(value))
65018
+ out.push(`${where}.model: not a model name; ignored`);
65019
+ if (isObject9(value) && value.effort !== undefined && !name(value.effort))
65020
+ out.push(`${where}.effort: not an effort name; ignored`);
65021
+ return;
65022
+ }
65023
+ if (!isObject9(value)) {
65024
+ out.push(`${where}: not a model name or a per-host object; ignored`);
65025
+ return;
65026
+ }
65027
+ for (const [host, entry] of Object.entries(value)) {
65028
+ if (!HOST_KEYS.has(host))
65029
+ out.push(`${where}.${host}: unknown host; ignored`);
65030
+ else {
65031
+ if (!leaf(entry))
65032
+ out.push(`${where}.${host}.model: not a model name; ignored`);
65033
+ if (isObject9(entry) && entry.effort !== undefined && !name(entry.effort))
65034
+ out.push(`${where}.${host}.effort: not an effort name; ignored`);
65035
+ }
65036
+ }
65037
+ }, roleModelIssues = (cwd, dir) => {
65038
+ const issues = [];
65039
+ for (const source of modelSources(cwd, dir)) {
65040
+ if (source.models === undefined)
65041
+ continue;
65042
+ const base = `${source.global ? "global default" : `workspace ${source.name}`} models.roles`;
65043
+ if (!isObject9(source.models) || source.models.roles !== undefined && !rolesOf(source.models)) {
65044
+ issues.push(`${base} is not an object; ignored`);
65045
+ continue;
65046
+ }
65047
+ for (const [role, value] of Object.entries(rolesOf(source.models) ?? {})) {
65048
+ const where = `${base}.${role}`;
65049
+ if (!MODEL_ROLES.includes(role))
65050
+ issues.push(`${base}.${role}: unknown role; ignored`);
65051
+ else if (role === "implementer") {
65052
+ if (!isObject9(value))
65053
+ issues.push(`${where}: not an object keyed by tier; ignored`);
65054
+ else
65055
+ for (const [tier, entry] of Object.entries(value))
65056
+ if (!MODEL_TIERS.includes(tier))
65057
+ issues.push(`${where}.${tier}: unknown tier; ignored`);
65058
+ else
65059
+ valueIssues(`${where}.${tier}`, entry, issues);
65060
+ } else
65061
+ valueIssues(where, value, issues);
65062
+ }
65063
+ }
65064
+ return issues;
65065
+ };
65066
+ var init_role_models = __esm(() => {
65067
+ init_workspaces();
65068
+ MODEL_ROLES = [
65069
+ "decider",
65070
+ "implementer",
65071
+ "verifier",
65072
+ "reviewer",
65073
+ "explore",
65074
+ "babysit"
65075
+ ];
65076
+ MODEL_TIERS = ["mundane", "standard", "hard"];
65077
+ HOST_KEYS = new Set([
65078
+ "claude_code",
65079
+ "opencode",
65080
+ "codex",
65081
+ "codex_cli",
65082
+ "codex_desktop",
65083
+ "cursor",
65084
+ "pi",
65085
+ "default"
65086
+ ]);
65087
+ BUILT_IN_CLAUDE_CODE = {
65088
+ decider: { model: "fable", effort: "high" },
65089
+ "implementer.hard": { model: "opus" },
65090
+ "implementer.standard": { model: "sonnet" },
65091
+ "implementer.mundane": { model: "haiku" },
65092
+ verifier: { model: "sonnet" },
65093
+ reviewer: { model: "opus" },
65094
+ explore: { model: "haiku" },
65095
+ babysit: { model: "haiku" }
65096
+ };
65097
+ ROLE_SELECTORS = MODEL_ROLES.flatMap((role) => role === "implementer" ? MODEL_TIERS.map((tier) => ({ role, tier })) : [{ role }]);
65098
+ });
65099
+
64961
65100
  // packages/workit-cli/src/admin/host-install.ts
64962
65101
  import { spawnSync as spawnSync14 } from "node:child_process";
64963
65102
  import {
@@ -67758,6 +67897,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67758
67897
  const tracks = releaseTracksReport(res.cwd);
67759
67898
  const lines = describeReleaseTracks(tracks);
67760
67899
  const detail = [matched, ...branchPresetLine(res, match), ...lines].join("; ");
67900
+ const modelIssues = roleModelIssues(res.cwd, res.configDir);
67761
67901
  if (tracks.error)
67762
67902
  return {
67763
67903
  id: "workspace_mismatch",
@@ -67772,6 +67912,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
67772
67912
  detail,
67773
67913
  fix: `Fix the reported releaseTracks fields in ${file}, or pass --track <name> where the track is not determined`
67774
67914
  };
67915
+ if (modelIssues.length)
67916
+ return {
67917
+ id: "workspace_mismatch",
67918
+ status: "warn",
67919
+ detail: [detail, ...modelIssues].join("; "),
67920
+ fix: `Fix the reported models.roles entries in ${file} (roles: decider, implementer, verifier, reviewer, explore, babysit; hosts: claude_code, opencode, codex, cursor, pi, default)`
67921
+ };
67775
67922
  return { id: "workspace_mismatch", status: "pass", detail };
67776
67923
  }
67777
67924
  return {
@@ -68436,6 +68583,7 @@ var init_doctor = __esm(() => {
68436
68583
  init_package_root();
68437
68584
  init_registration();
68438
68585
  init_workspaces();
68586
+ init_role_models();
68439
68587
  init_host_install();
68440
68588
  init_skill_manifests();
68441
68589
  init_session_hook();
@@ -75089,7 +75237,7 @@ function show(argv, io) {
75089
75237
  return emit(io, fail2("invalid_input", error instanceof Error ? error.message : String(error)));
75090
75238
  }
75091
75239
  const tracks = releaseTracksReport(io.cwd);
75092
- const tierModelIssues = workspaceTierModelIssues(io.cwd);
75240
+ const tierModelIssues = [...workspaceTierModelIssues(io.cwd), ...roleModelIssues(io.cwd)];
75093
75241
  const shown = {
75094
75242
  ...autonomy,
75095
75243
  ...tracks.tracks.length || tracks.error ? { releaseTracks: tracks } : {},
@@ -75195,6 +75343,7 @@ usage: ${USAGE3}`)), run10 = (argv, io) => runGrant(argv, io);
75195
75343
  var init_grant = __esm(() => {
75196
75344
  init_autonomy();
75197
75345
  init_release_tracks();
75346
+ init_role_models();
75198
75347
  init_workspaces();
75199
75348
  init_output();
75200
75349
  init_prompt();
@@ -76760,6 +76909,60 @@ var init_lock = __esm(() => {
76760
76909
  init_check();
76761
76910
  });
76762
76911
 
76912
+ // packages/workit-cli/src/verbs/models.ts
76913
+ var exports_models = {};
76914
+ __export(exports_models, {
76915
+ run: () => run13
76916
+ });
76917
+ async function run13(argv, io) {
76918
+ const [sub, ...args] = argv.filter((arg) => arg !== "--json");
76919
+ if (sub !== "show")
76920
+ return emit(io, fail2("invalid_input", `usage: ${USAGE6}`, { unblock: "workit help models" }));
76921
+ const role = flag3(args, "--role");
76922
+ const tier = flag3(args, "--tier");
76923
+ const hostFlag = flag3(args, "--host");
76924
+ for (const value of [role, tier, hostFlag])
76925
+ if (value instanceof Error)
76926
+ return emit(io, fail2("invalid_input", value.message));
76927
+ if (role && !MODEL_ROLES.includes(role))
76928
+ return emit(io, fail2("invalid_input", `unknown role ${role}: ${MODEL_ROLES.join(", ")}`));
76929
+ if (tier && !MODEL_TIERS.includes(tier))
76930
+ return emit(io, fail2("invalid_input", `unknown tier ${tier}: ${MODEL_TIERS.join(", ")}`));
76931
+ const envHost = actorFromEnv(io.env).host;
76932
+ const host = hostFlag ?? (envHost === "cli" ? "claude_code" : envHost);
76933
+ const row = (selector) => resolveRoleModel(io.cwd, selector, host) ?? { model: null, effort: null, source: "none" };
76934
+ const roles = {};
76935
+ for (const selector of ROLE_SELECTORS) {
76936
+ if (role && selector.role !== role)
76937
+ continue;
76938
+ if (selector.tier) {
76939
+ if (tier && selector.tier !== tier)
76940
+ continue;
76941
+ const tiers = roles[selector.role] ??= {};
76942
+ tiers[selector.tier] = row(selector);
76943
+ } else
76944
+ roles[selector.role] = row(selector);
76945
+ }
76946
+ const issues = roleModelIssues(io.cwd);
76947
+ return emit(io, ok2({ host, roles, ...issues.length ? { issues } : {} }), (data) => [
76948
+ `models for ${data.host}`,
76949
+ ...Object.entries(data.roles).flatMap(([name, entry]) => ("source" in entry) ? [line2(name, entry)] : Object.entries(entry).map(([t, tierRow]) => line2(`${name} ${t}`, tierRow))),
76950
+ ...(data.issues ?? []).map((issue) => `note: ${issue}`)
76951
+ ]);
76952
+ }
76953
+ var USAGE6 = "workit models show [--role <role>] [--tier <tier>] [--host <host>] [--json]", flag3 = (argv, name) => {
76954
+ const at = argv.findIndex((arg) => arg === name || arg.startsWith(`${name}=`));
76955
+ if (at < 0)
76956
+ return null;
76957
+ const value = argv[at].includes("=") ? argv[at].slice(name.length + 1) : argv[at + 1];
76958
+ return value && !value.startsWith("--") ? value : new Error(`${name} needs a value`);
76959
+ }, line2 = (label, entry) => ` ${label}: ${entry.model ? `${entry.model}${entry.effort ? ` (effort ${entry.effort})` : ""} [${entry.source}]` : "host default (nothing configured)"}`;
76960
+ var init_models = __esm(() => {
76961
+ init_role_models();
76962
+ init_ledger();
76963
+ init_output();
76964
+ });
76965
+
76763
76966
  // packages/workit-core/src/core/youtrack-tools.ts
76764
76967
  async function logTimeUpdate(input, operation = defaultOperations) {
76765
76968
  try {
@@ -82805,7 +83008,7 @@ var init_forge_common = __esm(() => {
82805
83008
  // packages/workit-cli/src/verbs/pr.ts
82806
83009
  var exports_pr = {};
82807
83010
  __export(exports_pr, {
82808
- run: () => run13
83011
+ run: () => run14
82809
83012
  });
82810
83013
  import { readFileSync as readFileSync23 } from "node:fs";
82811
83014
  import path57 from "node:path";
@@ -83254,7 +83457,7 @@ async function reply(argv, io) {
83254
83457
  `${[data.replied ? "replied to" : null, data.resolved ? "resolved" : null].filter(Boolean).join(" and ")} thread ${data.thread} on ${prLabel(kind, data.number)}${data.replyUrl ? ` ${data.replyUrl}` : ""}`
83255
83458
  ]);
83256
83459
  }
83257
- async function run13(argv, io) {
83460
+ async function run14(argv, io) {
83258
83461
  const [sub, ...rest] = argv;
83259
83462
  if (sub === "status")
83260
83463
  return status2(rest, io);
@@ -83270,9 +83473,9 @@ async function run13(argv, io) {
83270
83473
  return threads(rest, io);
83271
83474
  if (sub === "reply")
83272
83475
  return reply(rest, io);
83273
- return usage3(io, sub && !sub.startsWith("-") ? `unknown pr subcommand "${sub}"` : "missing pr subcommand", USAGE6);
83476
+ return usage3(io, sub && !sub.startsWith("-") ? `unknown pr subcommand "${sub}"` : "missing pr subcommand", USAGE7);
83274
83477
  }
83275
- var STATUS_USAGE = "workit pr status [--pr <n> | --branch <b>] [--log-lines 60] [--json]", CREATE_USAGE = "workit pr create [--base <b> | --track <t>] (--title <t> [--body <text> | --body-file <f|->] | --fill) [--issue <#n|ID|url>]… [--refs] [--label <l>]… [--reviewer <login>]… [--draft] [--json]", MERGE_USAGE = "workit pr merge [--pr <n>] [--method squash|merge|rebase] [--subject <s>] [--body <b> | --body-file <f|->] [--delete-branch] [--unverified --reason <why>] [--json]", READY_USAGE = "workit pr ready [--pr <n>] [--undo] [--json]", EDIT_USAGE = "workit pr edit [--pr <n>] [--title <t>] [--body-file <f|->] [--add-label <l>]… [--remove-label <l>]… [--add-reviewer <login>]… [--base <b>] [--json]", THREADS_USAGE = "workit pr threads [--pr <n>] [--json]", REPLY_USAGE = "workit pr reply [--pr <n>] --thread <id> [--body-file <f|->] [--resolve] [--json]", USAGE6 = "workit pr status|create|merge|ready|edit|threads|reply ... (workit help pr)", prLabel = (kind, number) => `${kind === "github" ? "PR #" : "MR !"}${number}`, NEED_TEXT, mergedVerdictLine = (landed) => landed === "untracked" ? "merged outside workit (no merge record)" : landed.unverified ? `merged unverified at ${(landed.head ?? "?").slice(0, 12)} (recorded bypass)` : landed.lane === "none" && !landed.verdictId ? `merged at ${(landed.head ?? "?").slice(0, 12)} with no verdict (lane none)` : landed.review === "self-reviewed" ? `merged self-reviewed (lane self) with the author's verdict ${landed.verdictId ?? "?"} at ${(landed.head ?? "?").slice(0, 12)}` : `merged with accepted verdict ${landed.verdictId ?? "?"} at ${(landed.head ?? "?").slice(0, 12)}${landed.intentOnly ? " (merge intent recorded; the merge call itself failed)" : ""}`, acceptedHow = (verdict) => verdict.cover ? `stack verdict ${verdict.cover.verdictId} on ${verdict.cover.branch} @ ${verdict.cover.head.slice(0, 12)}` : verdict.carry ? carryLabel(verdict.carry) : verdict.basis, METHODS2;
83478
+ var STATUS_USAGE = "workit pr status [--pr <n> | --branch <b>] [--log-lines 60] [--json]", CREATE_USAGE = "workit pr create [--base <b> | --track <t>] (--title <t> [--body <text> | --body-file <f|->] | --fill) [--issue <#n|ID|url>]… [--refs] [--label <l>]… [--reviewer <login>]… [--draft] [--json]", MERGE_USAGE = "workit pr merge [--pr <n>] [--method squash|merge|rebase] [--subject <s>] [--body <b> | --body-file <f|->] [--delete-branch] [--unverified --reason <why>] [--json]", READY_USAGE = "workit pr ready [--pr <n>] [--undo] [--json]", EDIT_USAGE = "workit pr edit [--pr <n>] [--title <t>] [--body-file <f|->] [--add-label <l>]… [--remove-label <l>]… [--add-reviewer <login>]… [--base <b>] [--json]", THREADS_USAGE = "workit pr threads [--pr <n>] [--json]", REPLY_USAGE = "workit pr reply [--pr <n>] --thread <id> [--body-file <f|->] [--resolve] [--json]", USAGE7 = "workit pr status|create|merge|ready|edit|threads|reply ... (workit help pr)", prLabel = (kind, number) => `${kind === "github" ? "PR #" : "MR !"}${number}`, NEED_TEXT, mergedVerdictLine = (landed) => landed === "untracked" ? "merged outside workit (no merge record)" : landed.unverified ? `merged unverified at ${(landed.head ?? "?").slice(0, 12)} (recorded bypass)` : landed.lane === "none" && !landed.verdictId ? `merged at ${(landed.head ?? "?").slice(0, 12)} with no verdict (lane none)` : landed.review === "self-reviewed" ? `merged self-reviewed (lane self) with the author's verdict ${landed.verdictId ?? "?"} at ${(landed.head ?? "?").slice(0, 12)}` : `merged with accepted verdict ${landed.verdictId ?? "?"} at ${(landed.head ?? "?").slice(0, 12)}${landed.intentOnly ? " (merge intent recorded; the merge call itself failed)" : ""}`, acceptedHow = (verdict) => verdict.cover ? `stack verdict ${verdict.cover.verdictId} on ${verdict.cover.branch} @ ${verdict.cover.head.slice(0, 12)}` : verdict.carry ? carryLabel(verdict.carry) : verdict.basis, METHODS2;
83276
83479
  var init_pr = __esm(() => {
83277
83480
  init_issue_link();
83278
83481
  init_pr_edit();
@@ -83298,7 +83501,7 @@ var init_pr = __esm(() => {
83298
83501
  // packages/workit-cli/src/verbs/ci.ts
83299
83502
  var exports_ci = {};
83300
83503
  __export(exports_ci, {
83301
- run: () => run14
83504
+ run: () => run15
83302
83505
  });
83303
83506
  async function wait2(argv, io) {
83304
83507
  const flags = parseFlags(argv, {
@@ -83467,7 +83670,7 @@ async function rerun(argv, io) {
83467
83670
  "next: workit ci wait"
83468
83671
  ]);
83469
83672
  }
83470
- async function run14(argv, io) {
83673
+ async function run15(argv, io) {
83471
83674
  const [sub, ...rest] = argv;
83472
83675
  if (sub === "wait")
83473
83676
  return wait2(rest, io);
@@ -83515,7 +83718,7 @@ var init_implicit_task = __esm(() => {
83515
83718
  // packages/workit-cli/src/verbs/git.ts
83516
83719
  var exports_git = {};
83517
83720
  __export(exports_git, {
83518
- run: () => run15
83721
+ run: () => run16
83519
83722
  });
83520
83723
  import { readFileSync as readFileSync24 } from "node:fs";
83521
83724
  import path58 from "node:path";
@@ -83773,7 +83976,7 @@ function trailers(argv, io) {
83773
83976
  const state = workspaceTrailers(io.cwd);
83774
83977
  return emit(io, ok2(state), (data) => data.enabled ? "on" : "off");
83775
83978
  }
83776
- async function run15(argv, io) {
83979
+ async function run16(argv, io) {
83777
83980
  const [sub, ...rest] = argv;
83778
83981
  if (sub === "branch")
83779
83982
  return branch(rest, io);
@@ -83783,9 +83986,9 @@ async function run15(argv, io) {
83783
83986
  return push(rest, io);
83784
83987
  if (sub === "trailers")
83785
83988
  return trailers(rest, io);
83786
- return usage3(io, sub && !sub.startsWith("-") ? `unknown git subcommand "${sub}"` : "missing git subcommand", USAGE7);
83989
+ return usage3(io, sub && !sub.startsWith("-") ? `unknown git subcommand "${sub}"` : "missing git subcommand", USAGE8);
83787
83990
  }
83788
- var BRANCH_USAGE = "workit git branch <name> | --kind feature|bugfix|release|hotfix --slug <s> [--base <b>] [--track <t>] [--carry] [--json]", COMMIT_USAGE = "workit git commit -m|--message <msg>… | -F|--file <file|-> [--trailer <key: value>]… [--amend [--no-edit]] [--allow-empty] [-a|--all | [--] <paths…>] [--json]", PUSH_USAGE = "workit git push [--set-upstream] [--force-with-lease [--expect <sha>] [--overwrite-unintegrated]] [--release <main|develop|v-tag>…] [--json]", USAGE7 = "workit git branch|commit|push|trailers ... (workit help git)", short2 = (sha) => sha ? sha.slice(0, 12) : "(none)", COMMIT_SWITCHES;
83991
+ var BRANCH_USAGE = "workit git branch <name> | --kind feature|bugfix|release|hotfix --slug <s> [--base <b>] [--track <t>] [--carry] [--json]", COMMIT_USAGE = "workit git commit -m|--message <msg>… | -F|--file <file|-> [--trailer <key: value>]… [--amend [--no-edit]] [--allow-empty] [-a|--all | [--] <paths…>] [--json]", PUSH_USAGE = "workit git push [--set-upstream] [--force-with-lease [--expect <sha>] [--overwrite-unintegrated]] [--release <main|develop|v-tag>…] [--json]", USAGE8 = "workit git branch|commit|push|trailers ... (workit help git)", short2 = (sha) => sha ? sha.slice(0, 12) : "(none)", COMMIT_SWITCHES;
83789
83992
  var init_git2 = __esm(() => {
83790
83993
  init_autonomy();
83791
83994
  init_branch();
@@ -84466,7 +84669,7 @@ var init_release = __esm(() => {
84466
84669
  // packages/workit-cli/src/verbs/release.ts
84467
84670
  var exports_release = {};
84468
84671
  __export(exports_release, {
84469
- run: () => run16
84672
+ run: () => run17
84470
84673
  });
84471
84674
  async function subVerb(load, argv, io) {
84472
84675
  let out = "";
@@ -84689,7 +84892,7 @@ async function publish(argv, io) {
84689
84892
  `published ${data.branch} (${short4(data.sha)}) to ${data.remote}; remote tip verified`
84690
84893
  ]);
84691
84894
  }
84692
- async function run16(argv, io) {
84895
+ async function run17(argv, io) {
84693
84896
  const [sub, ...rest] = argv;
84694
84897
  if (sub === "start")
84695
84898
  return start(rest, io);
@@ -84697,9 +84900,9 @@ async function run16(argv, io) {
84697
84900
  return finish2(rest, io);
84698
84901
  if (sub === "publish")
84699
84902
  return publish(rest, io);
84700
- return usage3(io, sub && !sub.startsWith("-") ? `unknown release subcommand "${sub}"` : "missing release subcommand", USAGE8);
84903
+ return usage3(io, sub && !sub.startsWith("-") ? `unknown release subcommand "${sub}"` : "missing release subcommand", USAGE9);
84701
84904
  }
84702
- var START_USAGE = "workit release start <version> [--hotfix] [--track <t>] [--json]", FINISH_USAGE = "workit release finish [<version>] [--track <t>] [--dry-run] [--json]", PUBLISH_USAGE = "workit release publish [<version>] [--json]", USAGE8 = "workit release start|finish|publish ... (workit help release)", short4 = (sha) => sha ? sha.slice(0, 12) : "(none)", blocked = (io, grant) => emit(io, fail2("blocked", grant.error, { unblock: grant.unblock, data: { reason: grant.reason } })), isLocalRemote = (cwd, remote) => {
84905
+ var START_USAGE = "workit release start <version> [--hotfix] [--track <t>] [--json]", FINISH_USAGE = "workit release finish [<version>] [--track <t>] [--dry-run] [--json]", PUBLISH_USAGE = "workit release publish [<version>] [--json]", USAGE9 = "workit release start|finish|publish ... (workit help release)", short4 = (sha) => sha ? sha.slice(0, 12) : "(none)", blocked = (io, grant) => emit(io, fail2("blocked", grant.error, { unblock: grant.unblock, data: { reason: grant.reason } })), isLocalRemote = (cwd, remote) => {
84703
84906
  const url = remote ? pushUrl(cwd, remote) : null;
84704
84907
  return !url || parseRemoteUrl(url)?.protocol === "file";
84705
84908
  }, stepsOf = (plan) => [
@@ -84731,9 +84934,9 @@ var init_release2 = __esm(() => {
84731
84934
  // packages/workit-cli/src/verbs/verify-delivery.ts
84732
84935
  var exports_verify_delivery = {};
84733
84936
  __export(exports_verify_delivery, {
84734
- run: () => run17
84937
+ run: () => run18
84735
84938
  });
84736
- async function run17(argv, io) {
84939
+ async function run18(argv, io) {
84737
84940
  const flags = parseFlags(argv, {
84738
84941
  expect: "value",
84739
84942
  branch: "value",
@@ -84743,31 +84946,31 @@ async function run17(argv, io) {
84743
84946
  package: "value"
84744
84947
  });
84745
84948
  if (typeof flags === "string")
84746
- return usage3(io, flags, USAGE9);
84949
+ return usage3(io, flags, USAGE10);
84747
84950
  if (flags.positionals.length > 1)
84748
- return usage3(io, `unexpected argument ${flags.positionals[1]}`, USAGE9);
84951
+ return usage3(io, `unexpected argument ${flags.positionals[1]}`, USAGE10);
84749
84952
  const named = flags.positionals[0];
84750
84953
  if (named !== undefined && !ENDPOINTS[named])
84751
- return usage3(io, `unknown endpoint "${named}"`, USAGE9);
84954
+ return usage3(io, `unknown endpoint "${named}"`, USAGE10);
84752
84955
  if (flags.values.expect !== undefined && !ENDPOINTS[flags.values.expect])
84753
- return usage3(io, "--expect must be pushed, pr, merged or released", USAGE9);
84956
+ return usage3(io, "--expect must be pushed, pr, merged or released", USAGE10);
84754
84957
  if (named && flags.values.expect && ENDPOINTS[named] !== ENDPOINTS[flags.values.expect])
84755
- return usage3(io, `${named} and --expect ${flags.values.expect} disagree`, USAGE9);
84958
+ return usage3(io, `${named} and --expect ${flags.values.expect} disagree`, USAGE10);
84756
84959
  const expect = ENDPOINTS[named ?? ""] ?? ENDPOINTS[flags.values.expect ?? ""] ?? (flags.values.tag || flags.values.package ? "released" : flags.values.pr ? "pr" : "pushed");
84757
84960
  const pr = positiveInt(flags.values.pr, "--pr");
84758
84961
  if (typeof pr === "string")
84759
- return usage3(io, pr, USAGE9);
84962
+ return usage3(io, pr, USAGE10);
84760
84963
  if (pr && flags.values.branch)
84761
- return usage3(io, "pass --pr or --branch, not both", USAGE9);
84964
+ return usage3(io, "pass --pr or --branch, not both", USAGE10);
84762
84965
  const sha = flags.values.sha ?? null;
84763
84966
  if (sha !== null && !/^[0-9a-f]{7,64}$/u.test(sha))
84764
- return usage3(io, "--sha must be a commit sha (7-64 hex chars)", USAGE9);
84967
+ return usage3(io, "--sha must be a commit sha (7-64 hex chars)", USAGE10);
84765
84968
  const actor = actorFromEnv(io.env);
84766
84969
  const branch = flags.values.branch ?? null;
84767
84970
  let result;
84768
84971
  if (expect === "pushed") {
84769
84972
  if (pr)
84770
- return usage3(io, "push is checked by --branch, not --pr", USAGE9);
84973
+ return usage3(io, "push is checked by --branch, not --pr", USAGE10);
84771
84974
  result = verifyPushed(io.cwd, { branch, sha, actor });
84772
84975
  } else if (expect === "released") {
84773
84976
  result = verifyReleased(io.cwd, { tag: flags.values.tag ?? null, pkg: flags.values.package ?? null, sha, actor }, forgeDeps.npm);
@@ -84792,7 +84995,7 @@ async function run17(argv, io) {
84792
84995
  unblock: expect === "pushed" ? "workit git push" : expect === "pr" ? "workit git push && workit pr create --fill" : expect === "merged" ? "workit pr status # then workit pr merge when READY and granted" : "check the release workflow; the tag/package is not published"
84793
84996
  }));
84794
84997
  }
84795
- var USAGE9 = "workit verify-delivery [push|pr|merge|release] [--expect pushed|pr|merged|released] [--branch <b>] [--pr <n>] [--sha <sha>] [--tag <t>] [--package <name[@version]>] [--json]", ENDPOINTS, render2 = (report) => [
84998
+ var USAGE10 = "workit verify-delivery [push|pr|merge|release] [--expect pushed|pr|merged|released] [--branch <b>] [--pr <n>] [--sha <sha>] [--tag <t>] [--package <name[@version]>] [--json]", ENDPOINTS, render2 = (report) => [
84796
84999
  `${report.expect}: ${report.delivered ? "delivered" : "NOT delivered"}${report.branch ? ` (${report.branch}${report.sha ? ` @ ${report.sha.slice(0, 12)}` : ""})` : ""}${report.pr ? ` #${report.pr}` : ""}`,
84797
85000
  ...report.observations.map((entry) => ` ${entry.ok ? "ok" : "x "} ${entry.kind}: expected ${entry.expected ?? "-"}, observed ${entry.observed ?? "(none)"}${entry.note ? ` — ${entry.note}` : ""}`)
84798
85001
  ];
@@ -84815,7 +85018,7 @@ var init_verify_delivery = __esm(() => {
84815
85018
  // packages/workit-cli/src/verbs/stack.ts
84816
85019
  var exports_stack = {};
84817
85020
  __export(exports_stack, {
84818
- run: () => run18
85021
+ run: () => run19
84819
85022
  });
84820
85023
  async function plan(argv, io) {
84821
85024
  const flags = parseFlags(argv, { name: "value", trunk: "value", track: "value" });
@@ -84997,7 +85200,7 @@ async function land(argv, io) {
84997
85200
  unblock: ${data.stoppedAt.unblock}` : data.complete ? "stack complete" : ""
84998
85201
  ].filter(Boolean));
84999
85202
  }
85000
- async function run18(argv, io) {
85203
+ async function run19(argv, io) {
85001
85204
  const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
85002
85205
  if (sub === "plan")
85003
85206
  return plan(rest, io);
@@ -85007,9 +85210,9 @@ async function run18(argv, io) {
85007
85210
  return sync(rest, io);
85008
85211
  if (sub === "land")
85009
85212
  return land(rest, io);
85010
- return usage3(io, sub && !sub.startsWith("-") ? `unknown stack subcommand "${sub}"` : "missing stack subcommand", USAGE10);
85213
+ return usage3(io, sub && !sub.startsWith("-") ? `unknown stack subcommand "${sub}"` : "missing stack subcommand", USAGE11);
85011
85214
  }
85012
- var PLAN_USAGE = "workit stack plan [--name <n>] [--trunk <b> | --track <t>] [<bottom> … <top>] [--json]", STATUS_USAGE2 = "workit stack status [--name <n>] [--json]", SYNC_USAGE = "workit stack sync [--name <n>] [--local] [--dry-run] [--force <branch>]… [--json]", LAND_USAGE = "workit stack land [--name <n>] [--dry-run] [--max <n>] [--method squash|merge|rebase] [--unverified --reason <why>] [--timeout 20m] [--interval 30s] [--json]", USAGE10 = "workit stack plan|status|sync|land ... (workit help stack)", short5 = (sha) => sha ? sha.slice(0, 12) : "?", stackFailed = (io, result) => emit(io, fail2(result.code, result.error, { unblock: result.unblock, data: result.data ?? {} })), label3 = (forge, pr) => pr === null ? "no PR" : `${forge === "gitlab" ? "MR !" : "PR #"}${pr}`, renderSync = (data) => [
85215
+ var PLAN_USAGE = "workit stack plan [--name <n>] [--trunk <b> | --track <t>] [<bottom> … <top>] [--json]", STATUS_USAGE2 = "workit stack status [--name <n>] [--json]", SYNC_USAGE = "workit stack sync [--name <n>] [--local] [--dry-run] [--force <branch>]… [--json]", LAND_USAGE = "workit stack land [--name <n>] [--dry-run] [--max <n>] [--method squash|merge|rebase] [--unverified --reason <why>] [--timeout 20m] [--interval 30s] [--json]", USAGE11 = "workit stack plan|status|sync|land ... (workit help stack)", short5 = (sha) => sha ? sha.slice(0, 12) : "?", stackFailed = (io, result) => emit(io, fail2(result.code, result.error, { unblock: result.unblock, data: result.data ?? {} })), label3 = (forge, pr) => pr === null ? "no PR" : `${forge === "gitlab" ? "MR !" : "PR #"}${pr}`, renderSync = (data) => [
85013
85216
  `${data.dryRun ? "would sync" : "synced"} stack ${data.name}${data.merged.length ? `; merged: ${data.merged.map((item) => item.branch).join(", ")}` : ""}`,
85014
85217
  ...data.steps.map((step) => [
85015
85218
  ` ${step.branch} on ${step.parent}:`,
@@ -85618,7 +85821,8 @@ function renderBrief(cwd, plan, input) {
85618
85821
  what: String(row.what)
85619
85822
  }));
85620
85823
  const identity = identityOf(input.actor.host);
85621
- const model = workspaceTierModel(cwd, slice.tier, input.actor.host);
85824
+ const model = resolveRoleModel(cwd, { role: "implementer", tier: slice.tier }, input.actor.host);
85825
+ const verifier = resolveRoleModel(cwd, { role: "verifier" }, input.actor.host);
85622
85826
  const minted = workerSession(sessionSafe(input.actor.session), slice.id, input.attempt);
85623
85827
  const session = identity === "declared" ? minted : null;
85624
85828
  const fanIn = plan.fanIn === "integration" ? [
@@ -85646,7 +85850,12 @@ function renderBrief(cwd, plan, input) {
85646
85850
  `VERIFY: ${slice.verify.join("; ")}`,
85647
85851
  ...slice.reason ? [`REASON: ${slice.reason}`] : [],
85648
85852
  `TIER: ${slice.tier}`,
85649
- ...model ? [` model: ${model.model} (fanout.tierModels in workspace ${model.workspace})`] : [],
85853
+ ...model ? [
85854
+ ` model: ${model.model}${model.effort ? ` effort: ${model.effort}` : ""} (${model.source})`
85855
+ ] : [],
85856
+ ...verifier ? [
85857
+ ` verifier: model ${verifier.model}${verifier.effort ? ` effort ${verifier.effort}` : ""} (${verifier.source})`
85858
+ ] : [],
85650
85859
  `TIMEBOX: ${slice.timebox ?? DEFAULT_TIMEBOX}; past it without a new commit you will be replaced`,
85651
85860
  scratchLine,
85652
85861
  `FORBIDDEN: ${slice.forbidden.join("; ")}`,
@@ -85670,6 +85879,8 @@ function renderBrief(cwd, plan, input) {
85670
85879
  tier: slice.tier,
85671
85880
  issues: slice.issues,
85672
85881
  model: model?.model ?? null,
85882
+ effort: model?.effort ?? null,
85883
+ verifier: verifier ? { model: verifier.model, effort: verifier.effort } : null,
85673
85884
  scratch,
85674
85885
  session,
85675
85886
  standing,
@@ -85714,7 +85925,7 @@ var DEFAULT_TIMEBOX = "30 minutes", REPORT, identityOf = (host) => {
85714
85925
  ];
85715
85926
  }, sessionSafe = (text) => text.replace(/[^A-Za-z0-9_.:@/+-]/gu, "-"), SESSION_MAX = 128;
85716
85927
  var init_fanout_brief = __esm(() => {
85717
- init_workspaces();
85928
+ init_role_models();
85718
85929
  init_ledger();
85719
85930
  init_fanout();
85720
85931
  init_fanout_worktree();
@@ -86336,7 +86547,7 @@ function fanoutStatus(cwd, plan, options) {
86336
86547
  const spawnModels = {};
86337
86548
  for (const id of spawnable) {
86338
86549
  const tier = plan.slices.find((slice) => slice.id === id)?.tier;
86339
- const model = tier ? workspaceTierModel(cwd, tier, host) : null;
86550
+ const model = tier ? resolveRoleModel(cwd, { role: "implementer", tier }, host) : null;
86340
86551
  if (model)
86341
86552
  spawnModels[id] = model.model;
86342
86553
  }
@@ -86378,7 +86589,7 @@ var DEFAULT_STUCK_MS, isoOf = (seconds) => {
86378
86589
  var init_fanout_status = __esm(() => {
86379
86590
  init_duration();
86380
86591
  init_report();
86381
- init_workspaces();
86592
+ init_role_models();
86382
86593
  init_ledger();
86383
86594
  init_fanout_check();
86384
86595
  init_fanout_landed();
@@ -86389,7 +86600,7 @@ var init_fanout_status = __esm(() => {
86389
86600
  // packages/workit-cli/src/verbs/fanout.ts
86390
86601
  var exports_fanout = {};
86391
86602
  __export(exports_fanout, {
86392
- run: () => run19
86603
+ run: () => run20
86393
86604
  });
86394
86605
  import fs34 from "node:fs";
86395
86606
  import path62 from "node:path";
@@ -86609,7 +86820,7 @@ function worktree(argv, io) {
86609
86820
  ...data.notes.map((note) => `note: ${note}`)
86610
86821
  ]);
86611
86822
  }
86612
- async function run19(argv, io) {
86823
+ async function run20(argv, io) {
86613
86824
  const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
86614
86825
  if (sub === "plan")
86615
86826
  return plan2(rest, io);
@@ -86621,9 +86832,9 @@ async function run19(argv, io) {
86621
86832
  return status4(rest, io);
86622
86833
  if (sub === "worktree")
86623
86834
  return worktree(rest, io);
86624
- return usage3(io, sub && !sub.startsWith("-") ? `unknown fanout subcommand "${sub}"` : "missing fanout subcommand", USAGE11);
86835
+ return usage3(io, sub && !sub.startsWith("-") ? `unknown fanout subcommand "${sub}"` : "missing fanout subcommand", USAGE12);
86625
86836
  }
86626
- var PLAN_USAGE2 = "workit fanout plan <plan.json> [--name <n>] [--trunk <b> | --track <t>] [--take-lead] [--json]", BRIEF_USAGE = "workit fanout brief <slice> [--name <n>] [--mode new|resume] [--attempt <n>] [--json]", CHECK_USAGE = "workit fanout check [<slice>…] [--name <n>] [--base <ref>] [--offline] [--json]", STATUS_USAGE3 = "workit fanout status [--name <n>] [--stuck-after 30m] [--offline] [--json]", WORKTREE_USAGE = "workit fanout worktree create <slice> [--name <n>] | worktree release <slice> [--name <n>] [--force] [--json]", USAGE11 = "workit fanout plan|brief|check|status|worktree ... (workit help fanout)", failed = (io, result) => emit(io, fail2(result.code, result.error, { unblock: result.unblock, data: result.data ?? {} })), renderCheck = (data) => [
86837
+ var PLAN_USAGE2 = "workit fanout plan <plan.json> [--name <n>] [--trunk <b> | --track <t>] [--take-lead] [--json]", BRIEF_USAGE = "workit fanout brief <slice> [--name <n>] [--mode new|resume] [--attempt <n>] [--json]", CHECK_USAGE = "workit fanout check [<slice>…] [--name <n>] [--base <ref>] [--offline] [--json]", STATUS_USAGE3 = "workit fanout status [--name <n>] [--stuck-after 30m] [--offline] [--json]", WORKTREE_USAGE = "workit fanout worktree create <slice> [--name <n>] | worktree release <slice> [--name <n>] [--force] [--json]", USAGE12 = "workit fanout plan|brief|check|status|worktree ... (workit help fanout)", failed = (io, result) => emit(io, fail2(result.code, result.error, { unblock: result.unblock, data: result.data ?? {} })), renderCheck = (data) => [
86627
86838
  `fanout ${data.name} against ${data.trunkRef}: ${data.ready ? "ready to land" : "blocked"}`,
86628
86839
  ...data.slices.map((slice) => slice.status === "landed" ? ` -- ${slice.id} (${slice.branch}) landed (${slice.landed?.how}${slice.landed?.pr ? ` #${slice.landed.pr}` : ""})` : ` ${slice.status === "ready" ? "ok " : "x "}${slice.id} (${slice.branch}) ${slice.changed} file${slice.changed === 1 ? "" : "s"} · verdict ${slice.verdict.accepted ? "accepted" : slice.verdict.basis}${slice.reasons.length ? `
86629
86840
  ${slice.reasons.join(`
@@ -86675,7 +86886,7 @@ var init_fanout2 = __esm(() => {
86675
86886
  // packages/workit-cli/src/verbs/ledger.ts
86676
86887
  var exports_ledger = {};
86677
86888
  __export(exports_ledger, {
86678
- run: () => run20
86889
+ run: () => run21
86679
86890
  });
86680
86891
  import { randomBytes as randomBytes6 } from "node:crypto";
86681
86892
  import { parseArgs } from "node:util";
@@ -86699,7 +86910,7 @@ function targetBranch(io, rows, branch, pr) {
86699
86910
  }
86700
86911
  return { ok: true, value: branch ?? null };
86701
86912
  }
86702
- async function run20(argv, io) {
86913
+ async function run21(argv, io) {
86703
86914
  let parsed;
86704
86915
  try {
86705
86916
  parsed = parseArgs({ args: argv, options: OPTIONS, allowPositionals: true, strict: true });
@@ -86921,7 +87132,7 @@ async function standing(io, values, args) {
86921
87132
  return usage4(io, `unexpected argument: ${rest[1]}`);
86922
87133
  return fromResult(io, clearStanding(context, { fanout, lead, leads, target: rest[0] ?? null }), (row) => row.target ? `cleared standing order ${row.target} for fanout ${fanout}` : `cleared every standing order for fanout ${fanout}`);
86923
87134
  }
86924
- var USAGE12 = "workit ledger decision|ruling|verdict|standing|list|check ... (workit help ledger for the grammar)", STANDING_USAGE = 'workit ledger standing add "<order>" | add --stop ["<note>"] | add --clear | list | clear [<id>] [--fanout <name>] [--json]', OPTIONS, SESSION_SAFE2, ROLE_SAFE, actorFor = (io, values) => {
87135
+ var USAGE13 = "workit ledger decision|ruling|verdict|standing|list|check ... (workit help ledger for the grammar)", STANDING_USAGE = 'workit ledger standing add "<order>" | add --stop ["<note>"] | add --clear | list | clear [<id>] [--fanout <name>] [--json]', OPTIONS, SESSION_SAFE2, ROLE_SAFE, actorFor = (io, values) => {
86925
87136
  const actor = actorFromEnv(io.env);
86926
87137
  if (values.session !== undefined && values.as !== undefined)
86927
87138
  return new Error("pass --session or --as, not both");
@@ -86946,7 +87157,7 @@ var USAGE12 = "workit ledger decision|ruling|verdict|standing|list|check ... (wo
86946
87157
  return;
86947
87158
  const parsed = Number(value);
86948
87159
  return Number.isInteger(parsed) && parsed > 0 ? parsed : new Error(`${flag} must be a positive integer`);
86949
- }, failed2 = (io, result) => emit(io, fail2(result.code, result.error, result.unblock ? { unblock: result.unblock } : {})), fromResult = (io, result, human) => result.ok ? emit(io, ok2(result.value), human) : failed2(io, result), usage4 = (io, error) => emit(io, fail2("invalid_input", error, { unblock: USAGE12 })), passedTestOn = (cwd, verdict) => {
87160
+ }, failed2 = (io, result) => emit(io, fail2(result.code, result.error, result.unblock ? { unblock: result.unblock } : {})), fromResult = (io, result, human) => result.ok ? emit(io, ok2(result.value), human) : failed2(io, result), usage4 = (io, error) => emit(io, fail2("invalid_input", error, { unblock: USAGE13 })), passedTestOn = (cwd, verdict) => {
86950
87161
  const ledger = readLedger(cwd);
86951
87162
  return ledger.ok && ledger.value.rows.some((row) => row.type === "check" && row.observer === "workit_cli" && row.name === "test" && row.result === "passed" && row.dirty !== true && row.branch === verdict.branch && row.head === verdict.head);
86952
87163
  }, verdictLines = (check) => {
@@ -103489,7 +103700,7 @@ var init_mutate = __esm(() => {
103489
103700
  // packages/workit-cli/src/verbs/test-audit.ts
103490
103701
  var exports_test_audit = {};
103491
103702
  __export(exports_test_audit, {
103492
- run: () => run21
103703
+ run: () => run22
103493
103704
  });
103494
103705
  import { existsSync as existsSync24 } from "node:fs";
103495
103706
  import path66 from "node:path";
@@ -103591,11 +103802,11 @@ function human(data) {
103591
103802
  }
103592
103803
  return lines;
103593
103804
  }
103594
- async function run21(argv, io) {
103805
+ async function run22(argv, io) {
103595
103806
  const options = parse8(argv);
103596
103807
  if (typeof options === "string")
103597
103808
  return emit(io, fail2("invalid_input", `${options}
103598
- usage: ${USAGE13}`));
103809
+ usage: ${USAGE14}`));
103599
103810
  const top = git7(io.cwd, ["rev-parse", "--show-toplevel"]);
103600
103811
  const repo = top.ok ? path66.resolve(top.stdout.trim()) : null;
103601
103812
  const display = (file) => toPosix(path66.relative(io.cwd, file) || file);
@@ -103681,7 +103892,7 @@ usage: ${USAGE13}`));
103681
103892
  }
103682
103893
  return emit(io, ok2(data), human);
103683
103894
  }
103684
- var USAGE13 = "workit test-audit [paths…] [--diff [base]] [--rule <ids>] [--min-severity <level>] [--fail-on <level>] [--mutate [--test-cmd <cmd>] [--max-mutants <n>] [--budget <s>] [--timeout <s>]] [--json]", LEVELS, VALUE_FLAGS2, quote = (arg) => /^[\w./@:=+-]+$/.test(arg) ? arg : `'${arg.replace(/'/g, "'\\''")}'`;
103895
+ var USAGE14 = "workit test-audit [paths…] [--diff [base]] [--rule <ids>] [--min-severity <level>] [--fail-on <level>] [--mutate [--test-cmd <cmd>] [--max-mutants <n>] [--budget <s>] [--timeout <s>]] [--json]", LEVELS, VALUE_FLAGS2, quote = (arg) => /^[\w./@:=+-]+$/.test(arg) ? arg : `'${arg.replace(/'/g, "'\\''")}'`;
103685
103896
  var init_test_audit = __esm(() => {
103686
103897
  init_audit();
103687
103898
  init_mutate();
@@ -103702,12 +103913,12 @@ var init_test_audit = __esm(() => {
103702
103913
  // packages/workit-cli/src/verbs/knowledge.ts
103703
103914
  var exports_knowledge = {};
103704
103915
  __export(exports_knowledge, {
103705
- run: () => run22
103916
+ run: () => run23
103706
103917
  });
103707
- async function run22(argv, io) {
103918
+ async function run23(argv, io) {
103708
103919
  const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
103709
103920
  if (sub !== "lint" || rest.length > 0)
103710
- return emit(io, fail2("invalid_input", `usage: ${USAGE14}`));
103921
+ return emit(io, fail2("invalid_input", `usage: ${USAGE15}`));
103711
103922
  const report = lintKnowledge(checkRoot(io.cwd));
103712
103923
  if (report.unreadable.length > 0)
103713
103924
  return emit(io, fail2("unavailable", `knowledge lint: cannot read ${report.unreadable.join(", ")}`, {
@@ -103724,7 +103935,7 @@ async function run22(argv, io) {
103724
103935
  `);
103725
103936
  return report.findings.length === 0 ? 0 : 1;
103726
103937
  }
103727
- var USAGE14 = "workit knowledge lint [--json]";
103938
+ var USAGE15 = "workit knowledge lint [--json]";
103728
103939
  var init_knowledge2 = __esm(() => {
103729
103940
  init_check_config();
103730
103941
  init_knowledge();
@@ -103734,14 +103945,14 @@ var init_knowledge2 = __esm(() => {
103734
103945
  // packages/workit-cli/src/verbs/youtrack.ts
103735
103946
  var exports_youtrack = {};
103736
103947
  __export(exports_youtrack, {
103737
- run: () => run23
103948
+ run: () => run24
103738
103949
  });
103739
103950
  import { readFileSync as readFileSync27 } from "node:fs";
103740
103951
  import path67 from "node:path";
103741
- async function run23(argv, io) {
103952
+ async function run24(argv, io) {
103742
103953
  const [sub, ...rest] = argv;
103743
103954
  if (sub !== "note" && sub !== "time" && sub !== "meeting")
103744
- return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE15);
103955
+ return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE16);
103745
103956
  const flags = parseFlags(rest, {
103746
103957
  markdown: "value",
103747
103958
  file: "value",
@@ -103750,18 +103961,18 @@ async function run23(argv, io) {
103750
103961
  date: "value"
103751
103962
  });
103752
103963
  if (typeof flags === "string")
103753
- return usage3(io, flags, USAGE15);
103964
+ return usage3(io, flags, USAGE16);
103754
103965
  const [issueId, extra] = flags.positionals;
103755
103966
  if (!issueId || !ISSUE_RE2.test(issueId))
103756
- return usage3(io, "an issue id like ABC-123 is required", USAGE15);
103967
+ return usage3(io, "an issue id like ABC-123 is required", USAGE16);
103757
103968
  if (extra !== undefined)
103758
- return usage3(io, `unexpected argument ${extra}`, USAGE15);
103969
+ return usage3(io, `unexpected argument ${extra}`, USAGE16);
103759
103970
  const minutes = positiveInt(flags.values.minutes, "--minutes");
103760
103971
  if (typeof minutes === "string")
103761
- return usage3(io, minutes, USAGE15);
103972
+ return usage3(io, minutes, USAGE16);
103762
103973
  const date = youTrackWorkDateMs(flags.values.date ?? "auto");
103763
103974
  if ("error" in date)
103764
- return usage3(io, date.error, USAGE15);
103975
+ return usage3(io, date.error, USAGE16);
103765
103976
  const dateMs = date.data.dateMs;
103766
103977
  const markedDay = flags.values.date !== undefined && flags.values.date !== "auto" ? { dateMs } : {};
103767
103978
  const root = io.cwd;
@@ -103779,24 +103990,24 @@ async function run23(argv, io) {
103779
103990
  };
103780
103991
  if (sub === "note") {
103781
103992
  if (Boolean(flags.values.markdown) === Boolean(flags.values.file))
103782
- return usage3(io, "pass exactly one of --markdown or --file", USAGE15);
103993
+ return usage3(io, "pass exactly one of --markdown or --file", USAGE16);
103783
103994
  let markdown = flags.values.markdown ?? "";
103784
103995
  if (flags.values.file)
103785
103996
  try {
103786
103997
  markdown = readFileSync27(path67.resolve(io.cwd, flags.values.file), "utf8");
103787
103998
  } catch (error) {
103788
- return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE15);
103999
+ return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE16);
103789
104000
  }
103790
104001
  if (!markdown.trim())
103791
- return usage3(io, "the note is empty", USAGE15);
104002
+ return usage3(io, "the note is empty", USAGE16);
103792
104003
  const missing = step("comment", "comments", { operation: "note", issueId, markdown }, markdown, async (text) => commentResult(await postComment(issueId, text, root))) ?? (minutes ? step("time", "workItems", { operation: "note.time", issueId, markdown, minutes, ...markedDay }, "workit update", (text) => logTimeUpdate({ issueId, minutes, text, dateMs, workspace_root: root })) : null);
103793
104004
  if (missing)
103794
104005
  return emit(io, fail2("unavailable", missing));
103795
104006
  } else {
103796
104007
  if (!minutes)
103797
- return usage3(io, `${sub} needs --minutes <n>`, USAGE15);
104008
+ return usage3(io, `${sub} needs --minutes <n>`, USAGE16);
103798
104009
  if (sub === "meeting" && !flags.values.text)
103799
- return usage3(io, "meeting needs --text <what the meeting was>", USAGE15);
104010
+ return usage3(io, "meeting needs --text <what the meeting was>", USAGE16);
103800
104011
  const text = flags.values.text ?? "";
103801
104012
  const missing = step(sub, "workItems", { operation: sub, issueId, minutes, text, ...markedDay }, text, (marked) => logTimeUpdate({ issueId, minutes, text: marked, dateMs, workspace_root: root }));
103802
104013
  if (missing)
@@ -103825,7 +104036,7 @@ async function run23(argv, io) {
103825
104036
  ...data.steps.flatMap((entry) => entry.note ? [` note (${entry.step}): ${entry.note}`] : [])
103826
104037
  ]);
103827
104038
  }
103828
- var USAGE15 = "workit youtrack note <ISSUE> (--markdown <t> | --file <p>) [--minutes <n>] [--date auto|YYYY-MM-DD] | youtrack time <ISSUE> --minutes <n> [--text <t>] [--date …] | youtrack meeting <ISSUE> --minutes <n> --text <t> [--date …]", commentResult = (value) => {
104039
+ var USAGE16 = "workit youtrack note <ISSUE> (--markdown <t> | --file <p>) [--minutes <n>] [--date auto|YYYY-MM-DD] | youtrack time <ISSUE> --minutes <n> [--text <t>] [--date …] | youtrack meeting <ISSUE> --minutes <n> --text <t> [--date …]", commentResult = (value) => {
103829
104040
  try {
103830
104041
  return { ok: true, data: unwrap(value) };
103831
104042
  } catch (error) {
@@ -103849,14 +104060,14 @@ var init_youtrack2 = __esm(() => {
103849
104060
  // packages/workit-cli/src/verbs/changelog.ts
103850
104061
  var exports_changelog = {};
103851
104062
  __export(exports_changelog, {
103852
- run: () => run24
104063
+ run: () => run25
103853
104064
  });
103854
104065
  import { readFileSync as readFileSync28 } from "node:fs";
103855
104066
  import path68 from "node:path";
103856
- async function run24(argv, io) {
104067
+ async function run25(argv, io) {
103857
104068
  const [sub, ...rest] = argv;
103858
104069
  if (sub !== "apply")
103859
- return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE16);
104070
+ return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE17);
103860
104071
  const flags = parseFlags(rest, {
103861
104072
  entries: "value",
103862
104073
  path: "value",
@@ -103864,18 +104075,18 @@ async function run24(argv, io) {
103864
104075
  preview: "boolean"
103865
104076
  });
103866
104077
  if (typeof flags === "string")
103867
- return usage3(io, flags, USAGE16);
104078
+ return usage3(io, flags, USAGE17);
103868
104079
  if (flags.positionals.length)
103869
- return usage3(io, `unexpected argument ${flags.positionals[0]}`, USAGE16);
104080
+ return usage3(io, `unexpected argument ${flags.positionals[0]}`, USAGE17);
103870
104081
  const normalizeOnly = flags.booleans.has("normalize-only");
103871
104082
  if (!normalizeOnly && !flags.values.entries)
103872
- return usage3(io, "pass --entries <JSON> or --normalize-only", USAGE16);
104083
+ return usage3(io, "pass --entries <JSON> or --normalize-only", USAGE17);
103873
104084
  let entries;
103874
104085
  if (flags.values.entries)
103875
104086
  try {
103876
104087
  entries = readEntries(flags.values.entries, io.cwd);
103877
104088
  } catch (error) {
103878
- return usage3(io, `--entries is not valid JSON: ${String(error)}`, USAGE16);
104089
+ return usage3(io, `--entries is not valid JSON: ${String(error)}`, USAGE17);
103879
104090
  }
103880
104091
  const input = {
103881
104092
  entries,
@@ -103897,7 +104108,7 @@ async function run24(argv, io) {
103897
104108
  `changelog updated: ${String(applied.path ?? "CHANGELOG.md")}`
103898
104109
  ]);
103899
104110
  }
103900
- var USAGE16 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
104111
+ var USAGE17 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
103901
104112
  const text = raw === "-" ? readFileSync28(0, "utf8") : raw.startsWith("@") ? readFileSync28(path68.resolve(cwd, raw.slice(1)), "utf8") : raw;
103902
104113
  return JSON.parse(text);
103903
104114
  };
@@ -103910,7 +104121,7 @@ var init_changelog2 = __esm(() => {
103910
104121
  // packages/workit-cli/src/verbs/handoff.ts
103911
104122
  var exports_handoff = {};
103912
104123
  __export(exports_handoff, {
103913
- run: () => run25
104124
+ run: () => run26
103914
104125
  });
103915
104126
  import { parseArgs as parseArgs2 } from "node:util";
103916
104127
  function human2(brief) {
@@ -103958,11 +104169,11 @@ async function resumeBrief(argv, io) {
103958
104169
  strict: true
103959
104170
  }));
103960
104171
  } catch (error) {
103961
- return emit(io, fail2("invalid_input", error.message, { unblock: USAGE17 }));
104172
+ return emit(io, fail2("invalid_input", error.message, { unblock: USAGE18 }));
103962
104173
  }
103963
104174
  const last = values.last === undefined ? 10 : Number(values.last);
103964
104175
  if (!Number.isInteger(last) || last < 1)
103965
- return emit(io, fail2("invalid_input", "--last must be a positive integer", { unblock: USAGE17 }));
104176
+ return emit(io, fail2("invalid_input", "--last must be a positive integer", { unblock: USAGE18 }));
103966
104177
  const built = buildHandoff(io.cwd, {
103967
104178
  last,
103968
104179
  note: values.note ?? null,
@@ -103980,13 +104191,13 @@ async function resumeBrief(argv, io) {
103980
104191
  }
103981
104192
  return emit(io, ok2({ ...data, recorded }), human2);
103982
104193
  }
103983
- async function run25(argv, io) {
104194
+ async function run26(argv, io) {
103984
104195
  if (!argv.some((arg) => arg === "--task" || arg.startsWith("--task=")))
103985
104196
  return resumeBrief(argv, io);
103986
104197
  await Promise.resolve().then(() => init_task());
103987
104198
  return runTaskCommand(["handoff", ...argv]);
103988
104199
  }
103989
- var USAGE17 = "workit handoff [--note <text>] [--next <text>] [--record] [--last <n>] [--json]", short7 = (sha) => sha ? sha.slice(0, 12) : "no commit";
104200
+ var USAGE18 = "workit handoff [--note <text>] [--next <text>] [--record] [--last <n>] [--json]", short7 = (sha) => sha ? sha.slice(0, 12) : "no commit";
103990
104201
  var init_handoff = __esm(() => {
103991
104202
  init_ledger();
103992
104203
  init_output();
@@ -104233,6 +104444,23 @@ var VERBS = [
104233
104444
  notes: LEASE_NOTES,
104234
104445
  load: () => Promise.resolve().then(() => (init_lock(), exports_lock))
104235
104446
  }),
104447
+ withSubcommands({
104448
+ name: "models",
104449
+ group: "delivery",
104450
+ summary: "The model and effort each role (decider, implementer tiers, verifier, reviewer, explore, babysit) runs on for a host, from models.roles, fanout.tierModels and the built-in defaults",
104451
+ subcommands: [
104452
+ {
104453
+ name: "show",
104454
+ usage: "workit models show [--role <role>] [--tier <mundane|standard|hard>] [--host <host>] [--json]",
104455
+ summary: "Print the resolved model and effort per role for a host (default: the lead's host, else claude_code) and where each came from"
104456
+ }
104457
+ ],
104458
+ examples: [
104459
+ "workit models show --host claude_code --json",
104460
+ "workit models show --role verifier --host claude_code"
104461
+ ],
104462
+ load: () => Promise.resolve().then(() => (init_models(), exports_models))
104463
+ }),
104236
104464
  withSubcommands({
104237
104465
  name: "pr",
104238
104466
  group: "delivery",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cli",
3
- "version": "8.25.0",
3
+ "version": "8.26.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.25.0",
41
+ "@brainervirus/workit-cursor": "^8.26.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.25.0"
47
+ "@brainervirus/workit-core": "^8.26.1"
48
48
  },
49
49
  "engines": {
50
50
  "node": ">=24"