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