@brainervirus/workit-mcp 8.23.0 → 8.24.0

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 +968 -143
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -6620,11 +6620,11 @@ var require_dist = __commonJS(function(exports, module) {
6620
6620
 
6621
6621
  // packages/workit-mcp/src/index.ts
6622
6622
  import { fileURLToPath as fileURLToPath3 } from "node:url";
6623
- import path23 from "node:path";
6623
+ import path24 from "node:path";
6624
6624
 
6625
6625
  // packages/workit-mcp/src/server.ts
6626
- import { existsSync as existsSync8, readFileSync as readFileSync6, realpathSync as realpathSync6 } from "node:fs";
6627
- import path22 from "node:path";
6626
+ import { existsSync as existsSync9, readFileSync as readFileSync7, realpathSync as realpathSync6 } from "node:fs";
6627
+ import path23 from "node:path";
6628
6628
 
6629
6629
  // node_modules/zod/v4/core/util.js
6630
6630
  function getEnumValues(entries) {
@@ -14937,8 +14937,8 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
14937
14937
 
14938
14938
  // packages/workit-core/src/core.ts
14939
14939
  import { spawnSync as spawnSync14 } from "node:child_process";
14940
- import { existsSync as existsSync7, realpathSync as realpathSync5 } from "node:fs";
14941
- import path21 from "node:path";
14940
+ import { existsSync as existsSync8, realpathSync as realpathSync5 } from "node:fs";
14941
+ import path22 from "node:path";
14942
14942
 
14943
14943
  // packages/workit-core/src/core/task-contract.ts
14944
14944
  import { createHash, randomUUID } from "node:crypto";
@@ -17234,7 +17234,7 @@ var workspaceConfigSchema = object2({
17234
17234
  }).passthrough().optional(),
17235
17235
  autoApprove: union([boolean2(), array(nonBlank)]).optional(),
17236
17236
  defaultEndpoint: unknown().optional(),
17237
- verification: _enum(["self", "independent"]).optional(),
17237
+ verification: _enum(["proportional", "self", "independent"]).optional(),
17238
17238
  delegation: unknown().optional(),
17239
17239
  trailers: boolean2().optional(),
17240
17240
  liveSessionGuard: boolean2().optional(),
@@ -17775,6 +17775,124 @@ function resolveRef(cwd, ref) {
17775
17775
  return null;
17776
17776
  return line(git(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]));
17777
17777
  }
17778
+ var LANE_DIFF = [
17779
+ "-c",
17780
+ "core.quotePath=false",
17781
+ "diff",
17782
+ "--no-color",
17783
+ "--no-ext-diff",
17784
+ "--no-textconv",
17785
+ "--no-renames"
17786
+ ];
17787
+ var laneRange = (fork, head) => {
17788
+ if (!safeArg(fork) || head !== null && !safeArg(head))
17789
+ return null;
17790
+ return head === null ? [fork] : [fork, head];
17791
+ };
17792
+ function diffNumstat(cwd, fork, head) {
17793
+ const range = laneRange(fork, head);
17794
+ if (!range)
17795
+ return null;
17796
+ const run = git(cwd, [...LANE_DIFF, "--numstat", "-z", ...range, "--"]);
17797
+ if (!run.ok)
17798
+ return null;
17799
+ const out = [];
17800
+ for (const record of run.stdout.split("\x00")) {
17801
+ const match = /^(-|\d+)\t(-|\d+)\t(.+)$/su.exec(record.replace(/^\n/u, ""));
17802
+ if (!match)
17803
+ continue;
17804
+ const binary = match[1] === "-";
17805
+ out.push({
17806
+ path: match[3],
17807
+ added: binary ? 0 : Number(match[1]),
17808
+ deleted: binary ? 0 : Number(match[2]),
17809
+ binary
17810
+ });
17811
+ }
17812
+ return out;
17813
+ }
17814
+ function diffRaw(cwd, fork, head) {
17815
+ const range = laneRange(fork, head);
17816
+ if (!range)
17817
+ return null;
17818
+ const run = git(cwd, [...LANE_DIFF, "--raw", "-z", "--no-abbrev", ...range, "--"]);
17819
+ if (!run.ok)
17820
+ return null;
17821
+ const fields = run.stdout.split("\x00");
17822
+ const out = [];
17823
+ for (let index = 0;index + 1 < fields.length; index += 2) {
17824
+ const meta = /^:(\d{6}) (\d{6}) ([0-9a-f]+) ([0-9a-f]+) [A-Z]\d*$/u.exec(fields[index].replace(/^\n/u, ""));
17825
+ if (!meta)
17826
+ return null;
17827
+ out.push({
17828
+ path: fields[index + 1],
17829
+ oldMode: meta[1],
17830
+ newMode: meta[2],
17831
+ oldBlob: meta[3],
17832
+ newBlob: meta[4]
17833
+ });
17834
+ }
17835
+ return out;
17836
+ }
17837
+ function readBlobs(cwd, ids) {
17838
+ const out = new Map;
17839
+ const wanted = [...new Set(ids)].filter((id) => /^[0-9a-f]{40,64}$/u.test(id));
17840
+ if (!wanted.length)
17841
+ return out;
17842
+ const run = spawnSync3("git", ["cat-file", "--batch"], {
17843
+ cwd,
17844
+ input: `${wanted.join(`
17845
+ `)}
17846
+ `,
17847
+ maxBuffer: MAX_BUFFER,
17848
+ timeout: GIT_TIMEOUTS.local,
17849
+ killSignal: "SIGKILL",
17850
+ windowsHide: true
17851
+ });
17852
+ if (run.status !== 0 || !run.stdout)
17853
+ return null;
17854
+ const bytes = run.stdout;
17855
+ let at = 0;
17856
+ for (const id of wanted) {
17857
+ const end = bytes.indexOf(10, at);
17858
+ if (end < 0)
17859
+ return null;
17860
+ const header = bytes.subarray(at, end).toString("utf8").split(" ");
17861
+ at = end + 1;
17862
+ if (header[1] === "missing")
17863
+ continue;
17864
+ const size = Number(header[2]);
17865
+ if (header[0] !== id || !Number.isSafeInteger(size))
17866
+ return null;
17867
+ out.set(id, bytes.subarray(at, at + size));
17868
+ at += size + 1;
17869
+ }
17870
+ return out;
17871
+ }
17872
+ function treeFilesNamed(cwd, rev, name) {
17873
+ if (!safeArg(rev))
17874
+ return null;
17875
+ const run = git(cwd, ["ls-tree", "-r", "-z", "--full-tree", rev]);
17876
+ if (!run.ok)
17877
+ return null;
17878
+ const out = new Map;
17879
+ for (const record of run.stdout.split("\x00")) {
17880
+ const match = /^\d{6} blob ([0-9a-f]+)\t(.+)$/su.exec(record);
17881
+ if (match && (match[2] === name || match[2].endsWith(`/${name}`)))
17882
+ out.set(match[2], match[1]);
17883
+ }
17884
+ return out;
17885
+ }
17886
+ function fileAt(cwd, rev, file) {
17887
+ if (!safeArg(rev))
17888
+ return null;
17889
+ const run = git(cwd, ["cat-file", "blob", `${rev}:${file}`]);
17890
+ return run.ok ? run.stdout : null;
17891
+ }
17892
+ function untrackedFiles(cwd) {
17893
+ const run = git(cwd, ["ls-files", "-z", "--others", "--exclude-standard"]);
17894
+ return run.ok ? run.stdout.split("\x00").filter(Boolean) : [];
17895
+ }
17778
17896
  var config2 = (cwd, key) => line(git(cwd, ["config", "--get", key]));
17779
17897
  function currentBranch(cwd) {
17780
17898
  return line(git(cwd, ["symbolic-ref", "--short", "-q", "HEAD"]));
@@ -21283,9 +21401,9 @@ var workerBlocksTransition = (transition, state) => transition === "pause" ? fal
21283
21401
 
21284
21402
  // packages/workit-core/src/core/task-evaluation.ts
21285
21403
  import { createHash as createHash10 } from "node:crypto";
21286
- import * as fs13 from "node:fs";
21287
- import { spawnSync as spawnSync10 } from "node:child_process";
21288
- import path16 from "node:path";
21404
+ import * as fs14 from "node:fs";
21405
+ import { spawnSync as spawnSync11 } from "node:child_process";
21406
+ import path18 from "node:path";
21289
21407
 
21290
21408
  // packages/workit-core/src/check-config.ts
21291
21409
  import { spawnSync as spawnSync8 } from "node:child_process";
@@ -21505,8 +21623,8 @@ function checkCommand(args, version, onPath = workitAvailable()) {
21505
21623
  }
21506
21624
 
21507
21625
  // packages/workit-core/src/core/policy/derive.ts
21508
- import { existsSync as existsSync4 } from "node:fs";
21509
- import path15 from "node:path";
21626
+ import { existsSync as existsSync5 } from "node:fs";
21627
+ import path17 from "node:path";
21510
21628
 
21511
21629
  // packages/workit-core/src/ledger.ts
21512
21630
  import { spawnSync as spawnSync9 } from "node:child_process";
@@ -22350,7 +22468,8 @@ function checkVerdicts(cwd, branch, ledgerRows) {
22350
22468
  verdict: failing?.verdict ?? null,
22351
22469
  reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
22352
22470
  };
22353
- const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && !untrusted(entry.reasons) && STRONG_RESULTS.has(String(entry.verdict.result)));
22471
+ const latestSelf = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && !untrusted(entry.reasons) && (STRONG_RESULTS.has(String(entry.verdict.result)) || FAILING.has(String(entry.verdict.result))));
22472
+ const selfEntry = latestSelf && STRONG_RESULTS.has(String(latestSelf.verdict.result)) ? latestSelf : undefined;
22354
22473
  return {
22355
22474
  branch,
22356
22475
  head,
@@ -22372,12 +22491,721 @@ var OBSERVED_ONLY = new Set([
22372
22491
  ...PR_ROW_TYPES
22373
22492
  ]);
22374
22493
 
22494
+ // packages/workit-core/src/core/policy/lane.ts
22495
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
22496
+ import path16 from "node:path";
22497
+
22498
+ // packages/workit-core/src/core/pr-create.ts
22499
+ import fs13 from "node:fs";
22500
+ import path15 from "node:path";
22501
+ import { spawnSync as spawnSync10 } from "node:child_process";
22502
+ // packages/workit-core/src/forge/pr-body.ts
22503
+ function parseGhIssue(value) {
22504
+ const m = /issues\/(\d+)/.exec(value);
22505
+ return m ? m[1] : String(value).trim().replace(/^#/, "");
22506
+ }
22507
+
22508
+ // packages/workit-core/src/core/pr-create.ts
22509
+ function whichOnPath(tool) {
22510
+ const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
22511
+ for (const dir of (process.env.PATH ?? "").split(path15.delimiter)) {
22512
+ if (!dir)
22513
+ continue;
22514
+ for (const name of names) {
22515
+ const candidate = path15.join(dir, name);
22516
+ try {
22517
+ fs13.accessSync(candidate, fs13.constants.X_OK);
22518
+ return candidate;
22519
+ } catch {}
22520
+ }
22521
+ }
22522
+ return null;
22523
+ }
22524
+ var hostingCliAvailable = (provider) => whichOnPath(provider === "gitlab" ? "glab" : "gh") !== null;
22525
+ var pushRemote = (cwd) => {
22526
+ const result = spawnSync10("git", ["remote", "get-url", "--push", "--all", "origin"], {
22527
+ cwd,
22528
+ encoding: "utf8"
22529
+ });
22530
+ if (result.status !== 0)
22531
+ return null;
22532
+ const urls = (result.stdout ?? "").split(/\r?\n/u).map((url) => url.trim()).filter(Boolean);
22533
+ return urls.length === 1 ? urls[0] : null;
22534
+ };
22535
+
22536
+ // packages/workit-core/src/forge/redact.ts
22537
+ var KEY = String.raw`[A-Za-z0-9_.-]*?(?:token|secret|password|passwd|pwd|api[_-]?key|access[_-]?key|account[_-]?key|private[_-]?key|client[_-]?secret|credentials?|authorization|cookie|signature)[A-Za-z0-9_.-]*`;
22538
+ var ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*["']?)((?:bearer|basic|token|digest)\s+)?([^\s"',;&]+)`, "giu");
22539
+ var QUOTED_ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*)(["'])([^"'\n]*[^\s"'][^"'\n]*)\2`, "giu");
22540
+ var ANSI = new RegExp(String.raw`\u001b\[[0-9;?]*[ -/]*[@-~]|\u001b\][^\u0007]*\u0007`, "gu");
22541
+
22542
+ // packages/workit-core/src/git/ops.ts
22543
+ var COMMIT_TIMEOUT_MS = 10 * 60000;
22544
+
22545
+ // packages/workit-core/src/core/policy/attributes.ts
22546
+ function patternRegex(dir, pattern) {
22547
+ if (!pattern || pattern.endsWith("/") || pattern.startsWith('"') || pattern.startsWith("!"))
22548
+ return null;
22549
+ const anchored = pattern.includes("/");
22550
+ const body = pattern.replace(/^\//u, "");
22551
+ let source = "";
22552
+ for (let index = 0;index < body.length; index += 1) {
22553
+ const char = body[index];
22554
+ if (char === "*" && body[index + 1] === "*") {
22555
+ const slash = body[index + 2] === "/";
22556
+ source += slash ? "(?:.*/)?" : ".*";
22557
+ index += slash ? 2 : 1;
22558
+ } else if (char === "*")
22559
+ source += "[^/]*";
22560
+ else if (char === "?")
22561
+ source += "[^/]";
22562
+ else if (char === "[") {
22563
+ const end = body.indexOf("]", index + 2);
22564
+ if (end < 0)
22565
+ return null;
22566
+ const set = body.slice(index + 1, end).replace(/^!/u, "^").replace(/\\/gu, "\\\\");
22567
+ source += `[${set}]`;
22568
+ index = end;
22569
+ } else if (char === "\\" && index + 1 < body.length) {
22570
+ source += body[index + 1].replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
22571
+ index += 1;
22572
+ } else
22573
+ source += char.replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
22574
+ }
22575
+ const prefix = dir ? `${dir.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}/` : "";
22576
+ try {
22577
+ return new RegExp(anchored ? `^${prefix}${source}$` : `^${prefix}(?:.*/)?${source}$`, "u");
22578
+ } catch {
22579
+ return null;
22580
+ }
22581
+ }
22582
+ function rulesOf(dir, text) {
22583
+ const out = [];
22584
+ for (const raw of text.split(`
22585
+ `)) {
22586
+ const line = raw.trim();
22587
+ if (!line || line.startsWith("#") || line.startsWith("[attr]"))
22588
+ continue;
22589
+ const [pattern, ...attributes] = line.split(/\s+/u);
22590
+ let generated = null;
22591
+ for (const attribute of attributes) {
22592
+ if (attribute === "linguist-generated" || attribute === "linguist-generated=true")
22593
+ generated = true;
22594
+ else if (attribute === "-linguist-generated" || attribute === "!linguist-generated" || attribute.startsWith("linguist-generated="))
22595
+ generated = false;
22596
+ }
22597
+ if (generated === null)
22598
+ continue;
22599
+ const regex = patternRegex(dir, pattern);
22600
+ if (regex)
22601
+ out.push({ regex, generated });
22602
+ }
22603
+ return out;
22604
+ }
22605
+ function generatedByAttributes(files, paths) {
22606
+ const rules = [...files].map(([file, text]) => {
22607
+ const dir = file.includes("/") ? file.slice(0, file.lastIndexOf("/")) : "";
22608
+ return {
22609
+ depth: dir ? dir.split("/").length : 0,
22610
+ rules: rulesOf(dir, text)
22611
+ };
22612
+ }).toSorted((left, right) => left.depth - right.depth).flatMap((entry) => entry.rules);
22613
+ const out = new Set;
22614
+ for (const file of paths) {
22615
+ const last = rules.findLast((rule) => rule.regex.test(file));
22616
+ if (last?.generated)
22617
+ out.add(file);
22618
+ }
22619
+ return out;
22620
+ }
22621
+
22622
+ // packages/workit-core/src/core/policy/substance.ts
22623
+ var SLASH_BLOCK = [["/*", "*/"]];
22624
+ var C_LIKE = { line: ["//"], block: SLASH_BLOCK, quotes: `"'` };
22625
+ var SYNTAXES = Object.fromEntries([
22626
+ ...["ts", "mts", "cts", "js", "mjs", "cjs"].map((ext) => [ext, { ...C_LIKE, js: true }]),
22627
+ ...["java", "kt", "kts", "scala", "swift", "dart", "groovy"].map((ext) => [
22628
+ ext,
22629
+ { ...C_LIKE, triple: true }
22630
+ ]),
22631
+ ["go", { ...C_LIKE, rawBacktick: true }],
22632
+ ...["css", "scss", "less"].map((ext) => [
22633
+ ext,
22634
+ { line: [], block: SLASH_BLOCK, quotes: `"'`, cssUrl: true }
22635
+ ]),
22636
+ ...["py", "pyi"].map((ext) => [
22637
+ ext,
22638
+ { line: ["#"], block: [], quotes: `"'`, triple: true, indented: true, fstring: true }
22639
+ ]),
22640
+ ["toml", { line: ["#"], block: [], quotes: `"`, literal: "'", triple: true }],
22641
+ ...["html", "htm", "xml", "svg", "xhtml"].map((ext) => [
22642
+ ext,
22643
+ { line: [], block: [["<!--", "-->"]], quotes: "", indented: true }
22644
+ ])
22645
+ ]);
22646
+ var DIRECTIVE = /@ts-|eslint|prettier|biome|oxlint|istanbul|\bc8\b|\bv8\b|@jsx|@flow|@vite|webpack|__PURE__|__NO_SIDE_EFFECTS__|source(?:Mapping)?URL|^\/\s*<|go:|\+build|nolint|noqa|type:|pyright|mypy|pylint|pragma|coding[:=]|fmt:|NOSONAR|@license|@preserve|@refresh|environment|language=|cython|ruff|isort|deno-|@vitest|@jest|swiftlint|ktlint|checkstyle|suppress|nullable|#(?:end)?region/iu;
22647
+ var extensionOf = (file) => {
22648
+ const name = file.slice(file.lastIndexOf("/") + 1);
22649
+ const dot = name.lastIndexOf(".");
22650
+ return dot > 0 ? name.slice(dot + 1).toLowerCase() : "";
22651
+ };
22652
+ var CI_PATH = /^\.github\/|(?:^|\/)(?:\.gitlab-ci\.ya?ml|Jenkinsfile|azure-pipelines\.ya?ml|\.pre-commit-config\.ya?ml|\.circleci\/.*)$/u;
22653
+ var syntaxOf = (file) => CI_PATH.test(file) ? null : SYNTAXES[extensionOf(file)] ?? null;
22654
+ var SPACE = /[ \t\r\f\v]/u;
22655
+ var WORD = /[\w$]/u;
22656
+ var NO_SPACE_AFTER = "([{,;";
22657
+ var NO_SPACE_BEFORE = ")]},;";
22658
+ var REGEX_AFTER = "(,=:[!&|?{};+-*%<>~^";
22659
+ var REGEX_KEYWORDS = new Set([
22660
+ "return",
22661
+ "typeof",
22662
+ "instanceof",
22663
+ "case",
22664
+ "do",
22665
+ "else",
22666
+ "in",
22667
+ "of",
22668
+ "new",
22669
+ "delete",
22670
+ "void",
22671
+ "throw",
22672
+ "yield",
22673
+ "await"
22674
+ ]);
22675
+ function substanceOf(file, text) {
22676
+ const syntax = syntaxOf(file);
22677
+ if (!syntax)
22678
+ return plainSubstance(text);
22679
+ const markup = syntax.block.some(([open]) => open === "<!--");
22680
+ if (markup && (/<(?:script|style)\b|<!\[CDATA\[|<\?/iu.test(text) || /[^>\s][ \t]*<!--/u.test(text)))
22681
+ return plainSubstance(text);
22682
+ return lex(syntax, text);
22683
+ }
22684
+ function plainSubstance(text) {
22685
+ return text.split(`
22686
+ `).map((line) => line.replace(/[ \t\r\f\v]+$/u, "")).filter(Boolean).join(`
22687
+ `);
22688
+ }
22689
+ function lex(syntax, text) {
22690
+ const collapse = !syntax.indented;
22691
+ let out = "";
22692
+ let lineStart = 0;
22693
+ let kept = 0;
22694
+ let pendingSpace = false;
22695
+ const frames = [{ kind: "code", braces: 0 }];
22696
+ let index = 0;
22697
+ if (text.startsWith("#!")) {
22698
+ const end = text.indexOf(`
22699
+ `);
22700
+ out = end < 0 ? text : text.slice(0, end);
22701
+ kept = out.length;
22702
+ index = end < 0 ? text.length : end;
22703
+ }
22704
+ const emitCode = (chunk) => {
22705
+ if (collapse && pendingSpace && out.length > lineStart) {
22706
+ const before = out[out.length - 1];
22707
+ if (!NO_SPACE_AFTER.includes(before) && !NO_SPACE_BEFORE.includes(chunk[0]))
22708
+ out += " ";
22709
+ }
22710
+ pendingSpace = false;
22711
+ out += chunk;
22712
+ };
22713
+ const emitVerbatim = (chunk) => {
22714
+ emitCode(chunk);
22715
+ kept = out.length;
22716
+ };
22717
+ const newline = () => {
22718
+ if (!collapse) {
22719
+ let end = out.length;
22720
+ while (end > Math.max(lineStart, kept) && SPACE.test(out[end - 1]))
22721
+ end -= 1;
22722
+ out = out.slice(0, end);
22723
+ }
22724
+ pendingSpace = false;
22725
+ if (out.length > lineStart) {
22726
+ out += `
22727
+ `;
22728
+ lineStart = out.length;
22729
+ }
22730
+ };
22731
+ const regexAllowed = () => {
22732
+ let end = out.length;
22733
+ while (end > 0 && /\s/u.test(out[end - 1]))
22734
+ end -= 1;
22735
+ if (end === 0 || REGEX_AFTER.includes(out[end - 1]))
22736
+ return true;
22737
+ let start = end;
22738
+ while (start > 0 && WORD.test(out[start - 1]))
22739
+ start -= 1;
22740
+ return REGEX_KEYWORDS.has(out.slice(start, end));
22741
+ };
22742
+ const scanString = (quote, escapes, multiline) => {
22743
+ const prefix = text.slice(Math.max(0, index - 2), index).match(/[a-z]*$/iu)?.[0] ?? "";
22744
+ const fstring = syntax.fstring === true && /f/iu.test(prefix);
22745
+ let end = index + quote.length;
22746
+ while (end < text.length) {
22747
+ const char = text[end];
22748
+ if (escapes && char === "\\") {
22749
+ end += 2;
22750
+ continue;
22751
+ }
22752
+ if (text.startsWith(quote, end)) {
22753
+ if (fstring && unbalanced(text.slice(index + quote.length, end)))
22754
+ return false;
22755
+ emitVerbatim(text.slice(index, end + quote.length));
22756
+ index = end + quote.length;
22757
+ return true;
22758
+ }
22759
+ if (char === `
22760
+ ` && !multiline)
22761
+ return false;
22762
+ end += 1;
22763
+ }
22764
+ return false;
22765
+ };
22766
+ while (index < text.length) {
22767
+ const frame = frames[frames.length - 1];
22768
+ const char = text[index];
22769
+ if (frame.kind === "template") {
22770
+ if (char === "\\") {
22771
+ emitVerbatim(text.slice(index, index + 2));
22772
+ index += 2;
22773
+ } else if (char === "`") {
22774
+ emitVerbatim(char);
22775
+ frames.pop();
22776
+ index += 1;
22777
+ } else if (text.startsWith("${", index)) {
22778
+ emitVerbatim("${");
22779
+ frames.push({ kind: "code", braces: 0 });
22780
+ index += 2;
22781
+ } else {
22782
+ out += char;
22783
+ kept = out.length;
22784
+ index += 1;
22785
+ }
22786
+ continue;
22787
+ }
22788
+ if (char === `
22789
+ `) {
22790
+ newline();
22791
+ index += 1;
22792
+ continue;
22793
+ }
22794
+ if (SPACE.test(char)) {
22795
+ if (collapse)
22796
+ pendingSpace = true;
22797
+ else
22798
+ out += char;
22799
+ index += 1;
22800
+ continue;
22801
+ }
22802
+ const lineOpener = syntax.line.find((opener) => text.startsWith(opener, index));
22803
+ if (lineOpener) {
22804
+ const end = text.indexOf(`
22805
+ `, index);
22806
+ const comment = text.slice(index, end < 0 ? text.length : end);
22807
+ if (DIRECTIVE.test(comment.slice(lineOpener.length)))
22808
+ emitVerbatim(comment);
22809
+ else
22810
+ pendingSpace = true;
22811
+ index = end < 0 ? text.length : end;
22812
+ continue;
22813
+ }
22814
+ const block = syntax.block.find(([open]) => text.startsWith(open, index));
22815
+ if (block) {
22816
+ const end = text.indexOf(block[1], index + block[0].length);
22817
+ if (end < 0)
22818
+ return null;
22819
+ const comment = text.slice(index, end + block[1].length);
22820
+ if (DIRECTIVE.test(comment.slice(block[0].length, -block[1].length)))
22821
+ emitVerbatim(comment);
22822
+ else
22823
+ pendingSpace = true;
22824
+ if (comment.includes(`
22825
+ `))
22826
+ newline();
22827
+ index = end + block[1].length;
22828
+ continue;
22829
+ }
22830
+ if (syntax.triple && (char === '"' || char === "'") && text.startsWith(char.repeat(3), index)) {
22831
+ if (!scanString(char.repeat(3), !syntax.literal?.includes(char), true))
22832
+ return null;
22833
+ continue;
22834
+ }
22835
+ if (syntax.quotes.includes(char)) {
22836
+ if (!scanString(char, true, Boolean(syntax.multiline)))
22837
+ return null;
22838
+ continue;
22839
+ }
22840
+ if (syntax.literal?.includes(char)) {
22841
+ if (!scanString(char, false, false))
22842
+ return null;
22843
+ continue;
22844
+ }
22845
+ if (syntax.rawBacktick && char === "`") {
22846
+ if (!scanString("`", false, true))
22847
+ return null;
22848
+ continue;
22849
+ }
22850
+ if (syntax.js && char === "`") {
22851
+ emitVerbatim(char);
22852
+ frames.push({ kind: "template" });
22853
+ index += 1;
22854
+ continue;
22855
+ }
22856
+ if (syntax.cssUrl && /^url\(\s*[^"')\s]/iu.test(text.slice(index, index + 64)))
22857
+ return null;
22858
+ if (syntax.js && char === "/" && !regexAllowed() && out.trimEnd().endsWith(")")) {
22859
+ const lineEnd = text.indexOf(`
22860
+ `, index);
22861
+ if (text.slice(index + 1, lineEnd < 0 ? text.length : lineEnd).includes("/"))
22862
+ return null;
22863
+ }
22864
+ if (syntax.js && char === "/" && regexAllowed()) {
22865
+ let end = index + 1;
22866
+ let inClass = false;
22867
+ while (end < text.length && (inClass || text[end] !== "/")) {
22868
+ if (text[end] === `
22869
+ `)
22870
+ return null;
22871
+ if (text[end] === "\\")
22872
+ end += 1;
22873
+ else if (text[end] === "[")
22874
+ inClass = true;
22875
+ else if (text[end] === "]")
22876
+ inClass = false;
22877
+ end += 1;
22878
+ }
22879
+ if (end >= text.length)
22880
+ return null;
22881
+ emitVerbatim(text.slice(index, end + 1));
22882
+ index = end + 1;
22883
+ continue;
22884
+ }
22885
+ if (frames.length > 1 && frame.kind === "code") {
22886
+ if (char === "{")
22887
+ frame.braces += 1;
22888
+ else if (char === "}") {
22889
+ if (frame.braces === 0) {
22890
+ emitVerbatim(char);
22891
+ frames.pop();
22892
+ index += 1;
22893
+ continue;
22894
+ }
22895
+ frame.braces -= 1;
22896
+ }
22897
+ }
22898
+ emitCode(char);
22899
+ index += 1;
22900
+ }
22901
+ if (frames.length !== 1)
22902
+ return null;
22903
+ newline();
22904
+ return out;
22905
+ }
22906
+ function unbalanced(body) {
22907
+ let depth = 0;
22908
+ for (const part of body.replaceAll("{{", "").replaceAll("}}", "")) {
22909
+ if (part === "{")
22910
+ depth += 1;
22911
+ else if (part === "}")
22912
+ depth = Math.max(0, depth - 1);
22913
+ }
22914
+ return depth > 0;
22915
+ }
22916
+ function hasOpaqueLineBreak(text) {
22917
+ return /\r(?!\n)|[\u2028\u2029]/u.test(text);
22918
+ }
22919
+ var decoder = new TextDecoder("utf-8", { fatal: true });
22920
+ function textOf(bytes) {
22921
+ if (bytes.includes(0))
22922
+ return null;
22923
+ try {
22924
+ return decoder.decode(bytes);
22925
+ } catch {
22926
+ return null;
22927
+ }
22928
+ }
22929
+ function cosmeticChange(file, before, after) {
22930
+ const left = textOf(before);
22931
+ const right = textOf(after);
22932
+ if (left === null || right === null)
22933
+ return false;
22934
+ if (hasOpaqueLineBreak(left) || hasOpaqueLineBreak(right))
22935
+ return false;
22936
+ const a = substanceOf(file, left);
22937
+ return a !== null && a === substanceOf(file, right);
22938
+ }
22939
+
22940
+ // packages/workit-core/src/core/policy/lane.ts
22941
+ var LANE_THRESHOLDS = {
22942
+ selfMaxLines: 100,
22943
+ selfMaxFiles: 5,
22944
+ fullMinLines: 500
22945
+ };
22946
+ var RISK_TOKENS = new Set([
22947
+ "auth",
22948
+ "authn",
22949
+ "authz",
22950
+ "oauth",
22951
+ "security",
22952
+ "permission",
22953
+ "permissions",
22954
+ "secret",
22955
+ "secrets",
22956
+ "crypto",
22957
+ "gate",
22958
+ "gates",
22959
+ "policy",
22960
+ "policies",
22961
+ "hook",
22962
+ "hooks",
22963
+ "husky",
22964
+ "lefthook",
22965
+ "release",
22966
+ "releases",
22967
+ "migration",
22968
+ "migrations",
22969
+ "migrate",
22970
+ "workflows"
22971
+ ]);
22972
+ var RISK_FILES = new Set([
22973
+ ".gitlab-ci.yml",
22974
+ "Jenkinsfile",
22975
+ "azure-pipelines.yml",
22976
+ ".pre-commit-config.yaml",
22977
+ ".workit/risk-paths"
22978
+ ]);
22979
+ var RISK_NAMES = new Set([".gitattributes"]);
22980
+ var RISK_PATHS_FILE = ".workit/risk-paths";
22981
+ var LOCKFILES = new Set([
22982
+ "bun.lock",
22983
+ "bun.lockb",
22984
+ "package-lock.json",
22985
+ "npm-shrinkwrap.json",
22986
+ "yarn.lock",
22987
+ "pnpm-lock.yaml",
22988
+ "Cargo.lock",
22989
+ "go.sum",
22990
+ "poetry.lock",
22991
+ "uv.lock",
22992
+ "Pipfile.lock",
22993
+ "Gemfile.lock",
22994
+ "composer.lock"
22995
+ ]);
22996
+ var DOC_EXT = /\.(?:md|mdx|markdown|rst|adoc|txt)$/iu;
22997
+ var DOC_NAMES = /^(?:license|licence|notice|authors|changelog|changes|contributors)$/iu;
22998
+ var INSTRUCTIONS = /(?:^|\/)(?:AGENTS|CLAUDE|GEMINI|SKILL)\.md$|(?:^|\/)(?:skills|agents|commands|rules|prompts)\/[^/]+/iu;
22999
+ var TEST_PATH = /(?:^|\/)(?:test|tests|__tests__|spec|specs|fixtures)\/|\.(?:test|spec)\.[^/]+$/iu;
23000
+ var basename = (file) => file.slice(file.lastIndexOf("/") + 1);
23001
+ var isDoc = (file) => !INSTRUCTIONS.test(file) && (DOC_EXT.test(file) || DOC_NAMES.test(basename(file)));
23002
+ function kindOf(file) {
23003
+ if (file.binary)
23004
+ return "behavior";
23005
+ if (file.generated)
23006
+ return "generated";
23007
+ if (LOCKFILES.has(basename(file.path)))
23008
+ return "lockfile";
23009
+ if (isDoc(file.path))
23010
+ return "doc";
23011
+ if (file.cosmetic)
23012
+ return "cosmetic";
23013
+ return TEST_PATH.test(file.path) ? "test" : "behavior";
23014
+ }
23015
+ var globCache = new Map;
23016
+ function globMatch(pattern, file) {
23017
+ let regex = globCache.get(pattern);
23018
+ if (!regex) {
23019
+ let source = "";
23020
+ for (let index = 0;index < pattern.length; index += 1) {
23021
+ const char = pattern[index];
23022
+ if (char === "*" && pattern[index + 1] === "*") {
23023
+ source += pattern[index + 2] === "/" ? "(?:[^/]*/)*" : ".*";
23024
+ index += pattern[index + 2] === "/" ? 2 : 1;
23025
+ } else if (char === "*")
23026
+ source += "[^/]*";
23027
+ else if (char === "?")
23028
+ source += "[^/]";
23029
+ else
23030
+ source += char.replace(/[.+^${}()|[\]\\]/gu, "\\$&");
23031
+ }
23032
+ regex = new RegExp(`^${source}$`, "u");
23033
+ globCache.set(pattern, regex);
23034
+ }
23035
+ return regex.test(file) || file.startsWith(`${pattern.replace(/\/$/u, "")}/`);
23036
+ }
23037
+ function isRiskPath(file, extra = []) {
23038
+ if (extra.some((pattern) => globMatch(pattern, file)))
23039
+ return true;
23040
+ if (RISK_FILES.has(file) || RISK_NAMES.has(basename(file)))
23041
+ return true;
23042
+ if (TEST_PATH.test(file) || isDoc(file))
23043
+ return false;
23044
+ return file.split("/").map((segment, index, all) => index === all.length - 1 ? segment.replace(/\.[^.]+$/u, "") : segment).some((segment) => segment.toLowerCase().split(/[-_.]/u).some((token) => RISK_TOKENS.has(token)));
23045
+ }
23046
+ var parseRiskPaths = (text) => text.split(`
23047
+ `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.replace(/^\//u, ""));
23048
+ function computeLane(input) {
23049
+ const riskFiles = input.files.filter((file) => isRiskPath(file.path, input.riskPaths)).map((file) => file.path);
23050
+ const risky = new Set(riskFiles);
23051
+ const kinds = input.files.map((file) => ({
23052
+ file,
23053
+ kind: risky.has(file.path) ? "behavior" : kindOf(file)
23054
+ }));
23055
+ const behavior = kinds.filter((entry) => entry.kind === "behavior" || entry.kind === "test" || entry.kind === "lockfile");
23056
+ const lines = behavior.filter((entry) => entry.kind !== "lockfile").reduce((sum, entry) => sum + entry.file.added + entry.file.deleted, 0);
23057
+ const opaque = behavior.filter((entry) => entry.kind === "lockfile" || entry.file.binary);
23058
+ const result = (lane, reasons) => ({
23059
+ lane,
23060
+ reasons,
23061
+ lines,
23062
+ files: behavior.length,
23063
+ riskFiles
23064
+ });
23065
+ const { selfMaxLines, selfMaxFiles, fullMinLines } = LANE_THRESHOLDS;
23066
+ if (input.riskTier === "high")
23067
+ return result("full", ["the task judgment records high risk"]);
23068
+ if (riskFiles.length)
23069
+ return result("full", [
23070
+ `touches a risk path: ${riskFiles.slice(0, 3).join(", ")}${riskFiles.length > 3 ? ", …" : ""}`
23071
+ ]);
23072
+ if (!behavior.length)
23073
+ return result("none", [
23074
+ input.files.length ? "only docs, comments, formatting or generated copies changed" : "no changes"
23075
+ ]);
23076
+ if (lines >= fullMinLines)
23077
+ return result("full", [`large diff: ${lines} lines (≥ ${fullMinLines})`]);
23078
+ if (lines > selfMaxLines)
23079
+ return result("focused", [`${lines} lines changed (> ${selfMaxLines})`]);
23080
+ if (behavior.length > selfMaxFiles)
23081
+ return result("focused", [`${behavior.length} behavior files changed (> ${selfMaxFiles})`]);
23082
+ if (opaque.length)
23083
+ return result("focused", [
23084
+ `a lockfile or binary changed: ${opaque.slice(0, 3).map((entry) => entry.file.path).join(", ")}${opaque.length > 3 ? ", …" : ""}`
23085
+ ]);
23086
+ return result("self", [
23087
+ `small change: ${lines} line${lines === 1 ? "" : "s"} in ${behavior.length} file${behavior.length === 1 ? "" : "s"}, no risk path`
23088
+ ]);
23089
+ }
23090
+ function untrackedStat(cwd, file) {
23091
+ try {
23092
+ const bytes = readFileSync4(path16.join(cwd, file));
23093
+ if (bytes.includes(0))
23094
+ return { path: file, added: 0, deleted: 0, binary: true };
23095
+ const text = bytes.toString("utf8");
23096
+ if (hasOpaqueLineBreak(text))
23097
+ return { path: file, added: 0, deleted: 0, binary: true };
23098
+ const lines = text.split(`
23099
+ `).length - (text.endsWith(`
23100
+ `) ? 1 : 0);
23101
+ return { path: file, added: lines, deleted: 0 };
23102
+ } catch {
23103
+ return { path: file, added: 0, deleted: 0, binary: true };
23104
+ }
23105
+ }
23106
+ var REGULAR = new Set(["100644", "100755"]);
23107
+ var ABSENT = /^0+$/u;
23108
+ function cosmeticFiles(cwd, fork, head) {
23109
+ const raw = diffRaw(cwd, fork, head);
23110
+ if (!raw)
23111
+ return null;
23112
+ const candidates = raw.filter((entry) => REGULAR.has(entry.oldMode) && entry.oldMode === entry.newMode && !ABSENT.test(entry.oldBlob) && (head === null || !ABSENT.test(entry.newBlob)));
23113
+ const blobs = readBlobs(cwd, candidates.flatMap((entry) => [entry.oldBlob, entry.newBlob]));
23114
+ if (!blobs)
23115
+ return null;
23116
+ const out = new Set;
23117
+ const opaque = new Set;
23118
+ for (const entry of candidates) {
23119
+ const before = blobs.get(entry.oldBlob);
23120
+ let after = blobs.get(entry.newBlob);
23121
+ if (!after && head === null && ABSENT.test(entry.newBlob))
23122
+ try {
23123
+ after = readFileSync4(path16.join(cwd, entry.path));
23124
+ } catch {
23125
+ after = undefined;
23126
+ }
23127
+ if (before && after && cosmeticChange(entry.path, before, after))
23128
+ out.add(entry.path);
23129
+ else if ([before, after].some((bytes) => bytes && hasOpaqueLineBreak(bytes.toString("utf8"))))
23130
+ opaque.add(entry.path);
23131
+ }
23132
+ return { cosmetic: out, opaque };
23133
+ }
23134
+ function generatedAt(cwd, fork, paths) {
23135
+ const files = treeFilesNamed(cwd, fork, ".gitattributes");
23136
+ const blobs = files?.size ? readBlobs(cwd, [...files.values()]) : null;
23137
+ if (!files || !blobs)
23138
+ return new Set;
23139
+ const texts = new Map;
23140
+ for (const [file, id] of files) {
23141
+ const bytes = blobs.get(id);
23142
+ if (bytes)
23143
+ texts.set(file, bytes.toString("utf8"));
23144
+ }
23145
+ return generatedByAttributes(texts, paths);
23146
+ }
23147
+ var forkOf = (cwd, base, head) => mergeBase(cwd, base, head ?? "HEAD");
23148
+ function laneFiles(cwd, fork, head) {
23149
+ const stats = diffNumstat(cwd, fork, head);
23150
+ const cosmetic = stats ? cosmeticFiles(cwd, fork, head) : null;
23151
+ if (!stats || !cosmetic)
23152
+ return null;
23153
+ const files = [
23154
+ ...stats.map((entry) => ({
23155
+ ...entry,
23156
+ ...cosmetic.opaque.has(entry.path) ? { binary: true } : {},
23157
+ cosmetic: !entry.binary && cosmetic.cosmetic.has(entry.path)
23158
+ })),
23159
+ ...head === null ? untrackedFiles(cwd).map((file) => untrackedStat(cwd, file)) : []
23160
+ ];
23161
+ const generated = generatedAt(cwd, fork, files.map((entry) => entry.path));
23162
+ return files.map((entry) => ({
23163
+ ...entry,
23164
+ generated: generated.has(entry.path)
23165
+ }));
23166
+ }
23167
+ function branchLane(cwd, options) {
23168
+ const candidates = options.base ? [`origin/${options.base}`, options.base] : [];
23169
+ const base = candidates.find((ref) => resolveRef(cwd, ref) !== null) ?? defaultBase(cwd) ?? null;
23170
+ const head = options.workingTree ? null : options.head;
23171
+ const fork = base && (options.workingTree || options.head) ? forkOf(cwd, base, head) : null;
23172
+ const files = fork ? laneFiles(cwd, fork, head) : null;
23173
+ const riskTier = options.judgment?.riskTier ?? null;
23174
+ if (!fork || !files) {
23175
+ const high = riskTier === "high";
23176
+ return {
23177
+ lane: high ? "full" : "focused",
23178
+ reasons: [
23179
+ `the diff of ${options.head?.slice(0, 12) ?? "(no head)"} against ${base ?? "(no base)"} cannot be read`,
23180
+ ...high ? ["the task judgment records high risk"] : []
23181
+ ],
23182
+ lines: 0,
23183
+ files: 0,
23184
+ riskFiles: [],
23185
+ base,
23186
+ head: options.head
23187
+ };
23188
+ }
23189
+ const repoRisk = parseRiskPaths(fileAt(cwd, fork, RISK_PATHS_FILE) ?? "");
23190
+ return {
23191
+ ...computeLane({
23192
+ files,
23193
+ riskTier,
23194
+ riskPaths: [...repoRisk, ...options.riskPaths ?? []]
23195
+ }),
23196
+ base,
23197
+ head: options.head
23198
+ };
23199
+ }
23200
+ var laneNeed = (lane) => lane === "none" ? "none" : lane === "self" ? "self" : "non-author";
23201
+
22375
23202
  // packages/workit-core/src/core/policy/derive.ts
22376
23203
  var RULES = {
22377
23204
  test: "check:test",
22378
23205
  self: "verdict:self",
22379
23206
  nonAuthor: "verdict:non-author",
22380
23207
  verified: "verdict:verified",
23208
+ lane: "verdict:lane",
22381
23209
  product: "decision:product",
22382
23210
  plan: "plan"
22383
23211
  };
@@ -22400,6 +23228,7 @@ var normalizedScope = (scope) => ({
22400
23228
  function deriveRequirements(judgment, scope, constraints, verification = "self") {
22401
23229
  const out = [];
22402
23230
  const base = { scope, dependentAction: null };
23231
+ const proportional = verification === "proportional";
22403
23232
  if (judgment.behaviorChange)
22404
23233
  out.push(derived2({
22405
23234
  ...base,
@@ -22410,7 +23239,17 @@ function deriveRequirements(judgment, scope, constraints, verification = "self")
22410
23239
  before: "close",
22411
23240
  acceptanceAllowed: false
22412
23241
  }));
22413
- if (judgment.behaviorChange && judgment.riskTier === "normal")
23242
+ if (proportional && judgment.riskTier === "normal")
23243
+ out.push(derived2({
23244
+ ...base,
23245
+ ruleId: RULES.lane,
23246
+ dimension: "review",
23247
+ reason: "The review lane computed from the diff decides the verdict: none needs none, self the author's own (shown as self-reviewed), focused and full a non-author one.",
23248
+ satisfaction: "Read the lane in `workit policy assess` or `workit pr status`; record what it asks: `workit ledger verdict tests-verified --self --how <what you ran>` for self, or hand focused and full to a verifier.",
23249
+ before: "close",
23250
+ acceptanceAllowed: false
23251
+ }));
23252
+ if (!proportional && judgment.behaviorChange && judgment.riskTier === "normal")
22414
23253
  out.push(verification === "independent" ? derived2({
22415
23254
  ...base,
22416
23255
  ruleId: RULES.nonAuthor,
@@ -22513,7 +23352,7 @@ var productDecision = (task, ledger) => {
22513
23352
  };
22514
23353
  };
22515
23354
  var planRecorded = (task, root) => {
22516
- const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path15.resolve(root, ref.path)));
23355
+ const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync5(path17.resolve(root, ref.path)));
22517
23356
  if (cited)
22518
23357
  return {
22519
23358
  met: true,
@@ -22527,14 +23366,30 @@ var planRecorded = (task, root) => {
22527
23366
  decisionIds: []
22528
23367
  };
22529
23368
  };
22530
- var verdict = (requirement, root, ledger) => {
23369
+ var workingLane = (task, root) => branchLane(root, { head: null, workingTree: true, judgment: latestJudgment(task) });
23370
+ var laneVerdict = (task, root, ledger) => {
23371
+ if (!ledger.branch() && latestJudgment(task)?.behaviorChange === false)
23372
+ return {
23373
+ met: true,
23374
+ reason: "no branch to read a lane from, and the judgment records no behavior change",
23375
+ decisionIds: []
23376
+ };
23377
+ const lane = workingLane(task, root);
23378
+ const label = `lane ${lane.lane} (${lane.reasons.join("; ")})`;
23379
+ const need = laneNeed(lane.lane);
23380
+ if (need === "none")
23381
+ return { met: true, reason: `${label}: no verdict needed`, decisionIds: [] };
23382
+ const status = verdict(need === "self" ? RULES.self : RULES.nonAuthor, root, ledger);
23383
+ return { ...status, reason: `${label}: ${status.reason}` };
23384
+ };
23385
+ var verdict = (ruleId, root, ledger) => {
22531
23386
  const branch = ledger.branch();
22532
23387
  if (!branch)
22533
23388
  return { met: false, reason: "no branch is checked out to hold a verdict", decisionIds: [] };
22534
23389
  const check = checkVerdicts(root, branch, ledger.rows());
22535
23390
  const failing = check.accepted.reasons.includes("failing_verdict");
22536
23391
  const strong = (entry) => STRONG_RESULTS.has(String(entry.verdict.result));
22537
- const met = !failing && (requirement.ruleId === RULES.verified ? check.verdicts.find((entry) => entry.accepted && entry.kind === "live" && String(entry.verdict.result) === "verified") : requirement.ruleId === RULES.nonAuthor ? check.verdicts.find((entry) => entry.accepted && strong(entry)) : check.verdicts.find((entry) => entry.current && strong(entry)));
23392
+ const met = !failing && (ruleId === RULES.verified ? check.verdicts.find((entry) => entry.accepted && entry.kind === "live" && String(entry.verdict.result) === "verified") : ruleId === RULES.nonAuthor ? check.verdicts.find((entry) => entry.accepted && strong(entry)) : check.verdicts.find((entry) => entry.current && strong(entry)));
22538
23393
  if (met)
22539
23394
  return {
22540
23395
  met: true,
@@ -22542,7 +23397,7 @@ var verdict = (requirement, root, ledger) => {
22542
23397
  decisionIds: []
22543
23398
  };
22544
23399
  const why = failing ? "a current independent verdict fails" : check.verdicts.some((entry) => entry.current && entry.verdict.result === "type-check-only") ? "type-check-only does not prove a behavior change" : (check.accepted.reasons.join(", ") || "no_verdict").replace(/_/g, " ");
22545
- const unblock = requirement.ruleId === RULES.self ? "record your own verdict after an observed `workit check test`: `workit ledger verdict tests-verified --self --how <what you ran>` (shown as self-reviewed), or have a verifier record one" : `an independent session records \`workit ledger verdict verified${requirement.ruleId === RULES.verified ? " --kind live" : ""} --how <what it exercised>\``;
23400
+ const unblock = ruleId === RULES.self ? "record your own verdict after an observed `workit check test`: `workit ledger verdict tests-verified --self --how <what you ran>` (shown as self-reviewed), or have a verifier record one" : `an independent session records \`workit ledger verdict verified${ruleId === RULES.verified ? " --kind live" : ""} --how <what it exercised>\``;
22546
23401
  return { met: false, reason: `${why}: ${unblock}`, decisionIds: [] };
22547
23402
  };
22548
23403
  function derivedRuleStatus(task, requirement, root, ledger) {
@@ -22554,7 +23409,9 @@ function derivedRuleStatus(task, requirement, root, ledger) {
22554
23409
  case RULES.self:
22555
23410
  case RULES.nonAuthor:
22556
23411
  case RULES.verified:
22557
- return verdict(requirement, root, ledger);
23412
+ return verdict(requirement.ruleId, root, ledger);
23413
+ case RULES.lane:
23414
+ return laneVerdict(task, root, ledger);
22558
23415
  default:
22559
23416
  return null;
22560
23417
  }
@@ -22562,14 +23419,14 @@ function derivedRuleStatus(task, requirement, root, ledger) {
22562
23419
 
22563
23420
  // packages/workit-core/src/core/task-evaluation.ts
22564
23421
  var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
22565
- var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
22566
- var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
23422
+ var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path18.sep}`);
23423
+ var relative = (root, candidate) => path18.relative(root, candidate).split(path18.sep).join("/") || ".";
22567
23424
  var canonicalPath = (value) => {
22568
23425
  if (typeof value !== "string" || !value)
22569
23426
  return null;
22570
23427
  if (value.includes("\\") || value.split("/").includes(".."))
22571
23428
  return null;
22572
- const normalized = path16.posix.normalize(value);
23429
+ const normalized = path18.posix.normalize(value);
22573
23430
  if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
22574
23431
  return null;
22575
23432
  return normalized === "." ? "." : normalized.replace(/\/$/, "");
@@ -22605,7 +23462,7 @@ var compareCodeUnits2 = (left, right) => {
22605
23462
  return left.length - right.length;
22606
23463
  };
22607
23464
  var gitPaths = (root) => {
22608
- const result = spawnSync10("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
23465
+ const result = spawnSync11("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
22609
23466
  cwd: root,
22610
23467
  encoding: "buffer"
22611
23468
  });
@@ -22617,21 +23474,21 @@ var gitPaths = (root) => {
22617
23474
  git: !/not a git repository/i.test(stderr)
22618
23475
  };
22619
23476
  }
22620
- const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
22621
- const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
23477
+ const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path18.sep).join("/")) : [];
23478
+ const stagedDeleted = spawnSync11("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
22622
23479
  if (stagedDeleted.status !== 0) {
22623
23480
  const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
22624
23481
  if (!/not a git repository/i.test(stderr))
22625
23482
  return { paths, uncertain: true, git: true };
22626
23483
  } else if (stagedDeleted.stdout) {
22627
- paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
23484
+ paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path18.sep).join("/")));
22628
23485
  }
22629
23486
  return { paths: [...new Set(paths)], uncertain: false, git: true };
22630
23487
  };
22631
23488
  var walk = (root, directory, output) => {
22632
23489
  let names;
22633
23490
  try {
22634
- names = fs13.readdirSync(directory);
23491
+ names = fs14.readdirSync(directory);
22635
23492
  } catch {
22636
23493
  return true;
22637
23494
  }
@@ -22639,10 +23496,10 @@ var walk = (root, directory, output) => {
22639
23496
  for (const name of names) {
22640
23497
  if (name === ".git" || name === ".workit")
22641
23498
  continue;
22642
- const target = path16.join(directory, name);
23499
+ const target = path18.join(directory, name);
22643
23500
  let stat;
22644
23501
  try {
22645
- stat = fs13.lstatSync(target);
23502
+ stat = fs14.lstatSync(target);
22646
23503
  } catch {
22647
23504
  uncertain = true;
22648
23505
  continue;
@@ -22657,14 +23514,14 @@ var walk = (root, directory, output) => {
22657
23514
  var scopeRoots = (root, scope) => {
22658
23515
  const roots = [];
22659
23516
  for (const item of scope.paths.length ? scope.paths : ["."]) {
22660
- const target = path16.resolve(root, item);
23517
+ const target = path18.resolve(root, item);
22661
23518
  if (!inside(root, target))
22662
23519
  return failure2("invalid_input", `candidate scope escapes checkout: ${item} — keep one task per repository and coordinate a separate linked task in the other checkout`, { fields: [{ path: "scope.paths", reason: `${item} is outside the checkout` }] });
22663
23520
  let ancestor = target;
22664
- while (!fs13.existsSync(ancestor) && ancestor !== root)
22665
- ancestor = path16.dirname(ancestor);
23521
+ while (!fs14.existsSync(ancestor) && ancestor !== root)
23522
+ ancestor = path18.dirname(ancestor);
22666
23523
  try {
22667
- if (!inside(root, fs13.realpathSync(ancestor)))
23524
+ if (!inside(root, fs14.realpathSync(ancestor)))
22668
23525
  return failure2("invalid_input", `candidate scope escapes checkout through a symlink: ${item} — keep one task per repository and coordinate a separate linked task in the other checkout`, { fields: [{ path: "scope.paths", reason: `${item} resolves outside the checkout` }] });
22669
23526
  } catch {
22670
23527
  return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
@@ -22676,7 +23533,7 @@ var scopeRoots = (root, scope) => {
22676
23533
  function captureCandidate(root, scope, environment = []) {
22677
23534
  let checkout;
22678
23535
  try {
22679
- checkout = fs13.realpathSync(root);
23536
+ checkout = fs14.realpathSync(root);
22680
23537
  } catch {
22681
23538
  return failure2("invalid_input", "candidate root does not exist");
22682
23539
  }
@@ -22694,11 +23551,11 @@ function captureCandidate(root, scope, environment = []) {
22694
23551
  if (item === ".git" || item === ".workit")
22695
23552
  continue;
22696
23553
  names.add(item);
22697
- if (!fs13.existsSync(target))
23554
+ if (!fs14.existsSync(target))
22698
23555
  continue;
22699
23556
  let stat;
22700
23557
  try {
22701
- stat = fs13.lstatSync(target);
23558
+ stat = fs14.lstatSync(target);
22702
23559
  } catch {
22703
23560
  uncertain = true;
22704
23561
  continue;
@@ -22714,17 +23571,17 @@ function captureCandidate(root, scope, environment = []) {
22714
23571
  for (const item of [...names].toSorted()) {
22715
23572
  if (!scopeMatches(item, normalizedScope))
22716
23573
  continue;
22717
- const target = path16.join(checkout, item);
23574
+ const target = path18.join(checkout, item);
22718
23575
  try {
22719
- const stat = fs13.lstatSync(target);
23576
+ const stat = fs14.lstatSync(target);
22720
23577
  if (stat.isSymbolicLink()) {
22721
- const link = fs13.readlinkSync(target);
23578
+ const link = fs14.readlinkSync(target);
22722
23579
  files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
22723
23580
  } else if (stat.isFile()) {
22724
23581
  files.push({
22725
23582
  path: item,
22726
23583
  kind: "file",
22727
- digest: digestBytes(fs13.readFileSync(target)),
23584
+ digest: digestBytes(fs14.readFileSync(target)),
22728
23585
  executable: (stat.mode & 73) !== 0
22729
23586
  });
22730
23587
  } else if (!stat.isDirectory()) {
@@ -22749,7 +23606,7 @@ function captureCandidate(root, scope, environment = []) {
22749
23606
  const values = supplied.toSorted((left, right) => compareCodeUnits2(left.name, right.name)).map(({ name, value }) => ({ name, value, refs: [] }));
22750
23607
  if (values.some(({ value }) => value === null))
22751
23608
  completeness = "uncertain";
22752
- const headResult = spawnSync10("git", ["rev-parse", "HEAD"], { cwd: checkout, encoding: "utf8" });
23609
+ const headResult = spawnSync11("git", ["rev-parse", "HEAD"], { cwd: checkout, encoding: "utf8" });
22753
23610
  if (headResult.status !== 0 && !/not a git repository/i.test(headResult.stderr ?? ""))
22754
23611
  completeness = "uncertain";
22755
23612
  const head = headResult.status === 0 ? headResult.stdout.trim() : null;
@@ -22889,7 +23746,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
22889
23746
  var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
22890
23747
  let root;
22891
23748
  try {
22892
- root = fs13.realpathSync(checkoutRoot);
23749
+ root = fs14.realpathSync(checkoutRoot);
22893
23750
  } catch {
22894
23751
  return failure2("permission_denied", "checkout root is unavailable");
22895
23752
  }
@@ -22898,23 +23755,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
22898
23755
  continue;
22899
23756
  if (!reference.digest)
22900
23757
  return failure2("invalid_input", "document references require a byte digest");
22901
- const target = path16.resolve(root, reference.path);
22902
- if (target !== root && !target.startsWith(`${root}${path16.sep}`))
23758
+ const target = path18.resolve(root, reference.path);
23759
+ if (target !== root && !target.startsWith(`${root}${path18.sep}`))
22903
23760
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
22904
23761
  fields: [
22905
23762
  { path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
22906
23763
  ]
22907
23764
  });
22908
23765
  try {
22909
- const below = path16.relative(root, target);
23766
+ const below = path18.relative(root, target);
22910
23767
  let current = root;
22911
- for (const segment of below.split(path16.sep)) {
23768
+ for (const segment of below.split(path18.sep)) {
22912
23769
  if (!segment)
22913
23770
  continue;
22914
- current = path16.join(current, segment);
22915
- const stat = fs13.lstatSync(current);
22916
- const real = fs13.realpathSync(current);
22917
- if (real !== root && !real.startsWith(`${root}${path16.sep}`))
23771
+ current = path18.join(current, segment);
23772
+ const stat = fs14.lstatSync(current);
23773
+ const real = fs14.realpathSync(current);
23774
+ if (real !== root && !real.startsWith(`${root}${path18.sep}`))
22918
23775
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
22919
23776
  fields: [
22920
23777
  {
@@ -22930,7 +23787,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
22930
23787
  if (current !== target && !stat.isDirectory())
22931
23788
  return failure2("invalid_input", "document reference ancestor is not a directory");
22932
23789
  }
22933
- if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
23790
+ if (digestBytes(fs14.readFileSync(target)) !== reference.digest)
22934
23791
  return failure2("permission_denied", "decision document bytes have changed");
22935
23792
  } catch {
22936
23793
  return failure2("invalid_input", "decision document is unavailable");
@@ -23773,7 +24630,7 @@ var judgeInputSummary = (raw) => {
23773
24630
 
23774
24631
  // packages/workit-core/src/autonomy.ts
23775
24632
  import os4 from "node:os";
23776
- import path17 from "node:path";
24633
+ import path19 from "node:path";
23777
24634
  var accountHome = () => {
23778
24635
  try {
23779
24636
  return os4.userInfo().homedir;
@@ -23782,10 +24639,10 @@ var accountHome = () => {
23782
24639
  }
23783
24640
  };
23784
24641
  var grantsHome = { resolve: accountHome };
23785
- var grantsDir = () => path17.join(grantsHome.resolve(), ".config", "workit");
24642
+ var grantsDir = () => path19.join(grantsHome.resolve(), ".config", "workit");
23786
24643
  var grantsOverride = () => {
23787
- const configured = path17.resolve(resolveConfigDir());
23788
- return configured === path17.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path17.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
24644
+ const configured = path19.resolve(resolveConfigDir());
24645
+ return configured === path19.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path19.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
23789
24646
  };
23790
24647
  var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
23791
24648
  var DEFAULT_GRANTS = Object.freeze({
@@ -23838,8 +24695,16 @@ function endpointView(entry, context) {
23838
24695
  ...issue ? { endpointIssue: issue } : {}
23839
24696
  };
23840
24697
  }
23841
- var DEFAULT_VERIFICATION = "self";
23842
- var verificationOf = (entry) => entry?.verification === "independent" ? "independent" : "self";
24698
+ var VERIFICATION_MODES = [
24699
+ "proportional",
24700
+ "self",
24701
+ "independent"
24702
+ ];
24703
+ var DEFAULT_VERIFICATION = "proportional";
24704
+ var verificationOf = (entry) => {
24705
+ const value = entry?.verification;
24706
+ return VERIFICATION_MODES.includes(value) ? value : DEFAULT_VERIFICATION;
24707
+ };
23843
24708
  var isGrantValue = (value) => value === true || value === false || value === "verified";
23844
24709
  var normalized = (kind, value) => value === "verified" && kind !== "merge" ? true : value;
23845
24710
  var fromAutoApprove = (value) => {
@@ -25586,9 +26451,9 @@ class WorkitCore {
25586
26451
  }
25587
26452
  }
25588
26453
  // packages/workit-core/src/core/repo-context.ts
25589
- import { spawnSync as spawnSync11 } from "node:child_process";
25590
- import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
25591
- import path18 from "node:path";
26454
+ import { spawnSync as spawnSync12 } from "node:child_process";
26455
+ import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "node:fs";
26456
+ import path20 from "node:path";
25592
26457
  var isSafeContextRange = (value) => value.length <= 4096 && (() => {
25593
26458
  try {
25594
26459
  gitRevisionParts(value);
@@ -25615,7 +26480,7 @@ var invalidRange = (cwd) => ({
25615
26480
  cwd
25616
26481
  });
25617
26482
  var runGit = (cwd, args) => {
25618
- const result = spawnSync11("git", args, { cwd, encoding: "utf8" });
26483
+ const result = spawnSync12("git", args, { cwd, encoding: "utf8" });
25619
26484
  return {
25620
26485
  stdout: (result.stdout ?? "").trimEnd(),
25621
26486
  stderr: (result.stderr ?? "").trimEnd(),
@@ -25722,7 +26587,7 @@ var findPrTemplate = (cwd) => {
25722
26587
  ]) {
25723
26588
  const parts = rel.split("/");
25724
26589
  const base = parts[parts.length - 1];
25725
- const dir = parts.length > 1 ? path18.join(cwd, ...parts.slice(0, -1)) : cwd;
26590
+ const dir = parts.length > 1 ? path20.join(cwd, ...parts.slice(0, -1)) : cwd;
25726
26591
  const actual = probeCaseInsensitive(dir, base);
25727
26592
  if (actual)
25728
26593
  return [...parts.slice(0, -1), actual].join("/");
@@ -25753,11 +26618,11 @@ var diffStatForRange = (cwd, range) => {
25753
26618
  return runGit(cwd, ["diff", "--stat", "--"]).stdout;
25754
26619
  };
25755
26620
  var packageScripts = (cwd, keys) => {
25756
- const pkgPath = path18.join(cwd, "package.json");
25757
- if (!existsSync6(pkgPath))
26621
+ const pkgPath = path20.join(cwd, "package.json");
26622
+ if (!existsSync7(pkgPath))
25758
26623
  return [];
25759
26624
  try {
25760
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
26625
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
25761
26626
  return keys.filter((k) => pkg.scripts && typeof pkg.scripts[k] === "string").map((k) => `${k}: ${pkg.scripts?.[k]}`);
25762
26627
  } catch {
25763
26628
  return [];
@@ -25779,9 +26644,9 @@ var documentationFiles = (cwd) => {
25779
26644
  if (entry.isDirectory()) {
25780
26645
  if (excluded.has(entry.name))
25781
26646
  continue;
25782
- walk(path18.join(dir, entry.name), depth + 1);
26647
+ walk(path20.join(dir, entry.name), depth + 1);
25783
26648
  } else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
25784
- matches.push("./" + path18.relative(cwd, path18.join(dir, entry.name)).replaceAll("\\", "/"));
26649
+ matches.push("./" + path20.relative(cwd, path20.join(dir, entry.name)).replaceAll("\\", "/"));
25785
26650
  }
25786
26651
  }
25787
26652
  };
@@ -25789,15 +26654,15 @@ var documentationFiles = (cwd) => {
25789
26654
  return matches.toSorted().slice(0, 200);
25790
26655
  };
25791
26656
  var readTrimmed2 = (file, maxLines) => {
25792
- if (!existsSync6(file))
26657
+ if (!existsSync7(file))
25793
26658
  return "";
25794
- const lines = readFileSync5(file, "utf8").split(`
26659
+ const lines = readFileSync6(file, "utf8").split(`
25795
26660
  `);
25796
26661
  return lines.slice(0, maxLines).join(`
25797
26662
  `);
25798
26663
  };
25799
26664
  function prReadyContext(root, range) {
25800
- const cwd = path18.resolve(repoRoot(root));
26665
+ const cwd = path20.resolve(repoRoot(root));
25801
26666
  if (range !== undefined && !isResolvableContextRange(cwd, range))
25802
26667
  return invalidRange(cwd);
25803
26668
  let stdout = "";
@@ -25855,7 +26720,7 @@ ${status.stderr}` : "");
25855
26720
  stdout += `template_path: ${template}
25856
26721
 
25857
26722
  `;
25858
- stdout += readTrimmed2(path18.join(cwd, template), 220);
26723
+ stdout += readTrimmed2(path20.join(cwd, template), 220);
25859
26724
  } else {
25860
26725
  stdout += `template_path: none
25861
26726
 
@@ -25865,7 +26730,7 @@ ${status.stderr}` : "");
25865
26730
  stdout += `
25866
26731
  `;
25867
26732
  stdout += printSection("Recent Validation Signals");
25868
- if (existsSync6(path18.join(cwd, "package.json"))) {
26733
+ if (existsSync7(path20.join(cwd, "package.json"))) {
25869
26734
  stdout += `package.json detected. Common scripts:
25870
26735
  `;
25871
26736
  const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
@@ -25874,7 +26739,7 @@ ${status.stderr}` : "");
25874
26739
  `) + `
25875
26740
  `;
25876
26741
  }
25877
- if (existsSync6(path18.join(cwd, "Cargo.toml")) || existsSync6(path18.join(cwd, "src-tauri/Cargo.toml"))) {
26742
+ if (existsSync7(path20.join(cwd, "Cargo.toml")) || existsSync7(path20.join(cwd, "src-tauri/Cargo.toml"))) {
25878
26743
  stdout += `Rust project detected.
25879
26744
  `;
25880
26745
  }
@@ -25907,7 +26772,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
25907
26772
  - Apply with the host-native editor, preserving the repository changelog conventions.
25908
26773
  - If Unreleased already has duplicate category headings, normalize_only first.`;
25909
26774
  function changelogContext(root, range) {
25910
- const cwd = path18.resolve(repoRoot(root));
26775
+ const cwd = path20.resolve(repoRoot(root));
25911
26776
  if (range !== undefined && !isResolvableContextRange(cwd, range))
25912
26777
  return invalidRange(cwd);
25913
26778
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -25925,8 +26790,8 @@ function changelogContext(root, range) {
25925
26790
  stdout += CHANGELOG_RULES + `
25926
26791
  `;
25927
26792
  stdout += printSection("Existing CHANGELOG.md");
25928
- const changelogPath = path18.join(cwd, "CHANGELOG.md");
25929
- if (existsSync6(changelogPath)) {
26793
+ const changelogPath = path20.join(cwd, "CHANGELOG.md");
26794
+ if (existsSync7(changelogPath)) {
25930
26795
  stdout += readTrimmed2(changelogPath, 260) + `
25931
26796
  `;
25932
26797
  } else {
@@ -25945,7 +26810,7 @@ function changelogContext(root, range) {
25945
26810
  return { stdout, stderr: "", exitCode: 0, cwd };
25946
26811
  }
25947
26812
  function docsRefreshContext(root, range) {
25948
- const cwd = path18.resolve(repoRoot(root));
26813
+ const cwd = path20.resolve(repoRoot(root));
25949
26814
  if (range !== undefined && !isResolvableContextRange(cwd, range))
25950
26815
  return invalidRange(cwd);
25951
26816
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -25967,8 +26832,8 @@ function docsRefreshContext(root, range) {
25967
26832
  `) + `
25968
26833
  `;
25969
26834
  stdout += printSection("README Preview");
25970
- const readme = path18.join(cwd, "README.md");
25971
- if (existsSync6(readme)) {
26835
+ const readme = path20.join(cwd, "README.md");
26836
+ if (existsSync7(readme)) {
25972
26837
  stdout += readTrimmed2(readme, 220) + `
25973
26838
  `;
25974
26839
  } else {
@@ -25976,10 +26841,10 @@ function docsRefreshContext(root, range) {
25976
26841
  `;
25977
26842
  }
25978
26843
  stdout += printSection("Package Scripts");
25979
- const pkgPath = path18.join(cwd, "package.json");
25980
- if (existsSync6(pkgPath)) {
26844
+ const pkgPath = path20.join(cwd, "package.json");
26845
+ if (existsSync7(pkgPath)) {
25981
26846
  try {
25982
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
26847
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
25983
26848
  stdout += JSON.stringify({ name: pkg.name, version: pkg.version, scripts: pkg.scripts }, null, 2) + `
25984
26849
  `;
25985
26850
  } catch {}
@@ -25990,7 +26855,7 @@ function docsRefreshContext(root, range) {
25990
26855
  return { stdout, stderr: "", exitCode: 0, cwd };
25991
26856
  }
25992
26857
  function releaseNotesContext(root, rangeOrTag) {
25993
- const cwd = path18.resolve(repoRoot(root));
26858
+ const cwd = path20.resolve(repoRoot(root));
25994
26859
  if (!rangeOrTag) {
25995
26860
  return { stdout: "", stderr: `ERROR: release tag or range required
25996
26861
  `, exitCode: 1, cwd };
@@ -26028,7 +26893,7 @@ function releaseNotesContext(root, rangeOrTag) {
26028
26893
  `;
26029
26894
  stdout += printSection("Existing Release Files");
26030
26895
  for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
26031
- if (existsSync6(path18.join(cwd, rel)))
26896
+ if (existsSync7(path20.join(cwd, rel)))
26032
26897
  stdout += rel + `
26033
26898
  `;
26034
26899
  }
@@ -26057,46 +26922,6 @@ function releaseNotesContext(root, rangeOrTag) {
26057
26922
 
26058
26923
  // packages/workit-core/src/core/tracker-issues.ts
26059
26924
  import { spawnSync as spawnSync13 } from "node:child_process";
26060
-
26061
- // packages/workit-core/src/core/pr-create.ts
26062
- import fs14 from "node:fs";
26063
- import path19 from "node:path";
26064
- import { spawnSync as spawnSync12 } from "node:child_process";
26065
- // packages/workit-core/src/forge/pr-body.ts
26066
- function parseGhIssue(value) {
26067
- const m = /issues\/(\d+)/.exec(value);
26068
- return m ? m[1] : String(value).trim().replace(/^#/, "");
26069
- }
26070
-
26071
- // packages/workit-core/src/core/pr-create.ts
26072
- function whichOnPath(tool) {
26073
- const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
26074
- for (const dir of (process.env.PATH ?? "").split(path19.delimiter)) {
26075
- if (!dir)
26076
- continue;
26077
- for (const name of names) {
26078
- const candidate = path19.join(dir, name);
26079
- try {
26080
- fs14.accessSync(candidate, fs14.constants.X_OK);
26081
- return candidate;
26082
- } catch {}
26083
- }
26084
- }
26085
- return null;
26086
- }
26087
- var hostingCliAvailable = (provider) => whichOnPath(provider === "gitlab" ? "glab" : "gh") !== null;
26088
- var pushRemote = (cwd) => {
26089
- const result = spawnSync12("git", ["remote", "get-url", "--push", "--all", "origin"], {
26090
- cwd,
26091
- encoding: "utf8"
26092
- });
26093
- if (result.status !== 0)
26094
- return null;
26095
- const urls = (result.stdout ?? "").split(/\r?\n/u).map((url) => url.trim()).filter(Boolean);
26096
- return urls.length === 1 ? urls[0] : null;
26097
- };
26098
-
26099
- // packages/workit-core/src/core/tracker-issues.ts
26100
26925
  var repoPathFromRemote = (remote) => {
26101
26926
  let rest = (remote || "").trim().replace(/\/+$/, "");
26102
26927
  if (!rest)
@@ -26196,7 +27021,7 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
26196
27021
 
26197
27022
  // packages/workit-core/src/core/youtrack.ts
26198
27023
  import fs15 from "node:fs";
26199
- import path20 from "node:path";
27024
+ import path21 from "node:path";
26200
27025
 
26201
27026
  // packages/workit-core/src/core/templates.ts
26202
27027
  var repoRoot2 = assetRoot();
@@ -26209,8 +27034,8 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
26209
27034
  // packages/workit-core/src/core/youtrack.ts
26210
27035
  var ISSUE_RE = /^[A-Z]+-\d+$/;
26211
27036
  var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
26212
- var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(configDir(), "youtrack.json");
26213
- var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(resolveConfigDir(), "youtrack.json");
27037
+ var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path21.join(configDir(), "youtrack.json");
27038
+ var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path21.join(resolveConfigDir(), "youtrack.json");
26214
27039
  var youTrackTokenModeOk = (p) => {
26215
27040
  if (process.platform === "win32")
26216
27041
  return true;
@@ -26278,7 +27103,7 @@ var youTrackToken = () => {
26278
27103
  if ("error" in loaded)
26279
27104
  return loaded;
26280
27105
  const tokenFile = String(loaded.config.tokenFile ?? "");
26281
- const tokenPath = tokenFile ? path20.isAbsolute(tokenFile) ? path20.resolve(tokenFile) : path20.resolve(process.cwd(), tokenFile) : "";
27106
+ const tokenPath = tokenFile ? path21.isAbsolute(tokenFile) ? path21.resolve(tokenFile) : path21.resolve(process.cwd(), tokenFile) : "";
26282
27107
  if (!tokenPath || !fs15.existsSync(tokenPath))
26283
27108
  return { error: "missing youtrack.token" };
26284
27109
  if (!youTrackTokenModeOk(tokenPath))
@@ -26620,15 +27445,15 @@ function resolveGitRevision(root, value) {
26620
27445
  }
26621
27446
  function resolveInside(root, candidate) {
26622
27447
  const base = realpathSync5(root);
26623
- const target = path21.resolve(base, candidate);
26624
- if (target !== base && !target.startsWith(base + path21.sep)) {
27448
+ const target = path22.resolve(base, candidate);
27449
+ if (target !== base && !target.startsWith(base + path22.sep)) {
26625
27450
  throw new Error("path must stay inside repository root");
26626
27451
  }
26627
27452
  let ancestor = target;
26628
- while (!existsSync7(ancestor))
26629
- ancestor = path21.dirname(ancestor);
27453
+ while (!existsSync8(ancestor))
27454
+ ancestor = path22.dirname(ancestor);
26630
27455
  const canonicalAncestor = realpathSync5(ancestor);
26631
- if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path21.sep)) {
27456
+ if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path22.sep)) {
26632
27457
  throw new Error("path must stay inside repository root");
26633
27458
  }
26634
27459
  return target;
@@ -26676,7 +27501,7 @@ var safeCapability = (value, allowed) => allowed.includes(value) ? value : "cont
26676
27501
  var TOOL_CAPABILITIES = [...CONTEXT_KINDS, "workspace", "native_caller_identity"];
26677
27502
  var VERSION = (() => {
26678
27503
  try {
26679
- const packageJson = JSON.parse(readFileSync6(new URL("../package.json", import.meta.url), "utf8"));
27504
+ const packageJson = JSON.parse(readFileSync7(new URL("../package.json", import.meta.url), "utf8"));
26680
27505
  return typeof packageJson.version === "string" ? packageJson.version : "0.0.0";
26681
27506
  } catch {
26682
27507
  return "0.0.0";
@@ -26686,13 +27511,13 @@ var rootVariants = (workspaceRoot) => {
26686
27511
  if (!workspaceRoot)
26687
27512
  return [];
26688
27513
  const roots = new Set;
26689
- for (const candidate of [workspaceRoot, path22.resolve(workspaceRoot)]) {
26690
- if (path22.isAbsolute(candidate) && candidate !== path22.parse(candidate).root)
27514
+ for (const candidate of [workspaceRoot, path23.resolve(workspaceRoot)]) {
27515
+ if (path23.isAbsolute(candidate) && candidate !== path23.parse(candidate).root)
26691
27516
  roots.add(candidate);
26692
27517
  }
26693
27518
  try {
26694
27519
  const canonical = realpathSync6(workspaceRoot);
26695
- if (canonical !== path22.parse(canonical).root)
27520
+ if (canonical !== path23.parse(canonical).root)
26696
27521
  roots.add(canonical);
26697
27522
  } catch {}
26698
27523
  return [...roots].toSorted((left, right) => right.length - left.length);
@@ -26774,12 +27599,12 @@ var thrownResult = (tool, error, workspaceRoot) => {
26774
27599
  };
26775
27600
  function createMcpServer(host, contextProvider) {
26776
27601
  assertMcpHost(host);
26777
- const here = path22.dirname(fileURLToPath2(import.meta.url));
27602
+ const here = path23.dirname(fileURLToPath2(import.meta.url));
26778
27603
  const sourceMarker = markSourcesLoaded([
26779
- path22.join(here, "server.ts"),
26780
- path22.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
26781
- path22.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
26782
- ].filter((file) => existsSync8(file)));
27604
+ path23.join(here, "server.ts"),
27605
+ path23.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
27606
+ path23.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
27607
+ ].filter((file) => existsSync9(file)));
26783
27608
  let staleWarned = false;
26784
27609
  const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
26785
27610
  server.setRequestHandler(ListToolsRequestSchema, async () => {
@@ -26959,8 +27784,8 @@ var main = async () => {
26959
27784
  process.exitCode = 2;
26960
27785
  }
26961
27786
  };
26962
- var entryPath = process.argv[1] ? path23.resolve(process.argv[1]) : "";
26963
- if (entryPath === path23.resolve(fileURLToPath3(import.meta.url)))
27787
+ var entryPath = process.argv[1] ? path24.resolve(process.argv[1]) : "";
27788
+ if (entryPath === path24.resolve(fileURLToPath3(import.meta.url)))
26964
27789
  await main();
26965
27790
  export {
26966
27791
  McpCapabilityUnavailableError,