@brainervirus/workit-cli 8.39.2 → 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 +131 -11
  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.2",
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.2",
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.2"
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
  }
@@ -78399,7 +78406,7 @@ var init_resources = __esm(() => {
78399
78406
  init_checks3();
78400
78407
  init_heavy();
78401
78408
  init_heavy_scope();
78402
- DEFAULT_HEAVY_CHECKS = ["test", "build"];
78409
+ DEFAULT_HEAVY_CHECKS = ["test", "build", "packaging"];
78403
78410
  DEFAULT_LIGHT_CHECKS = ["lint", "typecheck", "format"];
78404
78411
  SIZE = /^(\d+(?:\.\d+)?)([KMGT]?)$/iu;
78405
78412
  PERCENT = /^(\d+(?:\.\d+)?)%$/u;
@@ -78617,28 +78624,39 @@ function countWarnings(log) {
78617
78624
  return redactLog(log).replace(ANSI_COLOR, "").split(`
78618
78625
  `).filter((line) => WARNING_LINE.test(line) && !NO_WARNINGS.test(line)).length;
78619
78626
  }
78620
- function boundedOutput(log, lines, stderr = "") {
78627
+ function boundedOutput(log, lines, stderr = "", failed = false) {
78621
78628
  const all = tailLines(log, Number.MAX_SAFE_INTEGER);
78622
78629
  if (all.length === 0)
78623
78630
  return "";
78624
- 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));
78625
78636
  const errors = tailLines(redactLog(stderr), STDERR_TAIL_LINES);
78626
78637
  let missing = [];
78627
78638
  if (errors.length) {
78628
78639
  const tail = new Set(shown);
78629
78640
  if (errors.some((line) => !tail.has(line))) {
78630
- shown = all.slice(-Math.max(1, lines - errors.length - 2));
78641
+ shown = all.slice(-Math.max(1, lines - failureRoom - errors.length - 2));
78631
78642
  const kept = new Set(shown);
78632
78643
  missing = errors.filter((line) => !kept.has(line));
78633
78644
  }
78634
78645
  }
78635
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
+ ` : ""}` : "";
78636
78654
  const footer = missing.length ? `… the last stderr lines, which the merged log holds earlier:
78637
78655
  ${missing.join(`
78638
78656
  `)}
78639
78657
  ` : "";
78640
78658
  return `${omitted ? `… ${omitted} earlier line${omitted === 1 ? "" : "s"} omitted (the full log is named below; --full streams it)
78641
- ` : ""}${shown.join(`
78659
+ ` : ""}${failureFooter}${shown.join(`
78642
78660
  `)}
78643
78661
  ${footer}`;
78644
78662
  }
@@ -78938,7 +78956,7 @@ async function run12(argv, io) {
78938
78956
  `);
78939
78957
  else {
78940
78958
  if (!options.full)
78941
- io.stdout(boundedOutput(result.log, OUTPUT_LINES, stderrTail));
78959
+ io.stdout(boundedOutput(result.log, OUTPUT_LINES, stderrTail, !passed));
78942
78960
  io.stderr(`${summary}
78943
78961
  `);
78944
78962
  if (recordError && passed)
@@ -78955,7 +78973,7 @@ async function run12(argv, io) {
78955
78973
  return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
78956
78974
  return 0;
78957
78975
  }
78958
- 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;
78959
78977
  var init_check = __esm(() => {
78960
78978
  init_check_config();
78961
78979
  init_checks3();
@@ -78976,6 +78994,7 @@ var init_check = __esm(() => {
78976
78994
  ANSI_COLOR = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
78977
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)/;
78978
78996
  NO_WARNINGS = /\b(?:no|0|zero|none)\s+warnings?\b/i;
78997
+ FAILURE_LINE = /^\s*(?:\(fail\)|FAIL\b|✗|error:)/u;
78979
78998
  });
78980
78999
 
78981
79000
  // packages/workit-cli/src/verbs/lock.ts
@@ -80398,6 +80417,67 @@ var init_pr_lane = __esm(() => {
80398
80417
  init_lane();
80399
80418
  });
80400
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
+
80401
80481
  // packages/workit-core/src/forge/reruns.ts
80402
80482
  import fs27 from "node:fs";
80403
80483
  import path58 from "node:path";
@@ -80614,6 +80694,14 @@ function selectPr(cwd, resolved, options) {
80614
80694
  }
80615
80695
  return success2(found.data.number);
80616
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
+ }
80617
80705
  function buildStatusDoc(cwd, resolved, status, options) {
80618
80706
  const { forge } = resolved;
80619
80707
  const reruns = rerunCounts(cwd, { repo: forge.repo, pr: status.number, head: status.head.sha });
@@ -80691,6 +80779,7 @@ function buildStatusDoc(cwd, resolved, status, options) {
80691
80779
  passing: status.checks.filter((check) => check.state === "passing").length,
80692
80780
  missingRequired: missing
80693
80781
  },
80782
+ evidence: evidenceFor(cwd, status),
80694
80783
  reviews: { decision: status.reviewDecision, unresolvedThreads: status.threads },
80695
80784
  blockers: status.state === "open" ? blockers.map((blocker) => blocker.reason) : [],
80696
80785
  identity: options.identity ?? null,
@@ -80874,6 +80963,9 @@ var MAX_LOG_TAILS = 5, GITLAB_MERGEABLE, GITHUB_MERGEABLE, NO_CHECKS_GRACE_MS =
80874
80963
  var init_report2 = __esm(() => {
80875
80964
  init_rev();
80876
80965
  init_ledger();
80966
+ init_check_config();
80967
+ init_lane();
80968
+ init_check_evidence();
80877
80969
  init_reruns();
80878
80970
  GITLAB_MERGEABLE = new Set(["mergeable"]);
80879
80971
  GITHUB_MERGEABLE = new Set(["clean", "unstable", "has_hooks"]);
@@ -86620,6 +86712,8 @@ function renderStatus(doc) {
86620
86712
  lines.push(` - ${thread.path ? `${thread.path}${thread.line ? `:${thread.line}` : ""} ` : ""}@${thread.author ?? "?"}${thread.isBot ? " (bot)" : ""}: ${thread.body}`);
86621
86713
  if (doc.truncated)
86622
86714
  lines.push("(lists truncated at the page cap)");
86715
+ if (doc.evidence)
86716
+ lines.push(...evidenceLines(doc.evidence));
86623
86717
  if (doc.blockers.length)
86624
86718
  lines.push(`blockers: ${doc.blockers.join(", ")}`);
86625
86719
  if (doc.identity?.note)
@@ -86636,6 +86730,7 @@ var forgeDeps, MAX_REASON = 500, usage4 = (io, message, line) => emit(io, fail2(
86636
86730
  now: forgeDeps.now
86637
86731
  }), short = (sha) => sha ? sha.slice(0, 7) : "?";
86638
86732
  var init_forge_common = __esm(() => {
86733
+ init_check_evidence();
86639
86734
  init_resolve();
86640
86735
  init_vcs_config();
86641
86736
  init_duration();
@@ -90105,6 +90200,16 @@ async function run22(argv, io) {
90105
90200
  const refusal = claimed === null ? null : sessionClaimRefusal(io.env, claimed, io.cwd, { token, flag: acting.source === "flag" });
90106
90201
  if (refusal)
90107
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
+ `);
90108
90213
  const bound = claimed !== null && issuedTokenMatches(io.cwd, claimed, token);
90109
90214
  const verdict = await recorded(recordVerdict({ ...context, ...bound ? { sessionBound: true } : {} }, {
90110
90215
  result: rest[0],
@@ -90113,6 +90218,13 @@ async function run22(argv, io) {
90113
90218
  surface: values.surface ?? null,
90114
90219
  self: values.self === true,
90115
90220
  evidenceRefs: values.evidence,
90221
+ ...evidence?.needed.length ? {
90222
+ checkEvidence: evidence.needed.map(({ name, status, via }) => ({
90223
+ name,
90224
+ status,
90225
+ via
90226
+ }))
90227
+ } : {},
90116
90228
  ..."derivedFrom" in acting ? { derivedFrom: acting.derivedFrom } : {}
90117
90229
  }));
90118
90230
  if (verdict.ok && verdict.value.selfReason === "flag" && !passedTestOn(io.cwd, verdict.value))
@@ -90129,6 +90241,13 @@ async function run22(argv, io) {
90129
90241
  ].join(`
90130
90242
  `));
90131
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
+ }
90132
90251
  function standingFanout(io, values) {
90133
90252
  if (values.fanout !== undefined) {
90134
90253
  const name = values.fanout.trim();
@@ -90273,6 +90392,7 @@ var init_ledger2 = __esm(() => {
90273
90392
  init_fanout();
90274
90393
  init_rev();
90275
90394
  init_host_session();
90395
+ init_check_evidence();
90276
90396
  init_implicit_task();
90277
90397
  init_output();
90278
90398
  OPTIONS = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cli",
3
- "version": "8.39.2",
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.2",
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.2"
47
+ "@brainervirus/workit-core": "^8.39.3"
48
48
  },
49
49
  "engines": {
50
50
  "node": ">=24"