@brainervirus/workit-codex 8.23.0 → 8.25.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.
@@ -6621,14 +6621,14 @@ var require_dist = __commonJS(function(exports, module) {
6621
6621
  });
6622
6622
 
6623
6623
  // packages/workit-codex/scripts/launch-mcp.ts
6624
- import { existsSync as existsSync10, realpathSync as realpathSync7, statSync as statSync3 } from "node:fs";
6625
- import path25 from "node:path";
6624
+ import { existsSync as existsSync11, realpathSync as realpathSync7, statSync as statSync3 } from "node:fs";
6625
+ import path26 from "node:path";
6626
6626
  import { fileURLToPath as fileURLToPath3 } from "node:url";
6627
6627
 
6628
6628
  // packages/workit-core/src/core.ts
6629
6629
  import { spawnSync as spawnSync14 } from "node:child_process";
6630
- import { existsSync as existsSync7, realpathSync as realpathSync5 } from "node:fs";
6631
- import path21 from "node:path";
6630
+ import { existsSync as existsSync8, realpathSync as realpathSync5 } from "node:fs";
6631
+ import path22 from "node:path";
6632
6632
 
6633
6633
  // packages/workit-core/src/core/task-contract.ts
6634
6634
  import { createHash, randomUUID } from "node:crypto";
@@ -14859,7 +14859,7 @@ var workspaceConfigSchema = object({
14859
14859
  }).passthrough().optional(),
14860
14860
  autoApprove: union([boolean2(), array(nonBlank)]).optional(),
14861
14861
  defaultEndpoint: unknown().optional(),
14862
- verification: _enum(["self", "independent"]).optional(),
14862
+ verification: _enum(["proportional", "self", "independent"]).optional(),
14863
14863
  delegation: unknown().optional(),
14864
14864
  trailers: boolean2().optional(),
14865
14865
  liveSessionGuard: boolean2().optional(),
@@ -15400,6 +15400,144 @@ function resolveRef(cwd, ref) {
15400
15400
  return null;
15401
15401
  return line(git(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]));
15402
15402
  }
15403
+ function originHeadRef(cwd) {
15404
+ return line(git(cwd, ["symbolic-ref", "-q", "--short", "refs/remotes/origin/HEAD"]));
15405
+ }
15406
+ function ownChangeDrift(cwd, range) {
15407
+ const before = diffRaw(cwd, range.fromFork, range.from);
15408
+ const after = diffRaw(cwd, range.toFork, range.to);
15409
+ if (!before || !after)
15410
+ return null;
15411
+ const judged = new Map(before.map((entry) => [entry.path, entry]));
15412
+ const current = new Map(after.map((entry) => [entry.path, entry]));
15413
+ const same = (a, b) => a !== undefined && b !== undefined && a.oldMode === b.oldMode && a.oldBlob === b.oldBlob && a.newMode === b.newMode && a.newBlob === b.newBlob;
15414
+ return [...new Set([...judged.keys(), ...current.keys()])].filter((file) => !same(judged.get(file), current.get(file))).toSorted();
15415
+ }
15416
+ function sameOwnChange(cwd, range) {
15417
+ const fromFork = mergeBase(cwd, range.fromBase, range.from);
15418
+ const toFork = mergeBase(cwd, range.toBase, range.to);
15419
+ if (!fromFork || !toFork)
15420
+ return false;
15421
+ return ownChangeDrift(cwd, { from: range.from, to: range.to, fromFork, toFork })?.length === 0;
15422
+ }
15423
+ var LANE_DIFF = [
15424
+ "-c",
15425
+ "core.quotePath=false",
15426
+ "diff",
15427
+ "--no-color",
15428
+ "--no-ext-diff",
15429
+ "--no-textconv",
15430
+ "--no-renames"
15431
+ ];
15432
+ var laneRange = (fork, head) => {
15433
+ if (!safeArg(fork) || head !== null && !safeArg(head))
15434
+ return null;
15435
+ return head === null ? [fork] : [fork, head];
15436
+ };
15437
+ function diffNumstat(cwd, fork, head) {
15438
+ const range = laneRange(fork, head);
15439
+ if (!range)
15440
+ return null;
15441
+ const run = git(cwd, [...LANE_DIFF, "--numstat", "-z", ...range, "--"]);
15442
+ if (!run.ok)
15443
+ return null;
15444
+ const out = [];
15445
+ for (const record of run.stdout.split("\x00")) {
15446
+ const match = /^(-|\d+)\t(-|\d+)\t(.+)$/su.exec(record.replace(/^\n/u, ""));
15447
+ if (!match)
15448
+ continue;
15449
+ const binary = match[1] === "-";
15450
+ out.push({
15451
+ path: match[3],
15452
+ added: binary ? 0 : Number(match[1]),
15453
+ deleted: binary ? 0 : Number(match[2]),
15454
+ binary
15455
+ });
15456
+ }
15457
+ return out;
15458
+ }
15459
+ function diffRaw(cwd, fork, head) {
15460
+ const range = laneRange(fork, head);
15461
+ if (!range)
15462
+ return null;
15463
+ const run = git(cwd, [...LANE_DIFF, "--raw", "-z", "--no-abbrev", ...range, "--"]);
15464
+ if (!run.ok)
15465
+ return null;
15466
+ const fields = run.stdout.split("\x00");
15467
+ const out = [];
15468
+ for (let index = 0;index + 1 < fields.length; index += 2) {
15469
+ const meta = /^:(\d{6}) (\d{6}) ([0-9a-f]+) ([0-9a-f]+) [A-Z]\d*$/u.exec(fields[index].replace(/^\n/u, ""));
15470
+ if (!meta)
15471
+ return null;
15472
+ out.push({
15473
+ path: fields[index + 1],
15474
+ oldMode: meta[1],
15475
+ newMode: meta[2],
15476
+ oldBlob: meta[3],
15477
+ newBlob: meta[4]
15478
+ });
15479
+ }
15480
+ return out;
15481
+ }
15482
+ function readBlobs(cwd, ids) {
15483
+ const out = new Map;
15484
+ const wanted = [...new Set(ids)].filter((id) => /^[0-9a-f]{40,64}$/u.test(id));
15485
+ if (!wanted.length)
15486
+ return out;
15487
+ const run = spawnSync3("git", ["cat-file", "--batch"], {
15488
+ cwd,
15489
+ input: `${wanted.join(`
15490
+ `)}
15491
+ `,
15492
+ maxBuffer: MAX_BUFFER,
15493
+ timeout: GIT_TIMEOUTS.local,
15494
+ killSignal: "SIGKILL",
15495
+ windowsHide: true
15496
+ });
15497
+ if (run.status !== 0 || !run.stdout)
15498
+ return null;
15499
+ const bytes = run.stdout;
15500
+ let at = 0;
15501
+ for (const id of wanted) {
15502
+ const end = bytes.indexOf(10, at);
15503
+ if (end < 0)
15504
+ return null;
15505
+ const header = bytes.subarray(at, end).toString("utf8").split(" ");
15506
+ at = end + 1;
15507
+ if (header[1] === "missing")
15508
+ continue;
15509
+ const size = Number(header[2]);
15510
+ if (header[0] !== id || !Number.isSafeInteger(size))
15511
+ return null;
15512
+ out.set(id, bytes.subarray(at, at + size));
15513
+ at += size + 1;
15514
+ }
15515
+ return out;
15516
+ }
15517
+ function treeFilesNamed(cwd, rev, name) {
15518
+ if (!safeArg(rev))
15519
+ return null;
15520
+ const run = git(cwd, ["ls-tree", "-r", "-z", "--full-tree", rev]);
15521
+ if (!run.ok)
15522
+ return null;
15523
+ const out = new Map;
15524
+ for (const record of run.stdout.split("\x00")) {
15525
+ const match = /^\d{6} blob ([0-9a-f]+)\t(.+)$/su.exec(record);
15526
+ if (match && (match[2] === name || match[2].endsWith(`/${name}`)))
15527
+ out.set(match[2], match[1]);
15528
+ }
15529
+ return out;
15530
+ }
15531
+ function fileAt(cwd, rev, file) {
15532
+ if (!safeArg(rev))
15533
+ return null;
15534
+ const run = git(cwd, ["cat-file", "blob", `${rev}:${file}`]);
15535
+ return run.ok ? run.stdout : null;
15536
+ }
15537
+ function untrackedFiles(cwd) {
15538
+ const run = git(cwd, ["ls-files", "-z", "--others", "--exclude-standard"]);
15539
+ return run.ok ? run.stdout.split("\x00").filter(Boolean) : [];
15540
+ }
15403
15541
  var config2 = (cwd, key) => line(git(cwd, ["config", "--get", key]));
15404
15542
  function currentBranch(cwd) {
15405
15543
  return line(git(cwd, ["symbolic-ref", "--short", "-q", "HEAD"]));
@@ -18910,7 +19048,7 @@ var workerBlocksTransition = (transition, state) => transition === "pause" ? fal
18910
19048
  import { createHash as createHash10 } from "node:crypto";
18911
19049
  import * as fs13 from "node:fs";
18912
19050
  import { spawnSync as spawnSync10 } from "node:child_process";
18913
- import path16 from "node:path";
19051
+ import path17 from "node:path";
18914
19052
 
18915
19053
  // packages/workit-core/src/check-config.ts
18916
19054
  import { spawnSync as spawnSync8 } from "node:child_process";
@@ -19130,14 +19268,757 @@ function checkCommand(args, version, onPath = workitAvailable()) {
19130
19268
  }
19131
19269
 
19132
19270
  // packages/workit-core/src/core/policy/derive.ts
19133
- import { existsSync as existsSync4 } from "node:fs";
19134
- import path15 from "node:path";
19271
+ import { existsSync as existsSync5 } from "node:fs";
19272
+ import path16 from "node:path";
19135
19273
 
19136
19274
  // packages/workit-core/src/ledger.ts
19137
19275
  import { spawnSync as spawnSync9 } from "node:child_process";
19138
19276
  import { createHash as createHash9, randomBytes as randomBytes3 } from "node:crypto";
19139
19277
  import fs12 from "node:fs";
19278
+ import path15 from "node:path";
19279
+
19280
+ // packages/workit-core/src/core/policy/lane.ts
19281
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
19140
19282
  import path14 from "node:path";
19283
+
19284
+ // packages/workit-core/src/git/default-base.ts
19285
+ var safeRef = (value) => value.length > 0 && !value.startsWith("-");
19286
+ var trackTrunk = (cwd) => {
19287
+ try {
19288
+ const resolved = vcsConfig("resolve", cwd);
19289
+ if (resolved.ok === false || !resolved.releaseTrack || resolved.releaseTrack.blocking)
19290
+ return null;
19291
+ const target = String(resolved.defaultTargetBranch ?? "").trim();
19292
+ return target && safeRef(target) ? target : null;
19293
+ } catch {
19294
+ return null;
19295
+ }
19296
+ };
19297
+ function defaultBase(cwd) {
19298
+ const trunk = trackTrunk(cwd);
19299
+ if (trunk) {
19300
+ for (const candidate of [`origin/${trunk}`, trunk])
19301
+ if (resolveRef(cwd, candidate))
19302
+ return candidate;
19303
+ }
19304
+ const originHead = originHeadRef(cwd);
19305
+ if (originHead && resolveRef(cwd, originHead))
19306
+ return originHead;
19307
+ for (const candidate of [
19308
+ "origin/main",
19309
+ "origin/master",
19310
+ "main",
19311
+ "master",
19312
+ "origin/develop",
19313
+ "develop"
19314
+ ])
19315
+ if (resolveRef(cwd, candidate))
19316
+ return candidate;
19317
+ return null;
19318
+ }
19319
+
19320
+ // packages/workit-core/src/core/policy/attributes.ts
19321
+ function patternRegex(dir, pattern) {
19322
+ if (!pattern || pattern.endsWith("/") || pattern.startsWith('"') || pattern.startsWith("!"))
19323
+ return null;
19324
+ const anchored = pattern.includes("/");
19325
+ const body = pattern.replace(/^\//u, "");
19326
+ let source = "";
19327
+ for (let index = 0;index < body.length; index += 1) {
19328
+ const char = body[index];
19329
+ if (char === "*" && body[index + 1] === "*") {
19330
+ const slash = body[index + 2] === "/";
19331
+ source += slash ? "(?:.*/)?" : ".*";
19332
+ index += slash ? 2 : 1;
19333
+ } else if (char === "*")
19334
+ source += "[^/]*";
19335
+ else if (char === "?")
19336
+ source += "[^/]";
19337
+ else if (char === "[") {
19338
+ const end = body.indexOf("]", index + 2);
19339
+ if (end < 0)
19340
+ return null;
19341
+ const set = body.slice(index + 1, end).replace(/^!/u, "^").replace(/\\/gu, "\\\\");
19342
+ source += `[${set}]`;
19343
+ index = end;
19344
+ } else if (char === "\\" && index + 1 < body.length) {
19345
+ source += body[index + 1].replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
19346
+ index += 1;
19347
+ } else
19348
+ source += char.replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
19349
+ }
19350
+ const prefix = dir ? `${dir.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}/` : "";
19351
+ try {
19352
+ return new RegExp(anchored ? `^${prefix}${source}$` : `^${prefix}(?:.*/)?${source}$`, "u");
19353
+ } catch {
19354
+ return null;
19355
+ }
19356
+ }
19357
+ function rulesOf(dir, text) {
19358
+ const out = [];
19359
+ for (const raw of text.split(`
19360
+ `)) {
19361
+ const line = raw.trim();
19362
+ if (!line || line.startsWith("#") || line.startsWith("[attr]"))
19363
+ continue;
19364
+ const [pattern, ...attributes] = line.split(/\s+/u);
19365
+ let generated = null;
19366
+ for (const attribute of attributes) {
19367
+ if (attribute === "linguist-generated" || attribute === "linguist-generated=true")
19368
+ generated = true;
19369
+ else if (attribute === "-linguist-generated" || attribute === "!linguist-generated" || attribute.startsWith("linguist-generated="))
19370
+ generated = false;
19371
+ }
19372
+ if (generated === null)
19373
+ continue;
19374
+ const regex = patternRegex(dir, pattern);
19375
+ if (regex)
19376
+ out.push({ regex, generated });
19377
+ }
19378
+ return out;
19379
+ }
19380
+ function generatedByAttributes(files, paths) {
19381
+ const rules = [...files].map(([file, text]) => {
19382
+ const dir = file.includes("/") ? file.slice(0, file.lastIndexOf("/")) : "";
19383
+ return {
19384
+ depth: dir ? dir.split("/").length : 0,
19385
+ rules: rulesOf(dir, text)
19386
+ };
19387
+ }).toSorted((left, right) => left.depth - right.depth).flatMap((entry) => entry.rules);
19388
+ const out = new Set;
19389
+ for (const file of paths) {
19390
+ const last = rules.findLast((rule) => rule.regex.test(file));
19391
+ if (last?.generated)
19392
+ out.add(file);
19393
+ }
19394
+ return out;
19395
+ }
19396
+
19397
+ // packages/workit-core/src/core/policy/substance.ts
19398
+ var SLASH_BLOCK = [["/*", "*/"]];
19399
+ var C_LIKE = { line: ["//"], block: SLASH_BLOCK, quotes: `"'` };
19400
+ var SYNTAXES = Object.fromEntries([
19401
+ ...["ts", "mts", "cts", "js", "mjs", "cjs"].map((ext) => [ext, { ...C_LIKE, js: true }]),
19402
+ ...["java", "kt", "kts", "scala", "swift", "dart", "groovy"].map((ext) => [
19403
+ ext,
19404
+ { ...C_LIKE, triple: true }
19405
+ ]),
19406
+ ["go", { ...C_LIKE, rawBacktick: true }],
19407
+ ...["css", "scss", "less"].map((ext) => [
19408
+ ext,
19409
+ { line: [], block: SLASH_BLOCK, quotes: `"'`, cssUrl: true }
19410
+ ]),
19411
+ ...["py", "pyi"].map((ext) => [
19412
+ ext,
19413
+ { line: ["#"], block: [], quotes: `"'`, triple: true, indented: true, fstring: true }
19414
+ ]),
19415
+ ["toml", { line: ["#"], block: [], quotes: `"`, literal: "'", triple: true }],
19416
+ ...["html", "htm", "xml", "svg", "xhtml"].map((ext) => [
19417
+ ext,
19418
+ { line: [], block: [["<!--", "-->"]], quotes: "", indented: true }
19419
+ ])
19420
+ ]);
19421
+ 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;
19422
+ var extensionOf = (file) => {
19423
+ const name = file.slice(file.lastIndexOf("/") + 1);
19424
+ const dot = name.lastIndexOf(".");
19425
+ return dot > 0 ? name.slice(dot + 1).toLowerCase() : "";
19426
+ };
19427
+ var CI_PATH = /^\.github\/|(?:^|\/)(?:\.gitlab-ci\.ya?ml|Jenkinsfile|azure-pipelines\.ya?ml|\.pre-commit-config\.ya?ml|\.circleci\/.*)$/u;
19428
+ var syntaxOf = (file) => CI_PATH.test(file) ? null : SYNTAXES[extensionOf(file)] ?? null;
19429
+ var SPACE = /[ \t\r\f\v]/u;
19430
+ var WORD = /[\w$]/u;
19431
+ var NO_SPACE_AFTER = "([{,;";
19432
+ var NO_SPACE_BEFORE = ")]},;";
19433
+ var REGEX_AFTER = "(,=:[!&|?{};+-*%<>~^";
19434
+ var REGEX_KEYWORDS = new Set([
19435
+ "return",
19436
+ "typeof",
19437
+ "instanceof",
19438
+ "case",
19439
+ "do",
19440
+ "else",
19441
+ "in",
19442
+ "of",
19443
+ "new",
19444
+ "delete",
19445
+ "void",
19446
+ "throw",
19447
+ "yield",
19448
+ "await"
19449
+ ]);
19450
+ function substanceOf(file, text) {
19451
+ const syntax = syntaxOf(file);
19452
+ if (!syntax)
19453
+ return plainSubstance(text);
19454
+ const markup = syntax.block.some(([open]) => open === "<!--");
19455
+ if (markup && (/<(?:script|style)\b|<!\[CDATA\[|<\?/iu.test(text) || /[^>\s][ \t]*<!--/u.test(text)))
19456
+ return plainSubstance(text);
19457
+ return lex(syntax, text);
19458
+ }
19459
+ function plainSubstance(text) {
19460
+ return text.split(`
19461
+ `).map((line) => line.replace(/[ \t\r\f\v]+$/u, "")).filter(Boolean).join(`
19462
+ `);
19463
+ }
19464
+ function lex(syntax, text) {
19465
+ const collapse = !syntax.indented;
19466
+ let out = "";
19467
+ let lineStart = 0;
19468
+ let kept = 0;
19469
+ let pendingSpace = false;
19470
+ const frames = [{ kind: "code", braces: 0 }];
19471
+ let index = 0;
19472
+ if (text.startsWith("#!")) {
19473
+ const end = text.indexOf(`
19474
+ `);
19475
+ out = end < 0 ? text : text.slice(0, end);
19476
+ kept = out.length;
19477
+ index = end < 0 ? text.length : end;
19478
+ }
19479
+ const emitCode = (chunk) => {
19480
+ if (collapse && pendingSpace && out.length > lineStart) {
19481
+ const before = out[out.length - 1];
19482
+ if (!NO_SPACE_AFTER.includes(before) && !NO_SPACE_BEFORE.includes(chunk[0]))
19483
+ out += " ";
19484
+ }
19485
+ pendingSpace = false;
19486
+ out += chunk;
19487
+ };
19488
+ const emitVerbatim = (chunk) => {
19489
+ emitCode(chunk);
19490
+ kept = out.length;
19491
+ };
19492
+ const newline = () => {
19493
+ if (!collapse) {
19494
+ let end = out.length;
19495
+ while (end > Math.max(lineStart, kept) && SPACE.test(out[end - 1]))
19496
+ end -= 1;
19497
+ out = out.slice(0, end);
19498
+ }
19499
+ pendingSpace = false;
19500
+ if (out.length > lineStart) {
19501
+ out += `
19502
+ `;
19503
+ lineStart = out.length;
19504
+ }
19505
+ };
19506
+ const regexAllowed = () => {
19507
+ let end = out.length;
19508
+ while (end > 0 && /\s/u.test(out[end - 1]))
19509
+ end -= 1;
19510
+ if (end === 0 || REGEX_AFTER.includes(out[end - 1]))
19511
+ return true;
19512
+ let start = end;
19513
+ while (start > 0 && WORD.test(out[start - 1]))
19514
+ start -= 1;
19515
+ return REGEX_KEYWORDS.has(out.slice(start, end));
19516
+ };
19517
+ const scanString = (quote, escapes, multiline) => {
19518
+ const prefix = text.slice(Math.max(0, index - 2), index).match(/[a-z]*$/iu)?.[0] ?? "";
19519
+ const fstring = syntax.fstring === true && /f/iu.test(prefix);
19520
+ let end = index + quote.length;
19521
+ while (end < text.length) {
19522
+ const char = text[end];
19523
+ if (escapes && char === "\\") {
19524
+ end += 2;
19525
+ continue;
19526
+ }
19527
+ if (text.startsWith(quote, end)) {
19528
+ if (fstring && unbalanced(text.slice(index + quote.length, end)))
19529
+ return false;
19530
+ emitVerbatim(text.slice(index, end + quote.length));
19531
+ index = end + quote.length;
19532
+ return true;
19533
+ }
19534
+ if (char === `
19535
+ ` && !multiline)
19536
+ return false;
19537
+ end += 1;
19538
+ }
19539
+ return false;
19540
+ };
19541
+ while (index < text.length) {
19542
+ const frame = frames[frames.length - 1];
19543
+ const char = text[index];
19544
+ if (frame.kind === "template") {
19545
+ if (char === "\\") {
19546
+ emitVerbatim(text.slice(index, index + 2));
19547
+ index += 2;
19548
+ } else if (char === "`") {
19549
+ emitVerbatim(char);
19550
+ frames.pop();
19551
+ index += 1;
19552
+ } else if (text.startsWith("${", index)) {
19553
+ emitVerbatim("${");
19554
+ frames.push({ kind: "code", braces: 0 });
19555
+ index += 2;
19556
+ } else {
19557
+ out += char;
19558
+ kept = out.length;
19559
+ index += 1;
19560
+ }
19561
+ continue;
19562
+ }
19563
+ if (char === `
19564
+ `) {
19565
+ newline();
19566
+ index += 1;
19567
+ continue;
19568
+ }
19569
+ if (SPACE.test(char)) {
19570
+ if (collapse)
19571
+ pendingSpace = true;
19572
+ else
19573
+ out += char;
19574
+ index += 1;
19575
+ continue;
19576
+ }
19577
+ const lineOpener = syntax.line.find((opener) => text.startsWith(opener, index));
19578
+ if (lineOpener) {
19579
+ const end = text.indexOf(`
19580
+ `, index);
19581
+ const comment = text.slice(index, end < 0 ? text.length : end);
19582
+ if (DIRECTIVE.test(comment.slice(lineOpener.length)))
19583
+ emitVerbatim(comment);
19584
+ else
19585
+ pendingSpace = true;
19586
+ index = end < 0 ? text.length : end;
19587
+ continue;
19588
+ }
19589
+ const block = syntax.block.find(([open]) => text.startsWith(open, index));
19590
+ if (block) {
19591
+ const end = text.indexOf(block[1], index + block[0].length);
19592
+ if (end < 0)
19593
+ return null;
19594
+ const comment = text.slice(index, end + block[1].length);
19595
+ if (DIRECTIVE.test(comment.slice(block[0].length, -block[1].length)))
19596
+ emitVerbatim(comment);
19597
+ else
19598
+ pendingSpace = true;
19599
+ if (comment.includes(`
19600
+ `))
19601
+ newline();
19602
+ index = end + block[1].length;
19603
+ continue;
19604
+ }
19605
+ if (syntax.triple && (char === '"' || char === "'") && text.startsWith(char.repeat(3), index)) {
19606
+ if (!scanString(char.repeat(3), !syntax.literal?.includes(char), true))
19607
+ return null;
19608
+ continue;
19609
+ }
19610
+ if (syntax.quotes.includes(char)) {
19611
+ if (!scanString(char, true, Boolean(syntax.multiline)))
19612
+ return null;
19613
+ continue;
19614
+ }
19615
+ if (syntax.literal?.includes(char)) {
19616
+ if (!scanString(char, false, false))
19617
+ return null;
19618
+ continue;
19619
+ }
19620
+ if (syntax.rawBacktick && char === "`") {
19621
+ if (!scanString("`", false, true))
19622
+ return null;
19623
+ continue;
19624
+ }
19625
+ if (syntax.js && char === "`") {
19626
+ emitVerbatim(char);
19627
+ frames.push({ kind: "template" });
19628
+ index += 1;
19629
+ continue;
19630
+ }
19631
+ if (syntax.cssUrl && /^url\(\s*[^"')\s]/iu.test(text.slice(index, index + 64)))
19632
+ return null;
19633
+ if (syntax.js && char === "/" && !regexAllowed() && out.trimEnd().endsWith(")")) {
19634
+ const lineEnd = text.indexOf(`
19635
+ `, index);
19636
+ if (text.slice(index + 1, lineEnd < 0 ? text.length : lineEnd).includes("/"))
19637
+ return null;
19638
+ }
19639
+ if (syntax.js && char === "/" && regexAllowed()) {
19640
+ let end = index + 1;
19641
+ let inClass = false;
19642
+ while (end < text.length && (inClass || text[end] !== "/")) {
19643
+ if (text[end] === `
19644
+ `)
19645
+ return null;
19646
+ if (text[end] === "\\")
19647
+ end += 1;
19648
+ else if (text[end] === "[")
19649
+ inClass = true;
19650
+ else if (text[end] === "]")
19651
+ inClass = false;
19652
+ end += 1;
19653
+ }
19654
+ if (end >= text.length)
19655
+ return null;
19656
+ emitVerbatim(text.slice(index, end + 1));
19657
+ index = end + 1;
19658
+ continue;
19659
+ }
19660
+ if (frames.length > 1 && frame.kind === "code") {
19661
+ if (char === "{")
19662
+ frame.braces += 1;
19663
+ else if (char === "}") {
19664
+ if (frame.braces === 0) {
19665
+ emitVerbatim(char);
19666
+ frames.pop();
19667
+ index += 1;
19668
+ continue;
19669
+ }
19670
+ frame.braces -= 1;
19671
+ }
19672
+ }
19673
+ emitCode(char);
19674
+ index += 1;
19675
+ }
19676
+ if (frames.length !== 1)
19677
+ return null;
19678
+ newline();
19679
+ return out;
19680
+ }
19681
+ function unbalanced(body) {
19682
+ let depth = 0;
19683
+ for (const part of body.replaceAll("{{", "").replaceAll("}}", "")) {
19684
+ if (part === "{")
19685
+ depth += 1;
19686
+ else if (part === "}")
19687
+ depth = Math.max(0, depth - 1);
19688
+ }
19689
+ return depth > 0;
19690
+ }
19691
+ function hasOpaqueLineBreak(text) {
19692
+ return /\r(?!\n)|[\u2028\u2029]/u.test(text);
19693
+ }
19694
+ var decoder = new TextDecoder("utf-8", { fatal: true });
19695
+ function textOf(bytes) {
19696
+ if (bytes.includes(0))
19697
+ return null;
19698
+ try {
19699
+ return decoder.decode(bytes);
19700
+ } catch {
19701
+ return null;
19702
+ }
19703
+ }
19704
+ function cosmeticChange(file, before, after) {
19705
+ const left = textOf(before);
19706
+ const right = textOf(after);
19707
+ if (left === null || right === null)
19708
+ return false;
19709
+ if (hasOpaqueLineBreak(left) || hasOpaqueLineBreak(right))
19710
+ return false;
19711
+ const a = substanceOf(file, left);
19712
+ return a !== null && a === substanceOf(file, right);
19713
+ }
19714
+
19715
+ // packages/workit-core/src/core/policy/lane.ts
19716
+ var LANE_THRESHOLDS = {
19717
+ selfMaxLines: 100,
19718
+ selfMaxFiles: 5,
19719
+ fullMinLines: 500
19720
+ };
19721
+ var RISK_TOKENS = new Set([
19722
+ "auth",
19723
+ "authn",
19724
+ "authz",
19725
+ "oauth",
19726
+ "security",
19727
+ "permission",
19728
+ "permissions",
19729
+ "secret",
19730
+ "secrets",
19731
+ "crypto",
19732
+ "gate",
19733
+ "gates",
19734
+ "policy",
19735
+ "policies",
19736
+ "hook",
19737
+ "hooks",
19738
+ "husky",
19739
+ "lefthook",
19740
+ "release",
19741
+ "releases",
19742
+ "migration",
19743
+ "migrations",
19744
+ "migrate",
19745
+ "workflows"
19746
+ ]);
19747
+ var RISK_FILES = new Set([
19748
+ ".gitlab-ci.yml",
19749
+ "Jenkinsfile",
19750
+ "azure-pipelines.yml",
19751
+ ".pre-commit-config.yaml",
19752
+ ".workit/risk-paths"
19753
+ ]);
19754
+ var RISK_NAMES = new Set([".gitattributes"]);
19755
+ var RISK_PATHS_FILE = ".workit/risk-paths";
19756
+ var LOCKFILES = new Set([
19757
+ "bun.lock",
19758
+ "bun.lockb",
19759
+ "package-lock.json",
19760
+ "npm-shrinkwrap.json",
19761
+ "yarn.lock",
19762
+ "pnpm-lock.yaml",
19763
+ "Cargo.lock",
19764
+ "go.sum",
19765
+ "poetry.lock",
19766
+ "uv.lock",
19767
+ "Pipfile.lock",
19768
+ "Gemfile.lock",
19769
+ "composer.lock"
19770
+ ]);
19771
+ var DOC_EXT = /\.(?:md|mdx|markdown|rst|adoc)$/iu;
19772
+ var DOC_NAMES = /^(?:license|licence|notice|authors|changelog|changes|contributors)$/iu;
19773
+ var INSTRUCTIONS = /(?:^|\/)(?:AGENTS|CLAUDE|GEMINI|SKILL)\.md$|(?:^|\/)(?:skills|agents|commands|rules|prompts)\/[^/]+/iu;
19774
+ var TEST_PATH = /(?:^|\/)(?:test|tests|__tests__)\/|\.(?:test|spec)\.[^/]+$|_test\.[^/]+$/iu;
19775
+ var basename = (file) => file.slice(file.lastIndexOf("/") + 1);
19776
+ var isDoc = (file) => !INSTRUCTIONS.test(file) && (DOC_EXT.test(file) || DOC_NAMES.test(basename(file)));
19777
+ function kindOf(file) {
19778
+ if (file.binary)
19779
+ return "behavior";
19780
+ if (file.generated)
19781
+ return "generated";
19782
+ if (LOCKFILES.has(basename(file.path)))
19783
+ return "lockfile";
19784
+ if (isDoc(file.path))
19785
+ return "doc";
19786
+ if (file.cosmetic)
19787
+ return "cosmetic";
19788
+ return TEST_PATH.test(file.path) ? "test" : "behavior";
19789
+ }
19790
+ var globCache = new Map;
19791
+ function globMatch(pattern, file) {
19792
+ let regex = globCache.get(pattern);
19793
+ if (!regex) {
19794
+ let source = "";
19795
+ for (let index = 0;index < pattern.length; index += 1) {
19796
+ const char = pattern[index];
19797
+ if (char === "*" && pattern[index + 1] === "*") {
19798
+ source += pattern[index + 2] === "/" ? "(?:[^/]*/)*" : ".*";
19799
+ index += pattern[index + 2] === "/" ? 2 : 1;
19800
+ } else if (char === "*")
19801
+ source += "[^/]*";
19802
+ else if (char === "?")
19803
+ source += "[^/]";
19804
+ else
19805
+ source += char.replace(/[.+^${}()|[\]\\]/gu, "\\$&");
19806
+ }
19807
+ regex = new RegExp(`^${source}$`, "u");
19808
+ globCache.set(pattern, regex);
19809
+ }
19810
+ return regex.test(file) || file.startsWith(`${pattern.replace(/\/$/u, "")}/`);
19811
+ }
19812
+ function isRiskPath(file, extra = []) {
19813
+ if (extra.some((pattern) => globMatch(pattern, file)))
19814
+ return true;
19815
+ if (RISK_FILES.has(file) || RISK_NAMES.has(basename(file)))
19816
+ return true;
19817
+ if (TEST_PATH.test(file) || isDoc(file))
19818
+ return false;
19819
+ 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)));
19820
+ }
19821
+ var parseRiskPaths = (text) => text.split(`
19822
+ `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.replace(/^\//u, ""));
19823
+ function computeLane(input) {
19824
+ const riskFiles = input.files.filter((file) => isRiskPath(file.path, input.riskPaths)).map((file) => file.path);
19825
+ const risky = new Set(riskFiles);
19826
+ const kinds = input.files.map((file) => ({
19827
+ file,
19828
+ kind: risky.has(file.path) ? "behavior" : kindOf(file)
19829
+ }));
19830
+ const behavior = kinds.filter((entry) => entry.kind === "behavior" || entry.kind === "test" || entry.kind === "lockfile");
19831
+ const lines = behavior.filter((entry) => entry.kind !== "lockfile").reduce((sum, entry) => sum + entry.file.added + entry.file.deleted, 0);
19832
+ const opaque = behavior.filter((entry) => entry.kind === "lockfile" || entry.file.binary);
19833
+ const result = (lane, reasons) => ({
19834
+ lane,
19835
+ reasons,
19836
+ lines,
19837
+ files: behavior.length,
19838
+ riskFiles
19839
+ });
19840
+ const { selfMaxLines, selfMaxFiles, fullMinLines } = LANE_THRESHOLDS;
19841
+ if (input.riskTier === "high")
19842
+ return result("full", ["the task judgment records high risk"]);
19843
+ if (riskFiles.length)
19844
+ return result("full", [
19845
+ `touches a risk path: ${riskFiles.slice(0, 3).join(", ")}${riskFiles.length > 3 ? ", …" : ""}`
19846
+ ]);
19847
+ if (!behavior.length)
19848
+ return result("none", [
19849
+ input.files.length ? "only docs, comments, formatting or generated copies changed" : "no changes"
19850
+ ]);
19851
+ if (lines >= fullMinLines)
19852
+ return result("full", [`large diff: ${lines} lines (≥ ${fullMinLines})`]);
19853
+ if (lines > selfMaxLines)
19854
+ return result("focused", [`${lines} lines changed (> ${selfMaxLines})`]);
19855
+ if (behavior.length > selfMaxFiles)
19856
+ return result("focused", [`${behavior.length} behavior files changed (> ${selfMaxFiles})`]);
19857
+ if (opaque.length)
19858
+ return result("focused", [
19859
+ `a lockfile or binary changed: ${opaque.slice(0, 3).map((entry) => entry.file.path).join(", ")}${opaque.length > 3 ? ", …" : ""}`
19860
+ ]);
19861
+ return result("self", [
19862
+ `small change: ${lines} line${lines === 1 ? "" : "s"} in ${behavior.length} file${behavior.length === 1 ? "" : "s"}, no risk path`
19863
+ ]);
19864
+ }
19865
+ function untrackedStat(cwd, file) {
19866
+ try {
19867
+ const bytes = readFileSync4(path14.join(cwd, file));
19868
+ if (bytes.includes(0))
19869
+ return { path: file, added: 0, deleted: 0, binary: true };
19870
+ const text = bytes.toString("utf8");
19871
+ if (hasOpaqueLineBreak(text))
19872
+ return { path: file, added: 0, deleted: 0, binary: true };
19873
+ const lines = text.split(`
19874
+ `).length - (text.endsWith(`
19875
+ `) ? 1 : 0);
19876
+ return { path: file, added: lines, deleted: 0 };
19877
+ } catch {
19878
+ return { path: file, added: 0, deleted: 0, binary: true };
19879
+ }
19880
+ }
19881
+ var REGULAR = new Set(["100644", "100755"]);
19882
+ var ABSENT = /^0+$/u;
19883
+ function cosmeticFiles(cwd, fork, head) {
19884
+ const raw = diffRaw(cwd, fork, head);
19885
+ if (!raw)
19886
+ return null;
19887
+ const candidates = raw.filter((entry) => REGULAR.has(entry.oldMode) && entry.oldMode === entry.newMode && !ABSENT.test(entry.oldBlob) && (head === null || !ABSENT.test(entry.newBlob)));
19888
+ const blobs = readBlobs(cwd, candidates.flatMap((entry) => [entry.oldBlob, entry.newBlob]));
19889
+ if (!blobs)
19890
+ return null;
19891
+ const out = new Set;
19892
+ const opaque = new Set;
19893
+ for (const entry of candidates) {
19894
+ const before = blobs.get(entry.oldBlob);
19895
+ let after = blobs.get(entry.newBlob);
19896
+ if (!after && head === null && ABSENT.test(entry.newBlob))
19897
+ try {
19898
+ after = readFileSync4(path14.join(cwd, entry.path));
19899
+ } catch {
19900
+ after = undefined;
19901
+ }
19902
+ if (before && after && cosmeticChange(entry.path, before, after))
19903
+ out.add(entry.path);
19904
+ else if ([before, after].some((bytes) => bytes && hasOpaqueLineBreak(bytes.toString("utf8"))))
19905
+ opaque.add(entry.path);
19906
+ }
19907
+ return { cosmetic: out, opaque };
19908
+ }
19909
+ function generatedAt(cwd, fork, paths) {
19910
+ const files = treeFilesNamed(cwd, fork, ".gitattributes");
19911
+ const blobs = files?.size ? readBlobs(cwd, [...files.values()]) : null;
19912
+ if (!files || !blobs)
19913
+ return new Set;
19914
+ const texts = new Map;
19915
+ for (const [file, id] of files) {
19916
+ const bytes = blobs.get(id);
19917
+ if (bytes)
19918
+ texts.set(file, bytes.toString("utf8"));
19919
+ }
19920
+ return generatedByAttributes(texts, paths);
19921
+ }
19922
+ var forkOf = (cwd, base, head) => mergeBase(cwd, base, head ?? "HEAD");
19923
+ function laneFiles(cwd, fork, head, attributesAt = fork) {
19924
+ const stats = diffNumstat(cwd, fork, head);
19925
+ const cosmetic = stats ? cosmeticFiles(cwd, fork, head) : null;
19926
+ if (!stats || !cosmetic)
19927
+ return null;
19928
+ const files = [
19929
+ ...stats.map((entry) => ({
19930
+ ...entry,
19931
+ ...cosmetic.opaque.has(entry.path) ? { binary: true } : {},
19932
+ cosmetic: !entry.binary && cosmetic.cosmetic.has(entry.path)
19933
+ })),
19934
+ ...head === null ? untrackedFiles(cwd).map((file) => untrackedStat(cwd, file)) : []
19935
+ ];
19936
+ const generated = generatedAt(cwd, attributesAt, files.map((entry) => entry.path));
19937
+ return files.map((entry) => ({
19938
+ ...entry,
19939
+ generated: generated.has(entry.path)
19940
+ }));
19941
+ }
19942
+ function driftFiles(cwd, range) {
19943
+ if (range.fromFork === range.toFork)
19944
+ return laneFiles(cwd, range.from, range.to, range.toFork);
19945
+ const drifted = ownChangeDrift(cwd, range);
19946
+ const stats = drifted ? diffNumstat(cwd, range.from, range.to) : null;
19947
+ if (!drifted || !stats)
19948
+ return null;
19949
+ const byPath = new Map(stats.map((entry) => [entry.path, entry]));
19950
+ const generated = generatedAt(cwd, range.toFork, drifted);
19951
+ return drifted.map((file) => ({
19952
+ path: file,
19953
+ added: byPath.get(file)?.added ?? 0,
19954
+ deleted: byPath.get(file)?.deleted ?? 0,
19955
+ ...byPath.get(file)?.binary ? { binary: true } : {},
19956
+ cosmetic: false,
19957
+ generated: generated.has(file)
19958
+ }));
19959
+ }
19960
+ function branchLane(cwd, options) {
19961
+ const candidates = options.base ? [`origin/${options.base}`, options.base] : [];
19962
+ const base = candidates.find((ref) => resolveRef(cwd, ref) !== null) ?? defaultBase(cwd) ?? null;
19963
+ const head = options.workingTree ? null : options.head;
19964
+ const fork = base && (options.workingTree || options.head) ? forkOf(cwd, base, head) : null;
19965
+ const files = fork ? laneFiles(cwd, fork, head) : null;
19966
+ const riskTier = options.judgment?.riskTier ?? null;
19967
+ if (!fork || !files) {
19968
+ const high = riskTier === "high";
19969
+ return {
19970
+ lane: high ? "full" : "focused",
19971
+ reasons: [
19972
+ `the diff of ${options.head?.slice(0, 12) ?? "(no head)"} against ${base ?? "(no base)"} cannot be read`,
19973
+ ...high ? ["the task judgment records high risk"] : []
19974
+ ],
19975
+ lines: 0,
19976
+ files: 0,
19977
+ riskFiles: [],
19978
+ base,
19979
+ head: options.head
19980
+ };
19981
+ }
19982
+ const repoRisk = parseRiskPaths(fileAt(cwd, fork, RISK_PATHS_FILE) ?? "");
19983
+ return {
19984
+ ...computeLane({
19985
+ files,
19986
+ riskTier,
19987
+ riskPaths: [...repoRisk, ...options.riskPaths ?? []]
19988
+ }),
19989
+ base,
19990
+ head: options.head
19991
+ };
19992
+ }
19993
+ var laneNeed = (lane) => lane === "none" ? "none" : lane === "self" ? "self" : "non-author";
19994
+
19995
+ // packages/workit-core/src/core/policy/carry.ts
19996
+ var TEST_ONLY_KINDS = new Set(["doc", "cosmetic", "generated", "test"]);
19997
+ function verdictDrift(cwd, input) {
19998
+ const since = input.from;
19999
+ const stale = (reason, files = null, focused = false) => ({
20000
+ carries: false,
20001
+ since,
20002
+ files,
20003
+ focused,
20004
+ reason
20005
+ });
20006
+ const fromFork = mergeBase(cwd, input.fromBase, input.from);
20007
+ const toFork = mergeBase(cwd, input.toBase, input.to);
20008
+ const files = fromFork && toFork ? driftFiles(cwd, { from: input.from, to: input.to, fromFork, toFork }) : null;
20009
+ if (!fromFork || !toFork || !files)
20010
+ return stale(`the change since ${since.slice(0, 12)} cannot be read`);
20011
+ const riskPaths = [fromFork, toFork].flatMap((fork) => parseRiskPaths(fileAt(cwd, fork, RISK_PATHS_FILE) ?? ""));
20012
+ const lane = computeLane({ files, riskPaths });
20013
+ const paths = files.map((file) => file.path);
20014
+ if (lane.lane === "none")
20015
+ return { carries: true, rule: "lane-none", since, files: paths };
20016
+ if (input.kind === "unit" && lane.lane === "self" && files.every((file) => TEST_ONLY_KINDS.has(kindOf(file))))
20017
+ return { carries: true, rule: "tests-only", since, files: paths };
20018
+ return stale(lane.reasons[0] ?? `lane ${lane.lane}`, paths, lane.lane === "self");
20019
+ }
20020
+
20021
+ // packages/workit-core/src/ledger.ts
19141
20022
  var LEDGER_VERSION = 1;
19142
20023
  var MAX_LINE_BYTES = 4096;
19143
20024
  var PASSING = new Set(["verified", "tests-verified", "type-check-only"]);
@@ -19182,52 +20063,19 @@ var git4 = (cwd, args) => {
19182
20063
  const value = run.ok ? run.stdout.trim() : "";
19183
20064
  return value ? value : null;
19184
20065
  };
19185
- var safeRef = (value) => value.length > 0 && !value.startsWith("-");
20066
+ var safeRef2 = (value) => value.length > 0 && !value.startsWith("-");
19186
20067
  function resolveCommit(cwd, ref) {
19187
- if (!safeRef(ref))
20068
+ if (!safeRef2(ref))
19188
20069
  return null;
19189
20070
  return git4(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]);
19190
20071
  }
19191
20072
  function branchHead(cwd, branch) {
19192
- if (!safeRef(branch))
20073
+ if (!safeRef2(branch))
19193
20074
  return null;
19194
20075
  return resolveCommit(cwd, `refs/heads/${branch}`) ?? resolveCommit(cwd, `refs/remotes/origin/${branch}`);
19195
20076
  }
19196
- var trackTrunk = (cwd) => {
19197
- try {
19198
- const resolved = vcsConfig("resolve", cwd);
19199
- if (resolved.ok === false || !resolved.releaseTrack || resolved.releaseTrack.blocking)
19200
- return null;
19201
- const target = String(resolved.defaultTargetBranch ?? "").trim();
19202
- return target && safeRef(target) ? target : null;
19203
- } catch {
19204
- return null;
19205
- }
19206
- };
19207
- function defaultBase(cwd) {
19208
- const trunk = trackTrunk(cwd);
19209
- if (trunk) {
19210
- for (const candidate of [`origin/${trunk}`, trunk])
19211
- if (resolveCommit(cwd, candidate))
19212
- return candidate;
19213
- }
19214
- const originHead = git4(cwd, ["symbolic-ref", "-q", "--short", "refs/remotes/origin/HEAD"]);
19215
- if (originHead && resolveCommit(cwd, originHead))
19216
- return originHead;
19217
- for (const candidate of [
19218
- "origin/main",
19219
- "origin/master",
19220
- "main",
19221
- "master",
19222
- "origin/develop",
19223
- "develop"
19224
- ])
19225
- if (resolveCommit(cwd, candidate))
19226
- return candidate;
19227
- return null;
19228
- }
19229
20077
  function diffHash(cwd, base, head) {
19230
- if (!safeRef(base) || !safeRef(head))
20078
+ if (!safeRef2(base) || !safeRef2(head))
19231
20079
  return null;
19232
20080
  const diff = gitRun2(cwd, [
19233
20081
  "diff",
@@ -19259,14 +20107,14 @@ function diffHash(cwd, base, head) {
19259
20107
  return `sha256:${hash.digest("hex")}`;
19260
20108
  }
19261
20109
  function storeRoot(cwd) {
19262
- const location = resolveStore(path14.resolve(cwd));
20110
+ const location = resolveStore(path15.resolve(cwd));
19263
20111
  if (location instanceof Error)
19264
20112
  return err("unavailable", location.message.replace(/; fix the repository.*$/u, ""), "fix the repository (git status should work here) or run from a non-git directory");
19265
20113
  return { ok: true, value: { root: location.dir, shared: location.shared } };
19266
20114
  }
19267
20115
  function ledgerPath(cwd) {
19268
20116
  const root = storeRoot(cwd);
19269
- return root.ok ? { ok: true, value: path14.join(root.value.root, "ledger", "ledger.jsonl") } : root;
20117
+ return root.ok ? { ok: true, value: path15.join(root.value.root, "ledger", "ledger.jsonl") } : root;
19270
20118
  }
19271
20119
  var newId2 = () => `${Date.now().toString(36)}-${randomBytes3(6).toString("hex")}`;
19272
20120
  var NETWORK_FS_TYPES = new Set([
@@ -19296,13 +20144,13 @@ var LOCK_STALE_MS = 30000;
19296
20144
  var LOCK_OWNER = "owner";
19297
20145
  var lockToken = (lock) => {
19298
20146
  try {
19299
- return fs12.readFileSync(path14.join(lock, LOCK_OWNER), "utf8");
20147
+ return fs12.readFileSync(path15.join(lock, LOCK_OWNER), "utf8");
19300
20148
  } catch {
19301
20149
  return null;
19302
20150
  }
19303
20151
  };
19304
20152
  var lockAgeMs = (lock) => {
19305
- for (const target of [path14.join(lock, LOCK_OWNER), lock]) {
20153
+ for (const target of [path15.join(lock, LOCK_OWNER), lock]) {
19306
20154
  try {
19307
20155
  return Date.now() - fs12.statSync(target).mtimeMs;
19308
20156
  } catch {}
@@ -19319,7 +20167,7 @@ var ledgerLock = {
19319
20167
  throw error;
19320
20168
  }
19321
20169
  const token = `${process.pid}-${randomBytes3(8).toString("hex")}`;
19322
- fs12.writeFileSync(path14.join(lock, LOCK_OWNER), token);
20170
+ fs12.writeFileSync(path15.join(lock, LOCK_OWNER), token);
19323
20171
  return token;
19324
20172
  },
19325
20173
  release(lock, token) {
@@ -19452,8 +20300,8 @@ function appendLine(file, build, options) {
19452
20300
  }
19453
20301
  };
19454
20302
  try {
19455
- fs12.mkdirSync(path14.dirname(file), { recursive: true });
19456
- if (!options.forceLock && !onNetworkFs(path14.dirname(file)))
20303
+ fs12.mkdirSync(path15.dirname(file), { recursive: true });
20304
+ if (!options.forceLock && !onNetworkFs(path15.dirname(file)))
19457
20305
  return write();
19458
20306
  const locked = withLedgerLock(file, write);
19459
20307
  return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
@@ -19684,7 +20532,7 @@ function verdictBasis(verdict, current) {
19684
20532
  }
19685
20533
  var isLiveVerdict = (row, retired) => row.type === "verdict" && typeof row.result === "string" && !retired.has(row.id);
19686
20534
  function trailerSessions(cwd, base, head) {
19687
- if (!base || !head || !safeRef(base) || !safeRef(head))
20535
+ if (!base || !head || !safeRef2(base) || !safeRef2(head))
19688
20536
  return [];
19689
20537
  const out = git4(cwd, [
19690
20538
  "log",
@@ -19697,7 +20545,7 @@ var RENAMED = /^branch: renamed refs\/heads\/(.+) to refs\/heads\/(.+)$/iu;
19697
20545
  function branchScope(cwd, branch) {
19698
20546
  const renamedAt = new Map;
19699
20547
  let since = Number.NEGATIVE_INFINITY;
19700
- if (safeRef(branch)) {
20548
+ if (safeRef2(branch)) {
19701
20549
  const log = git4(cwd, [
19702
20550
  "log",
19703
20551
  "-g",
@@ -19842,12 +20690,29 @@ function effectiveOf(rows, reasonsOf, sameCode, isCurrent) {
19842
20690
  }
19843
20691
  return effective;
19844
20692
  }
19845
- function restackCarries(rows, branch, from, to) {
20693
+ var restackExact = new WeakMap;
20694
+ function restackCarries(exactIn, rows, branch, from, to) {
19846
20695
  if (!from || !to)
19847
20696
  return false;
20697
+ const exact = (row, fromHead, head) => {
20698
+ if (exactIn === null)
20699
+ return true;
20700
+ const cwd = exactIn;
20701
+ let known = restackExact.get(row);
20702
+ if (known === undefined) {
20703
+ known = typeof row.fromBase === "string" && typeof row.toBase === "string" && sameOwnChange(cwd, {
20704
+ from: fromHead,
20705
+ to: head,
20706
+ fromBase: row.fromBase,
20707
+ toBase: row.toBase
20708
+ });
20709
+ restackExact.set(row, known);
20710
+ }
20711
+ return known;
20712
+ };
19848
20713
  const edges = new Map;
19849
20714
  for (const row of rows)
19850
- if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.integrity === "verified" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
20715
+ if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.integrity === "verified" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head && exact(row, row.fromHead, row.head))
19851
20716
  edges.set(row.fromHead, [...edges.get(row.fromHead) ?? [], row.head]);
19852
20717
  const seen = new Set([from]);
19853
20718
  const queue = [from];
@@ -19881,9 +20746,57 @@ function checkVerdicts(cwd, branch, ledgerRows) {
19881
20746
  return key;
19882
20747
  };
19883
20748
  const keyFor = (base) => keysAt(base, head);
19884
- const basisOf = (row) => {
20749
+ const driftCache = new Map;
20750
+ const driftOf = (row) => {
20751
+ if (driftCache.has(row))
20752
+ return driftCache.get(row) ?? null;
20753
+ let drift = null;
20754
+ const toBase = row.base ?? fallbackBase;
20755
+ const toBaseSha = toBase ? resolveCommit(cwd, toBase) : null;
20756
+ const fromBase = row.baseSha ?? toBaseSha;
20757
+ if (row.head && head && row.head !== head && toBaseSha && fromBase && !untrusted(reasonsOf(row)))
20758
+ drift = verdictDrift(cwd, {
20759
+ from: row.head,
20760
+ to: head,
20761
+ fromBase,
20762
+ toBase: toBaseSha,
20763
+ kind: typeof row.kind === "string" ? row.kind : "review"
20764
+ });
20765
+ driftCache.set(row, drift);
20766
+ return drift;
20767
+ };
20768
+ const exactCache = new Map;
20769
+ const exactCarry = (row) => {
20770
+ if (FAILING.has(String(row.result)))
20771
+ return true;
20772
+ let exact = exactCache.get(row);
20773
+ if (exact === undefined) {
20774
+ const toBase = row.base ?? fallbackBase;
20775
+ const toBaseSha = toBase ? resolveCommit(cwd, toBase) : null;
20776
+ const fromBase = row.baseSha ?? toBaseSha;
20777
+ exact = Boolean(row.head && head && toBaseSha && fromBase && sameOwnChange(cwd, { from: row.head, to: head, fromBase, toBase: toBaseSha }));
20778
+ exactCache.set(row, exact);
20779
+ }
20780
+ return exact;
20781
+ };
20782
+ const keyBasis = (row) => {
19885
20783
  const basis = verdictBasis(row, { head, ...keyFor(row.base ?? fallbackBase) });
19886
- return basis === "stale" && restackCarries(rows, branch, row.head, head) ? "carried" : basis;
20784
+ return basis === "carried" && !exactCarry(row) ? "stale" : basis;
20785
+ };
20786
+ const restacked = (row) => restackCarries(FAILING.has(String(row.result)) ? null : cwd, rows, branch, row.head, head);
20787
+ const carryOf = (row) => {
20788
+ if (keyBasis(row) !== "stale")
20789
+ return null;
20790
+ if (restacked(row))
20791
+ return null;
20792
+ const drift = driftOf(row);
20793
+ return drift?.carries ? { rule: drift.rule, since: drift.since, files: drift.files } : null;
20794
+ };
20795
+ const basisOf = (row) => {
20796
+ const basis = keyBasis(row);
20797
+ if (basis !== "stale")
20798
+ return basis;
20799
+ return restacked(row) || carryOf(row) ? "carried" : basis;
19887
20800
  };
19888
20801
  const sameCode = (failed, row) => {
19889
20802
  if (failed.head && failed.head === row.head)
@@ -19891,7 +20804,7 @@ function checkVerdicts(cwd, branch, ledgerRows) {
19891
20804
  const base = failed.base ?? fallbackBase;
19892
20805
  const stored = (row.base ?? fallbackBase) === base && row.baseSha !== null && row.baseSha === failed.baseSha;
19893
20806
  const keys = stored ? { patchId: row.patchId, diffHash: row.diffHash } : keysAt(base, row.head);
19894
- return verdictBasis(failed, { head: row.head, ...keys }) !== "stale" || restackCarries(rows, branch, failed.head, row.head);
20807
+ return verdictBasis(failed, { head: row.head, ...keys }) !== "stale" || restackCarries(null, rows, branch, failed.head, row.head);
19895
20808
  };
19896
20809
  const authors = authorSessions(cwd, rows, branch, { base: fallbackBase, head }, scope);
19897
20810
  const failureAuthorCache = new Map;
@@ -19947,6 +20860,7 @@ function checkVerdicts(cwd, branch, ledgerRows) {
19947
20860
  independent: independence.length === 0,
19948
20861
  accepted: reasons.length === 0,
19949
20862
  reasons,
20863
+ carry: basis === "carried" ? carryOf(row) : null,
19950
20864
  verdict: row
19951
20865
  });
19952
20866
  if (reasons.length === 0) {
@@ -19975,7 +20889,12 @@ function checkVerdicts(cwd, branch, ledgerRows) {
19975
20889
  verdict: failing?.verdict ?? null,
19976
20890
  reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
19977
20891
  };
19978
- const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && !untrusted(entry.reasons) && STRONG_RESULTS.has(String(entry.verdict.result)));
20892
+ 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))));
20893
+ const selfEntry = latestSelf && STRONG_RESULTS.has(String(latestSelf.verdict.result)) ? latestSelf : undefined;
20894
+ const carryEntry = verdicts.find((entry) => entry.verdict === accepted.verdict && entry.accepted) ?? newestCurrent;
20895
+ const lastPass = accepted.accepted || failing || tampered.length ? undefined : verdicts.findLast((entry) => !entry.current && !untrusted(entry.reasons) && STRONG_RESULTS.has(String(entry.verdict.result)));
20896
+ const drift = lastPass ? driftOf(lastPass.verdict) : null;
20897
+ const reverify = drift && !drift.carries && drift.focused && drift.files ? { scope: "focused", since: drift.since, files: drift.files } : null;
19979
20898
  return {
19980
20899
  branch,
19981
20900
  head,
@@ -19984,6 +20903,8 @@ function checkVerdicts(cwd, branch, ledgerRows) {
19984
20903
  base: newestCurrent?.verdict.base ?? fallbackBase,
19985
20904
  patchId: keyFor(newestCurrent?.verdict.base ?? fallbackBase).patchId,
19986
20905
  current: { basis: newestCurrent?.basis ?? "none", verdict: newestCurrent?.verdict ?? null },
20906
+ carry: carryEntry?.carry ?? null,
20907
+ reverify,
19987
20908
  accepted,
19988
20909
  verdicts,
19989
20910
  authors: [...authors].toSorted(),
@@ -20003,6 +20924,7 @@ var RULES = {
20003
20924
  self: "verdict:self",
20004
20925
  nonAuthor: "verdict:non-author",
20005
20926
  verified: "verdict:verified",
20927
+ lane: "verdict:lane",
20006
20928
  product: "decision:product",
20007
20929
  plan: "plan"
20008
20930
  };
@@ -20025,6 +20947,7 @@ var normalizedScope = (scope) => ({
20025
20947
  function deriveRequirements(judgment, scope, constraints, verification = "self") {
20026
20948
  const out = [];
20027
20949
  const base = { scope, dependentAction: null };
20950
+ const proportional = verification === "proportional";
20028
20951
  if (judgment.behaviorChange)
20029
20952
  out.push(derived2({
20030
20953
  ...base,
@@ -20035,7 +20958,17 @@ function deriveRequirements(judgment, scope, constraints, verification = "self")
20035
20958
  before: "close",
20036
20959
  acceptanceAllowed: false
20037
20960
  }));
20038
- if (judgment.behaviorChange && judgment.riskTier === "normal")
20961
+ if (proportional && judgment.riskTier === "normal")
20962
+ out.push(derived2({
20963
+ ...base,
20964
+ ruleId: RULES.lane,
20965
+ dimension: "review",
20966
+ 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.",
20967
+ 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.",
20968
+ before: "close",
20969
+ acceptanceAllowed: false
20970
+ }));
20971
+ if (!proportional && judgment.behaviorChange && judgment.riskTier === "normal")
20039
20972
  out.push(verification === "independent" ? derived2({
20040
20973
  ...base,
20041
20974
  ruleId: RULES.nonAuthor,
@@ -20138,7 +21071,7 @@ var productDecision = (task, ledger) => {
20138
21071
  };
20139
21072
  };
20140
21073
  var planRecorded = (task, root) => {
20141
- const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path15.resolve(root, ref.path)));
21074
+ const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync5(path16.resolve(root, ref.path)));
20142
21075
  if (cited)
20143
21076
  return {
20144
21077
  met: true,
@@ -20152,14 +21085,30 @@ var planRecorded = (task, root) => {
20152
21085
  decisionIds: []
20153
21086
  };
20154
21087
  };
20155
- var verdict = (requirement, root, ledger) => {
21088
+ var workingLane = (task, root) => branchLane(root, { head: null, workingTree: true, judgment: latestJudgment(task) });
21089
+ var laneVerdict = (task, root, ledger) => {
21090
+ if (!ledger.branch() && latestJudgment(task)?.behaviorChange === false)
21091
+ return {
21092
+ met: true,
21093
+ reason: "no branch to read a lane from, and the judgment records no behavior change",
21094
+ decisionIds: []
21095
+ };
21096
+ const lane = workingLane(task, root);
21097
+ const label = `lane ${lane.lane} (${lane.reasons.join("; ")})`;
21098
+ const need = laneNeed(lane.lane);
21099
+ if (need === "none")
21100
+ return { met: true, reason: `${label}: no verdict needed`, decisionIds: [] };
21101
+ const status = verdict(need === "self" ? RULES.self : RULES.nonAuthor, root, ledger);
21102
+ return { ...status, reason: `${label}: ${status.reason}` };
21103
+ };
21104
+ var verdict = (ruleId, root, ledger) => {
20156
21105
  const branch = ledger.branch();
20157
21106
  if (!branch)
20158
21107
  return { met: false, reason: "no branch is checked out to hold a verdict", decisionIds: [] };
20159
21108
  const check = checkVerdicts(root, branch, ledger.rows());
20160
21109
  const failing = check.accepted.reasons.includes("failing_verdict");
20161
21110
  const strong = (entry) => STRONG_RESULTS.has(String(entry.verdict.result));
20162
- 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)));
21111
+ 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)));
20163
21112
  if (met)
20164
21113
  return {
20165
21114
  met: true,
@@ -20167,7 +21116,7 @@ var verdict = (requirement, root, ledger) => {
20167
21116
  decisionIds: []
20168
21117
  };
20169
21118
  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, " ");
20170
- 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>\``;
21119
+ 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>\``;
20171
21120
  return { met: false, reason: `${why}: ${unblock}`, decisionIds: [] };
20172
21121
  };
20173
21122
  function derivedRuleStatus(task, requirement, root, ledger) {
@@ -20179,7 +21128,9 @@ function derivedRuleStatus(task, requirement, root, ledger) {
20179
21128
  case RULES.self:
20180
21129
  case RULES.nonAuthor:
20181
21130
  case RULES.verified:
20182
- return verdict(requirement, root, ledger);
21131
+ return verdict(requirement.ruleId, root, ledger);
21132
+ case RULES.lane:
21133
+ return laneVerdict(task, root, ledger);
20183
21134
  default:
20184
21135
  return null;
20185
21136
  }
@@ -20187,14 +21138,14 @@ function derivedRuleStatus(task, requirement, root, ledger) {
20187
21138
 
20188
21139
  // packages/workit-core/src/core/task-evaluation.ts
20189
21140
  var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
20190
- var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
20191
- var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
21141
+ var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path17.sep}`);
21142
+ var relative = (root, candidate) => path17.relative(root, candidate).split(path17.sep).join("/") || ".";
20192
21143
  var canonicalPath = (value) => {
20193
21144
  if (typeof value !== "string" || !value)
20194
21145
  return null;
20195
21146
  if (value.includes("\\") || value.split("/").includes(".."))
20196
21147
  return null;
20197
- const normalized = path16.posix.normalize(value);
21148
+ const normalized = path17.posix.normalize(value);
20198
21149
  if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
20199
21150
  return null;
20200
21151
  return normalized === "." ? "." : normalized.replace(/\/$/, "");
@@ -20242,14 +21193,14 @@ var gitPaths = (root) => {
20242
21193
  git: !/not a git repository/i.test(stderr)
20243
21194
  };
20244
21195
  }
20245
- const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
21196
+ const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path17.sep).join("/")) : [];
20246
21197
  const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
20247
21198
  if (stagedDeleted.status !== 0) {
20248
21199
  const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
20249
21200
  if (!/not a git repository/i.test(stderr))
20250
21201
  return { paths, uncertain: true, git: true };
20251
21202
  } else if (stagedDeleted.stdout) {
20252
- paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
21203
+ paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path17.sep).join("/")));
20253
21204
  }
20254
21205
  return { paths: [...new Set(paths)], uncertain: false, git: true };
20255
21206
  };
@@ -20264,7 +21215,7 @@ var walk = (root, directory, output) => {
20264
21215
  for (const name of names) {
20265
21216
  if (name === ".git" || name === ".workit")
20266
21217
  continue;
20267
- const target = path16.join(directory, name);
21218
+ const target = path17.join(directory, name);
20268
21219
  let stat;
20269
21220
  try {
20270
21221
  stat = fs13.lstatSync(target);
@@ -20282,12 +21233,12 @@ var walk = (root, directory, output) => {
20282
21233
  var scopeRoots = (root, scope) => {
20283
21234
  const roots = [];
20284
21235
  for (const item of scope.paths.length ? scope.paths : ["."]) {
20285
- const target = path16.resolve(root, item);
21236
+ const target = path17.resolve(root, item);
20286
21237
  if (!inside(root, target))
20287
21238
  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` }] });
20288
21239
  let ancestor = target;
20289
21240
  while (!fs13.existsSync(ancestor) && ancestor !== root)
20290
- ancestor = path16.dirname(ancestor);
21241
+ ancestor = path17.dirname(ancestor);
20291
21242
  try {
20292
21243
  if (!inside(root, fs13.realpathSync(ancestor)))
20293
21244
  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` }] });
@@ -20339,7 +21290,7 @@ function captureCandidate(root, scope, environment = []) {
20339
21290
  for (const item of [...names].toSorted()) {
20340
21291
  if (!scopeMatches(item, normalizedScope))
20341
21292
  continue;
20342
- const target = path16.join(checkout, item);
21293
+ const target = path17.join(checkout, item);
20343
21294
  try {
20344
21295
  const stat = fs13.lstatSync(target);
20345
21296
  if (stat.isSymbolicLink()) {
@@ -20523,23 +21474,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
20523
21474
  continue;
20524
21475
  if (!reference.digest)
20525
21476
  return failure2("invalid_input", "document references require a byte digest");
20526
- const target = path16.resolve(root, reference.path);
20527
- if (target !== root && !target.startsWith(`${root}${path16.sep}`))
21477
+ const target = path17.resolve(root, reference.path);
21478
+ if (target !== root && !target.startsWith(`${root}${path17.sep}`))
20528
21479
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
20529
21480
  fields: [
20530
21481
  { path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
20531
21482
  ]
20532
21483
  });
20533
21484
  try {
20534
- const below = path16.relative(root, target);
21485
+ const below = path17.relative(root, target);
20535
21486
  let current = root;
20536
- for (const segment of below.split(path16.sep)) {
21487
+ for (const segment of below.split(path17.sep)) {
20537
21488
  if (!segment)
20538
21489
  continue;
20539
- current = path16.join(current, segment);
21490
+ current = path17.join(current, segment);
20540
21491
  const stat = fs13.lstatSync(current);
20541
21492
  const real = fs13.realpathSync(current);
20542
- if (real !== root && !real.startsWith(`${root}${path16.sep}`))
21493
+ if (real !== root && !real.startsWith(`${root}${path17.sep}`))
20543
21494
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
20544
21495
  fields: [
20545
21496
  {
@@ -21398,7 +22349,7 @@ var judgeInputSummary = (raw) => {
21398
22349
 
21399
22350
  // packages/workit-core/src/autonomy.ts
21400
22351
  import os4 from "node:os";
21401
- import path17 from "node:path";
22352
+ import path18 from "node:path";
21402
22353
  var accountHome = () => {
21403
22354
  try {
21404
22355
  return os4.userInfo().homedir;
@@ -21407,10 +22358,10 @@ var accountHome = () => {
21407
22358
  }
21408
22359
  };
21409
22360
  var grantsHome = { resolve: accountHome };
21410
- var grantsDir = () => path17.join(grantsHome.resolve(), ".config", "workit");
22361
+ var grantsDir = () => path18.join(grantsHome.resolve(), ".config", "workit");
21411
22362
  var grantsOverride = () => {
21412
- const configured = path17.resolve(resolveConfigDir());
21413
- 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`;
22363
+ const configured = path18.resolve(resolveConfigDir());
22364
+ return configured === path18.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 ${path18.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
21414
22365
  };
21415
22366
  var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
21416
22367
  var DEFAULT_GRANTS = Object.freeze({
@@ -21463,8 +22414,16 @@ function endpointView(entry, context) {
21463
22414
  ...issue ? { endpointIssue: issue } : {}
21464
22415
  };
21465
22416
  }
21466
- var DEFAULT_VERIFICATION = "self";
21467
- var verificationOf = (entry) => entry?.verification === "independent" ? "independent" : "self";
22417
+ var VERIFICATION_MODES = [
22418
+ "proportional",
22419
+ "self",
22420
+ "independent"
22421
+ ];
22422
+ var DEFAULT_VERIFICATION = "proportional";
22423
+ var verificationOf = (entry) => {
22424
+ const value = entry?.verification;
22425
+ return VERIFICATION_MODES.includes(value) ? value : DEFAULT_VERIFICATION;
22426
+ };
21468
22427
  var isGrantValue = (value) => value === true || value === false || value === "verified";
21469
22428
  var normalized = (kind, value) => value === "verified" && kind !== "merge" ? true : value;
21470
22429
  var fromAutoApprove = (value) => {
@@ -23212,8 +24171,8 @@ class WorkitCore {
23212
24171
  }
23213
24172
  // packages/workit-core/src/core/repo-context.ts
23214
24173
  import { spawnSync as spawnSync11 } from "node:child_process";
23215
- import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
23216
- import path18 from "node:path";
24174
+ import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "node:fs";
24175
+ import path19 from "node:path";
23217
24176
  var isSafeContextRange = (value) => value.length <= 4096 && (() => {
23218
24177
  try {
23219
24178
  gitRevisionParts(value);
@@ -23347,7 +24306,7 @@ var findPrTemplate = (cwd) => {
23347
24306
  ]) {
23348
24307
  const parts = rel.split("/");
23349
24308
  const base = parts[parts.length - 1];
23350
- const dir = parts.length > 1 ? path18.join(cwd, ...parts.slice(0, -1)) : cwd;
24309
+ const dir = parts.length > 1 ? path19.join(cwd, ...parts.slice(0, -1)) : cwd;
23351
24310
  const actual = probeCaseInsensitive(dir, base);
23352
24311
  if (actual)
23353
24312
  return [...parts.slice(0, -1), actual].join("/");
@@ -23378,11 +24337,11 @@ var diffStatForRange = (cwd, range) => {
23378
24337
  return runGit(cwd, ["diff", "--stat", "--"]).stdout;
23379
24338
  };
23380
24339
  var packageScripts = (cwd, keys) => {
23381
- const pkgPath = path18.join(cwd, "package.json");
23382
- if (!existsSync6(pkgPath))
24340
+ const pkgPath = path19.join(cwd, "package.json");
24341
+ if (!existsSync7(pkgPath))
23383
24342
  return [];
23384
24343
  try {
23385
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
24344
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
23386
24345
  return keys.filter((k) => pkg.scripts && typeof pkg.scripts[k] === "string").map((k) => `${k}: ${pkg.scripts?.[k]}`);
23387
24346
  } catch {
23388
24347
  return [];
@@ -23404,9 +24363,9 @@ var documentationFiles = (cwd) => {
23404
24363
  if (entry.isDirectory()) {
23405
24364
  if (excluded.has(entry.name))
23406
24365
  continue;
23407
- walk(path18.join(dir, entry.name), depth + 1);
24366
+ walk(path19.join(dir, entry.name), depth + 1);
23408
24367
  } else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
23409
- matches.push("./" + path18.relative(cwd, path18.join(dir, entry.name)).replaceAll("\\", "/"));
24368
+ matches.push("./" + path19.relative(cwd, path19.join(dir, entry.name)).replaceAll("\\", "/"));
23410
24369
  }
23411
24370
  }
23412
24371
  };
@@ -23414,15 +24373,15 @@ var documentationFiles = (cwd) => {
23414
24373
  return matches.toSorted().slice(0, 200);
23415
24374
  };
23416
24375
  var readTrimmed2 = (file, maxLines) => {
23417
- if (!existsSync6(file))
24376
+ if (!existsSync7(file))
23418
24377
  return "";
23419
- const lines = readFileSync5(file, "utf8").split(`
24378
+ const lines = readFileSync6(file, "utf8").split(`
23420
24379
  `);
23421
24380
  return lines.slice(0, maxLines).join(`
23422
24381
  `);
23423
24382
  };
23424
24383
  function prReadyContext(root, range) {
23425
- const cwd = path18.resolve(repoRoot(root));
24384
+ const cwd = path19.resolve(repoRoot(root));
23426
24385
  if (range !== undefined && !isResolvableContextRange(cwd, range))
23427
24386
  return invalidRange(cwd);
23428
24387
  let stdout = "";
@@ -23480,7 +24439,7 @@ ${status.stderr}` : "");
23480
24439
  stdout += `template_path: ${template}
23481
24440
 
23482
24441
  `;
23483
- stdout += readTrimmed2(path18.join(cwd, template), 220);
24442
+ stdout += readTrimmed2(path19.join(cwd, template), 220);
23484
24443
  } else {
23485
24444
  stdout += `template_path: none
23486
24445
 
@@ -23490,7 +24449,7 @@ ${status.stderr}` : "");
23490
24449
  stdout += `
23491
24450
  `;
23492
24451
  stdout += printSection("Recent Validation Signals");
23493
- if (existsSync6(path18.join(cwd, "package.json"))) {
24452
+ if (existsSync7(path19.join(cwd, "package.json"))) {
23494
24453
  stdout += `package.json detected. Common scripts:
23495
24454
  `;
23496
24455
  const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
@@ -23499,7 +24458,7 @@ ${status.stderr}` : "");
23499
24458
  `) + `
23500
24459
  `;
23501
24460
  }
23502
- if (existsSync6(path18.join(cwd, "Cargo.toml")) || existsSync6(path18.join(cwd, "src-tauri/Cargo.toml"))) {
24461
+ if (existsSync7(path19.join(cwd, "Cargo.toml")) || existsSync7(path19.join(cwd, "src-tauri/Cargo.toml"))) {
23503
24462
  stdout += `Rust project detected.
23504
24463
  `;
23505
24464
  }
@@ -23532,7 +24491,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
23532
24491
  - Apply with the host-native editor, preserving the repository changelog conventions.
23533
24492
  - If Unreleased already has duplicate category headings, normalize_only first.`;
23534
24493
  function changelogContext(root, range) {
23535
- const cwd = path18.resolve(repoRoot(root));
24494
+ const cwd = path19.resolve(repoRoot(root));
23536
24495
  if (range !== undefined && !isResolvableContextRange(cwd, range))
23537
24496
  return invalidRange(cwd);
23538
24497
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -23550,8 +24509,8 @@ function changelogContext(root, range) {
23550
24509
  stdout += CHANGELOG_RULES + `
23551
24510
  `;
23552
24511
  stdout += printSection("Existing CHANGELOG.md");
23553
- const changelogPath = path18.join(cwd, "CHANGELOG.md");
23554
- if (existsSync6(changelogPath)) {
24512
+ const changelogPath = path19.join(cwd, "CHANGELOG.md");
24513
+ if (existsSync7(changelogPath)) {
23555
24514
  stdout += readTrimmed2(changelogPath, 260) + `
23556
24515
  `;
23557
24516
  } else {
@@ -23570,7 +24529,7 @@ function changelogContext(root, range) {
23570
24529
  return { stdout, stderr: "", exitCode: 0, cwd };
23571
24530
  }
23572
24531
  function docsRefreshContext(root, range) {
23573
- const cwd = path18.resolve(repoRoot(root));
24532
+ const cwd = path19.resolve(repoRoot(root));
23574
24533
  if (range !== undefined && !isResolvableContextRange(cwd, range))
23575
24534
  return invalidRange(cwd);
23576
24535
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -23592,8 +24551,8 @@ function docsRefreshContext(root, range) {
23592
24551
  `) + `
23593
24552
  `;
23594
24553
  stdout += printSection("README Preview");
23595
- const readme = path18.join(cwd, "README.md");
23596
- if (existsSync6(readme)) {
24554
+ const readme = path19.join(cwd, "README.md");
24555
+ if (existsSync7(readme)) {
23597
24556
  stdout += readTrimmed2(readme, 220) + `
23598
24557
  `;
23599
24558
  } else {
@@ -23601,10 +24560,10 @@ function docsRefreshContext(root, range) {
23601
24560
  `;
23602
24561
  }
23603
24562
  stdout += printSection("Package Scripts");
23604
- const pkgPath = path18.join(cwd, "package.json");
23605
- if (existsSync6(pkgPath)) {
24563
+ const pkgPath = path19.join(cwd, "package.json");
24564
+ if (existsSync7(pkgPath)) {
23606
24565
  try {
23607
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
24566
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
23608
24567
  stdout += JSON.stringify({ name: pkg.name, version: pkg.version, scripts: pkg.scripts }, null, 2) + `
23609
24568
  `;
23610
24569
  } catch {}
@@ -23615,7 +24574,7 @@ function docsRefreshContext(root, range) {
23615
24574
  return { stdout, stderr: "", exitCode: 0, cwd };
23616
24575
  }
23617
24576
  function releaseNotesContext(root, rangeOrTag) {
23618
- const cwd = path18.resolve(repoRoot(root));
24577
+ const cwd = path19.resolve(repoRoot(root));
23619
24578
  if (!rangeOrTag) {
23620
24579
  return { stdout: "", stderr: `ERROR: release tag or range required
23621
24580
  `, exitCode: 1, cwd };
@@ -23653,7 +24612,7 @@ function releaseNotesContext(root, rangeOrTag) {
23653
24612
  `;
23654
24613
  stdout += printSection("Existing Release Files");
23655
24614
  for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
23656
- if (existsSync6(path18.join(cwd, rel)))
24615
+ if (existsSync7(path19.join(cwd, rel)))
23657
24616
  stdout += rel + `
23658
24617
  `;
23659
24618
  }
@@ -23685,7 +24644,7 @@ import { spawnSync as spawnSync13 } from "node:child_process";
23685
24644
 
23686
24645
  // packages/workit-core/src/core/pr-create.ts
23687
24646
  import fs14 from "node:fs";
23688
- import path19 from "node:path";
24647
+ import path20 from "node:path";
23689
24648
  import { spawnSync as spawnSync12 } from "node:child_process";
23690
24649
  // packages/workit-core/src/forge/pr-body.ts
23691
24650
  function parseGhIssue(value) {
@@ -23696,11 +24655,11 @@ function parseGhIssue(value) {
23696
24655
  // packages/workit-core/src/core/pr-create.ts
23697
24656
  function whichOnPath(tool) {
23698
24657
  const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
23699
- for (const dir of (process.env.PATH ?? "").split(path19.delimiter)) {
24658
+ for (const dir of (process.env.PATH ?? "").split(path20.delimiter)) {
23700
24659
  if (!dir)
23701
24660
  continue;
23702
24661
  for (const name of names) {
23703
- const candidate = path19.join(dir, name);
24662
+ const candidate = path20.join(dir, name);
23704
24663
  try {
23705
24664
  fs14.accessSync(candidate, fs14.constants.X_OK);
23706
24665
  return candidate;
@@ -23821,7 +24780,7 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
23821
24780
 
23822
24781
  // packages/workit-core/src/core/youtrack.ts
23823
24782
  import fs15 from "node:fs";
23824
- import path20 from "node:path";
24783
+ import path21 from "node:path";
23825
24784
 
23826
24785
  // packages/workit-core/src/core/templates.ts
23827
24786
  var repoRoot2 = assetRoot();
@@ -23834,8 +24793,8 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
23834
24793
  // packages/workit-core/src/core/youtrack.ts
23835
24794
  var ISSUE_RE = /^[A-Z]+-\d+$/;
23836
24795
  var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
23837
- var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(configDir(), "youtrack.json");
23838
- var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(resolveConfigDir(), "youtrack.json");
24796
+ var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path21.join(configDir(), "youtrack.json");
24797
+ var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path21.join(resolveConfigDir(), "youtrack.json");
23839
24798
  var youTrackTokenModeOk = (p) => {
23840
24799
  if (process.platform === "win32")
23841
24800
  return true;
@@ -23903,7 +24862,7 @@ var youTrackToken = () => {
23903
24862
  if ("error" in loaded)
23904
24863
  return loaded;
23905
24864
  const tokenFile = String(loaded.config.tokenFile ?? "");
23906
- const tokenPath = tokenFile ? path20.isAbsolute(tokenFile) ? path20.resolve(tokenFile) : path20.resolve(process.cwd(), tokenFile) : "";
24865
+ const tokenPath = tokenFile ? path21.isAbsolute(tokenFile) ? path21.resolve(tokenFile) : path21.resolve(process.cwd(), tokenFile) : "";
23907
24866
  if (!tokenPath || !fs15.existsSync(tokenPath))
23908
24867
  return { error: "missing youtrack.token" };
23909
24868
  if (!youTrackTokenModeOk(tokenPath))
@@ -24245,15 +25204,15 @@ function resolveGitRevision(root, value) {
24245
25204
  }
24246
25205
  function resolveInside(root, candidate) {
24247
25206
  const base = realpathSync5(root);
24248
- const target = path21.resolve(base, candidate);
24249
- if (target !== base && !target.startsWith(base + path21.sep)) {
25207
+ const target = path22.resolve(base, candidate);
25208
+ if (target !== base && !target.startsWith(base + path22.sep)) {
24250
25209
  throw new Error("path must stay inside repository root");
24251
25210
  }
24252
25211
  let ancestor = target;
24253
- while (!existsSync7(ancestor))
24254
- ancestor = path21.dirname(ancestor);
25212
+ while (!existsSync8(ancestor))
25213
+ ancestor = path22.dirname(ancestor);
24255
25214
  const canonicalAncestor = realpathSync5(ancestor);
24256
- if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path21.sep)) {
25215
+ if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path22.sep)) {
24257
25216
  throw new Error("path must stay inside repository root");
24258
25217
  }
24259
25218
  return target;
@@ -24284,8 +25243,8 @@ var SUPPORT_MATRIX = {
24284
25243
  };
24285
25244
 
24286
25245
  // packages/workit-mcp/src/server.ts
24287
- import { existsSync as existsSync8, readFileSync as readFileSync6, realpathSync as realpathSync6 } from "node:fs";
24288
- import path22 from "node:path";
25246
+ import { existsSync as existsSync9, readFileSync as readFileSync7, realpathSync as realpathSync6 } from "node:fs";
25247
+ import path23 from "node:path";
24289
25248
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
24290
25249
  function isZ4Schema(s) {
24291
25250
  const schema = s;
@@ -26689,7 +27648,7 @@ var safeCapability = (value, allowed) => allowed.includes(value) ? value : "cont
26689
27648
  var TOOL_CAPABILITIES = [...CONTEXT_KINDS, "workspace", "native_caller_identity"];
26690
27649
  var VERSION = (() => {
26691
27650
  try {
26692
- const packageJson = JSON.parse(readFileSync6(new URL("../package.json", import.meta.url), "utf8"));
27651
+ const packageJson = JSON.parse(readFileSync7(new URL("../package.json", import.meta.url), "utf8"));
26693
27652
  return typeof packageJson.version === "string" ? packageJson.version : "0.0.0";
26694
27653
  } catch {
26695
27654
  return "0.0.0";
@@ -26699,13 +27658,13 @@ var rootVariants = (workspaceRoot) => {
26699
27658
  if (!workspaceRoot)
26700
27659
  return [];
26701
27660
  const roots = new Set;
26702
- for (const candidate of [workspaceRoot, path22.resolve(workspaceRoot)]) {
26703
- if (path22.isAbsolute(candidate) && candidate !== path22.parse(candidate).root)
27661
+ for (const candidate of [workspaceRoot, path23.resolve(workspaceRoot)]) {
27662
+ if (path23.isAbsolute(candidate) && candidate !== path23.parse(candidate).root)
26704
27663
  roots.add(candidate);
26705
27664
  }
26706
27665
  try {
26707
27666
  const canonical = realpathSync6(workspaceRoot);
26708
- if (canonical !== path22.parse(canonical).root)
27667
+ if (canonical !== path23.parse(canonical).root)
26709
27668
  roots.add(canonical);
26710
27669
  } catch {}
26711
27670
  return [...roots].toSorted((left, right) => right.length - left.length);
@@ -26787,12 +27746,12 @@ var thrownResult = (tool, error, workspaceRoot) => {
26787
27746
  };
26788
27747
  function createMcpServer(host, contextProvider) {
26789
27748
  assertMcpHost(host);
26790
- const here = path22.dirname(fileURLToPath2(import.meta.url));
27749
+ const here = path23.dirname(fileURLToPath2(import.meta.url));
26791
27750
  const sourceMarker = markSourcesLoaded([
26792
- path22.join(here, "server.ts"),
26793
- path22.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
26794
- path22.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
26795
- ].filter((file) => existsSync8(file)));
27751
+ path23.join(here, "server.ts"),
27752
+ path23.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
27753
+ path23.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
27754
+ ].filter((file) => existsSync9(file)));
26796
27755
  let staleWarned = false;
26797
27756
  const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
26798
27757
  server.setRequestHandler(ListToolsRequestSchema, async () => {
@@ -26985,6 +27944,25 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
26985
27944
  var signals = new Map;
26986
27945
  var cache = new Map;
26987
27946
  var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
27947
+ // packages/workit-core/src/hooks/delivery-verbs.ts
27948
+ var WORKIT_ALLOWED_VERBS = [
27949
+ "git",
27950
+ "pr",
27951
+ "ci",
27952
+ "stack",
27953
+ "release",
27954
+ "task",
27955
+ "ledger",
27956
+ "evidence",
27957
+ "finding",
27958
+ "decision",
27959
+ "worker",
27960
+ "verify-delivery",
27961
+ "policy",
27962
+ "doctor",
27963
+ "help"
27964
+ ];
27965
+ var ALLOWED = new Set(WORKIT_ALLOWED_VERBS);
26988
27966
  // packages/workit-core/src/core/heavy.ts
26989
27967
  var INFO_FLAGS = new Set(["--version", "-v", "-V", "--help", "-h", "help", "version"]);
26990
27968
  var sub = (...names) => new Set(names);
@@ -27109,7 +28087,7 @@ var EXEC = new Set(["exec", "x", "dlx"]);
27109
28087
  // packages/workit-core/src/core/heavy-words.ts
27110
28088
  var HEAVY_WORDS = new Set(("npm npx pnpm pnpx yarn bun bunx deno corepack make gmake docker podman nerdctl " + "python python3 py uv poetry pdm pipenv hatch rye bundle rake nx " + "jest vitest mocha ava tap karma jasmine nyc c8 tsc vue-tsc svelte-check eslint stylelint " + "tslint webpack webpack-cli rollup parcel tsup vite next nuxt nuxi astro ng react-scripts " + "playwright cypress wdio testcafe turbo lerna sonar-scanner sonarless sonarless-mcp go " + "golangci-lint gotestsum staticcheck cargo mvn mvnw gradle gradlew ant sbt bazel bazelisk " + "buck2 dotnet msbuild pytest py.test tox nox mypy pyright pylint coverage maturin pip pip3 " + "rspec rails phpunit pest phpstan psalm composer mix swift xcodebuild flutter dart pod cmake " + "ninja meson ctest scons docker-compose buildah earthly").split(" "));
27111
28089
  // packages/workit-core/src/hooks/write-gate.ts
27112
- import path23 from "node:path";
28090
+ import path24 from "node:path";
27113
28091
 
27114
28092
  // packages/workit-core/src/core/live-session.ts
27115
28093
  import { spawnSync as spawnSync15 } from "node:child_process";
@@ -27150,7 +28128,7 @@ var MUTATING_WORKIT_GIT = new Set(["commit", "branch"]);
27150
28128
  var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
27151
28129
  var PUSHD2 = new Set(["pushd", "push-location"]);
27152
28130
  var POPD2 = new Set(["popd", "pop-location"]);
27153
- var UNKNOWN_DIR = path23.resolve(path23.parse(process.cwd()).root, ".workit-unknown-dir");
28131
+ var UNKNOWN_DIR = path24.resolve(path24.parse(process.cwd()).root, ".workit-unknown-dir");
27154
28132
  // packages/workit-core/src/core/skill-manifests.ts
27155
28133
  if (false) {}
27156
28134
 
@@ -27193,6 +28171,10 @@ var WRITE_TOOLS = new Set([
27193
28171
  // packages/workit-core/src/hooks/standing.ts
27194
28172
  var sinceStart = new Map;
27195
28173
  // packages/workit-core/src/hooks/cwd-normalize.ts
28174
+ var DIR = String.raw`[A-Za-z0-9_./@%+:,=-]+|'[^'$${"`"}\\\n]*'|"[^"$${"`"}\\!\n]*"`;
28175
+ var COMPOUND = new RegExp(String.raw`^\s*cd\s+(${DIR})\s*&&\s*(workit(?:\s[\s\S]*)?)$`, "u");
28176
+ var GLOBALS_FIRST = new RegExp(String.raw`^(\s*workit)((?:\s+(?:--json|--cwd(?:=|\s+)(?:${DIR})))+)\s+([a-z][a-z-]*)(?=\s|$)`, "u");
28177
+ var VERBS = new Set(WORKIT_ALLOWED_VERBS);
27196
28178
  var FILTERS = new Set(["tail", "head", "grep"]);
27197
28179
 
27198
28180
  // packages/workit-core/src/hooks/worktree-confine.ts
@@ -27363,24 +28345,24 @@ if (false)
27363
28345
 
27364
28346
  // packages/workit-codex/scripts/agents.ts
27365
28347
  import {
27366
- existsSync as existsSync9,
28348
+ existsSync as existsSync10,
27367
28349
  lstatSync as lstatSync3,
27368
28350
  mkdirSync as mkdirSync3,
27369
28351
  readdirSync as readdirSync5,
27370
- readFileSync as readFileSync7,
28352
+ readFileSync as readFileSync8,
27371
28353
  renameSync as renameSync2,
27372
28354
  rmSync as rmSync2,
27373
28355
  writeFileSync as writeFileSync3
27374
28356
  } from "node:fs";
27375
28357
  import os5 from "node:os";
27376
- import path24 from "node:path";
28358
+ import path25 from "node:path";
27377
28359
  var CODEX_AGENT_MARKER = "# Generated by Workit";
27378
28360
  var codexHomeOfInstall = (pluginRoot) => {
27379
- const parts = path24.resolve(pluginRoot).split(path24.sep);
28361
+ const parts = path25.resolve(pluginRoot).split(path25.sep);
27380
28362
  const cache = parts.length - 4;
27381
- return cache >= 2 && parts[cache] === "cache" && parts[cache - 1] === "plugins" ? parts.slice(0, cache - 1).join(path24.sep) || path24.sep : null;
28363
+ return cache >= 2 && parts[cache] === "cache" && parts[cache - 1] === "plugins" ? parts.slice(0, cache - 1).join(path25.sep) || path25.sep : null;
27382
28364
  };
27383
- var codexHomeFor = (pluginRoot, env) => codexHomeOfInstall(pluginRoot) ?? (env.CODEX_HOME || path24.join(env.HOME || os5.homedir(), ".codex"));
28365
+ var codexHomeFor = (pluginRoot, env) => codexHomeOfInstall(pluginRoot) ?? (env.CODEX_HOME || path25.join(env.HOME || os5.homedir(), ".codex"));
27384
28366
  var MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
27385
28367
  var agentMarkerVersion = (text) => MARKER_VERSION.exec(text)?.[1] ?? null;
27386
28368
  var stampCodexAgent = (content, version) => version && content.startsWith(CODEX_AGENT_MARKER) && !agentMarkerVersion(content) ? `${CODEX_AGENT_MARKER} ${version}${content.slice(CODEX_AGENT_MARKER.length)}` : content;
@@ -27394,7 +28376,7 @@ var versionAtLeast = (version, min) => {
27394
28376
  };
27395
28377
  var pluginVersion = (pluginRoot) => {
27396
28378
  try {
27397
- const version = JSON.parse(readFileSync7(path24.join(pluginRoot, "package.json"), "utf8")).version;
28379
+ const version = JSON.parse(readFileSync8(path25.join(pluginRoot, "package.json"), "utf8")).version;
27398
28380
  return typeof version === "string" && /^\d+\.\d+\.\d+/.test(version) ? version.match(/^\d+\.\d+\.\d+/)[0] : null;
27399
28381
  } catch {
27400
28382
  return null;
@@ -27408,15 +28390,15 @@ var lstatOrNull = (file) => {
27408
28390
  }
27409
28391
  };
27410
28392
  var installCodexAgents = (pluginRoot, codexHome) => {
27411
- const source = path24.join(pluginRoot, "agents");
27412
- if (!existsSync9(source))
28393
+ const source = path25.join(pluginRoot, "agents");
28394
+ if (!existsSync10(source))
27413
28395
  return [];
27414
28396
  const version = pluginVersion(pluginRoot);
27415
- const target = path24.join(codexHome, "agents");
28397
+ const target = path25.join(codexHome, "agents");
27416
28398
  const results = [];
27417
28399
  for (const file of readdirSync5(source).filter((name) => name.endsWith(".toml")).toSorted()) {
27418
- const content = stampCodexAgent(readFileSync7(path24.join(source, file), "utf8"), version);
27419
- const dest = path24.join(target, file);
28400
+ const content = stampCodexAgent(readFileSync8(path25.join(source, file), "utf8"), version);
28401
+ const dest = path25.join(target, file);
27420
28402
  const stat = lstatOrNull(dest);
27421
28403
  if (stat?.isSymbolicLink()) {
27422
28404
  results.push({ file: dest, action: "skipped-symlink" });
@@ -27438,7 +28420,7 @@ var installCodexAgents = (pluginRoot, codexHome) => {
27438
28420
  results.push({ file: dest, action: "kept-user-file" });
27439
28421
  continue;
27440
28422
  }
27441
- const current = readFileSync7(dest, "utf8");
28423
+ const current = readFileSync8(dest, "utf8");
27442
28424
  if (current === content) {
27443
28425
  results.push({ file: dest, action: "current" });
27444
28426
  continue;
@@ -27452,7 +28434,7 @@ var installCodexAgents = (pluginRoot, codexHome) => {
27452
28434
  results.push({ file: dest, action: "kept-newer-version" });
27453
28435
  continue;
27454
28436
  }
27455
- const temp = path24.join(target, `.${file}.${process.pid}.${Date.now()}.tmp`);
28437
+ const temp = path25.join(target, `.${file}.${process.pid}.${Date.now()}.tmp`);
27456
28438
  writeFileSync3(temp, content, { flag: "wx" });
27457
28439
  try {
27458
28440
  renameSync2(temp, dest);
@@ -27474,8 +28456,8 @@ var codexQualification = (host) => host === "codex_cli" ? { surface: host, cli:
27474
28456
  var resolveCodexWorkspaceRoot = (pluginRoot, env) => {
27475
28457
  const explicit = env.WORKFLOW_WORKSPACE_ROOT;
27476
28458
  const inherited = env.PWD;
27477
- const candidate = explicit ?? (inherited && path25.resolve(inherited) !== path25.resolve(pluginRoot) ? inherited : undefined);
27478
- if (!candidate || !path25.isAbsolute(candidate) || !existsSync10(candidate))
28459
+ const candidate = explicit ?? (inherited && path26.resolve(inherited) !== path26.resolve(pluginRoot) ? inherited : undefined);
28460
+ if (!candidate || !path26.isAbsolute(candidate) || !existsSync11(candidate))
27479
28461
  return null;
27480
28462
  try {
27481
28463
  if (!statSync3(candidate).isDirectory())
@@ -27514,7 +28496,7 @@ var codexContextProvider = (host = detectCodexSurface(process.env), root) => ({
27514
28496
  };
27515
28497
  }
27516
28498
  });
27517
- var pluginRoot = () => path25.resolve(path25.dirname(fileURLToPath3(import.meta.url)), "..");
28499
+ var pluginRoot = () => path26.resolve(path26.dirname(fileURLToPath3(import.meta.url)), "..");
27518
28500
  var syncCodexAgents = (root) => {
27519
28501
  const codexHome = codexHomeOfInstall(root);
27520
28502
  if (!codexHome)