@brainervirus/workit-cli 8.39.1 → 8.39.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +137 -15
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -9317,7 +9317,7 @@ var package_default;
9317
9317
  var init_package = __esm(() => {
9318
9318
  package_default = {
9319
9319
  name: "@brainervirus/workit-cli",
9320
- version: "8.39.1",
9320
+ version: "8.39.3",
9321
9321
  private: false,
9322
9322
  description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
9323
9323
  keywords: [
@@ -9355,13 +9355,13 @@ var init_package = __esm(() => {
9355
9355
  },
9356
9356
  dependencies: {
9357
9357
  "@babel/parser": "7.29.9",
9358
- "@brainervirus/workit-cursor": "^8.39.1",
9358
+ "@brainervirus/workit-cursor": "^8.39.3",
9359
9359
  "@inkjs/ui": "2.0.0",
9360
9360
  ink: "7.1.1",
9361
9361
  react: "19.2.8"
9362
9362
  },
9363
9363
  devDependencies: {
9364
- "@brainervirus/workit-core": "^8.39.1"
9364
+ "@brainervirus/workit-core": "^8.39.3"
9365
9365
  },
9366
9366
  engines: {
9367
9367
  node: ">=24"
@@ -9462,6 +9462,11 @@ function detectedChecks(root) {
9462
9462
  if (typeof script === "string" && script.trim() !== "")
9463
9463
  add(scriptCheck(pm, name));
9464
9464
  }
9465
+ for (const [name, script] of Object.entries(SCRIPT_CHECK_ALIASES)) {
9466
+ const body = scripts[script];
9467
+ if (typeof body === "string" && body.trim() !== "")
9468
+ add({ ...scriptCheck(pm, script), name });
9469
+ }
9465
9470
  }
9466
9471
  const plain = (name, argv) => ({ name, argv, accepts: [argv] });
9467
9472
  if (read("go.mod") !== null)
@@ -9580,7 +9585,7 @@ function workitAvailable(env = process.env) {
9580
9585
  function checkCommand(args, version, onPath = workitAvailable()) {
9581
9586
  return onPath ? `workit check ${args}` : `npx -y @brainervirus/workit-cli@${version} check ${args}`;
9582
9587
  }
9583
- var SCRIPT_CHECKS, CHECKS_FILE = ".workit/checks.json", LEGACY_CHECKS_FILE = "workit.checks.json", WORKIT_GITIGNORE = `*
9588
+ var SCRIPT_CHECKS, SCRIPT_CHECK_ALIASES, CHECKS_FILE = ".workit/checks.json", LEGACY_CHECKS_FILE = "workit.checks.json", WORKIT_GITIGNORE = `*
9584
9589
  !risk-paths
9585
9590
  `, isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SHELL_META, git3 = (cwd, args) => {
9586
9591
  const run = spawnSync7("git", args, {
@@ -9610,6 +9615,7 @@ var SCRIPT_CHECKS, CHECKS_FILE = ".workit/checks.json", LEGACY_CHECKS_FILE = "wo
9610
9615
  }, CHECK_NAME, GATES, sameArgv = (left, right) => left.length === right.length && left.every((item, index) => item === right[index]), workitOnPath;
9611
9616
  var init_check_config = __esm(() => {
9612
9617
  SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
9618
+ SCRIPT_CHECK_ALIASES = { packaging: "test:packaging" };
9613
9619
  SHELL_META = /[|&;<>()$`\\*?[\]{}~!#]/u;
9614
9620
  CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
9615
9621
  GATES = ["testing", "verification"];
@@ -15571,6 +15577,7 @@ function recordVerdict(context, input) {
15571
15577
  sessionSource: context.sessionSource ?? "env",
15572
15578
  ...context.sessionBound === true ? { sessionBound: true } : {},
15573
15579
  evidenceRefs: input.evidenceRefs ?? [],
15580
+ ...input.checkEvidence?.length ? { checkEvidence: input.checkEvidence } : {},
15574
15581
  ...untrackedField(context.cwd)
15575
15582
  }, { now: context.now });
15576
15583
  }
@@ -78219,11 +78226,12 @@ async function acquireLease(options) {
78219
78226
  position: ahead + 1
78220
78227
  };
78221
78228
  if (!queued) {
78222
- writeTicket(ticket, ticketRecord);
78223
- queued = true;
78224
78229
  process.on("exit", leave);
78225
78230
  process.on("SIGINT", onSignal);
78226
78231
  process.on("SIGTERM", onSignal);
78232
+ await new Promise((resolve) => setImmediate(resolve));
78233
+ writeTicket(ticket, ticketRecord);
78234
+ queued = true;
78227
78235
  } else if (!fs24.existsSync(ticket)) {
78228
78236
  writeTicket(ticket, ticketRecord);
78229
78237
  }
@@ -78232,7 +78240,8 @@ async function acquireLease(options) {
78232
78240
  position: ahead + 1,
78233
78241
  ahead,
78234
78242
  holders,
78235
- waitedMs: waited
78243
+ waitedMs: waited,
78244
+ first: nextStatus === 0
78236
78245
  });
78237
78246
  nextStatus = waited + (options.statusEveryMs ?? 30000);
78238
78247
  }
@@ -78397,7 +78406,7 @@ var init_resources = __esm(() => {
78397
78406
  init_checks3();
78398
78407
  init_heavy();
78399
78408
  init_heavy_scope();
78400
- DEFAULT_HEAVY_CHECKS = ["test", "build"];
78409
+ DEFAULT_HEAVY_CHECKS = ["test", "build", "packaging"];
78401
78410
  DEFAULT_LIGHT_CHECKS = ["lint", "typecheck", "format"];
78402
78411
  SIZE = /^(\d+(?:\.\d+)?)([KMGT]?)$/iu;
78403
78412
  PERCENT = /^(\d+(?:\.\d+)?)%$/u;
@@ -78615,28 +78624,39 @@ function countWarnings(log) {
78615
78624
  return redactLog(log).replace(ANSI_COLOR, "").split(`
78616
78625
  `).filter((line) => WARNING_LINE.test(line) && !NO_WARNINGS.test(line)).length;
78617
78626
  }
78618
- function boundedOutput(log, lines, stderr = "") {
78627
+ function boundedOutput(log, lines, stderr = "", failed = false) {
78619
78628
  const all = tailLines(log, Number.MAX_SAFE_INTEGER);
78620
78629
  if (all.length === 0)
78621
78630
  return "";
78622
- let shown = all.slice(-lines);
78631
+ const markers = failed ? [...new Set(all.filter((line) => FAILURE_LINE.test(line)))] : [];
78632
+ const listed = markers.slice(0, MAX_FAILURE_LINES);
78633
+ const more = markers.length - listed.length;
78634
+ const failureRoom = listed.length ? listed.length + 2 + (more > 0 ? 1 : 0) : 0;
78635
+ let shown = all.slice(-Math.max(1, lines - failureRoom));
78623
78636
  const errors = tailLines(redactLog(stderr), STDERR_TAIL_LINES);
78624
78637
  let missing = [];
78625
78638
  if (errors.length) {
78626
78639
  const tail = new Set(shown);
78627
78640
  if (errors.some((line) => !tail.has(line))) {
78628
- shown = all.slice(-Math.max(1, lines - errors.length - 2));
78641
+ shown = all.slice(-Math.max(1, lines - failureRoom - errors.length - 2));
78629
78642
  const kept = new Set(shown);
78630
78643
  missing = errors.filter((line) => !kept.has(line));
78631
78644
  }
78632
78645
  }
78633
78646
  const omitted = all.length - shown.length;
78647
+ const inTail = new Set([...shown, ...missing]);
78648
+ const failures = listed.filter((line) => !inTail.has(line));
78649
+ const failureFooter = failures.length ? `… failures from the omitted lines:
78650
+ ${failures.join(`
78651
+ `)}
78652
+ ${more > 0 ? `+${more} more failures in the log
78653
+ ` : ""}` : "";
78634
78654
  const footer = missing.length ? `… the last stderr lines, which the merged log holds earlier:
78635
78655
  ${missing.join(`
78636
78656
  `)}
78637
78657
  ` : "";
78638
78658
  return `${omitted ? `… ${omitted} earlier line${omitted === 1 ? "" : "s"} omitted (the full log is named below; --full streams it)
78639
- ` : ""}${shown.join(`
78659
+ ` : ""}${failureFooter}${shown.join(`
78640
78660
  `)}
78641
78661
  ${footer}`;
78642
78662
  }
@@ -78675,7 +78695,7 @@ async function prepareHeavy(io, settings, label, runCwd, timeoutMs) {
78675
78695
  onStatus: (status) => {
78676
78696
  const slots = `${settings.slots} slot${settings.slots === 1 ? "" : "s"}`;
78677
78697
  const holders = status.holders.map((holder) => describeHolder(holder)).join("; ");
78678
- io.stderr(status.waitedMs === 0 ? `workit: waiting for the heavy-check lease (${slots}): held by ${holders || "nobody; waiters ahead"}; queued at position ${status.position}, waiting up to ${formatWait(settings.waitMs)} (--wait <dur> sets it)
78698
+ io.stderr(status.first ? `workit: waiting for the heavy-check lease (${slots}): held by ${holders || "nobody; waiters ahead"}; queued at position ${status.position}, waiting up to ${formatWait(settings.waitMs)} (--wait <dur> sets it)
78679
78699
  ` : `workit: still queued for the heavy-check lease: position ${status.position}, ${formatWait(status.waitedMs)} of ${formatWait(settings.waitMs)} waited; held by ${holders || "nobody; waiters ahead"}
78680
78700
  `);
78681
78701
  }
@@ -78936,7 +78956,7 @@ async function run12(argv, io) {
78936
78956
  `);
78937
78957
  else {
78938
78958
  if (!options.full)
78939
- io.stdout(boundedOutput(result.log, OUTPUT_LINES, stderrTail));
78959
+ io.stdout(boundedOutput(result.log, OUTPUT_LINES, stderrTail, !passed));
78940
78960
  io.stderr(`${summary}
78941
78961
  `);
78942
78962
  if (recordError && passed)
@@ -78953,7 +78973,7 @@ async function run12(argv, io) {
78953
78973
  return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
78954
78974
  return 0;
78955
78975
  }
78956
- var USAGE6 = 'workit check <name> [--full] [--wait <dur> | --no-wait] [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--heavy] [--full] [--wait <dur> | --no-wait] [--timeout <s>] [--task <id>] [--json] -- <cmd…>', OUTPUT_LINES = 60, MAX_UNVERIFIED_RUN_MS, RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path53.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS, ANSI_COLOR, WARNING_LINE, NO_WARNINGS, STDERR_TAIL_LINES = 10, STDERR_KEEP_CHARS = 65536;
78976
+ var USAGE6 = 'workit check <name> [--full] [--wait <dur> | --no-wait] [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--heavy] [--full] [--wait <dur> | --no-wait] [--timeout <s>] [--task <id>] [--json] -- <cmd…>', OUTPUT_LINES = 60, MAX_UNVERIFIED_RUN_MS, RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path53.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS, ANSI_COLOR, WARNING_LINE, NO_WARNINGS, STDERR_TAIL_LINES = 10, STDERR_KEEP_CHARS = 65536, FAILURE_LINE, MAX_FAILURE_LINES = 15;
78957
78977
  var init_check = __esm(() => {
78958
78978
  init_check_config();
78959
78979
  init_checks3();
@@ -78974,6 +78994,7 @@ var init_check = __esm(() => {
78974
78994
  ANSI_COLOR = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
78975
78995
  WARNING_LINE = /^\s*(?:⚠|\[(?:WARN|WARNING|warn|warning)\]|(?:npm\s+)?(?:WARN\s|warn\s)|warn(?:ing)?(?:\[[^\]]*\])?:|\d+:\d+\s+warning\s|\S+\(\d+,\d+\):\s*warning\s|\S+:\d+:\d+:\s*warning\b)/;
78976
78996
  NO_WARNINGS = /\b(?:no|0|zero|none)\s+warnings?\b/i;
78997
+ FAILURE_LINE = /^\s*(?:\(fail\)|FAIL\b|✗|error:)/u;
78977
78998
  });
78978
78999
 
78979
79000
  // packages/workit-cli/src/verbs/lock.ts
@@ -80396,6 +80417,67 @@ var init_pr_lane = __esm(() => {
80396
80417
  init_lane();
80397
80418
  });
80398
80419
 
80420
+ // packages/workit-core/src/core/policy/check-evidence.ts
80421
+ function neededChecks(lane, configured) {
80422
+ if (lane !== "focused" && lane !== "full")
80423
+ return [];
80424
+ const names = configured.filter((name) => name !== AGGREGATE);
80425
+ return names.length ? names : [...configured];
80426
+ }
80427
+ function localCheckRows(rows) {
80428
+ return rows.filter((row) => row.type === "check" && row.observer === "workit_cli").map((row) => ({
80429
+ name: String(row.name ?? ""),
80430
+ head: String(row.head ?? ""),
80431
+ dirty: row.dirty === true,
80432
+ passed: row.result === "passed"
80433
+ }));
80434
+ }
80435
+ function verdictEvidence(cwd, input) {
80436
+ const lane = branchLane(cwd, { base: input.base ?? null, head: input.head });
80437
+ return checkEvidence({
80438
+ lane: lane.lane,
80439
+ head: input.head,
80440
+ configured: gateCheckNames(loadCheckConfig(cwd), "verification"),
80441
+ local: localCheckRows(input.rows),
80442
+ ci: []
80443
+ });
80444
+ }
80445
+ function checkEvidence(input) {
80446
+ const ciCovers = input.lane === "focused";
80447
+ const needed = neededChecks(input.lane, input.configured).map((name) => {
80448
+ const last = input.local.findLast((row) => row.name === name && row.head === input.head && !row.dirty);
80449
+ if (last?.passed)
80450
+ return { name, status: "fresh", via: "local", ciCovers };
80451
+ const ci = input.ci.filter((check) => ciMatch(check, name));
80452
+ if (ci.some((check) => check.state === "failing"))
80453
+ return { name, status: "failing", via: "ci", ciCovers };
80454
+ if (last)
80455
+ return { name, status: "failing", via: "local", ciCovers };
80456
+ if (ciCovers && ci.some((check) => check.state === "passing"))
80457
+ return { name, status: "fresh", via: "ci", ciCovers };
80458
+ return { name, status: "missing", via: null, ciCovers };
80459
+ });
80460
+ return {
80461
+ lane: input.lane,
80462
+ head: input.head,
80463
+ needed,
80464
+ satisfied: needed.every((item) => item.status === "fresh")
80465
+ };
80466
+ }
80467
+ function evidenceLines(doc) {
80468
+ if (!doc.needed.length)
80469
+ return [`evidence: lane ${doc.lane} needs no check run`];
80470
+ return [
80471
+ `evidence for lane ${doc.lane} on ${doc.head.slice(0, 7)}: ${doc.satisfied ? "complete" : "incomplete"}`,
80472
+ ...doc.needed.map((item) => ` ${item.status === "fresh" ? "ok" : "x"} ${item.name}: ${item.status}${item.via ? ` (${item.via})` : item.ciCovers ? " (run it, or green CI covers it)" : " (run workit check " + item.name + " on this head)"}`)
80473
+ ];
80474
+ }
80475
+ var AGGREGATE = "check", ciMatch = (ci, name) => new RegExp(`(^|[^a-z0-9])${name.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}([^a-z0-9]|$)`, "iu").test(ci.name);
80476
+ var init_check_evidence = __esm(() => {
80477
+ init_check_config();
80478
+ init_lane();
80479
+ });
80480
+
80399
80481
  // packages/workit-core/src/forge/reruns.ts
80400
80482
  import fs27 from "node:fs";
80401
80483
  import path58 from "node:path";
@@ -80612,6 +80694,14 @@ function selectPr(cwd, resolved, options) {
80612
80694
  }
80613
80695
  return success2(found.data.number);
80614
80696
  }
80697
+ function evidenceFor(cwd, status, ci = status.checks) {
80698
+ const lane = branchLane(cwd, { base: status.base, head: status.head.sha });
80699
+ const configured = gateCheckNames(loadCheckConfig(cwd), "verification");
80700
+ const read = readLedger(cwd);
80701
+ const local = read.ok ? localCheckRows(read.value.rows) : [];
80702
+ const ciChecks = ci.flatMap((check) => check.state === "skipped" ? [] : [{ name: check.name, state: check.state }]);
80703
+ return checkEvidence({ lane: lane.lane, head: status.head.sha, configured, local, ci: ciChecks });
80704
+ }
80615
80705
  function buildStatusDoc(cwd, resolved, status, options) {
80616
80706
  const { forge } = resolved;
80617
80707
  const reruns = rerunCounts(cwd, { repo: forge.repo, pr: status.number, head: status.head.sha });
@@ -80689,6 +80779,7 @@ function buildStatusDoc(cwd, resolved, status, options) {
80689
80779
  passing: status.checks.filter((check) => check.state === "passing").length,
80690
80780
  missingRequired: missing
80691
80781
  },
80782
+ evidence: evidenceFor(cwd, status),
80692
80783
  reviews: { decision: status.reviewDecision, unresolvedThreads: status.threads },
80693
80784
  blockers: status.state === "open" ? blockers.map((blocker) => blocker.reason) : [],
80694
80785
  identity: options.identity ?? null,
@@ -80872,6 +80963,9 @@ var MAX_LOG_TAILS = 5, GITLAB_MERGEABLE, GITHUB_MERGEABLE, NO_CHECKS_GRACE_MS =
80872
80963
  var init_report2 = __esm(() => {
80873
80964
  init_rev();
80874
80965
  init_ledger();
80966
+ init_check_config();
80967
+ init_lane();
80968
+ init_check_evidence();
80875
80969
  init_reruns();
80876
80970
  GITLAB_MERGEABLE = new Set(["mergeable"]);
80877
80971
  GITHUB_MERGEABLE = new Set(["clean", "unstable", "has_hooks"]);
@@ -86618,6 +86712,8 @@ function renderStatus(doc) {
86618
86712
  lines.push(` - ${thread.path ? `${thread.path}${thread.line ? `:${thread.line}` : ""} ` : ""}@${thread.author ?? "?"}${thread.isBot ? " (bot)" : ""}: ${thread.body}`);
86619
86713
  if (doc.truncated)
86620
86714
  lines.push("(lists truncated at the page cap)");
86715
+ if (doc.evidence)
86716
+ lines.push(...evidenceLines(doc.evidence));
86621
86717
  if (doc.blockers.length)
86622
86718
  lines.push(`blockers: ${doc.blockers.join(", ")}`);
86623
86719
  if (doc.identity?.note)
@@ -86634,6 +86730,7 @@ var forgeDeps, MAX_REASON = 500, usage4 = (io, message, line) => emit(io, fail2(
86634
86730
  now: forgeDeps.now
86635
86731
  }), short = (sha) => sha ? sha.slice(0, 7) : "?";
86636
86732
  var init_forge_common = __esm(() => {
86733
+ init_check_evidence();
86637
86734
  init_resolve();
86638
86735
  init_vcs_config();
86639
86736
  init_duration();
@@ -90103,6 +90200,16 @@ async function run22(argv, io) {
90103
90200
  const refusal = claimed === null ? null : sessionClaimRefusal(io.env, claimed, io.cwd, { token, flag: acting.source === "flag" });
90104
90201
  if (refusal)
90105
90202
  return emit(io, fail2("blocked", refusal.error, { unblock: refusal.unblock }));
90203
+ const evidence = values.self !== true && (rest[0] === "verified" || rest[0] === "tests-verified") ? verdictCheckEvidence(io.cwd, target.value, values.base ?? null) : null;
90204
+ const redCheck = evidence?.needed.find((item) => item.status === "failing");
90205
+ if (redCheck)
90206
+ return emit(io, fail2("blocked", `check_failing: the configured check "${redCheck.name}" is failing on ${evidence?.head.slice(0, 12)} (${redCheck.via ?? "local"} run); a ${rest[0]} verdict cannot be recorded`, {
90207
+ unblock: `fix it, then workit check ${redCheck.name} on this head, or record failed/blocked`
90208
+ }));
90209
+ const missingChecks = evidence?.needed.filter((item) => item.status === "missing") ?? [];
90210
+ if (missingChecks.length)
90211
+ io.stderr(`warning: no fresh run on ${evidence?.head.slice(0, 12)} of the configured check${missingChecks.length === 1 ? "" : "s"} ${missingChecks.map((item) => item.name).join(", ")}; the verdict records it as missing
90212
+ `);
90106
90213
  const bound = claimed !== null && issuedTokenMatches(io.cwd, claimed, token);
90107
90214
  const verdict = await recorded(recordVerdict({ ...context, ...bound ? { sessionBound: true } : {} }, {
90108
90215
  result: rest[0],
@@ -90111,6 +90218,13 @@ async function run22(argv, io) {
90111
90218
  surface: values.surface ?? null,
90112
90219
  self: values.self === true,
90113
90220
  evidenceRefs: values.evidence,
90221
+ ...evidence?.needed.length ? {
90222
+ checkEvidence: evidence.needed.map(({ name, status, via }) => ({
90223
+ name,
90224
+ status,
90225
+ via
90226
+ }))
90227
+ } : {},
90114
90228
  ..."derivedFrom" in acting ? { derivedFrom: acting.derivedFrom } : {}
90115
90229
  }));
90116
90230
  if (verdict.ok && verdict.value.selfReason === "flag" && !passedTestOn(io.cwd, verdict.value))
@@ -90127,6 +90241,13 @@ async function run22(argv, io) {
90127
90241
  ].join(`
90128
90242
  `));
90129
90243
  }
90244
+ function verdictCheckEvidence(cwd, branch, base) {
90245
+ const head = branch === null ? headSha(cwd) : resolveRef(cwd, branch);
90246
+ const ledger = readLedger(cwd);
90247
+ if (!head || !ledger.ok)
90248
+ return null;
90249
+ return verdictEvidence(cwd, { head, base, rows: ledger.value.rows });
90250
+ }
90130
90251
  function standingFanout(io, values) {
90131
90252
  if (values.fanout !== undefined) {
90132
90253
  const name = values.fanout.trim();
@@ -90271,6 +90392,7 @@ var init_ledger2 = __esm(() => {
90271
90392
  init_fanout();
90272
90393
  init_rev();
90273
90394
  init_host_session();
90395
+ init_check_evidence();
90274
90396
  init_implicit_task();
90275
90397
  init_output();
90276
90398
  OPTIONS = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cli",
3
- "version": "8.39.1",
3
+ "version": "8.39.3",
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.39.1",
41
+ "@brainervirus/workit-cursor": "^8.39.3",
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.39.1"
47
+ "@brainervirus/workit-core": "^8.39.3"
48
48
  },
49
49
  "engines": {
50
50
  "node": ">=24"