@brainervirus/workit-pi 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.
package/dist/workit.js CHANGED
@@ -4,8 +4,8 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
4
4
 
5
5
  // packages/workit-core/src/core.ts
6
6
  import { spawnSync as spawnSync16 } from "node:child_process";
7
- import { existsSync as existsSync8, realpathSync as realpathSync5 } from "node:fs";
8
- import path25 from "node:path";
7
+ import { existsSync as existsSync9, realpathSync as realpathSync5 } from "node:fs";
8
+ import path26 from "node:path";
9
9
 
10
10
  // packages/workit-core/src/core/task-contract.ts
11
11
  import { createHash, randomUUID } from "node:crypto";
@@ -8402,7 +8402,7 @@ var workspaceConfigSchema = object({
8402
8402
  }).passthrough().optional(),
8403
8403
  autoApprove: union([boolean2(), array(nonBlank)]).optional(),
8404
8404
  defaultEndpoint: unknown().optional(),
8405
- verification: _enum(["self", "independent"]).optional(),
8405
+ verification: _enum(["proportional", "self", "independent"]).optional(),
8406
8406
  delegation: unknown().optional(),
8407
8407
  trailers: boolean2().optional(),
8408
8408
  liveSessionGuard: boolean2().optional(),
@@ -8965,6 +8965,124 @@ function resolveRef(cwd, ref) {
8965
8965
  return null;
8966
8966
  return line(git(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]));
8967
8967
  }
8968
+ var LANE_DIFF = [
8969
+ "-c",
8970
+ "core.quotePath=false",
8971
+ "diff",
8972
+ "--no-color",
8973
+ "--no-ext-diff",
8974
+ "--no-textconv",
8975
+ "--no-renames"
8976
+ ];
8977
+ var laneRange = (fork, head) => {
8978
+ if (!safeArg(fork) || head !== null && !safeArg(head))
8979
+ return null;
8980
+ return head === null ? [fork] : [fork, head];
8981
+ };
8982
+ function diffNumstat(cwd, fork, head) {
8983
+ const range = laneRange(fork, head);
8984
+ if (!range)
8985
+ return null;
8986
+ const run = git(cwd, [...LANE_DIFF, "--numstat", "-z", ...range, "--"]);
8987
+ if (!run.ok)
8988
+ return null;
8989
+ const out = [];
8990
+ for (const record of run.stdout.split("\x00")) {
8991
+ const match = /^(-|\d+)\t(-|\d+)\t(.+)$/su.exec(record.replace(/^\n/u, ""));
8992
+ if (!match)
8993
+ continue;
8994
+ const binary = match[1] === "-";
8995
+ out.push({
8996
+ path: match[3],
8997
+ added: binary ? 0 : Number(match[1]),
8998
+ deleted: binary ? 0 : Number(match[2]),
8999
+ binary
9000
+ });
9001
+ }
9002
+ return out;
9003
+ }
9004
+ function diffRaw(cwd, fork, head) {
9005
+ const range = laneRange(fork, head);
9006
+ if (!range)
9007
+ return null;
9008
+ const run = git(cwd, [...LANE_DIFF, "--raw", "-z", "--no-abbrev", ...range, "--"]);
9009
+ if (!run.ok)
9010
+ return null;
9011
+ const fields = run.stdout.split("\x00");
9012
+ const out = [];
9013
+ for (let index = 0;index + 1 < fields.length; index += 2) {
9014
+ const meta = /^:(\d{6}) (\d{6}) ([0-9a-f]+) ([0-9a-f]+) [A-Z]\d*$/u.exec(fields[index].replace(/^\n/u, ""));
9015
+ if (!meta)
9016
+ return null;
9017
+ out.push({
9018
+ path: fields[index + 1],
9019
+ oldMode: meta[1],
9020
+ newMode: meta[2],
9021
+ oldBlob: meta[3],
9022
+ newBlob: meta[4]
9023
+ });
9024
+ }
9025
+ return out;
9026
+ }
9027
+ function readBlobs(cwd, ids) {
9028
+ const out = new Map;
9029
+ const wanted = [...new Set(ids)].filter((id) => /^[0-9a-f]{40,64}$/u.test(id));
9030
+ if (!wanted.length)
9031
+ return out;
9032
+ const run = spawnSync3("git", ["cat-file", "--batch"], {
9033
+ cwd,
9034
+ input: `${wanted.join(`
9035
+ `)}
9036
+ `,
9037
+ maxBuffer: MAX_BUFFER,
9038
+ timeout: GIT_TIMEOUTS.local,
9039
+ killSignal: "SIGKILL",
9040
+ windowsHide: true
9041
+ });
9042
+ if (run.status !== 0 || !run.stdout)
9043
+ return null;
9044
+ const bytes = run.stdout;
9045
+ let at = 0;
9046
+ for (const id of wanted) {
9047
+ const end = bytes.indexOf(10, at);
9048
+ if (end < 0)
9049
+ return null;
9050
+ const header = bytes.subarray(at, end).toString("utf8").split(" ");
9051
+ at = end + 1;
9052
+ if (header[1] === "missing")
9053
+ continue;
9054
+ const size = Number(header[2]);
9055
+ if (header[0] !== id || !Number.isSafeInteger(size))
9056
+ return null;
9057
+ out.set(id, bytes.subarray(at, at + size));
9058
+ at += size + 1;
9059
+ }
9060
+ return out;
9061
+ }
9062
+ function treeFilesNamed(cwd, rev, name) {
9063
+ if (!safeArg(rev))
9064
+ return null;
9065
+ const run = git(cwd, ["ls-tree", "-r", "-z", "--full-tree", rev]);
9066
+ if (!run.ok)
9067
+ return null;
9068
+ const out = new Map;
9069
+ for (const record of run.stdout.split("\x00")) {
9070
+ const match = /^\d{6} blob ([0-9a-f]+)\t(.+)$/su.exec(record);
9071
+ if (match && (match[2] === name || match[2].endsWith(`/${name}`)))
9072
+ out.set(match[2], match[1]);
9073
+ }
9074
+ return out;
9075
+ }
9076
+ function fileAt(cwd, rev, file) {
9077
+ if (!safeArg(rev))
9078
+ return null;
9079
+ const run = git(cwd, ["cat-file", "blob", `${rev}:${file}`]);
9080
+ return run.ok ? run.stdout : null;
9081
+ }
9082
+ function untrackedFiles(cwd) {
9083
+ const run = git(cwd, ["ls-files", "-z", "--others", "--exclude-standard"]);
9084
+ return run.ok ? run.stdout.split("\x00").filter(Boolean) : [];
9085
+ }
8968
9086
  var config2 = (cwd, key) => line(git(cwd, ["config", "--get", key]));
8969
9087
  function currentBranch(cwd) {
8970
9088
  return line(git(cwd, ["symbolic-ref", "--short", "-q", "HEAD"]));
@@ -12742,9 +12860,9 @@ var workerBlocksTransition = (transition, state) => transition === "pause" ? fal
12742
12860
 
12743
12861
  // packages/workit-core/src/core/task-evaluation.ts
12744
12862
  import { createHash as createHash12 } from "node:crypto";
12745
- import * as fs14 from "node:fs";
12746
- import { spawnSync as spawnSync10 } from "node:child_process";
12747
- import path17 from "node:path";
12863
+ import * as fs15 from "node:fs";
12864
+ import { spawnSync as spawnSync11 } from "node:child_process";
12865
+ import path19 from "node:path";
12748
12866
 
12749
12867
  // packages/workit-core/src/check-config.ts
12750
12868
  import { spawnSync as spawnSync8 } from "node:child_process";
@@ -12974,8 +13092,8 @@ function checkCommand(args, version, onPath = workitAvailable()) {
12974
13092
  }
12975
13093
 
12976
13094
  // packages/workit-core/src/core/policy/derive.ts
12977
- import { existsSync as existsSync4 } from "node:fs";
12978
- import path16 from "node:path";
13095
+ import { existsSync as existsSync5 } from "node:fs";
13096
+ import path18 from "node:path";
12979
13097
 
12980
13098
  // packages/workit-core/src/ledger.ts
12981
13099
  import { spawnSync as spawnSync9 } from "node:child_process";
@@ -13879,7 +13997,8 @@ function checkVerdicts(cwd, branch, ledgerRows) {
13879
13997
  verdict: failing?.verdict ?? null,
13880
13998
  reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
13881
13999
  };
13882
- const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && !untrusted(entry.reasons) && STRONG_RESULTS.has(String(entry.verdict.result)));
14000
+ 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))));
14001
+ const selfEntry = latestSelf && STRONG_RESULTS.has(String(latestSelf.verdict.result)) ? latestSelf : undefined;
13883
14002
  return {
13884
14003
  branch,
13885
14004
  head,
@@ -13923,12 +14042,721 @@ var OBSERVED_ONLY = new Set([
13923
14042
  ...PR_ROW_TYPES
13924
14043
  ]);
13925
14044
 
14045
+ // packages/workit-core/src/core/policy/lane.ts
14046
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
14047
+ import path17 from "node:path";
14048
+
14049
+ // packages/workit-core/src/core/pr-create.ts
14050
+ import fs14 from "node:fs";
14051
+ import path16 from "node:path";
14052
+ import { spawnSync as spawnSync10 } from "node:child_process";
14053
+ // packages/workit-core/src/forge/pr-body.ts
14054
+ function parseGhIssue(value) {
14055
+ const m = /issues\/(\d+)/.exec(value);
14056
+ return m ? m[1] : String(value).trim().replace(/^#/, "");
14057
+ }
14058
+
14059
+ // packages/workit-core/src/core/pr-create.ts
14060
+ function whichOnPath(tool) {
14061
+ const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
14062
+ for (const dir of (process.env.PATH ?? "").split(path16.delimiter)) {
14063
+ if (!dir)
14064
+ continue;
14065
+ for (const name of names) {
14066
+ const candidate = path16.join(dir, name);
14067
+ try {
14068
+ fs14.accessSync(candidate, fs14.constants.X_OK);
14069
+ return candidate;
14070
+ } catch {}
14071
+ }
14072
+ }
14073
+ return null;
14074
+ }
14075
+ var hostingCliAvailable = (provider) => whichOnPath(provider === "gitlab" ? "glab" : "gh") !== null;
14076
+ var pushRemote = (cwd) => {
14077
+ const result = spawnSync10("git", ["remote", "get-url", "--push", "--all", "origin"], {
14078
+ cwd,
14079
+ encoding: "utf8"
14080
+ });
14081
+ if (result.status !== 0)
14082
+ return null;
14083
+ const urls = (result.stdout ?? "").split(/\r?\n/u).map((url) => url.trim()).filter(Boolean);
14084
+ return urls.length === 1 ? urls[0] : null;
14085
+ };
14086
+
14087
+ // packages/workit-core/src/forge/redact.ts
14088
+ 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_.-]*`;
14089
+ var ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*["']?)((?:bearer|basic|token|digest)\s+)?([^\s"',;&]+)`, "giu");
14090
+ var QUOTED_ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*)(["'])([^"'\n]*[^\s"'][^"'\n]*)\2`, "giu");
14091
+ var ANSI = new RegExp(String.raw`\u001b\[[0-9;?]*[ -/]*[@-~]|\u001b\][^\u0007]*\u0007`, "gu");
14092
+
14093
+ // packages/workit-core/src/git/ops.ts
14094
+ var COMMIT_TIMEOUT_MS = 10 * 60000;
14095
+
14096
+ // packages/workit-core/src/core/policy/attributes.ts
14097
+ function patternRegex(dir, pattern) {
14098
+ if (!pattern || pattern.endsWith("/") || pattern.startsWith('"') || pattern.startsWith("!"))
14099
+ return null;
14100
+ const anchored = pattern.includes("/");
14101
+ const body = pattern.replace(/^\//u, "");
14102
+ let source = "";
14103
+ for (let index = 0;index < body.length; index += 1) {
14104
+ const char = body[index];
14105
+ if (char === "*" && body[index + 1] === "*") {
14106
+ const slash = body[index + 2] === "/";
14107
+ source += slash ? "(?:.*/)?" : ".*";
14108
+ index += slash ? 2 : 1;
14109
+ } else if (char === "*")
14110
+ source += "[^/]*";
14111
+ else if (char === "?")
14112
+ source += "[^/]";
14113
+ else if (char === "[") {
14114
+ const end = body.indexOf("]", index + 2);
14115
+ if (end < 0)
14116
+ return null;
14117
+ const set = body.slice(index + 1, end).replace(/^!/u, "^").replace(/\\/gu, "\\\\");
14118
+ source += `[${set}]`;
14119
+ index = end;
14120
+ } else if (char === "\\" && index + 1 < body.length) {
14121
+ source += body[index + 1].replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
14122
+ index += 1;
14123
+ } else
14124
+ source += char.replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
14125
+ }
14126
+ const prefix = dir ? `${dir.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}/` : "";
14127
+ try {
14128
+ return new RegExp(anchored ? `^${prefix}${source}$` : `^${prefix}(?:.*/)?${source}$`, "u");
14129
+ } catch {
14130
+ return null;
14131
+ }
14132
+ }
14133
+ function rulesOf(dir, text) {
14134
+ const out = [];
14135
+ for (const raw of text.split(`
14136
+ `)) {
14137
+ const line = raw.trim();
14138
+ if (!line || line.startsWith("#") || line.startsWith("[attr]"))
14139
+ continue;
14140
+ const [pattern, ...attributes] = line.split(/\s+/u);
14141
+ let generated = null;
14142
+ for (const attribute of attributes) {
14143
+ if (attribute === "linguist-generated" || attribute === "linguist-generated=true")
14144
+ generated = true;
14145
+ else if (attribute === "-linguist-generated" || attribute === "!linguist-generated" || attribute.startsWith("linguist-generated="))
14146
+ generated = false;
14147
+ }
14148
+ if (generated === null)
14149
+ continue;
14150
+ const regex = patternRegex(dir, pattern);
14151
+ if (regex)
14152
+ out.push({ regex, generated });
14153
+ }
14154
+ return out;
14155
+ }
14156
+ function generatedByAttributes(files, paths) {
14157
+ const rules = [...files].map(([file, text]) => {
14158
+ const dir = file.includes("/") ? file.slice(0, file.lastIndexOf("/")) : "";
14159
+ return {
14160
+ depth: dir ? dir.split("/").length : 0,
14161
+ rules: rulesOf(dir, text)
14162
+ };
14163
+ }).toSorted((left, right) => left.depth - right.depth).flatMap((entry) => entry.rules);
14164
+ const out = new Set;
14165
+ for (const file of paths) {
14166
+ const last = rules.findLast((rule) => rule.regex.test(file));
14167
+ if (last?.generated)
14168
+ out.add(file);
14169
+ }
14170
+ return out;
14171
+ }
14172
+
14173
+ // packages/workit-core/src/core/policy/substance.ts
14174
+ var SLASH_BLOCK = [["/*", "*/"]];
14175
+ var C_LIKE = { line: ["//"], block: SLASH_BLOCK, quotes: `"'` };
14176
+ var SYNTAXES = Object.fromEntries([
14177
+ ...["ts", "mts", "cts", "js", "mjs", "cjs"].map((ext) => [ext, { ...C_LIKE, js: true }]),
14178
+ ...["java", "kt", "kts", "scala", "swift", "dart", "groovy"].map((ext) => [
14179
+ ext,
14180
+ { ...C_LIKE, triple: true }
14181
+ ]),
14182
+ ["go", { ...C_LIKE, rawBacktick: true }],
14183
+ ...["css", "scss", "less"].map((ext) => [
14184
+ ext,
14185
+ { line: [], block: SLASH_BLOCK, quotes: `"'`, cssUrl: true }
14186
+ ]),
14187
+ ...["py", "pyi"].map((ext) => [
14188
+ ext,
14189
+ { line: ["#"], block: [], quotes: `"'`, triple: true, indented: true, fstring: true }
14190
+ ]),
14191
+ ["toml", { line: ["#"], block: [], quotes: `"`, literal: "'", triple: true }],
14192
+ ...["html", "htm", "xml", "svg", "xhtml"].map((ext) => [
14193
+ ext,
14194
+ { line: [], block: [["<!--", "-->"]], quotes: "", indented: true }
14195
+ ])
14196
+ ]);
14197
+ 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;
14198
+ var extensionOf = (file) => {
14199
+ const name = file.slice(file.lastIndexOf("/") + 1);
14200
+ const dot = name.lastIndexOf(".");
14201
+ return dot > 0 ? name.slice(dot + 1).toLowerCase() : "";
14202
+ };
14203
+ var CI_PATH = /^\.github\/|(?:^|\/)(?:\.gitlab-ci\.ya?ml|Jenkinsfile|azure-pipelines\.ya?ml|\.pre-commit-config\.ya?ml|\.circleci\/.*)$/u;
14204
+ var syntaxOf = (file) => CI_PATH.test(file) ? null : SYNTAXES[extensionOf(file)] ?? null;
14205
+ var SPACE = /[ \t\r\f\v]/u;
14206
+ var WORD = /[\w$]/u;
14207
+ var NO_SPACE_AFTER = "([{,;";
14208
+ var NO_SPACE_BEFORE = ")]},;";
14209
+ var REGEX_AFTER = "(,=:[!&|?{};+-*%<>~^";
14210
+ var REGEX_KEYWORDS = new Set([
14211
+ "return",
14212
+ "typeof",
14213
+ "instanceof",
14214
+ "case",
14215
+ "do",
14216
+ "else",
14217
+ "in",
14218
+ "of",
14219
+ "new",
14220
+ "delete",
14221
+ "void",
14222
+ "throw",
14223
+ "yield",
14224
+ "await"
14225
+ ]);
14226
+ function substanceOf(file, text) {
14227
+ const syntax = syntaxOf(file);
14228
+ if (!syntax)
14229
+ return plainSubstance(text);
14230
+ const markup = syntax.block.some(([open]) => open === "<!--");
14231
+ if (markup && (/<(?:script|style)\b|<!\[CDATA\[|<\?/iu.test(text) || /[^>\s][ \t]*<!--/u.test(text)))
14232
+ return plainSubstance(text);
14233
+ return lex(syntax, text);
14234
+ }
14235
+ function plainSubstance(text) {
14236
+ return text.split(`
14237
+ `).map((line) => line.replace(/[ \t\r\f\v]+$/u, "")).filter(Boolean).join(`
14238
+ `);
14239
+ }
14240
+ function lex(syntax, text) {
14241
+ const collapse = !syntax.indented;
14242
+ let out = "";
14243
+ let lineStart = 0;
14244
+ let kept = 0;
14245
+ let pendingSpace = false;
14246
+ const frames = [{ kind: "code", braces: 0 }];
14247
+ let index = 0;
14248
+ if (text.startsWith("#!")) {
14249
+ const end = text.indexOf(`
14250
+ `);
14251
+ out = end < 0 ? text : text.slice(0, end);
14252
+ kept = out.length;
14253
+ index = end < 0 ? text.length : end;
14254
+ }
14255
+ const emitCode = (chunk) => {
14256
+ if (collapse && pendingSpace && out.length > lineStart) {
14257
+ const before = out[out.length - 1];
14258
+ if (!NO_SPACE_AFTER.includes(before) && !NO_SPACE_BEFORE.includes(chunk[0]))
14259
+ out += " ";
14260
+ }
14261
+ pendingSpace = false;
14262
+ out += chunk;
14263
+ };
14264
+ const emitVerbatim = (chunk) => {
14265
+ emitCode(chunk);
14266
+ kept = out.length;
14267
+ };
14268
+ const newline = () => {
14269
+ if (!collapse) {
14270
+ let end = out.length;
14271
+ while (end > Math.max(lineStart, kept) && SPACE.test(out[end - 1]))
14272
+ end -= 1;
14273
+ out = out.slice(0, end);
14274
+ }
14275
+ pendingSpace = false;
14276
+ if (out.length > lineStart) {
14277
+ out += `
14278
+ `;
14279
+ lineStart = out.length;
14280
+ }
14281
+ };
14282
+ const regexAllowed = () => {
14283
+ let end = out.length;
14284
+ while (end > 0 && /\s/u.test(out[end - 1]))
14285
+ end -= 1;
14286
+ if (end === 0 || REGEX_AFTER.includes(out[end - 1]))
14287
+ return true;
14288
+ let start = end;
14289
+ while (start > 0 && WORD.test(out[start - 1]))
14290
+ start -= 1;
14291
+ return REGEX_KEYWORDS.has(out.slice(start, end));
14292
+ };
14293
+ const scanString = (quote, escapes, multiline) => {
14294
+ const prefix = text.slice(Math.max(0, index - 2), index).match(/[a-z]*$/iu)?.[0] ?? "";
14295
+ const fstring = syntax.fstring === true && /f/iu.test(prefix);
14296
+ let end = index + quote.length;
14297
+ while (end < text.length) {
14298
+ const char = text[end];
14299
+ if (escapes && char === "\\") {
14300
+ end += 2;
14301
+ continue;
14302
+ }
14303
+ if (text.startsWith(quote, end)) {
14304
+ if (fstring && unbalanced(text.slice(index + quote.length, end)))
14305
+ return false;
14306
+ emitVerbatim(text.slice(index, end + quote.length));
14307
+ index = end + quote.length;
14308
+ return true;
14309
+ }
14310
+ if (char === `
14311
+ ` && !multiline)
14312
+ return false;
14313
+ end += 1;
14314
+ }
14315
+ return false;
14316
+ };
14317
+ while (index < text.length) {
14318
+ const frame = frames[frames.length - 1];
14319
+ const char = text[index];
14320
+ if (frame.kind === "template") {
14321
+ if (char === "\\") {
14322
+ emitVerbatim(text.slice(index, index + 2));
14323
+ index += 2;
14324
+ } else if (char === "`") {
14325
+ emitVerbatim(char);
14326
+ frames.pop();
14327
+ index += 1;
14328
+ } else if (text.startsWith("${", index)) {
14329
+ emitVerbatim("${");
14330
+ frames.push({ kind: "code", braces: 0 });
14331
+ index += 2;
14332
+ } else {
14333
+ out += char;
14334
+ kept = out.length;
14335
+ index += 1;
14336
+ }
14337
+ continue;
14338
+ }
14339
+ if (char === `
14340
+ `) {
14341
+ newline();
14342
+ index += 1;
14343
+ continue;
14344
+ }
14345
+ if (SPACE.test(char)) {
14346
+ if (collapse)
14347
+ pendingSpace = true;
14348
+ else
14349
+ out += char;
14350
+ index += 1;
14351
+ continue;
14352
+ }
14353
+ const lineOpener = syntax.line.find((opener) => text.startsWith(opener, index));
14354
+ if (lineOpener) {
14355
+ const end = text.indexOf(`
14356
+ `, index);
14357
+ const comment = text.slice(index, end < 0 ? text.length : end);
14358
+ if (DIRECTIVE.test(comment.slice(lineOpener.length)))
14359
+ emitVerbatim(comment);
14360
+ else
14361
+ pendingSpace = true;
14362
+ index = end < 0 ? text.length : end;
14363
+ continue;
14364
+ }
14365
+ const block = syntax.block.find(([open]) => text.startsWith(open, index));
14366
+ if (block) {
14367
+ const end = text.indexOf(block[1], index + block[0].length);
14368
+ if (end < 0)
14369
+ return null;
14370
+ const comment = text.slice(index, end + block[1].length);
14371
+ if (DIRECTIVE.test(comment.slice(block[0].length, -block[1].length)))
14372
+ emitVerbatim(comment);
14373
+ else
14374
+ pendingSpace = true;
14375
+ if (comment.includes(`
14376
+ `))
14377
+ newline();
14378
+ index = end + block[1].length;
14379
+ continue;
14380
+ }
14381
+ if (syntax.triple && (char === '"' || char === "'") && text.startsWith(char.repeat(3), index)) {
14382
+ if (!scanString(char.repeat(3), !syntax.literal?.includes(char), true))
14383
+ return null;
14384
+ continue;
14385
+ }
14386
+ if (syntax.quotes.includes(char)) {
14387
+ if (!scanString(char, true, Boolean(syntax.multiline)))
14388
+ return null;
14389
+ continue;
14390
+ }
14391
+ if (syntax.literal?.includes(char)) {
14392
+ if (!scanString(char, false, false))
14393
+ return null;
14394
+ continue;
14395
+ }
14396
+ if (syntax.rawBacktick && char === "`") {
14397
+ if (!scanString("`", false, true))
14398
+ return null;
14399
+ continue;
14400
+ }
14401
+ if (syntax.js && char === "`") {
14402
+ emitVerbatim(char);
14403
+ frames.push({ kind: "template" });
14404
+ index += 1;
14405
+ continue;
14406
+ }
14407
+ if (syntax.cssUrl && /^url\(\s*[^"')\s]/iu.test(text.slice(index, index + 64)))
14408
+ return null;
14409
+ if (syntax.js && char === "/" && !regexAllowed() && out.trimEnd().endsWith(")")) {
14410
+ const lineEnd = text.indexOf(`
14411
+ `, index);
14412
+ if (text.slice(index + 1, lineEnd < 0 ? text.length : lineEnd).includes("/"))
14413
+ return null;
14414
+ }
14415
+ if (syntax.js && char === "/" && regexAllowed()) {
14416
+ let end = index + 1;
14417
+ let inClass = false;
14418
+ while (end < text.length && (inClass || text[end] !== "/")) {
14419
+ if (text[end] === `
14420
+ `)
14421
+ return null;
14422
+ if (text[end] === "\\")
14423
+ end += 1;
14424
+ else if (text[end] === "[")
14425
+ inClass = true;
14426
+ else if (text[end] === "]")
14427
+ inClass = false;
14428
+ end += 1;
14429
+ }
14430
+ if (end >= text.length)
14431
+ return null;
14432
+ emitVerbatim(text.slice(index, end + 1));
14433
+ index = end + 1;
14434
+ continue;
14435
+ }
14436
+ if (frames.length > 1 && frame.kind === "code") {
14437
+ if (char === "{")
14438
+ frame.braces += 1;
14439
+ else if (char === "}") {
14440
+ if (frame.braces === 0) {
14441
+ emitVerbatim(char);
14442
+ frames.pop();
14443
+ index += 1;
14444
+ continue;
14445
+ }
14446
+ frame.braces -= 1;
14447
+ }
14448
+ }
14449
+ emitCode(char);
14450
+ index += 1;
14451
+ }
14452
+ if (frames.length !== 1)
14453
+ return null;
14454
+ newline();
14455
+ return out;
14456
+ }
14457
+ function unbalanced(body) {
14458
+ let depth = 0;
14459
+ for (const part of body.replaceAll("{{", "").replaceAll("}}", "")) {
14460
+ if (part === "{")
14461
+ depth += 1;
14462
+ else if (part === "}")
14463
+ depth = Math.max(0, depth - 1);
14464
+ }
14465
+ return depth > 0;
14466
+ }
14467
+ function hasOpaqueLineBreak(text) {
14468
+ return /\r(?!\n)|[\u2028\u2029]/u.test(text);
14469
+ }
14470
+ var decoder = new TextDecoder("utf-8", { fatal: true });
14471
+ function textOf(bytes) {
14472
+ if (bytes.includes(0))
14473
+ return null;
14474
+ try {
14475
+ return decoder.decode(bytes);
14476
+ } catch {
14477
+ return null;
14478
+ }
14479
+ }
14480
+ function cosmeticChange(file, before, after) {
14481
+ const left = textOf(before);
14482
+ const right = textOf(after);
14483
+ if (left === null || right === null)
14484
+ return false;
14485
+ if (hasOpaqueLineBreak(left) || hasOpaqueLineBreak(right))
14486
+ return false;
14487
+ const a = substanceOf(file, left);
14488
+ return a !== null && a === substanceOf(file, right);
14489
+ }
14490
+
14491
+ // packages/workit-core/src/core/policy/lane.ts
14492
+ var LANE_THRESHOLDS = {
14493
+ selfMaxLines: 100,
14494
+ selfMaxFiles: 5,
14495
+ fullMinLines: 500
14496
+ };
14497
+ var RISK_TOKENS = new Set([
14498
+ "auth",
14499
+ "authn",
14500
+ "authz",
14501
+ "oauth",
14502
+ "security",
14503
+ "permission",
14504
+ "permissions",
14505
+ "secret",
14506
+ "secrets",
14507
+ "crypto",
14508
+ "gate",
14509
+ "gates",
14510
+ "policy",
14511
+ "policies",
14512
+ "hook",
14513
+ "hooks",
14514
+ "husky",
14515
+ "lefthook",
14516
+ "release",
14517
+ "releases",
14518
+ "migration",
14519
+ "migrations",
14520
+ "migrate",
14521
+ "workflows"
14522
+ ]);
14523
+ var RISK_FILES = new Set([
14524
+ ".gitlab-ci.yml",
14525
+ "Jenkinsfile",
14526
+ "azure-pipelines.yml",
14527
+ ".pre-commit-config.yaml",
14528
+ ".workit/risk-paths"
14529
+ ]);
14530
+ var RISK_NAMES = new Set([".gitattributes"]);
14531
+ var RISK_PATHS_FILE = ".workit/risk-paths";
14532
+ var LOCKFILES = new Set([
14533
+ "bun.lock",
14534
+ "bun.lockb",
14535
+ "package-lock.json",
14536
+ "npm-shrinkwrap.json",
14537
+ "yarn.lock",
14538
+ "pnpm-lock.yaml",
14539
+ "Cargo.lock",
14540
+ "go.sum",
14541
+ "poetry.lock",
14542
+ "uv.lock",
14543
+ "Pipfile.lock",
14544
+ "Gemfile.lock",
14545
+ "composer.lock"
14546
+ ]);
14547
+ var DOC_EXT = /\.(?:md|mdx|markdown|rst|adoc|txt)$/iu;
14548
+ var DOC_NAMES = /^(?:license|licence|notice|authors|changelog|changes|contributors)$/iu;
14549
+ var INSTRUCTIONS = /(?:^|\/)(?:AGENTS|CLAUDE|GEMINI|SKILL)\.md$|(?:^|\/)(?:skills|agents|commands|rules|prompts)\/[^/]+/iu;
14550
+ var TEST_PATH = /(?:^|\/)(?:test|tests|__tests__|spec|specs|fixtures)\/|\.(?:test|spec)\.[^/]+$/iu;
14551
+ var basename = (file) => file.slice(file.lastIndexOf("/") + 1);
14552
+ var isDoc = (file) => !INSTRUCTIONS.test(file) && (DOC_EXT.test(file) || DOC_NAMES.test(basename(file)));
14553
+ function kindOf(file) {
14554
+ if (file.binary)
14555
+ return "behavior";
14556
+ if (file.generated)
14557
+ return "generated";
14558
+ if (LOCKFILES.has(basename(file.path)))
14559
+ return "lockfile";
14560
+ if (isDoc(file.path))
14561
+ return "doc";
14562
+ if (file.cosmetic)
14563
+ return "cosmetic";
14564
+ return TEST_PATH.test(file.path) ? "test" : "behavior";
14565
+ }
14566
+ var globCache = new Map;
14567
+ function globMatch(pattern, file) {
14568
+ let regex = globCache.get(pattern);
14569
+ if (!regex) {
14570
+ let source = "";
14571
+ for (let index = 0;index < pattern.length; index += 1) {
14572
+ const char = pattern[index];
14573
+ if (char === "*" && pattern[index + 1] === "*") {
14574
+ source += pattern[index + 2] === "/" ? "(?:[^/]*/)*" : ".*";
14575
+ index += pattern[index + 2] === "/" ? 2 : 1;
14576
+ } else if (char === "*")
14577
+ source += "[^/]*";
14578
+ else if (char === "?")
14579
+ source += "[^/]";
14580
+ else
14581
+ source += char.replace(/[.+^${}()|[\]\\]/gu, "\\$&");
14582
+ }
14583
+ regex = new RegExp(`^${source}$`, "u");
14584
+ globCache.set(pattern, regex);
14585
+ }
14586
+ return regex.test(file) || file.startsWith(`${pattern.replace(/\/$/u, "")}/`);
14587
+ }
14588
+ function isRiskPath(file, extra = []) {
14589
+ if (extra.some((pattern) => globMatch(pattern, file)))
14590
+ return true;
14591
+ if (RISK_FILES.has(file) || RISK_NAMES.has(basename(file)))
14592
+ return true;
14593
+ if (TEST_PATH.test(file) || isDoc(file))
14594
+ return false;
14595
+ 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)));
14596
+ }
14597
+ var parseRiskPaths = (text) => text.split(`
14598
+ `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.replace(/^\//u, ""));
14599
+ function computeLane(input) {
14600
+ const riskFiles = input.files.filter((file) => isRiskPath(file.path, input.riskPaths)).map((file) => file.path);
14601
+ const risky = new Set(riskFiles);
14602
+ const kinds = input.files.map((file) => ({
14603
+ file,
14604
+ kind: risky.has(file.path) ? "behavior" : kindOf(file)
14605
+ }));
14606
+ const behavior = kinds.filter((entry) => entry.kind === "behavior" || entry.kind === "test" || entry.kind === "lockfile");
14607
+ const lines = behavior.filter((entry) => entry.kind !== "lockfile").reduce((sum, entry) => sum + entry.file.added + entry.file.deleted, 0);
14608
+ const opaque = behavior.filter((entry) => entry.kind === "lockfile" || entry.file.binary);
14609
+ const result = (lane, reasons) => ({
14610
+ lane,
14611
+ reasons,
14612
+ lines,
14613
+ files: behavior.length,
14614
+ riskFiles
14615
+ });
14616
+ const { selfMaxLines, selfMaxFiles, fullMinLines } = LANE_THRESHOLDS;
14617
+ if (input.riskTier === "high")
14618
+ return result("full", ["the task judgment records high risk"]);
14619
+ if (riskFiles.length)
14620
+ return result("full", [
14621
+ `touches a risk path: ${riskFiles.slice(0, 3).join(", ")}${riskFiles.length > 3 ? ", …" : ""}`
14622
+ ]);
14623
+ if (!behavior.length)
14624
+ return result("none", [
14625
+ input.files.length ? "only docs, comments, formatting or generated copies changed" : "no changes"
14626
+ ]);
14627
+ if (lines >= fullMinLines)
14628
+ return result("full", [`large diff: ${lines} lines (≥ ${fullMinLines})`]);
14629
+ if (lines > selfMaxLines)
14630
+ return result("focused", [`${lines} lines changed (> ${selfMaxLines})`]);
14631
+ if (behavior.length > selfMaxFiles)
14632
+ return result("focused", [`${behavior.length} behavior files changed (> ${selfMaxFiles})`]);
14633
+ if (opaque.length)
14634
+ return result("focused", [
14635
+ `a lockfile or binary changed: ${opaque.slice(0, 3).map((entry) => entry.file.path).join(", ")}${opaque.length > 3 ? ", …" : ""}`
14636
+ ]);
14637
+ return result("self", [
14638
+ `small change: ${lines} line${lines === 1 ? "" : "s"} in ${behavior.length} file${behavior.length === 1 ? "" : "s"}, no risk path`
14639
+ ]);
14640
+ }
14641
+ function untrackedStat(cwd, file) {
14642
+ try {
14643
+ const bytes = readFileSync4(path17.join(cwd, file));
14644
+ if (bytes.includes(0))
14645
+ return { path: file, added: 0, deleted: 0, binary: true };
14646
+ const text = bytes.toString("utf8");
14647
+ if (hasOpaqueLineBreak(text))
14648
+ return { path: file, added: 0, deleted: 0, binary: true };
14649
+ const lines = text.split(`
14650
+ `).length - (text.endsWith(`
14651
+ `) ? 1 : 0);
14652
+ return { path: file, added: lines, deleted: 0 };
14653
+ } catch {
14654
+ return { path: file, added: 0, deleted: 0, binary: true };
14655
+ }
14656
+ }
14657
+ var REGULAR = new Set(["100644", "100755"]);
14658
+ var ABSENT = /^0+$/u;
14659
+ function cosmeticFiles(cwd, fork, head) {
14660
+ const raw = diffRaw(cwd, fork, head);
14661
+ if (!raw)
14662
+ return null;
14663
+ const candidates = raw.filter((entry) => REGULAR.has(entry.oldMode) && entry.oldMode === entry.newMode && !ABSENT.test(entry.oldBlob) && (head === null || !ABSENT.test(entry.newBlob)));
14664
+ const blobs = readBlobs(cwd, candidates.flatMap((entry) => [entry.oldBlob, entry.newBlob]));
14665
+ if (!blobs)
14666
+ return null;
14667
+ const out = new Set;
14668
+ const opaque = new Set;
14669
+ for (const entry of candidates) {
14670
+ const before = blobs.get(entry.oldBlob);
14671
+ let after = blobs.get(entry.newBlob);
14672
+ if (!after && head === null && ABSENT.test(entry.newBlob))
14673
+ try {
14674
+ after = readFileSync4(path17.join(cwd, entry.path));
14675
+ } catch {
14676
+ after = undefined;
14677
+ }
14678
+ if (before && after && cosmeticChange(entry.path, before, after))
14679
+ out.add(entry.path);
14680
+ else if ([before, after].some((bytes) => bytes && hasOpaqueLineBreak(bytes.toString("utf8"))))
14681
+ opaque.add(entry.path);
14682
+ }
14683
+ return { cosmetic: out, opaque };
14684
+ }
14685
+ function generatedAt(cwd, fork, paths) {
14686
+ const files = treeFilesNamed(cwd, fork, ".gitattributes");
14687
+ const blobs = files?.size ? readBlobs(cwd, [...files.values()]) : null;
14688
+ if (!files || !blobs)
14689
+ return new Set;
14690
+ const texts = new Map;
14691
+ for (const [file, id] of files) {
14692
+ const bytes = blobs.get(id);
14693
+ if (bytes)
14694
+ texts.set(file, bytes.toString("utf8"));
14695
+ }
14696
+ return generatedByAttributes(texts, paths);
14697
+ }
14698
+ var forkOf = (cwd, base, head) => mergeBase(cwd, base, head ?? "HEAD");
14699
+ function laneFiles(cwd, fork, head) {
14700
+ const stats = diffNumstat(cwd, fork, head);
14701
+ const cosmetic = stats ? cosmeticFiles(cwd, fork, head) : null;
14702
+ if (!stats || !cosmetic)
14703
+ return null;
14704
+ const files = [
14705
+ ...stats.map((entry) => ({
14706
+ ...entry,
14707
+ ...cosmetic.opaque.has(entry.path) ? { binary: true } : {},
14708
+ cosmetic: !entry.binary && cosmetic.cosmetic.has(entry.path)
14709
+ })),
14710
+ ...head === null ? untrackedFiles(cwd).map((file) => untrackedStat(cwd, file)) : []
14711
+ ];
14712
+ const generated = generatedAt(cwd, fork, files.map((entry) => entry.path));
14713
+ return files.map((entry) => ({
14714
+ ...entry,
14715
+ generated: generated.has(entry.path)
14716
+ }));
14717
+ }
14718
+ function branchLane(cwd, options) {
14719
+ const candidates = options.base ? [`origin/${options.base}`, options.base] : [];
14720
+ const base = candidates.find((ref) => resolveRef(cwd, ref) !== null) ?? defaultBase(cwd) ?? null;
14721
+ const head = options.workingTree ? null : options.head;
14722
+ const fork = base && (options.workingTree || options.head) ? forkOf(cwd, base, head) : null;
14723
+ const files = fork ? laneFiles(cwd, fork, head) : null;
14724
+ const riskTier = options.judgment?.riskTier ?? null;
14725
+ if (!fork || !files) {
14726
+ const high = riskTier === "high";
14727
+ return {
14728
+ lane: high ? "full" : "focused",
14729
+ reasons: [
14730
+ `the diff of ${options.head?.slice(0, 12) ?? "(no head)"} against ${base ?? "(no base)"} cannot be read`,
14731
+ ...high ? ["the task judgment records high risk"] : []
14732
+ ],
14733
+ lines: 0,
14734
+ files: 0,
14735
+ riskFiles: [],
14736
+ base,
14737
+ head: options.head
14738
+ };
14739
+ }
14740
+ const repoRisk = parseRiskPaths(fileAt(cwd, fork, RISK_PATHS_FILE) ?? "");
14741
+ return {
14742
+ ...computeLane({
14743
+ files,
14744
+ riskTier,
14745
+ riskPaths: [...repoRisk, ...options.riskPaths ?? []]
14746
+ }),
14747
+ base,
14748
+ head: options.head
14749
+ };
14750
+ }
14751
+ var laneNeed = (lane) => lane === "none" ? "none" : lane === "self" ? "self" : "non-author";
14752
+
13926
14753
  // packages/workit-core/src/core/policy/derive.ts
13927
14754
  var RULES = {
13928
14755
  test: "check:test",
13929
14756
  self: "verdict:self",
13930
14757
  nonAuthor: "verdict:non-author",
13931
14758
  verified: "verdict:verified",
14759
+ lane: "verdict:lane",
13932
14760
  product: "decision:product",
13933
14761
  plan: "plan"
13934
14762
  };
@@ -13951,6 +14779,7 @@ var normalizedScope = (scope) => ({
13951
14779
  function deriveRequirements(judgment, scope, constraints, verification = "self") {
13952
14780
  const out = [];
13953
14781
  const base = { scope, dependentAction: null };
14782
+ const proportional = verification === "proportional";
13954
14783
  if (judgment.behaviorChange)
13955
14784
  out.push(derived2({
13956
14785
  ...base,
@@ -13961,7 +14790,17 @@ function deriveRequirements(judgment, scope, constraints, verification = "self")
13961
14790
  before: "close",
13962
14791
  acceptanceAllowed: false
13963
14792
  }));
13964
- if (judgment.behaviorChange && judgment.riskTier === "normal")
14793
+ if (proportional && judgment.riskTier === "normal")
14794
+ out.push(derived2({
14795
+ ...base,
14796
+ ruleId: RULES.lane,
14797
+ dimension: "review",
14798
+ 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.",
14799
+ 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.",
14800
+ before: "close",
14801
+ acceptanceAllowed: false
14802
+ }));
14803
+ if (!proportional && judgment.behaviorChange && judgment.riskTier === "normal")
13965
14804
  out.push(verification === "independent" ? derived2({
13966
14805
  ...base,
13967
14806
  ruleId: RULES.nonAuthor,
@@ -14064,7 +14903,7 @@ var productDecision = (task, ledger) => {
14064
14903
  };
14065
14904
  };
14066
14905
  var planRecorded = (task, root) => {
14067
- const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path16.resolve(root, ref.path)));
14906
+ const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync5(path18.resolve(root, ref.path)));
14068
14907
  if (cited)
14069
14908
  return {
14070
14909
  met: true,
@@ -14078,14 +14917,30 @@ var planRecorded = (task, root) => {
14078
14917
  decisionIds: []
14079
14918
  };
14080
14919
  };
14081
- var verdict = (requirement, root, ledger) => {
14920
+ var workingLane = (task, root) => branchLane(root, { head: null, workingTree: true, judgment: latestJudgment(task) });
14921
+ var laneVerdict = (task, root, ledger) => {
14922
+ if (!ledger.branch() && latestJudgment(task)?.behaviorChange === false)
14923
+ return {
14924
+ met: true,
14925
+ reason: "no branch to read a lane from, and the judgment records no behavior change",
14926
+ decisionIds: []
14927
+ };
14928
+ const lane = workingLane(task, root);
14929
+ const label = `lane ${lane.lane} (${lane.reasons.join("; ")})`;
14930
+ const need = laneNeed(lane.lane);
14931
+ if (need === "none")
14932
+ return { met: true, reason: `${label}: no verdict needed`, decisionIds: [] };
14933
+ const status = verdict(need === "self" ? RULES.self : RULES.nonAuthor, root, ledger);
14934
+ return { ...status, reason: `${label}: ${status.reason}` };
14935
+ };
14936
+ var verdict = (ruleId, root, ledger) => {
14082
14937
  const branch = ledger.branch();
14083
14938
  if (!branch)
14084
14939
  return { met: false, reason: "no branch is checked out to hold a verdict", decisionIds: [] };
14085
14940
  const check = checkVerdicts(root, branch, ledger.rows());
14086
14941
  const failing = check.accepted.reasons.includes("failing_verdict");
14087
14942
  const strong = (entry) => STRONG_RESULTS.has(String(entry.verdict.result));
14088
- 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)));
14943
+ 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)));
14089
14944
  if (met)
14090
14945
  return {
14091
14946
  met: true,
@@ -14093,7 +14948,7 @@ var verdict = (requirement, root, ledger) => {
14093
14948
  decisionIds: []
14094
14949
  };
14095
14950
  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, " ");
14096
- 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>\``;
14951
+ 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>\``;
14097
14952
  return { met: false, reason: `${why}: ${unblock}`, decisionIds: [] };
14098
14953
  };
14099
14954
  function derivedRuleStatus(task, requirement, root, ledger) {
@@ -14105,7 +14960,9 @@ function derivedRuleStatus(task, requirement, root, ledger) {
14105
14960
  case RULES.self:
14106
14961
  case RULES.nonAuthor:
14107
14962
  case RULES.verified:
14108
- return verdict(requirement, root, ledger);
14963
+ return verdict(requirement.ruleId, root, ledger);
14964
+ case RULES.lane:
14965
+ return laneVerdict(task, root, ledger);
14109
14966
  default:
14110
14967
  return null;
14111
14968
  }
@@ -14124,14 +14981,14 @@ function writeBlockers(task, root) {
14124
14981
 
14125
14982
  // packages/workit-core/src/core/task-evaluation.ts
14126
14983
  var digestBytes = (value) => createHash12("sha256").update(value).digest("hex");
14127
- var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path17.sep}`);
14128
- var relative = (root, candidate) => path17.relative(root, candidate).split(path17.sep).join("/") || ".";
14984
+ var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path19.sep}`);
14985
+ var relative = (root, candidate) => path19.relative(root, candidate).split(path19.sep).join("/") || ".";
14129
14986
  var canonicalPath = (value) => {
14130
14987
  if (typeof value !== "string" || !value)
14131
14988
  return null;
14132
14989
  if (value.includes("\\") || value.split("/").includes(".."))
14133
14990
  return null;
14134
- const normalized = path17.posix.normalize(value);
14991
+ const normalized = path19.posix.normalize(value);
14135
14992
  if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
14136
14993
  return null;
14137
14994
  return normalized === "." ? "." : normalized.replace(/\/$/, "");
@@ -14167,7 +15024,7 @@ var compareCodeUnits2 = (left, right) => {
14167
15024
  return left.length - right.length;
14168
15025
  };
14169
15026
  var gitPaths = (root) => {
14170
- const result = spawnSync10("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
15027
+ const result = spawnSync11("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
14171
15028
  cwd: root,
14172
15029
  encoding: "buffer"
14173
15030
  });
@@ -14179,21 +15036,21 @@ var gitPaths = (root) => {
14179
15036
  git: !/not a git repository/i.test(stderr)
14180
15037
  };
14181
15038
  }
14182
- const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path17.sep).join("/")) : [];
14183
- const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
15039
+ const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path19.sep).join("/")) : [];
15040
+ const stagedDeleted = spawnSync11("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
14184
15041
  if (stagedDeleted.status !== 0) {
14185
15042
  const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
14186
15043
  if (!/not a git repository/i.test(stderr))
14187
15044
  return { paths, uncertain: true, git: true };
14188
15045
  } else if (stagedDeleted.stdout) {
14189
- paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path17.sep).join("/")));
15046
+ paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path19.sep).join("/")));
14190
15047
  }
14191
15048
  return { paths: [...new Set(paths)], uncertain: false, git: true };
14192
15049
  };
14193
15050
  var walk = (root, directory, output) => {
14194
15051
  let names;
14195
15052
  try {
14196
- names = fs14.readdirSync(directory);
15053
+ names = fs15.readdirSync(directory);
14197
15054
  } catch {
14198
15055
  return true;
14199
15056
  }
@@ -14201,10 +15058,10 @@ var walk = (root, directory, output) => {
14201
15058
  for (const name of names) {
14202
15059
  if (name === ".git" || name === ".workit")
14203
15060
  continue;
14204
- const target = path17.join(directory, name);
15061
+ const target = path19.join(directory, name);
14205
15062
  let stat;
14206
15063
  try {
14207
- stat = fs14.lstatSync(target);
15064
+ stat = fs15.lstatSync(target);
14208
15065
  } catch {
14209
15066
  uncertain = true;
14210
15067
  continue;
@@ -14219,14 +15076,14 @@ var walk = (root, directory, output) => {
14219
15076
  var scopeRoots = (root, scope) => {
14220
15077
  const roots = [];
14221
15078
  for (const item of scope.paths.length ? scope.paths : ["."]) {
14222
- const target = path17.resolve(root, item);
15079
+ const target = path19.resolve(root, item);
14223
15080
  if (!inside(root, target))
14224
15081
  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` }] });
14225
15082
  let ancestor = target;
14226
- while (!fs14.existsSync(ancestor) && ancestor !== root)
14227
- ancestor = path17.dirname(ancestor);
15083
+ while (!fs15.existsSync(ancestor) && ancestor !== root)
15084
+ ancestor = path19.dirname(ancestor);
14228
15085
  try {
14229
- if (!inside(root, fs14.realpathSync(ancestor)))
15086
+ if (!inside(root, fs15.realpathSync(ancestor)))
14230
15087
  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` }] });
14231
15088
  } catch {
14232
15089
  return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
@@ -14238,7 +15095,7 @@ var scopeRoots = (root, scope) => {
14238
15095
  function captureCandidate(root, scope, environment = []) {
14239
15096
  let checkout;
14240
15097
  try {
14241
- checkout = fs14.realpathSync(root);
15098
+ checkout = fs15.realpathSync(root);
14242
15099
  } catch {
14243
15100
  return failure2("invalid_input", "candidate root does not exist");
14244
15101
  }
@@ -14256,11 +15113,11 @@ function captureCandidate(root, scope, environment = []) {
14256
15113
  if (item === ".git" || item === ".workit")
14257
15114
  continue;
14258
15115
  names.add(item);
14259
- if (!fs14.existsSync(target))
15116
+ if (!fs15.existsSync(target))
14260
15117
  continue;
14261
15118
  let stat;
14262
15119
  try {
14263
- stat = fs14.lstatSync(target);
15120
+ stat = fs15.lstatSync(target);
14264
15121
  } catch {
14265
15122
  uncertain = true;
14266
15123
  continue;
@@ -14276,17 +15133,17 @@ function captureCandidate(root, scope, environment = []) {
14276
15133
  for (const item of [...names].toSorted()) {
14277
15134
  if (!scopeMatches(item, normalizedScope))
14278
15135
  continue;
14279
- const target = path17.join(checkout, item);
15136
+ const target = path19.join(checkout, item);
14280
15137
  try {
14281
- const stat = fs14.lstatSync(target);
15138
+ const stat = fs15.lstatSync(target);
14282
15139
  if (stat.isSymbolicLink()) {
14283
- const link = fs14.readlinkSync(target);
15140
+ const link = fs15.readlinkSync(target);
14284
15141
  files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
14285
15142
  } else if (stat.isFile()) {
14286
15143
  files.push({
14287
15144
  path: item,
14288
15145
  kind: "file",
14289
- digest: digestBytes(fs14.readFileSync(target)),
15146
+ digest: digestBytes(fs15.readFileSync(target)),
14290
15147
  executable: (stat.mode & 73) !== 0
14291
15148
  });
14292
15149
  } else if (!stat.isDirectory()) {
@@ -14311,7 +15168,7 @@ function captureCandidate(root, scope, environment = []) {
14311
15168
  const values = supplied.toSorted((left, right) => compareCodeUnits2(left.name, right.name)).map(({ name, value }) => ({ name, value, refs: [] }));
14312
15169
  if (values.some(({ value }) => value === null))
14313
15170
  completeness = "uncertain";
14314
- const headResult = spawnSync10("git", ["rev-parse", "HEAD"], { cwd: checkout, encoding: "utf8" });
15171
+ const headResult = spawnSync11("git", ["rev-parse", "HEAD"], { cwd: checkout, encoding: "utf8" });
14315
15172
  if (headResult.status !== 0 && !/not a git repository/i.test(headResult.stderr ?? ""))
14316
15173
  completeness = "uncertain";
14317
15174
  const head = headResult.status === 0 ? headResult.stdout.trim() : null;
@@ -14451,7 +15308,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
14451
15308
  var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
14452
15309
  let root;
14453
15310
  try {
14454
- root = fs14.realpathSync(checkoutRoot);
15311
+ root = fs15.realpathSync(checkoutRoot);
14455
15312
  } catch {
14456
15313
  return failure2("permission_denied", "checkout root is unavailable");
14457
15314
  }
@@ -14460,23 +15317,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
14460
15317
  continue;
14461
15318
  if (!reference.digest)
14462
15319
  return failure2("invalid_input", "document references require a byte digest");
14463
- const target = path17.resolve(root, reference.path);
14464
- if (target !== root && !target.startsWith(`${root}${path17.sep}`))
15320
+ const target = path19.resolve(root, reference.path);
15321
+ if (target !== root && !target.startsWith(`${root}${path19.sep}`))
14465
15322
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
14466
15323
  fields: [
14467
15324
  { path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
14468
15325
  ]
14469
15326
  });
14470
15327
  try {
14471
- const below = path17.relative(root, target);
15328
+ const below = path19.relative(root, target);
14472
15329
  let current = root;
14473
- for (const segment of below.split(path17.sep)) {
15330
+ for (const segment of below.split(path19.sep)) {
14474
15331
  if (!segment)
14475
15332
  continue;
14476
- current = path17.join(current, segment);
14477
- const stat = fs14.lstatSync(current);
14478
- const real = fs14.realpathSync(current);
14479
- if (real !== root && !real.startsWith(`${root}${path17.sep}`))
15333
+ current = path19.join(current, segment);
15334
+ const stat = fs15.lstatSync(current);
15335
+ const real = fs15.realpathSync(current);
15336
+ if (real !== root && !real.startsWith(`${root}${path19.sep}`))
14480
15337
  return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
14481
15338
  fields: [
14482
15339
  {
@@ -14492,7 +15349,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
14492
15349
  if (current !== target && !stat.isDirectory())
14493
15350
  return failure2("invalid_input", "document reference ancestor is not a directory");
14494
15351
  }
14495
- if (digestBytes(fs14.readFileSync(target)) !== reference.digest)
15352
+ if (digestBytes(fs15.readFileSync(target)) !== reference.digest)
14496
15353
  return failure2("permission_denied", "decision document bytes have changed");
14497
15354
  } catch {
14498
15355
  return failure2("invalid_input", "decision document is unavailable");
@@ -14913,9 +15770,9 @@ Autonomy contract:
14913
15770
  Prose is a note: only a configured check the CLI ran (\`workit check <name>\`)
14914
15771
  satisfies a gate; an ad-hoc \`workit check -- <cmd>\` never does.
14915
15772
  - Author is not verifier: your own verdict is \`--self\`, shown as
14916
- self-reviewed, never verified. High risk, \`verification: independent\` and
14917
- merge need a verifier with its own host-derived session (a subagent's
14918
- \`<lead>:<child>\`); never hand-mint one (\`<lead>-v1\`).
15773
+ self-reviewed, never verified. High risk, a focused or full lane and
15774
+ merge under \`verification: self|independent\` need a verifier with its
15775
+ own host-derived session (a subagent's \`<lead>:<child>\`); never hand-mint one (\`<lead>-v1\`).
14919
15776
  - A local-commit endpoint does not imply PR readiness, and a local commit alone
14920
15777
  is not evidence of a requested remote push. Before reporting delivery,
14921
15778
  reconcile every requested item and observe it (\`workit verify-delivery\`).
@@ -15077,21 +15934,21 @@ var exportDigest = (bundle) => sha256({
15077
15934
  task: bundle.task
15078
15935
  });
15079
15936
  // packages/workit-core/src/core/route-intent.ts
15080
- import { spawnSync as spawnSync12 } from "node:child_process";
15081
- import { existsSync as existsSync6 } from "node:fs";
15082
- import path20 from "node:path";
15937
+ import { spawnSync as spawnSync13 } from "node:child_process";
15938
+ import { existsSync as existsSync7 } from "node:fs";
15939
+ import path22 from "node:path";
15083
15940
 
15084
15941
  // packages/workit-core/src/hooks/raw-git.ts
15085
- import { spawnSync as spawnSync11 } from "node:child_process";
15942
+ import { spawnSync as spawnSync12 } from "node:child_process";
15086
15943
  import { createHash as createHash14 } from "node:crypto";
15087
- import fs16 from "node:fs";
15944
+ import fs17 from "node:fs";
15088
15945
  import os4 from "node:os";
15089
- import path19 from "node:path";
15946
+ import path21 from "node:path";
15090
15947
 
15091
15948
  // packages/workit-core/src/hooks/session-marker.ts
15092
15949
  import { createHash as createHash13 } from "node:crypto";
15093
- import fs15 from "node:fs";
15094
- import path18 from "node:path";
15950
+ import fs16 from "node:fs";
15951
+ import path20 from "node:path";
15095
15952
  var sessionMarkerFile = (input, session, store) => {
15096
15953
  let dir = store;
15097
15954
  if (dir === undefined) {
@@ -15101,13 +15958,13 @@ var sessionMarkerFile = (input, session, store) => {
15101
15958
  dir = location.dir;
15102
15959
  }
15103
15960
  const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
15104
- return path18.join(dir, "hooks", `skills-${name}.json`);
15961
+ return path20.join(dir, "hooks", `skills-${name}.json`);
15105
15962
  };
15106
15963
  var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
15107
15964
  var EMPTY = { nudged: [], loaded: [], raw: [], stops: [], judges: [] };
15108
15965
  var readRaw = (file) => {
15109
15966
  try {
15110
- return fs15.readFileSync(file, "utf8");
15967
+ return fs16.readFileSync(file, "utf8");
15111
15968
  } catch {
15112
15969
  return "";
15113
15970
  }
@@ -15128,13 +15985,13 @@ var parseMarker = (text) => {
15128
15985
  };
15129
15986
  var readSessionMarker = (file) => parseMarker(readRaw(file));
15130
15987
  var writeAtomic = (file, marker) => {
15131
- fs15.mkdirSync(path18.dirname(file), { recursive: true });
15988
+ fs16.mkdirSync(path20.dirname(file), { recursive: true });
15132
15989
  const temp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
15133
15990
  try {
15134
- fs15.writeFileSync(temp, JSON.stringify(marker));
15135
- fs15.renameSync(temp, file);
15991
+ fs16.writeFileSync(temp, JSON.stringify(marker));
15992
+ fs16.renameSync(temp, file);
15136
15993
  } catch (error) {
15137
- fs15.rmSync(temp, { force: true });
15994
+ fs16.rmSync(temp, { force: true });
15138
15995
  throw error;
15139
15996
  }
15140
15997
  };
@@ -15656,17 +16513,17 @@ var GIT_VALUE_OPTIONS = new Set([
15656
16513
  ]);
15657
16514
  var GIT_CONFIG_OPTIONS = new Set(["-c", "--config-env", "--git-dir"]);
15658
16515
  var GIT_CONFIG_ENV = /^GIT_(?:CONFIG\w*|DIR|COMMON_DIR|WORK_TREE)$/;
15659
- var ASSIGNMENT = /^([A-Za-z_]\w*)=([\s\S]*)$/;
16516
+ var ASSIGNMENT2 = /^([A-Za-z_]\w*)=([\s\S]*)$/;
15660
16517
  var MAX_DEPTH = 4;
15661
16518
  var MAX_EXPANSIONS = 16;
15662
- var isAbsolute = (value) => path19.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
16519
+ var isAbsolute = (value) => path21.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
15663
16520
  var HERE = /^(?:\$PWD|\$\{PWD\}|\$\(\s*pwd\s*\)|`pwd`|\$\(\s*git\s+rev-parse\s+--show-toplevel\s*\))(?=$|[\\/])/;
15664
16521
  var joinDir = (base, raw) => {
15665
16522
  const next = raw.replace(HERE, ".");
15666
16523
  if (base === undefined || /[$`*?]/.test(next) || next === "-")
15667
16524
  return;
15668
- const expanded = next === "~" || next.startsWith("~/") ? path19.join(os4.homedir(), next.slice(1)) : next;
15669
- return base === null || isAbsolute(expanded) ? expanded : path19.join(base, expanded);
16525
+ const expanded = next === "~" || next.startsWith("~/") ? path21.join(os4.homedir(), next.slice(1)) : next;
16526
+ return base === null || isAbsolute(expanded) ? expanded : path21.join(base, expanded);
15670
16527
  };
15671
16528
  var rebase = (base, inner) => inner === null ? base : inner === undefined ? undefined : joinDir(base, inner);
15672
16529
  var cdTarget = (words) => {
@@ -15683,7 +16540,7 @@ var stripPrefixes = (input) => {
15683
16540
  const first = words[0];
15684
16541
  if (first === undefined)
15685
16542
  return { words, env };
15686
- const assignment = ASSIGNMENT.exec(first);
16543
+ const assignment = ASSIGNMENT2.exec(first);
15687
16544
  if (assignment) {
15688
16545
  if (GIT_CONFIG_ENV.test(assignment[1]))
15689
16546
  env[assignment[1]] = assignment[2];
@@ -15742,10 +16599,10 @@ var assignments = (words, vars) => {
15742
16599
  while (rest[0]?.startsWith("-"))
15743
16600
  rest = rest.slice(1);
15744
16601
  }
15745
- if (rest.length === 0 || !rest.every((word) => ASSIGNMENT.test(word)))
16602
+ if (rest.length === 0 || !rest.every((word) => ASSIGNMENT2.test(word)))
15746
16603
  return null;
15747
16604
  return rest.map((word) => {
15748
- const [, name, value] = ASSIGNMENT.exec(word);
16605
+ const [, name, value] = ASSIGNMENT2.exec(word);
15749
16606
  return [name, expandWord(value, vars)];
15750
16607
  });
15751
16608
  };
@@ -15933,7 +16790,7 @@ var splitString = (line) => {
15933
16790
  return line.slice(index).join(" ").slice(15);
15934
16791
  if (/^-S./.test(word))
15935
16792
  return [word.slice(2), ...line.slice(index + 1)].join(" ");
15936
- if (!word.startsWith("-") && !ASSIGNMENT.test(word))
16793
+ if (!word.startsWith("-") && !ASSIGNMENT2.test(word))
15937
16794
  return null;
15938
16795
  }
15939
16796
  return null;
@@ -16496,7 +17353,7 @@ var repoAt = (dir) => {
16496
17353
  return { location, dir, branch: resolveTaskKey(dir, location).branch };
16497
17354
  };
16498
17355
  var isWorkitWorkspace = (repo) => {
16499
- if (fs16.existsSync(repo.location.dir))
17356
+ if (fs17.existsSync(repo.location.dir))
16500
17357
  return true;
16501
17358
  try {
16502
17359
  return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
@@ -16517,17 +17374,17 @@ var headSha2 = (repo) => {
16517
17374
  if (!git || git.reftable)
16518
17375
  return null;
16519
17376
  try {
16520
- const head = fs16.readFileSync(path19.join(git.gitDir, "HEAD"), "utf8").trim();
17377
+ const head = fs17.readFileSync(path21.join(git.gitDir, "HEAD"), "utf8").trim();
16521
17378
  if (/^[0-9a-f]{40,64}$/.test(head))
16522
17379
  return head;
16523
17380
  const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
16524
17381
  if (!ref)
16525
17382
  return null;
16526
- const common = path19.dirname(repo.location.dir);
17383
+ const common = path21.dirname(repo.location.dir);
16527
17384
  try {
16528
- return fs16.readFileSync(path19.join(common, ref), "utf8").trim() || null;
17385
+ return fs17.readFileSync(path21.join(common, ref), "utf8").trim() || null;
16529
17386
  } catch {}
16530
- const packed = fs16.readFileSync(path19.join(common, "packed-refs"), "utf8");
17387
+ const packed = fs17.readFileSync(path21.join(common, "packed-refs"), "utf8");
16531
17388
  return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
16532
17389
  } catch {
16533
17390
  return null;
@@ -16539,7 +17396,7 @@ var gitConfig = (dir, invocation, cache) => {
16539
17396
  if (cached)
16540
17397
  return cached;
16541
17398
  const config = new Map;
16542
- const listed = spawnSync11("git", [...invocation.config ?? [], "config", "-z", "--list"], {
17399
+ const listed = spawnSync12("git", [...invocation.config ?? [], "config", "-z", "--list"], {
16543
17400
  cwd: dir,
16544
17401
  encoding: "utf8",
16545
17402
  timeout: 3000,
@@ -16615,8 +17472,8 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
16615
17472
  const sub = invocation.args[0];
16616
17473
  if (invocation.tool !== "git" || invocation.dir === undefined || !sub || sub.startsWith("-") || GIT_COMMANDS.has(sub) || depth >= MAX_DEPTH)
16617
17474
  return [invocation];
16618
- const dir = path19.resolve(root, invocation.dir ?? ".");
16619
- if (!fs16.existsSync(dir))
17475
+ const dir = path21.resolve(root, invocation.dir ?? ".");
17476
+ if (!fs17.existsSync(dir))
16620
17477
  return [invocation];
16621
17478
  const config = gitConfig(dir, invocation, cache);
16622
17479
  const alias = configValue(config, `alias.${sub.toLowerCase()}`);
@@ -16638,11 +17495,11 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
16638
17495
  var normalizedUrl = (url, dir) => {
16639
17496
  const trimmed = url.trim();
16640
17497
  if (/^file:\/\//i.test(trimmed))
16641
- return path19.resolve(dir, trimmed.slice(7)).replace(/\/+$/, "").replace(/\.git$/, "");
17498
+ return path21.resolve(dir, trimmed.slice(7)).replace(/\/+$/, "").replace(/\.git$/, "");
16642
17499
  const scheme = /^[a-z][a-z0-9+.-]*:\/\//i.exec(trimmed);
16643
17500
  const scp = !scheme && /^(?:[^@/\\]+@)?[^/\\:]{2,}:/.test(trimmed);
16644
17501
  if (!scheme && !scp)
16645
- return path19.resolve(dir, trimmed).replace(/\/+$/, "").replace(/\.git$/, "");
17502
+ return path21.resolve(dir, trimmed).replace(/\/+$/, "").replace(/\.git$/, "");
16646
17503
  const value = scheme ? trimmed.slice(scheme[0].length).replace(/^[^@/]*@/, "").replace(/^([^/:]+):\d+(?=\/)/, "$1") : trimmed.replace(/^[^@/]*@/, "").replace(":", "/");
16647
17504
  return value.toLowerCase().replace(/\/{2,}/g, "/").replace(/^www\./, "").replace(/\/+$/, "").replace(/\.git$/, "");
16648
17505
  };
@@ -16662,7 +17519,7 @@ var rewrittenUrl = (url, config) => {
16662
17519
  }
16663
17520
  return url;
16664
17521
  };
16665
- var pushUrl = (config, remote, dir) => {
17522
+ var pushUrl2 = (config, remote, dir) => {
16666
17523
  const configured = configValue(config, `remote.${remote}.pushurl`) ?? configValue(config, `remote.${remote}.url`);
16667
17524
  return normalizedUrl(rewrittenUrl(configured ?? remote, config), dir);
16668
17525
  };
@@ -16690,7 +17547,7 @@ var toPushRemote = (repo, remote, config) => {
16690
17547
  const pushRemote = pushRemoteOf(config, repo.branch);
16691
17548
  if (pushRemote === null || pushRemote === remote)
16692
17549
  return true;
16693
- return pushUrl(config, remote, repo.dir) === pushUrl(config, pushRemote, repo.dir);
17550
+ return pushUrl2(config, remote, repo.dir) === pushUrl2(config, pushRemote, repo.dir);
16694
17551
  };
16695
17552
  var quote = (text) => `\`${text}\``;
16696
17553
  var refusal = (action, branch, dir) => {
@@ -16703,7 +17560,7 @@ var refusal = (action, branch, dir) => {
16703
17560
  };
16704
17561
  var refFacts = (repo, remote) => {
16705
17562
  const facts = { heads: new Set, tags: new Set, remoteHeads: new Set };
16706
- const listed = spawnSync11("git", ["for-each-ref", "--format=%(refname)", "refs/heads", "refs/tags", `refs/remotes/${remote}`], { cwd: repo.dir, encoding: "utf8", timeout: 5000 });
17563
+ const listed = spawnSync12("git", ["for-each-ref", "--format=%(refname)", "refs/heads", "refs/tags", `refs/remotes/${remote}`], { cwd: repo.dir, encoding: "utf8", timeout: 5000 });
16707
17564
  const remotePrefix = `refs/remotes/${remote}/`;
16708
17565
  for (const ref of (listed.stdout ?? "").split(`
16709
17566
  `)) {
@@ -16720,7 +17577,7 @@ var globBranches = (repo, glob) => {
16720
17577
  const source = glob.source.startsWith("refs/") ? glob.source : `refs/heads/${glob.source}`;
16721
17578
  const [sourcePrefix, sourceSuffix = ""] = source.split("*");
16722
17579
  const [destinationPrefix, destinationSuffix = ""] = glob.destination.split("*");
16723
- const listed = spawnSync11("git", [
17580
+ const listed = spawnSync12("git", [
16724
17581
  "for-each-ref",
16725
17582
  "--format=%(refname)",
16726
17583
  sourcePrefix.slice(0, sourcePrefix.lastIndexOf("/") + 1)
@@ -16797,7 +17654,7 @@ var tagRefusal = (action, facts, dir) => {
16797
17654
  return `workit: raw ${quote(`git push${action.allTags ? " --tags" : ""}`)} of ${tags.length ? `tag ${tags.join(", ")}` : "tags"} bypasses the release grant. Push a release tag with ${quote(`workit git push --release ${named}`)} (${shape} tags whose commit the production branch already has; a tag never moves), under the ${quote("release")} grant (if refused, ask the user to run ${quote("workit grant set <workspace> release=true")}).`;
16798
17655
  };
16799
17656
  var remoteHeads = (repo, remote) => {
16800
- const listed = spawnSync11("git", ["ls-remote", "--heads", remote], {
17657
+ const listed = spawnSync12("git", ["ls-remote", "--heads", remote], {
16801
17658
  cwd: repo.dir,
16802
17659
  encoding: "utf8",
16803
17660
  timeout: 3000,
@@ -16866,7 +17723,7 @@ var actionsIn = (cwd, command, dialect, cache = new Map) => {
16866
17723
  const out = [];
16867
17724
  const repos = new Map;
16868
17725
  const repoFor = (relative) => {
16869
- const dir = path19.resolve(cwd, relative ?? ".");
17726
+ const dir = path21.resolve(cwd, relative ?? ".");
16870
17727
  if (!repos.has(dir)) {
16871
17728
  const repo = repoAt(dir);
16872
17729
  repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
@@ -16952,7 +17809,7 @@ var analysisDenial = (error) => ({
16952
17809
  });
16953
17810
  var NEXT_COMMAND = "next";
16954
17811
  var MARKER_TTL_SECONDS = 3600;
16955
- var markerFile = (repo, session, key) => path19.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
17812
+ var markerFile = (repo, session, key) => path21.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
16956
17813
  var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash14("sha256").update(command).digest("hex")}`;
16957
17814
  function noteRawCommit(input, command, key) {
16958
17815
  try {
@@ -16963,14 +17820,14 @@ function noteRawCommit(input, command, key) {
16963
17820
  if (action.kind !== "commit")
16964
17821
  continue;
16965
17822
  const file = markerFile(repo, input.session.id, key);
16966
- fs16.mkdirSync(path19.dirname(file), { recursive: true });
16967
- fs16.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
17823
+ fs17.mkdirSync(path21.dirname(file), { recursive: true });
17824
+ fs17.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
16968
17825
  `);
16969
17826
  }
16970
17827
  } catch {}
16971
17828
  }
16972
17829
  var headCommit = (dir) => {
16973
- const run = spawnSync11("git", [
17830
+ const run = spawnSync12("git", [
16974
17831
  "log",
16975
17832
  "-1",
16976
17833
  "--format=%H%x1f%ct%x1f%s%x1f%(trailers:key=Workit-Session,valueonly,separator=%x2c)"
@@ -16987,11 +17844,11 @@ var headCommit = (dir) => {
16987
17844
  var settle2 = (input, repo, file) => {
16988
17845
  let marker;
16989
17846
  try {
16990
- marker = JSON.parse(fs16.readFileSync(file, "utf8"));
17847
+ marker = JSON.parse(fs17.readFileSync(file, "utf8"));
16991
17848
  } catch {
16992
17849
  return;
16993
17850
  }
16994
- fs16.rmSync(file, { force: true });
17851
+ fs17.rmSync(file, { force: true });
16995
17852
  const session = input.session.id;
16996
17853
  const now = Date.now() / 1000;
16997
17854
  if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
@@ -17040,7 +17897,7 @@ function settlePendingCommit(input) {
17040
17897
  if (!repo)
17041
17898
  return;
17042
17899
  const file = markerFile(repo, input.session.id, NEXT_COMMAND);
17043
- if (fs16.existsSync(file))
17900
+ if (fs17.existsSync(file))
17044
17901
  settle2(input, repo, file);
17045
17902
  } catch {}
17046
17903
  }
@@ -17184,7 +18041,7 @@ var targetsOf = (invocations) => invocations.flatMap((invocation) => invocation.
17184
18041
  branch,
17185
18042
  dir: invocation.dir
17186
18043
  })) : []);
17187
- var localBranchExists = (dir, branch) => spawnSync12("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`], {
18044
+ var localBranchExists = (dir, branch) => spawnSync13("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`], {
17188
18045
  cwd: dir,
17189
18046
  stdio: "ignore",
17190
18047
  timeout: 5000
@@ -17194,8 +18051,8 @@ var judgedDir = (root, dir) => {
17194
18051
  return null;
17195
18052
  if (dir === null)
17196
18053
  return root;
17197
- const resolved = path20.resolve(root, dir);
17198
- return existsSync6(resolved) && inWorkitWorkspace(resolved) ? resolved : null;
18054
+ const resolved = path22.resolve(root, dir);
18055
+ return existsSync7(resolved) && inWorkitWorkspace(resolved) ? resolved : null;
17199
18056
  };
17200
18057
  var shellBranchPolicyViolation = (root, command, dialect = "posix") => {
17201
18058
  let judged = false;
@@ -17430,7 +18287,7 @@ var judgeInputSummary = (raw) => {
17430
18287
 
17431
18288
  // packages/workit-core/src/autonomy.ts
17432
18289
  import os5 from "node:os";
17433
- import path21 from "node:path";
18290
+ import path23 from "node:path";
17434
18291
  var accountHome = () => {
17435
18292
  try {
17436
18293
  return os5.userInfo().homedir;
@@ -17439,10 +18296,10 @@ var accountHome = () => {
17439
18296
  }
17440
18297
  };
17441
18298
  var grantsHome = { resolve: accountHome };
17442
- var grantsDir = () => path21.join(grantsHome.resolve(), ".config", "workit");
18299
+ var grantsDir = () => path23.join(grantsHome.resolve(), ".config", "workit");
17443
18300
  var grantsOverride = () => {
17444
- const configured = path21.resolve(resolveConfigDir());
17445
- return configured === path21.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 ${path21.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
18301
+ const configured = path23.resolve(resolveConfigDir());
18302
+ return configured === path23.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 ${path23.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
17446
18303
  };
17447
18304
  var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
17448
18305
  var DEFAULT_GRANTS = Object.freeze({
@@ -17495,8 +18352,16 @@ function endpointView(entry, context) {
17495
18352
  ...issue ? { endpointIssue: issue } : {}
17496
18353
  };
17497
18354
  }
17498
- var DEFAULT_VERIFICATION = "self";
17499
- var verificationOf = (entry) => entry?.verification === "independent" ? "independent" : "self";
18355
+ var VERIFICATION_MODES = [
18356
+ "proportional",
18357
+ "self",
18358
+ "independent"
18359
+ ];
18360
+ var DEFAULT_VERIFICATION = "proportional";
18361
+ var verificationOf = (entry) => {
18362
+ const value = entry?.verification;
18363
+ return VERIFICATION_MODES.includes(value) ? value : DEFAULT_VERIFICATION;
18364
+ };
17500
18365
  var isGrantValue = (value) => value === true || value === false || value === "verified";
17501
18366
  var normalized = (kind, value) => value === "verified" && kind !== "merge" ? true : value;
17502
18367
  var fromAutoApprove = (value) => {
@@ -19243,9 +20108,9 @@ class WorkitCore {
19243
20108
  }
19244
20109
  }
19245
20110
  // packages/workit-core/src/core/repo-context.ts
19246
- import { spawnSync as spawnSync13 } from "node:child_process";
19247
- import { existsSync as existsSync7, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
19248
- import path22 from "node:path";
20111
+ import { spawnSync as spawnSync14 } from "node:child_process";
20112
+ import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "node:fs";
20113
+ import path24 from "node:path";
19249
20114
  var isSafeContextRange = (value) => value.length <= 4096 && (() => {
19250
20115
  try {
19251
20116
  gitRevisionParts(value);
@@ -19272,7 +20137,7 @@ var invalidRange = (cwd) => ({
19272
20137
  cwd
19273
20138
  });
19274
20139
  var runGit = (cwd, args) => {
19275
- const result = spawnSync13("git", args, { cwd, encoding: "utf8" });
20140
+ const result = spawnSync14("git", args, { cwd, encoding: "utf8" });
19276
20141
  return {
19277
20142
  stdout: (result.stdout ?? "").trimEnd(),
19278
20143
  stderr: (result.stderr ?? "").trimEnd(),
@@ -19379,7 +20244,7 @@ var findPrTemplate = (cwd) => {
19379
20244
  ]) {
19380
20245
  const parts = rel.split("/");
19381
20246
  const base = parts[parts.length - 1];
19382
- const dir = parts.length > 1 ? path22.join(cwd, ...parts.slice(0, -1)) : cwd;
20247
+ const dir = parts.length > 1 ? path24.join(cwd, ...parts.slice(0, -1)) : cwd;
19383
20248
  const actual = probeCaseInsensitive(dir, base);
19384
20249
  if (actual)
19385
20250
  return [...parts.slice(0, -1), actual].join("/");
@@ -19410,11 +20275,11 @@ var diffStatForRange = (cwd, range) => {
19410
20275
  return runGit(cwd, ["diff", "--stat", "--"]).stdout;
19411
20276
  };
19412
20277
  var packageScripts = (cwd, keys) => {
19413
- const pkgPath = path22.join(cwd, "package.json");
19414
- if (!existsSync7(pkgPath))
20278
+ const pkgPath = path24.join(cwd, "package.json");
20279
+ if (!existsSync8(pkgPath))
19415
20280
  return [];
19416
20281
  try {
19417
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
20282
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
19418
20283
  return keys.filter((k) => pkg.scripts && typeof pkg.scripts[k] === "string").map((k) => `${k}: ${pkg.scripts?.[k]}`);
19419
20284
  } catch {
19420
20285
  return [];
@@ -19436,9 +20301,9 @@ var documentationFiles = (cwd) => {
19436
20301
  if (entry.isDirectory()) {
19437
20302
  if (excluded.has(entry.name))
19438
20303
  continue;
19439
- walk(path22.join(dir, entry.name), depth + 1);
20304
+ walk(path24.join(dir, entry.name), depth + 1);
19440
20305
  } else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
19441
- matches.push("./" + path22.relative(cwd, path22.join(dir, entry.name)).replaceAll("\\", "/"));
20306
+ matches.push("./" + path24.relative(cwd, path24.join(dir, entry.name)).replaceAll("\\", "/"));
19442
20307
  }
19443
20308
  }
19444
20309
  };
@@ -19446,15 +20311,15 @@ var documentationFiles = (cwd) => {
19446
20311
  return matches.toSorted().slice(0, 200);
19447
20312
  };
19448
20313
  var readTrimmed2 = (file, maxLines) => {
19449
- if (!existsSync7(file))
20314
+ if (!existsSync8(file))
19450
20315
  return "";
19451
- const lines = readFileSync5(file, "utf8").split(`
20316
+ const lines = readFileSync6(file, "utf8").split(`
19452
20317
  `);
19453
20318
  return lines.slice(0, maxLines).join(`
19454
20319
  `);
19455
20320
  };
19456
20321
  function prReadyContext(root, range) {
19457
- const cwd = path22.resolve(repoRoot(root));
20322
+ const cwd = path24.resolve(repoRoot(root));
19458
20323
  if (range !== undefined && !isResolvableContextRange(cwd, range))
19459
20324
  return invalidRange(cwd);
19460
20325
  let stdout = "";
@@ -19512,7 +20377,7 @@ ${status.stderr}` : "");
19512
20377
  stdout += `template_path: ${template}
19513
20378
 
19514
20379
  `;
19515
- stdout += readTrimmed2(path22.join(cwd, template), 220);
20380
+ stdout += readTrimmed2(path24.join(cwd, template), 220);
19516
20381
  } else {
19517
20382
  stdout += `template_path: none
19518
20383
 
@@ -19522,7 +20387,7 @@ ${status.stderr}` : "");
19522
20387
  stdout += `
19523
20388
  `;
19524
20389
  stdout += printSection("Recent Validation Signals");
19525
- if (existsSync7(path22.join(cwd, "package.json"))) {
20390
+ if (existsSync8(path24.join(cwd, "package.json"))) {
19526
20391
  stdout += `package.json detected. Common scripts:
19527
20392
  `;
19528
20393
  const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
@@ -19531,7 +20396,7 @@ ${status.stderr}` : "");
19531
20396
  `) + `
19532
20397
  `;
19533
20398
  }
19534
- if (existsSync7(path22.join(cwd, "Cargo.toml")) || existsSync7(path22.join(cwd, "src-tauri/Cargo.toml"))) {
20399
+ if (existsSync8(path24.join(cwd, "Cargo.toml")) || existsSync8(path24.join(cwd, "src-tauri/Cargo.toml"))) {
19535
20400
  stdout += `Rust project detected.
19536
20401
  `;
19537
20402
  }
@@ -19564,7 +20429,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
19564
20429
  - Apply with the host-native editor, preserving the repository changelog conventions.
19565
20430
  - If Unreleased already has duplicate category headings, normalize_only first.`;
19566
20431
  function changelogContext(root, range) {
19567
- const cwd = path22.resolve(repoRoot(root));
20432
+ const cwd = path24.resolve(repoRoot(root));
19568
20433
  if (range !== undefined && !isResolvableContextRange(cwd, range))
19569
20434
  return invalidRange(cwd);
19570
20435
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -19582,8 +20447,8 @@ function changelogContext(root, range) {
19582
20447
  stdout += CHANGELOG_RULES + `
19583
20448
  `;
19584
20449
  stdout += printSection("Existing CHANGELOG.md");
19585
- const changelogPath = path22.join(cwd, "CHANGELOG.md");
19586
- if (existsSync7(changelogPath)) {
20450
+ const changelogPath = path24.join(cwd, "CHANGELOG.md");
20451
+ if (existsSync8(changelogPath)) {
19587
20452
  stdout += readTrimmed2(changelogPath, 260) + `
19588
20453
  `;
19589
20454
  } else {
@@ -19602,7 +20467,7 @@ function changelogContext(root, range) {
19602
20467
  return { stdout, stderr: "", exitCode: 0, cwd };
19603
20468
  }
19604
20469
  function docsRefreshContext(root, range) {
19605
- const cwd = path22.resolve(repoRoot(root));
20470
+ const cwd = path24.resolve(repoRoot(root));
19606
20471
  if (range !== undefined && !isResolvableContextRange(cwd, range))
19607
20472
  return invalidRange(cwd);
19608
20473
  const resolvedRange = rangeArgOrDefault(range, cwd);
@@ -19624,8 +20489,8 @@ function docsRefreshContext(root, range) {
19624
20489
  `) + `
19625
20490
  `;
19626
20491
  stdout += printSection("README Preview");
19627
- const readme = path22.join(cwd, "README.md");
19628
- if (existsSync7(readme)) {
20492
+ const readme = path24.join(cwd, "README.md");
20493
+ if (existsSync8(readme)) {
19629
20494
  stdout += readTrimmed2(readme, 220) + `
19630
20495
  `;
19631
20496
  } else {
@@ -19633,10 +20498,10 @@ function docsRefreshContext(root, range) {
19633
20498
  `;
19634
20499
  }
19635
20500
  stdout += printSection("Package Scripts");
19636
- const pkgPath = path22.join(cwd, "package.json");
19637
- if (existsSync7(pkgPath)) {
20501
+ const pkgPath = path24.join(cwd, "package.json");
20502
+ if (existsSync8(pkgPath)) {
19638
20503
  try {
19639
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
20504
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
19640
20505
  stdout += JSON.stringify({ name: pkg.name, version: pkg.version, scripts: pkg.scripts }, null, 2) + `
19641
20506
  `;
19642
20507
  } catch {}
@@ -19647,7 +20512,7 @@ function docsRefreshContext(root, range) {
19647
20512
  return { stdout, stderr: "", exitCode: 0, cwd };
19648
20513
  }
19649
20514
  function releaseNotesContext(root, rangeOrTag) {
19650
- const cwd = path22.resolve(repoRoot(root));
20515
+ const cwd = path24.resolve(repoRoot(root));
19651
20516
  if (!rangeOrTag) {
19652
20517
  return { stdout: "", stderr: `ERROR: release tag or range required
19653
20518
  `, exitCode: 1, cwd };
@@ -19685,7 +20550,7 @@ function releaseNotesContext(root, rangeOrTag) {
19685
20550
  `;
19686
20551
  stdout += printSection("Existing Release Files");
19687
20552
  for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
19688
- if (existsSync7(path22.join(cwd, rel)))
20553
+ if (existsSync8(path24.join(cwd, rel)))
19689
20554
  stdout += rel + `
19690
20555
  `;
19691
20556
  }
@@ -19714,46 +20579,6 @@ function releaseNotesContext(root, rangeOrTag) {
19714
20579
 
19715
20580
  // packages/workit-core/src/core/tracker-issues.ts
19716
20581
  import { spawnSync as spawnSync15 } from "node:child_process";
19717
-
19718
- // packages/workit-core/src/core/pr-create.ts
19719
- import fs17 from "node:fs";
19720
- import path23 from "node:path";
19721
- import { spawnSync as spawnSync14 } from "node:child_process";
19722
- // packages/workit-core/src/forge/pr-body.ts
19723
- function parseGhIssue(value) {
19724
- const m = /issues\/(\d+)/.exec(value);
19725
- return m ? m[1] : String(value).trim().replace(/^#/, "");
19726
- }
19727
-
19728
- // packages/workit-core/src/core/pr-create.ts
19729
- function whichOnPath(tool) {
19730
- const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
19731
- for (const dir of (process.env.PATH ?? "").split(path23.delimiter)) {
19732
- if (!dir)
19733
- continue;
19734
- for (const name of names) {
19735
- const candidate = path23.join(dir, name);
19736
- try {
19737
- fs17.accessSync(candidate, fs17.constants.X_OK);
19738
- return candidate;
19739
- } catch {}
19740
- }
19741
- }
19742
- return null;
19743
- }
19744
- var hostingCliAvailable = (provider) => whichOnPath(provider === "gitlab" ? "glab" : "gh") !== null;
19745
- var pushRemote = (cwd) => {
19746
- const result = spawnSync14("git", ["remote", "get-url", "--push", "--all", "origin"], {
19747
- cwd,
19748
- encoding: "utf8"
19749
- });
19750
- if (result.status !== 0)
19751
- return null;
19752
- const urls = (result.stdout ?? "").split(/\r?\n/u).map((url) => url.trim()).filter(Boolean);
19753
- return urls.length === 1 ? urls[0] : null;
19754
- };
19755
-
19756
- // packages/workit-core/src/core/tracker-issues.ts
19757
20582
  var repoPathFromRemote = (remote) => {
19758
20583
  let rest = (remote || "").trim().replace(/\/+$/, "");
19759
20584
  if (!rest)
@@ -19853,7 +20678,7 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
19853
20678
 
19854
20679
  // packages/workit-core/src/core/youtrack.ts
19855
20680
  import fs18 from "node:fs";
19856
- import path24 from "node:path";
20681
+ import path25 from "node:path";
19857
20682
 
19858
20683
  // packages/workit-core/src/core/templates.ts
19859
20684
  var repoRoot2 = assetRoot();
@@ -19866,8 +20691,8 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
19866
20691
  // packages/workit-core/src/core/youtrack.ts
19867
20692
  var ISSUE_RE = /^[A-Z]+-\d+$/;
19868
20693
  var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
19869
- var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path24.join(configDir(), "youtrack.json");
19870
- var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path24.join(resolveConfigDir(), "youtrack.json");
20694
+ var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path25.join(configDir(), "youtrack.json");
20695
+ var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path25.join(resolveConfigDir(), "youtrack.json");
19871
20696
  var youTrackTokenModeOk = (p) => {
19872
20697
  if (process.platform === "win32")
19873
20698
  return true;
@@ -19935,7 +20760,7 @@ var youTrackToken = () => {
19935
20760
  if ("error" in loaded)
19936
20761
  return loaded;
19937
20762
  const tokenFile = String(loaded.config.tokenFile ?? "");
19938
- const tokenPath = tokenFile ? path24.isAbsolute(tokenFile) ? path24.resolve(tokenFile) : path24.resolve(process.cwd(), tokenFile) : "";
20763
+ const tokenPath = tokenFile ? path25.isAbsolute(tokenFile) ? path25.resolve(tokenFile) : path25.resolve(process.cwd(), tokenFile) : "";
19939
20764
  if (!tokenPath || !fs18.existsSync(tokenPath))
19940
20765
  return { error: "missing youtrack.token" };
19941
20766
  if (!youTrackTokenModeOk(tokenPath))
@@ -20292,15 +21117,15 @@ function resolveGitRevision(root, value) {
20292
21117
  }
20293
21118
  function resolveInside(root, candidate) {
20294
21119
  const base = realpathSync5(root);
20295
- const target = path25.resolve(base, candidate);
20296
- if (target !== base && !target.startsWith(base + path25.sep)) {
21120
+ const target = path26.resolve(base, candidate);
21121
+ if (target !== base && !target.startsWith(base + path26.sep)) {
20297
21122
  throw new Error("path must stay inside repository root");
20298
21123
  }
20299
21124
  let ancestor = target;
20300
- while (!existsSync8(ancestor))
20301
- ancestor = path25.dirname(ancestor);
21125
+ while (!existsSync9(ancestor))
21126
+ ancestor = path26.dirname(ancestor);
20302
21127
  const canonicalAncestor = realpathSync5(ancestor);
20303
- if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path25.sep)) {
21128
+ if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path26.sep)) {
20304
21129
  throw new Error("path must stay inside repository root");
20305
21130
  }
20306
21131
  return target;
@@ -20346,7 +21171,7 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
20346
21171
  // packages/workit-core/src/hooks/context.ts
20347
21172
  import { createHash as createHash15 } from "node:crypto";
20348
21173
  import fs19 from "node:fs";
20349
- import path26 from "node:path";
21174
+ import path27 from "node:path";
20350
21175
  var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
20351
21176
  var migrationPending = (result) => !result.ok && result.code === "needs_input" && (result.error ?? "").startsWith(MIGRATION_PENDING);
20352
21177
  var boundTo = (entry, session) => entry.sessions.some((item) => item.host === session.host && item.handle === session.handle);
@@ -20431,7 +21256,7 @@ function entryCompactContext(store, entry, session, context) {
20431
21256
  return null;
20432
21257
  const freshness = { mode: "signal", current: () => recentSignal(store.root) };
20433
21258
  const observed = task?.data.evidence.some(isObservedCheck) ?? false;
20434
- const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path26.resolve(store.root, ref.path)] : []));
21259
+ const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path27.resolve(store.root, ref.path)] : []));
20435
21260
  const observedFiles = filesKey(files);
20436
21261
  const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
20437
21262
  if (!compact.ok || !compact.data)
@@ -20509,14 +21334,14 @@ var turnMarker = (input) => {
20509
21334
  if (location instanceof Error)
20510
21335
  return null;
20511
21336
  const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
20512
- return path26.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
21337
+ return path27.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
20513
21338
  } catch {
20514
21339
  return null;
20515
21340
  }
20516
21341
  };
20517
21342
  var writeTurnDigest = (file, digest) => {
20518
21343
  try {
20519
- fs19.mkdirSync(path26.dirname(file), { recursive: true });
21344
+ fs19.mkdirSync(path27.dirname(file), { recursive: true });
20520
21345
  fs19.writeFileSync(file, `${JSON.stringify({ digest })}
20521
21346
  `);
20522
21347
  } catch {}
@@ -20531,7 +21356,7 @@ var pruneTurnDigests = (dir, now) => {
20531
21356
  for (const name of fs19.readdirSync(dir)) {
20532
21357
  if (!name.startsWith("turn-"))
20533
21358
  continue;
20534
- const file = path26.join(dir, name);
21359
+ const file = path27.join(dir, name);
20535
21360
  try {
20536
21361
  if (now - fs19.statSync(file).mtimeMs > TURN_TTL_MS)
20537
21362
  fs19.rmSync(file, { force: true });
@@ -20561,7 +21386,7 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
20561
21386
  const file = turnMarker(input);
20562
21387
  if (!file)
20563
21388
  return;
20564
- pruneTurnDigests(path26.dirname(file), Date.now());
21389
+ pruneTurnDigests(path27.dirname(file), Date.now());
20565
21390
  if (text)
20566
21391
  writeTurnDigest(file, digestOf(text));
20567
21392
  else
@@ -20582,7 +21407,7 @@ var shellPolicy = (cwd, command, dialect = "posix") => {
20582
21407
  // packages/workit-core/src/core/heavy-rules.ts
20583
21408
  import fs20 from "node:fs";
20584
21409
  import os6 from "node:os";
20585
- import path27 from "node:path";
21410
+ import path28 from "node:path";
20586
21411
  var EMPTY2 = () => ({ deny: [], allow: [] });
20587
21412
  var readText2 = (file) => {
20588
21413
  try {
@@ -20623,19 +21448,19 @@ function parseJsonc(text) {
20623
21448
  return JSON.parse(out.replace(/,(\s*[}\]])/gu, "$1"));
20624
21449
  }
20625
21450
  function gitTop(cwd) {
20626
- for (let dir = path27.resolve(cwd);; dir = path27.dirname(dir)) {
20627
- if (fs20.existsSync(path27.join(dir, ".git")))
21451
+ for (let dir = path28.resolve(cwd);; dir = path28.dirname(dir)) {
21452
+ if (fs20.existsSync(path28.join(dir, ".git")))
20628
21453
  return dir;
20629
- if (path27.dirname(dir) === dir)
21454
+ if (path28.dirname(dir) === dir)
20630
21455
  return null;
20631
21456
  }
20632
21457
  }
20633
21458
  var projectDirs = (cwd) => {
20634
21459
  const top = gitTop(cwd);
20635
21460
  const dirs = [];
20636
- for (let dir = path27.resolve(cwd);; dir = path27.dirname(dir)) {
21461
+ for (let dir = path28.resolve(cwd);; dir = path28.dirname(dir)) {
20637
21462
  dirs.push(dir);
20638
- if (!top || dir === top || path27.dirname(dir) === dir)
21463
+ if (!top || dir === top || path28.dirname(dir) === dir)
20639
21464
  return dirs;
20640
21465
  }
20641
21466
  };
@@ -20647,12 +21472,12 @@ var CLAUDE_MANAGED = {
20647
21472
  };
20648
21473
  function claudeSettingsFiles(cwd, env, platform = process.platform) {
20649
21474
  const project = env.CLAUDE_PROJECT_DIR || gitTop(cwd) || cwd;
20650
- const user = env.CLAUDE_CONFIG_DIR || path27.join(homeOf(env), ".claude");
21475
+ const user = env.CLAUDE_CONFIG_DIR || path28.join(homeOf(env), ".claude");
20651
21476
  return [
20652
21477
  ...CLAUDE_MANAGED[platform] ? [CLAUDE_MANAGED[platform]] : [],
20653
- path27.join(user, "settings.json"),
20654
- path27.join(project, ".claude", "settings.json"),
20655
- path27.join(project, ".claude", "settings.local.json")
21478
+ path28.join(user, "settings.json"),
21479
+ path28.join(project, ".claude", "settings.json"),
21480
+ path28.join(project, ".claude", "settings.local.json")
20656
21481
  ];
20657
21482
  }
20658
21483
  var bashPattern = (entry) => {
@@ -20742,10 +21567,10 @@ var opencodeConfig = (value, rules) => {
20742
21567
  function opencodeRules(cwd, env = process.env) {
20743
21568
  const rules = EMPTY2();
20744
21569
  try {
20745
- const config = env.XDG_CONFIG_HOME || path27.join(homeOf(env), ".config");
21570
+ const config = env.XDG_CONFIG_HOME || path28.join(homeOf(env), ".config");
20746
21571
  const files = [
20747
- ...OPENCODE_NAMES.map((name) => path27.join(config, "opencode", name)),
20748
- ...projectDirs(cwd).flatMap((dir) => OPENCODE_NAMES.flatMap((name) => [path27.join(dir, name), path27.join(dir, ".opencode", name)])),
21572
+ ...OPENCODE_NAMES.map((name) => path28.join(config, "opencode", name)),
21573
+ ...projectDirs(cwd).flatMap((dir) => OPENCODE_NAMES.flatMap((name) => [path28.join(dir, name), path28.join(dir, ".opencode", name)])),
20749
21574
  ...env.OPENCODE_CONFIG ? [env.OPENCODE_CONFIG] : []
20750
21575
  ];
20751
21576
  for (const file of files) {
@@ -20789,9 +21614,9 @@ var codexRule = (body) => {
20789
21614
  function codexRules(cwd, env = process.env) {
20790
21615
  const rules = EMPTY2();
20791
21616
  try {
20792
- const home = env.CODEX_HOME || path27.join(homeOf(env), ".codex");
21617
+ const home = env.CODEX_HOME || path28.join(homeOf(env), ".codex");
20793
21618
  const top = gitTop(cwd) ?? cwd;
20794
- for (const dir of [path27.join(home, "rules"), path27.join(top, ".codex", "rules")]) {
21619
+ for (const dir of [path28.join(home, "rules"), path28.join(top, ".codex", "rules")]) {
20795
21620
  let files;
20796
21621
  try {
20797
21622
  files = fs20.readdirSync(dir).filter((name) => name.endsWith(".rules"));
@@ -20801,7 +21626,7 @@ function codexRules(cwd, env = process.env) {
20801
21626
  return "unreadable";
20802
21627
  }
20803
21628
  for (const name of files) {
20804
- const text = readText2(path27.join(dir, name)) ?? "";
21629
+ const text = readText2(path28.join(dir, name)) ?? "";
20805
21630
  for (const part of text.split(/\bprefix_rule\s*\(/u).slice(1)) {
20806
21631
  const rule = codexRule(part);
20807
21632
  if (!rule)
@@ -20820,8 +21645,8 @@ function cursorRules(cwd, env = process.env) {
20820
21645
  try {
20821
21646
  const top = gitTop(cwd) ?? cwd;
20822
21647
  for (const file of [
20823
- path27.join(homeOf(env), ".cursor", "cli-config.json"),
20824
- path27.join(top, ".cursor", "cli.json")
21648
+ path28.join(homeOf(env), ".cursor", "cli-config.json"),
21649
+ path28.join(top, ".cursor", "cli.json")
20825
21650
  ]) {
20826
21651
  const text = readText2(file);
20827
21652
  if (text === null)
@@ -20897,21 +21722,21 @@ function wrapAllowed(read, words, command, options = {}) {
20897
21722
  // packages/workit-core/src/core/heavy.ts
20898
21723
  import fs21 from "node:fs";
20899
21724
  import os7 from "node:os";
20900
- import path28 from "node:path";
21725
+ import path29 from "node:path";
20901
21726
  function stateDir(env, platform = process.platform) {
20902
21727
  if (env.WORKFLOW_TOOLKIT_STATE)
20903
21728
  return env.WORKFLOW_TOOLKIT_STATE;
20904
21729
  if (env.XDG_STATE_HOME)
20905
- return path28.join(env.XDG_STATE_HOME, "workit");
21730
+ return path29.join(env.XDG_STATE_HOME, "workit");
20906
21731
  const home = env.HOME || os7.homedir();
20907
21732
  if (platform === "darwin")
20908
- return path28.join(home, "Library", "Application Support", "workit");
21733
+ return path29.join(home, "Library", "Application Support", "workit");
20909
21734
  if (platform === "win32")
20910
- return path28.join(env.LOCALAPPDATA ?? path28.join(home, "AppData", "Local"), "workit");
20911
- return path28.join(home, ".local", "state", "workit");
21735
+ return path29.join(env.LOCALAPPDATA ?? path29.join(home, "AppData", "Local"), "workit");
21736
+ return path29.join(home, ".local", "state", "workit");
20912
21737
  }
20913
21738
  var HEAVY_COMMANDS_FILE = "heavy-commands.json";
20914
- var heavyCommandsFile = (env) => path28.join(stateDir(env), HEAVY_COMMANDS_FILE);
21739
+ var heavyCommandsFile = (env) => path29.join(stateDir(env), HEAVY_COMMANDS_FILE);
20915
21740
  var HEAVY_SCRIPT = /^(?:test|tests|t|tst|unit|integration|e2e|coverage|cov|lint|eslint|typecheck|type-check|types|tsc|check|verify|validate|build|compile|bundle|ci|sonar|cypress|playwright|jest|vitest|mocha|bench|benchmark|all)(?:$|[:_.-])/iu;
20916
21741
  var INFO_FLAGS = new Set(["--version", "-v", "-V", "--help", "-h", "help", "version"]);
20917
21742
  var WATCH_FLAG = /^(?:--watch(?:All)?(?:=.*)?|-w|--serve)$/u;
@@ -21186,7 +22011,7 @@ function machinePatterns(env) {
21186
22011
  return isRecord5(value) ? stringList(value.patterns) : [];
21187
22012
  }
21188
22013
  function repoPatterns(cwd) {
21189
- return repoHeavyCommands(gitTop(cwd) ?? path28.resolve(cwd));
22014
+ return repoHeavyCommands(gitTop(cwd) ?? path29.resolve(cwd));
21190
22015
  }
21191
22016
  function heavyLines(lines, options) {
21192
22017
  const found = [];
@@ -21264,12 +22089,12 @@ function heavyPlan(command, options) {
21264
22089
  }
21265
22090
  function workitOnPath2(env = process.env) {
21266
22091
  const names = process.platform === "win32" ? ["workit.exe", "workit.cmd", "workit"] : ["workit"];
21267
- for (const dir of (env.PATH ?? "").split(path28.delimiter))
22092
+ for (const dir of (env.PATH ?? "").split(path29.delimiter))
21268
22093
  for (const name of names) {
21269
22094
  if (!dir)
21270
22095
  continue;
21271
22096
  try {
21272
- fs21.accessSync(path28.join(dir, name), fs21.constants.X_OK);
22097
+ fs21.accessSync(path29.join(dir, name), fs21.constants.X_OK);
21273
22098
  return true;
21274
22099
  } catch {}
21275
22100
  }
@@ -21288,20 +22113,20 @@ function leaseRewrite(command) {
21288
22113
  // packages/workit-core/src/core/heavy-words.ts
21289
22114
  import fs22 from "node:fs";
21290
22115
  import os8 from "node:os";
21291
- import path29 from "node:path";
22116
+ import path30 from "node:path";
21292
22117
  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(" "));
21293
22118
  var wordsOf = (command) => command.split(/[\s;&|()<>`'"]+/u).map((word) => (word.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat)$/u, "")).filter(Boolean);
21294
22119
  var stateDir2 = (env) => {
21295
22120
  if (env.WORKFLOW_TOOLKIT_STATE)
21296
22121
  return env.WORKFLOW_TOOLKIT_STATE;
21297
22122
  if (env.XDG_STATE_HOME)
21298
- return path29.join(env.XDG_STATE_HOME, "workit");
22123
+ return path30.join(env.XDG_STATE_HOME, "workit");
21299
22124
  const home = env.HOME || os8.homedir();
21300
22125
  if (process.platform === "darwin")
21301
- return path29.join(home, "Library", "Application Support", "workit");
22126
+ return path30.join(home, "Library", "Application Support", "workit");
21302
22127
  if (process.platform === "win32")
21303
- return path29.join(env.LOCALAPPDATA ?? path29.join(home, "AppData", "Local"), "workit");
21304
- return path29.join(home, ".local", "state", "workit");
22128
+ return path30.join(env.LOCALAPPDATA ?? path30.join(home, "AppData", "Local"), "workit");
22129
+ return path30.join(home, ".local", "state", "workit");
21305
22130
  };
21306
22131
  var readJson2 = (file) => {
21307
22132
  try {
@@ -21312,15 +22137,15 @@ var readJson2 = (file) => {
21312
22137
  };
21313
22138
  var patternWords = (cwd, env) => {
21314
22139
  const patterns = [];
21315
- const machine = readJson2(path29.join(stateDir2(env), "heavy-commands.json"));
22140
+ const machine = readJson2(path30.join(stateDir2(env), "heavy-commands.json"));
21316
22141
  if (Array.isArray(machine?.patterns))
21317
22142
  patterns.push(...machine.patterns);
21318
- for (let dir = path29.resolve(cwd);; dir = path29.dirname(dir)) {
21319
- if (fs22.existsSync(path29.join(dir, ".git"))) {
22143
+ for (let dir = path30.resolve(cwd);; dir = path30.dirname(dir)) {
22144
+ if (fs22.existsSync(path30.join(dir, ".git"))) {
21320
22145
  patterns.push(...repoHeavyCommands(dir));
21321
22146
  break;
21322
22147
  }
21323
- if (path29.dirname(dir) === dir)
22148
+ if (path30.dirname(dir) === dir)
21324
22149
  break;
21325
22150
  }
21326
22151
  const words = new Set;
@@ -21390,16 +22215,16 @@ var splitDenial = (plan) => ({
21390
22215
  unblock: plan.unblock
21391
22216
  });
21392
22217
  // packages/workit-core/src/hooks/write-gate.ts
21393
- import { existsSync as existsSync9, realpathSync as realpathSync6 } from "node:fs";
22218
+ import { existsSync as existsSync10, realpathSync as realpathSync6 } from "node:fs";
21394
22219
  import os10 from "node:os";
21395
- import path31 from "node:path";
22220
+ import path32 from "node:path";
21396
22221
 
21397
22222
  // packages/workit-core/src/core/live-session.ts
21398
22223
  import { spawnSync as spawnSync17 } from "node:child_process";
21399
22224
  import { createHash as createHash16 } from "node:crypto";
21400
22225
  import fs23 from "node:fs";
21401
22226
  import os9 from "node:os";
21402
- import path30 from "node:path";
22227
+ import path31 from "node:path";
21403
22228
  var LIVE_SESSION_TTL_MS = 15 * 60000;
21404
22229
  var HEARTBEAT_EVERY_MS = 30000;
21405
22230
  var liveProbe = {
@@ -21473,15 +22298,15 @@ var liveOwner = (input, transport, env = process.env) => {
21473
22298
  };
21474
22299
  };
21475
22300
  var checkoutOf = (target) => {
21476
- let dir = path30.resolve(target);
21477
- while (!fs23.existsSync(dir) && path30.dirname(dir) !== dir)
21478
- dir = path30.dirname(dir);
22301
+ let dir = path31.resolve(target);
22302
+ while (!fs23.existsSync(dir) && path31.dirname(dir) !== dir)
22303
+ dir = path31.dirname(dir);
21479
22304
  if (fs23.existsSync(dir) && !fs23.statSync(dir).isDirectory())
21480
- dir = path30.dirname(dir);
21481
- const parts = dir.split(path30.sep);
22305
+ dir = path31.dirname(dir);
22306
+ const parts = dir.split(path31.sep);
21482
22307
  const dotGit = parts.lastIndexOf(".git");
21483
22308
  if (dotGit > 0)
21484
- dir = parts.slice(0, dotGit).join(path30.sep) || path30.sep;
22309
+ dir = parts.slice(0, dotGit).join(path31.sep) || path31.sep;
21485
22310
  const location = resolveStore(dir);
21486
22311
  if (location instanceof Error || !location.shared || !location.top)
21487
22312
  return null;
@@ -21491,9 +22316,9 @@ var checkoutOf = (target) => {
21491
22316
  } catch {}
21492
22317
  return top;
21493
22318
  };
21494
- var markerFile2 = (top) => path30.join(resolveStateDir(), "live-sessions", `${createHash16("sha256").update(checkoutKey(top)).digest("hex").slice(0, 32)}.json`);
22319
+ var markerFile2 = (top) => path31.join(resolveStateDir(), "live-sessions", `${createHash16("sha256").update(checkoutKey(top)).digest("hex").slice(0, 32)}.json`);
21495
22320
  var checkoutKey = (top, platform = process.platform) => {
21496
- let key = path30.resolve(top);
22321
+ let key = path31.resolve(top);
21497
22322
  try {
21498
22323
  key = fs23.realpathSync.native(key);
21499
22324
  } catch {}
@@ -21588,7 +22413,7 @@ var claimLiveSession = (target, owner, deps = {}) => {
21588
22413
  checkout,
21589
22414
  heartbeatAt: now.toISOString()
21590
22415
  };
21591
- fs23.mkdirSync(path30.dirname(file), { recursive: true });
22416
+ fs23.mkdirSync(path31.dirname(file), { recursive: true });
21592
22417
  const temp = `${file}.${process.pid}.tmp`;
21593
22418
  fs23.writeFileSync(temp, JSON.stringify(marker));
21594
22419
  fs23.renameSync(temp, file);
@@ -21600,22 +22425,22 @@ var NONE3 = { kind: "none" };
21600
22425
  var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
21601
22426
  var canonical2 = (file) => {
21602
22427
  let rest = "";
21603
- for (let dir = path31.resolve(file);; dir = path31.dirname(dir)) {
22428
+ for (let dir = path32.resolve(file);; dir = path32.dirname(dir)) {
21604
22429
  try {
21605
- return path31.join(realpathSync6.native(dir), rest);
22430
+ return path32.join(realpathSync6.native(dir), rest);
21606
22431
  } catch {
21607
- if (path31.dirname(dir) === dir)
21608
- return path31.resolve(file);
21609
- rest = rest ? path31.join(path31.basename(dir), rest) : path31.basename(dir);
22432
+ if (path32.dirname(dir) === dir)
22433
+ return path32.resolve(file);
22434
+ rest = rest ? path32.join(path32.basename(dir), rest) : path32.basename(dir);
21610
22435
  }
21611
22436
  }
21612
22437
  };
21613
22438
  var exempt = (cwd, root, file, plans) => {
21614
22439
  const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
21615
- const relative = path31.relative(fold(canonical2(root)), fold(canonical2(path31.resolve(cwd, file))));
21616
- if (relative.startsWith("..") || path31.isAbsolute(relative))
22440
+ const relative = path32.relative(fold(canonical2(root)), fold(canonical2(path32.resolve(cwd, file))));
22441
+ if (relative.startsWith("..") || path32.isAbsolute(relative))
21617
22442
  return true;
21618
- const posix = relative.split(path31.sep).join("/");
22443
+ const posix = relative.split(path32.sep).join("/");
21619
22444
  const segments = posix.split("/");
21620
22445
  return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
21621
22446
  };
@@ -21792,10 +22617,10 @@ var linkSources = (args, at) => {
21792
22617
  const sources = names.filter((name, index) => into >= 0 ? name !== dest : index < names.length - 1 || names.length === 1);
21793
22618
  const target = dest === undefined ? null : at(dest);
21794
22619
  const symbolic = args.some((arg) => /^-[a-zA-Z]*s|^--symbolic$/.test(arg));
21795
- const base = target === null ? null : into >= 0 || sources.length > 1 || existsSync9(target) || /[\\/]$/.test(dest ?? "") ? target : path31.dirname(target);
22620
+ const base = target === null ? null : into >= 0 || sources.length > 1 || existsSync10(target) || /[\\/]$/.test(dest ?? "") ? target : path32.dirname(target);
21796
22621
  return sources.flatMap((source) => {
21797
- if (symbolic && base !== null && !path31.isAbsolute(homeExpanded(source)))
21798
- return [path31.resolve(base, source)];
22622
+ if (symbolic && base !== null && !path32.isAbsolute(homeExpanded(source)))
22623
+ return [path32.resolve(base, source)];
21799
22624
  const resolved = at(source);
21800
22625
  return resolved ? [resolved] : [];
21801
22626
  });
@@ -21824,7 +22649,7 @@ var shellWrites = (command, depth = 0) => {
21824
22649
  return { writes: true, targets: unknown ? null : targets };
21825
22650
  };
21826
22651
  var cache2 = new Map;
21827
- var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path31.resolve(root, file)) ?? "-").join("\x00");
22652
+ var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path32.resolve(root, file)) ?? "-").join("\x00");
21828
22653
  var gateFor = (cwd) => {
21829
22654
  const store = new TaskStore(cwd);
21830
22655
  const listed = store.listTaskIndex();
@@ -21903,13 +22728,13 @@ var gitMutationDirs = (cwd, command, dialect) => {
21903
22728
  return [];
21904
22729
  if (sub === "stash" && ["list", "show"].includes(rest[0] ?? ""))
21905
22730
  return [];
21906
- return [path31.resolve(cwd, invocation.dir ?? ".")];
22731
+ return [path32.resolve(cwd, invocation.dir ?? ".")];
21907
22732
  });
21908
22733
  };
21909
22734
  var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
21910
22735
  var PUSHD2 = new Set(["pushd", "push-location"]);
21911
22736
  var POPD2 = new Set(["popd", "pop-location"]);
21912
- var UNKNOWN_DIR = path31.resolve(path31.parse(process.cwd()).root, ".workit-unknown-dir");
22737
+ var UNKNOWN_DIR = path32.resolve(path32.parse(process.cwd()).root, ".workit-unknown-dir");
21913
22738
  var cdInto = (dir, words, strict = false) => {
21914
22739
  const lost = strict ? UNKNOWN_DIR : undefined;
21915
22740
  const named = words.slice(1).find((word) => !word.startsWith("-") || word === "-");
@@ -21918,7 +22743,7 @@ var cdInto = (dir, words, strict = false) => {
21918
22743
  return lost;
21919
22744
  if (dir === undefined)
21920
22745
  return lost;
21921
- return target === undefined ? os10.homedir() : path31.resolve(dir, target);
22746
+ return target === undefined ? os10.homedir() : path32.resolve(dir, target);
21922
22747
  };
21923
22748
  var quoteWord2 = (word) => /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`;
21924
22749
  var homeExpanded = (file) => {
@@ -21932,7 +22757,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
21932
22757
  const groups = [];
21933
22758
  const at = (file) => {
21934
22759
  const home = homeExpanded(file);
21935
- return path31.isAbsolute(home) ? home : dir === undefined ? null : path31.resolve(dir, home);
22760
+ return path32.isAbsolute(home) ? home : dir === undefined ? null : path32.resolve(dir, home);
21936
22761
  };
21937
22762
  for (const segment of segmentsOf(command, dialect)) {
21938
22763
  if (segment.group === "open") {
@@ -21972,7 +22797,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
21972
22797
  for (const file of opaque ?? []) {
21973
22798
  const resolved = at(file);
21974
22799
  if (resolved)
21975
- targets.push(file === "." ? path31.join(resolved, DIR_TARGET) : resolved);
22800
+ targets.push(file === "." ? path32.join(resolved, DIR_TARGET) : resolved);
21976
22801
  }
21977
22802
  const ln = words.findIndex((word) => /^ln$/i.test(word.split(/[\\/]/).at(-1) ?? ""));
21978
22803
  if (ln >= 0 && words.slice(0, ln).every((word) => PREFIXES2.has(word)))
@@ -21987,7 +22812,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
21987
22812
  const edits = editsOf(segment.words);
21988
22813
  if (edits === null) {
21989
22814
  if (dir !== undefined)
21990
- targets.push(path31.join(dir, DIR_TARGET));
22815
+ targets.push(path32.join(dir, DIR_TARGET));
21991
22816
  } else
21992
22817
  for (const file of edits) {
21993
22818
  const resolved = at(file);
@@ -21998,20 +22823,20 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
21998
22823
  for (const invocation of workitInvocations(segment.words.map(quoteWord2).join(" "), "posix")) {
21999
22824
  const { at: runsIn, args } = workitCwd(dir, invocation);
22000
22825
  if (args[0] === "git" && MUTATING_WORKIT_GIT.has(args[1] ?? "") && !inert(args.slice(2), ""))
22001
- targets.push(path31.join(runsIn, DIR_TARGET));
22826
+ targets.push(path32.join(runsIn, DIR_TARGET));
22002
22827
  }
22003
22828
  }
22004
22829
  return targets;
22005
22830
  };
22006
22831
  var workitCwd = (dir, args) => {
22007
22832
  const { rest, cwd } = skipWorkitGlobals(args);
22008
- return { at: cwd === null ? dir : path31.resolve(dir, homeExpanded(cwd)), args: rest };
22833
+ return { at: cwd === null ? dir : path32.resolve(dir, homeExpanded(cwd)), args: rest };
22009
22834
  };
22010
22835
  var shellMutationTargets = (cwd, command, dialect = "posix", strict = false) => {
22011
22836
  try {
22012
22837
  return [
22013
22838
  ...segmentTargets(cwd, command, dialect, 0, strict),
22014
- ...gitMutationDirs(cwd, command, dialect).map((dir) => path31.join(dir, DIR_TARGET))
22839
+ ...gitMutationDirs(cwd, command, dialect).map((dir) => path32.join(dir, DIR_TARGET))
22015
22840
  ];
22016
22841
  } catch {
22017
22842
  return [];
@@ -22048,7 +22873,7 @@ var liveDeny = ({ marker, checkout, ageMs, file }) => {
22048
22873
  var guarded = (targets) => {
22049
22874
  const seen = new Set;
22050
22875
  return targets.filter((target) => {
22051
- const dir = path31.dirname(target);
22876
+ const dir = path32.dirname(target);
22052
22877
  if (seen.has(dir))
22053
22878
  return false;
22054
22879
  seen.add(dir);
@@ -22069,7 +22894,7 @@ var claimAll = (owner, targets, deps) => {
22069
22894
  for (const target of guarded(targets))
22070
22895
  claimLiveSession(target, owner, deps);
22071
22896
  };
22072
- var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) => path31.resolve(cwd, file)) : [path31.join(cwd, DIR_TARGET)];
22897
+ var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) => path32.resolve(cwd, file)) : [path32.join(cwd, DIR_TARGET)];
22073
22898
  var issuedTarget = (cwd, targets) => {
22074
22899
  const state = resolveStateDir();
22075
22900
  const found = targets.find((target) => underIssued(state, cwd, homeExpanded(target), process.platform, canonical2));
@@ -22077,7 +22902,7 @@ var issuedTarget = (cwd, targets) => {
22077
22902
  };
22078
22903
  var underIssued = (state, cwd, target, platform = process.platform, real = (file) => file) => {
22079
22904
  const win = platform === "win32";
22080
- const p = win ? path31.win32 : path31.posix;
22905
+ const p = win ? path32.win32 : path32.posix;
22081
22906
  const fold = (value) => win || platform === "darwin" ? value.toLowerCase() : value;
22082
22907
  const named = win ? target.replace(/^\/([a-zA-Z])(?=\/|$)/, "$1:") : target;
22083
22908
  const relative = p.relative(fold(real(p.resolve(state))), fold(real(p.resolve(cwd, named))));
@@ -22168,6 +22993,24 @@ function beforeWriteGate(cwd, paths) {
22168
22993
  }
22169
22994
  // packages/workit-core/src/hooks/stop.ts
22170
22995
  import { spawnSync as spawnSync18 } from "node:child_process";
22996
+
22997
+ // packages/workit-core/src/core/policy/current-judgment.ts
22998
+ function currentJudgment(cwd) {
22999
+ try {
23000
+ const store = new TaskStore(cwd);
23001
+ const listed = store.listTaskIndex();
23002
+ const key = store.currentKey();
23003
+ if (!listed.ok || !key.ok)
23004
+ return null;
23005
+ const entry = listed.data.filter((item) => item.key === key.data.key && item.status !== "closed").toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt))[0];
23006
+ const task = entry ? store.readTask(entry.id) : null;
23007
+ return task?.ok === true ? latestJudgment(task.data) : null;
23008
+ } catch {
23009
+ return null;
23010
+ }
23011
+ }
23012
+
23013
+ // packages/workit-core/src/hooks/stop.ts
22171
23014
  var NONE4 = { kind: "none" };
22172
23015
  var QUESTION = /[??؟](?=[\s*_`"')\]>]*(?:\s|$))|¿/;
22173
23016
  var OFFER = /\b(?:let me know|want me to|should I|shall I|would you like|do you want|if you(?:'d| would) like|may I|can I go ahead)\b/i;
@@ -22260,29 +23103,32 @@ var redChecks = (rows, pr, head, endpoint) => {
22260
23103
  reason: `PR #${pr}'s checks were last seen ${state} at ${short(head)}, and this workspace's endpoint is \`${endpoint}\`: run \`workit ci wait --pr ${pr}\`${state === "failing" ? " after fixing the failures `workit pr status` lists (then push)" : ""}.`
22261
23104
  };
22262
23105
  };
22263
- var taskJudgment = (cwd) => {
22264
- try {
22265
- const store = new TaskStore(cwd);
22266
- const listed = store.listTaskIndex();
22267
- const key = store.currentKey();
22268
- if (!listed.ok || !key.ok)
22269
- return null;
22270
- const entry = listed.data.filter((item) => item.key === key.data.key && item.status !== "closed").toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt))[0];
22271
- const task = entry ? store.readTask(entry.id) : null;
22272
- return task?.ok === true ? latestJudgment(task.data) : null;
22273
- } catch {
22274
- return null;
22275
- }
23106
+ var prBase = (rows) => {
23107
+ const seen = rows.findLast((row) => (row.type === "pr.status" || row.type === "pr.created") && row.observer === "workit_cli" && typeof row.base === "string");
23108
+ return typeof seen?.base === "string" ? seen.base : null;
22276
23109
  };
22277
- var unverified = (cwd, branch, all, descriptor, verification) => {
23110
+ var unverified = (cwd, branch, all, descriptor, verification, head) => {
22278
23111
  const check = checkVerdicts(cwd, branch, all);
22279
23112
  if (check.accepted.accepted || check.accepted.reasons.includes("failing_verdict"))
22280
23113
  return null;
22281
- const judgment = taskJudgment(cwd);
23114
+ const judgment = currentJudgment(cwd);
22282
23115
  const high = judgment?.riskTier === "high";
22283
- if (judgment && !judgment.behaviorChange && !high)
22284
- return null;
22285
- const independent = verification === "independent" || high;
23116
+ let independent;
23117
+ if (verification === "proportional") {
23118
+ const lane = branchLane(cwd, {
23119
+ base: prBase(all.filter((row) => row.branch === branch)),
23120
+ head,
23121
+ judgment
23122
+ });
23123
+ const need = laneNeed(lane.lane);
23124
+ if (need === "none")
23125
+ return null;
23126
+ independent = need === "non-author";
23127
+ } else {
23128
+ if (judgment && !judgment.behaviorChange && !high)
23129
+ return null;
23130
+ independent = verification === "independent" || high;
23131
+ }
22286
23132
  if (!independent && check.review === "self-reviewed")
22287
23133
  return null;
22288
23134
  const has = check.review === "self-reviewed" ? "only a self verdict" : "no current verdict";
@@ -22329,7 +23175,7 @@ function stopObligation(input, descriptor) {
22329
23175
  }
22330
23176
  if (!delivered || endpoint !== "green" && endpoint !== "merged")
22331
23177
  return null;
22332
- const left = unverified(input.cwd, branch, all, descriptor, autonomy.verification);
23178
+ const left = unverified(input.cwd, branch, all, descriptor, autonomy.verification, head);
22333
23179
  return left ? { ...left, head } : null;
22334
23180
  } catch {
22335
23181
  return null;
@@ -22627,9 +23473,9 @@ var writePaths = (input) => {
22627
23473
  };
22628
23474
  // packages/workit-core/src/hooks/standing.ts
22629
23475
  import fs24 from "node:fs";
22630
- import path32 from "node:path";
23476
+ import path33 from "node:path";
22631
23477
  var readPlans = (store) => {
22632
- const dir = path32.join(store, "fanouts");
23478
+ const dir = path33.join(store, "fanouts");
22633
23479
  let names;
22634
23480
  try {
22635
23481
  names = fs24.readdirSync(dir).filter((name) => name.endsWith(".json"));
@@ -22639,7 +23485,7 @@ var readPlans = (store) => {
22639
23485
  const plans = [];
22640
23486
  for (const name of names) {
22641
23487
  try {
22642
- const raw = JSON.parse(fs24.readFileSync(path32.join(dir, name), "utf8"));
23488
+ const raw = JSON.parse(fs24.readFileSync(path33.join(dir, name), "utf8"));
22643
23489
  if (typeof raw.name !== "string" || !Array.isArray(raw.slices))
22644
23490
  continue;
22645
23491
  const texts = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string" && item !== "") : [];
@@ -22765,40 +23611,40 @@ var cwdRewrite = (command) => {
22765
23611
  // packages/workit-core/src/hooks/worktree-confine.ts
22766
23612
  import { createHash as createHash17 } from "node:crypto";
22767
23613
  import fs25 from "node:fs";
22768
- import path33 from "node:path";
23614
+ import path34 from "node:path";
22769
23615
  var FANOUT_TOKEN_FILE = "workit-fanout-token";
22770
23616
  var NONE5 = { kind: "none" };
22771
23617
  var CASE_INSENSITIVE2 = process.platform === "darwin" || process.platform === "win32";
22772
23618
  var canonical3 = (file) => {
22773
23619
  let rest = "";
22774
- for (let dir = path33.resolve(file);; dir = path33.dirname(dir)) {
23620
+ for (let dir = path34.resolve(file);; dir = path34.dirname(dir)) {
22775
23621
  try {
22776
- return path33.join(fs25.realpathSync.native(dir), rest);
23622
+ return path34.join(fs25.realpathSync.native(dir), rest);
22777
23623
  } catch {
22778
- if (path33.dirname(dir) === dir)
22779
- return path33.resolve(file);
22780
- rest = rest ? path33.join(path33.basename(dir), rest) : path33.basename(dir);
23624
+ if (path34.dirname(dir) === dir)
23625
+ return path34.resolve(file);
23626
+ rest = rest ? path34.join(path34.basename(dir), rest) : path34.basename(dir);
22781
23627
  }
22782
23628
  }
22783
23629
  };
22784
23630
  var within = (child, parent) => {
22785
23631
  const fold = (value) => CASE_INSENSITIVE2 ? value.toLowerCase() : value;
22786
- const relative = path33.relative(fold(parent), fold(child));
22787
- return relative === "" || !relative.startsWith("..") && !path33.isAbsolute(relative);
23632
+ const relative = path34.relative(fold(parent), fold(child));
23633
+ return relative === "" || !relative.startsWith("..") && !path34.isAbsolute(relative);
22788
23634
  };
22789
23635
  var checkoutOf2 = (file) => {
22790
- for (let dir = canonical3(file);; dir = path33.dirname(dir)) {
22791
- const dotGit = path33.join(dir, ".git");
23636
+ for (let dir = canonical3(file);; dir = path34.dirname(dir)) {
23637
+ const dotGit = path34.join(dir, ".git");
22792
23638
  if (fs25.existsSync(dotGit)) {
22793
23639
  if (!fs25.statSync(dotGit).isFile())
22794
23640
  return { root: dir, workit: false };
22795
23641
  const admin = /^gitdir:\s*(.+)$/mu.exec(fs25.readFileSync(dotGit, "utf8"))?.[1]?.trim();
22796
23642
  return {
22797
23643
  root: dir,
22798
- workit: Boolean(admin) && fs25.existsSync(path33.join(path33.resolve(dir, admin), FANOUT_TOKEN_FILE))
23644
+ workit: Boolean(admin) && fs25.existsSync(path34.join(path34.resolve(dir, admin), FANOUT_TOKEN_FILE))
22799
23645
  };
22800
23646
  }
22801
- if (path33.dirname(dir) === dir)
23647
+ if (path34.dirname(dir) === dir)
22802
23648
  return null;
22803
23649
  }
22804
23650
  };
@@ -22810,8 +23656,8 @@ var workitWorktreeOf = (file) => {
22810
23656
  return null;
22811
23657
  }
22812
23658
  };
22813
- var bindingDir = () => path33.join(resolveStateDir(), "worktree-bind");
22814
- var bindingFile = (session, agentId) => path33.join(bindingDir(), `${createHash17("sha256").update(`${session}\x00${agentId}`).digest("hex").slice(0, 32)}.json`);
23659
+ var bindingDir = () => path34.join(resolveStateDir(), "worktree-bind");
23660
+ var bindingFile = (session, agentId) => path34.join(bindingDir(), `${createHash17("sha256").update(`${session}\x00${agentId}`).digest("hex").slice(0, 32)}.json`);
22815
23661
  var readBinding = (file) => {
22816
23662
  try {
22817
23663
  const value = JSON.parse(fs25.readFileSync(file, "utf8"));
@@ -22836,7 +23682,7 @@ var bind = (input, worktree) => {
22836
23682
  agentId,
22837
23683
  at: new Date().toISOString()
22838
23684
  };
22839
- fs25.mkdirSync(path33.dirname(file), { recursive: true });
23685
+ fs25.mkdirSync(path34.dirname(file), { recursive: true });
22840
23686
  fs25.writeFileSync(file, JSON.stringify(binding));
22841
23687
  try {
22842
23688
  if (inWorkitWorkspace(input.cwd))
@@ -22855,25 +23701,25 @@ var hostIsolated = (cwd, agentId) => {
22855
23701
  const checkout = checkoutOf2(cwd);
22856
23702
  if (!checkout)
22857
23703
  return false;
22858
- const dotGit = path33.join(checkout.root, ".git");
23704
+ const dotGit = path34.join(checkout.root, ".git");
22859
23705
  if (!fs25.statSync(dotGit).isFile())
22860
23706
  return false;
22861
23707
  const admin = /^gitdir:\s*(.+)$/mu.exec(fs25.readFileSync(dotGit, "utf8"))?.[1]?.trim();
22862
23708
  if (!admin)
22863
23709
  return false;
22864
- const adminDir = path33.resolve(checkout.root, admin);
22865
- const back = fs25.readFileSync(path33.join(adminDir, "gitdir"), "utf8").trim();
22866
- if (path33.relative(canonical3(path33.resolve(adminDir, back)), canonical3(dotGit)) !== "")
23710
+ const adminDir = path34.resolve(checkout.root, admin);
23711
+ const back = fs25.readFileSync(path34.join(adminDir, "gitdir"), "utf8").trim();
23712
+ if (path34.relative(canonical3(path34.resolve(adminDir, back)), canonical3(dotGit)) !== "")
22867
23713
  return false;
22868
- const common = path33.join(adminDir, "commondir");
22869
- const gitDir = fs25.existsSync(common) ? path33.resolve(adminDir, fs25.readFileSync(common, "utf8").trim()) : adminDir;
22870
- const expected = path33.join(path33.dirname(canonical3(gitDir)), ".claude", "worktrees", `agent-${agentId}`);
22871
- return path33.relative(canonical3(expected), checkout.root) === "";
23714
+ const common = path34.join(adminDir, "commondir");
23715
+ const gitDir = fs25.existsSync(common) ? path34.resolve(adminDir, fs25.readFileSync(common, "utf8").trim()) : adminDir;
23716
+ const expected = path34.join(path34.dirname(canonical3(gitDir)), ".claude", "worktrees", `agent-${agentId}`);
23717
+ return path34.relative(canonical3(expected), checkout.root) === "";
22872
23718
  } catch {
22873
23719
  return false;
22874
23720
  }
22875
23721
  };
22876
- var shown = (target) => path33.basename(target) === ".workit-live-target" ? path33.dirname(target) : target;
23722
+ var shown = (target) => path34.basename(target) === ".workit-live-target" ? path34.dirname(target) : target;
22877
23723
  var unboundDeny = (input, target) => {
22878
23724
  const unblock = "Work only in the worktree your brief names, which the lead made with `workit fanout worktree create <slice>`: edit files under it and run one verb per call against it (`workit --cwd <worktree> git commit -m … -- <paths>`, `workit --cwd <worktree> check <name>`). If your brief names no worktree, stop and report that to the lead.";
22879
23725
  return {
@@ -22903,7 +23749,7 @@ function confineImplementer(input, targets) {
22903
23749
  try {
22904
23750
  if (!input.session.agentId || hostIsolated(input.cwd, input.session.agentId))
22905
23751
  return NONE5;
22906
- if (targets.some((target) => within(path33.resolve(target), UNKNOWN_DIR)))
23752
+ if (targets.some((target) => within(path34.resolve(target), UNKNOWN_DIR)))
22907
23753
  return unknownDirDeny(input, boundWorktree(input));
22908
23754
  const bindings = canonical3(bindingDir());
22909
23755
  const judged = targets.map((named) => ({ named, real: canonical3(named) })).filter(({ real }) => within(real, bindings) || checkoutOf2(real) !== null);
@@ -23496,14 +24342,14 @@ var observeToolResult = (event, ctx) => {
23496
24342
  var skillPromptNudge = (prompt, ctx) => process.env.WORKIT_PI_WORKER_SESSION ? null : promptNudge(hookInput(ctx, { kind: "context.turn", prompt }), prompt);
23497
24343
 
23498
24344
  // packages/workit-pi/src/launches.ts
23499
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync6, readdirSync as readdirSync5, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
24345
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync7, readdirSync as readdirSync5, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
23500
24346
  import os11 from "node:os";
23501
- import path34 from "node:path";
24347
+ import path35 from "node:path";
23502
24348
  var launchDir = (root) => {
23503
24349
  const location = resolveStore(root);
23504
- return location instanceof Error ? null : path34.join(location.dir, "pi-launches");
24350
+ return location instanceof Error ? null : path35.join(location.dir, "pi-launches");
23505
24351
  };
23506
- var fileFor = (dir, workerId) => path34.join(dir, `${workerId.replace(/[^A-Za-z0-9-]/g, "_")}.json`);
24352
+ var fileFor = (dir, workerId) => path35.join(dir, `${workerId.replace(/[^A-Za-z0-9-]/g, "_")}.json`);
23507
24353
  var recordLaunch = (root, attempt) => {
23508
24354
  const dir = launchDir(root);
23509
24355
  if (!dir)
@@ -23549,7 +24395,7 @@ var abandonedLaunches = (root) => {
23549
24395
  const found = [];
23550
24396
  for (const name of names) {
23551
24397
  try {
23552
- const attempt = JSON.parse(readFileSync6(path34.join(dir, name), "utf8"));
24398
+ const attempt = JSON.parse(readFileSync7(path35.join(dir, name), "utf8"));
23553
24399
  if (typeof attempt.workerId === "string" && typeof attempt.session === "string") {
23554
24400
  if (!alive(attempt))
23555
24401
  found.push(attempt);