@brainervirus/workit-mcp 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/dist/index.js +1095 -136
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6620,11 +6620,11 @@ var require_dist = __commonJS(function(exports, module) {
|
|
|
6620
6620
|
|
|
6621
6621
|
// packages/workit-mcp/src/index.ts
|
|
6622
6622
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
6623
|
-
import
|
|
6623
|
+
import path24 from "node:path";
|
|
6624
6624
|
|
|
6625
6625
|
// packages/workit-mcp/src/server.ts
|
|
6626
|
-
import { existsSync as
|
|
6627
|
-
import
|
|
6626
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, realpathSync as realpathSync6 } from "node:fs";
|
|
6627
|
+
import path23 from "node:path";
|
|
6628
6628
|
|
|
6629
6629
|
// node_modules/zod/v4/core/util.js
|
|
6630
6630
|
function getEnumValues(entries) {
|
|
@@ -14937,8 +14937,8 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
|
14937
14937
|
|
|
14938
14938
|
// packages/workit-core/src/core.ts
|
|
14939
14939
|
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
14940
|
-
import { existsSync as
|
|
14941
|
-
import
|
|
14940
|
+
import { existsSync as existsSync8, realpathSync as realpathSync5 } from "node:fs";
|
|
14941
|
+
import path22 from "node:path";
|
|
14942
14942
|
|
|
14943
14943
|
// packages/workit-core/src/core/task-contract.ts
|
|
14944
14944
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -17234,7 +17234,7 @@ var workspaceConfigSchema = object2({
|
|
|
17234
17234
|
}).passthrough().optional(),
|
|
17235
17235
|
autoApprove: union([boolean2(), array(nonBlank)]).optional(),
|
|
17236
17236
|
defaultEndpoint: unknown().optional(),
|
|
17237
|
-
verification: _enum(["self", "independent"]).optional(),
|
|
17237
|
+
verification: _enum(["proportional", "self", "independent"]).optional(),
|
|
17238
17238
|
delegation: unknown().optional(),
|
|
17239
17239
|
trailers: boolean2().optional(),
|
|
17240
17240
|
liveSessionGuard: boolean2().optional(),
|
|
@@ -17775,6 +17775,144 @@ function resolveRef(cwd, ref) {
|
|
|
17775
17775
|
return null;
|
|
17776
17776
|
return line(git(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]));
|
|
17777
17777
|
}
|
|
17778
|
+
function originHeadRef(cwd) {
|
|
17779
|
+
return line(git(cwd, ["symbolic-ref", "-q", "--short", "refs/remotes/origin/HEAD"]));
|
|
17780
|
+
}
|
|
17781
|
+
function ownChangeDrift(cwd, range) {
|
|
17782
|
+
const before = diffRaw(cwd, range.fromFork, range.from);
|
|
17783
|
+
const after = diffRaw(cwd, range.toFork, range.to);
|
|
17784
|
+
if (!before || !after)
|
|
17785
|
+
return null;
|
|
17786
|
+
const judged = new Map(before.map((entry) => [entry.path, entry]));
|
|
17787
|
+
const current = new Map(after.map((entry) => [entry.path, entry]));
|
|
17788
|
+
const same = (a, b) => a !== undefined && b !== undefined && a.oldMode === b.oldMode && a.oldBlob === b.oldBlob && a.newMode === b.newMode && a.newBlob === b.newBlob;
|
|
17789
|
+
return [...new Set([...judged.keys(), ...current.keys()])].filter((file) => !same(judged.get(file), current.get(file))).toSorted();
|
|
17790
|
+
}
|
|
17791
|
+
function sameOwnChange(cwd, range) {
|
|
17792
|
+
const fromFork = mergeBase(cwd, range.fromBase, range.from);
|
|
17793
|
+
const toFork = mergeBase(cwd, range.toBase, range.to);
|
|
17794
|
+
if (!fromFork || !toFork)
|
|
17795
|
+
return false;
|
|
17796
|
+
return ownChangeDrift(cwd, { from: range.from, to: range.to, fromFork, toFork })?.length === 0;
|
|
17797
|
+
}
|
|
17798
|
+
var LANE_DIFF = [
|
|
17799
|
+
"-c",
|
|
17800
|
+
"core.quotePath=false",
|
|
17801
|
+
"diff",
|
|
17802
|
+
"--no-color",
|
|
17803
|
+
"--no-ext-diff",
|
|
17804
|
+
"--no-textconv",
|
|
17805
|
+
"--no-renames"
|
|
17806
|
+
];
|
|
17807
|
+
var laneRange = (fork, head) => {
|
|
17808
|
+
if (!safeArg(fork) || head !== null && !safeArg(head))
|
|
17809
|
+
return null;
|
|
17810
|
+
return head === null ? [fork] : [fork, head];
|
|
17811
|
+
};
|
|
17812
|
+
function diffNumstat(cwd, fork, head) {
|
|
17813
|
+
const range = laneRange(fork, head);
|
|
17814
|
+
if (!range)
|
|
17815
|
+
return null;
|
|
17816
|
+
const run = git(cwd, [...LANE_DIFF, "--numstat", "-z", ...range, "--"]);
|
|
17817
|
+
if (!run.ok)
|
|
17818
|
+
return null;
|
|
17819
|
+
const out = [];
|
|
17820
|
+
for (const record of run.stdout.split("\x00")) {
|
|
17821
|
+
const match = /^(-|\d+)\t(-|\d+)\t(.+)$/su.exec(record.replace(/^\n/u, ""));
|
|
17822
|
+
if (!match)
|
|
17823
|
+
continue;
|
|
17824
|
+
const binary = match[1] === "-";
|
|
17825
|
+
out.push({
|
|
17826
|
+
path: match[3],
|
|
17827
|
+
added: binary ? 0 : Number(match[1]),
|
|
17828
|
+
deleted: binary ? 0 : Number(match[2]),
|
|
17829
|
+
binary
|
|
17830
|
+
});
|
|
17831
|
+
}
|
|
17832
|
+
return out;
|
|
17833
|
+
}
|
|
17834
|
+
function diffRaw(cwd, fork, head) {
|
|
17835
|
+
const range = laneRange(fork, head);
|
|
17836
|
+
if (!range)
|
|
17837
|
+
return null;
|
|
17838
|
+
const run = git(cwd, [...LANE_DIFF, "--raw", "-z", "--no-abbrev", ...range, "--"]);
|
|
17839
|
+
if (!run.ok)
|
|
17840
|
+
return null;
|
|
17841
|
+
const fields = run.stdout.split("\x00");
|
|
17842
|
+
const out = [];
|
|
17843
|
+
for (let index = 0;index + 1 < fields.length; index += 2) {
|
|
17844
|
+
const meta = /^:(\d{6}) (\d{6}) ([0-9a-f]+) ([0-9a-f]+) [A-Z]\d*$/u.exec(fields[index].replace(/^\n/u, ""));
|
|
17845
|
+
if (!meta)
|
|
17846
|
+
return null;
|
|
17847
|
+
out.push({
|
|
17848
|
+
path: fields[index + 1],
|
|
17849
|
+
oldMode: meta[1],
|
|
17850
|
+
newMode: meta[2],
|
|
17851
|
+
oldBlob: meta[3],
|
|
17852
|
+
newBlob: meta[4]
|
|
17853
|
+
});
|
|
17854
|
+
}
|
|
17855
|
+
return out;
|
|
17856
|
+
}
|
|
17857
|
+
function readBlobs(cwd, ids) {
|
|
17858
|
+
const out = new Map;
|
|
17859
|
+
const wanted = [...new Set(ids)].filter((id) => /^[0-9a-f]{40,64}$/u.test(id));
|
|
17860
|
+
if (!wanted.length)
|
|
17861
|
+
return out;
|
|
17862
|
+
const run = spawnSync3("git", ["cat-file", "--batch"], {
|
|
17863
|
+
cwd,
|
|
17864
|
+
input: `${wanted.join(`
|
|
17865
|
+
`)}
|
|
17866
|
+
`,
|
|
17867
|
+
maxBuffer: MAX_BUFFER,
|
|
17868
|
+
timeout: GIT_TIMEOUTS.local,
|
|
17869
|
+
killSignal: "SIGKILL",
|
|
17870
|
+
windowsHide: true
|
|
17871
|
+
});
|
|
17872
|
+
if (run.status !== 0 || !run.stdout)
|
|
17873
|
+
return null;
|
|
17874
|
+
const bytes = run.stdout;
|
|
17875
|
+
let at = 0;
|
|
17876
|
+
for (const id of wanted) {
|
|
17877
|
+
const end = bytes.indexOf(10, at);
|
|
17878
|
+
if (end < 0)
|
|
17879
|
+
return null;
|
|
17880
|
+
const header = bytes.subarray(at, end).toString("utf8").split(" ");
|
|
17881
|
+
at = end + 1;
|
|
17882
|
+
if (header[1] === "missing")
|
|
17883
|
+
continue;
|
|
17884
|
+
const size = Number(header[2]);
|
|
17885
|
+
if (header[0] !== id || !Number.isSafeInteger(size))
|
|
17886
|
+
return null;
|
|
17887
|
+
out.set(id, bytes.subarray(at, at + size));
|
|
17888
|
+
at += size + 1;
|
|
17889
|
+
}
|
|
17890
|
+
return out;
|
|
17891
|
+
}
|
|
17892
|
+
function treeFilesNamed(cwd, rev, name) {
|
|
17893
|
+
if (!safeArg(rev))
|
|
17894
|
+
return null;
|
|
17895
|
+
const run = git(cwd, ["ls-tree", "-r", "-z", "--full-tree", rev]);
|
|
17896
|
+
if (!run.ok)
|
|
17897
|
+
return null;
|
|
17898
|
+
const out = new Map;
|
|
17899
|
+
for (const record of run.stdout.split("\x00")) {
|
|
17900
|
+
const match = /^\d{6} blob ([0-9a-f]+)\t(.+)$/su.exec(record);
|
|
17901
|
+
if (match && (match[2] === name || match[2].endsWith(`/${name}`)))
|
|
17902
|
+
out.set(match[2], match[1]);
|
|
17903
|
+
}
|
|
17904
|
+
return out;
|
|
17905
|
+
}
|
|
17906
|
+
function fileAt(cwd, rev, file) {
|
|
17907
|
+
if (!safeArg(rev))
|
|
17908
|
+
return null;
|
|
17909
|
+
const run = git(cwd, ["cat-file", "blob", `${rev}:${file}`]);
|
|
17910
|
+
return run.ok ? run.stdout : null;
|
|
17911
|
+
}
|
|
17912
|
+
function untrackedFiles(cwd) {
|
|
17913
|
+
const run = git(cwd, ["ls-files", "-z", "--others", "--exclude-standard"]);
|
|
17914
|
+
return run.ok ? run.stdout.split("\x00").filter(Boolean) : [];
|
|
17915
|
+
}
|
|
17778
17916
|
var config2 = (cwd, key) => line(git(cwd, ["config", "--get", key]));
|
|
17779
17917
|
function currentBranch(cwd) {
|
|
17780
17918
|
return line(git(cwd, ["symbolic-ref", "--short", "-q", "HEAD"]));
|
|
@@ -21285,7 +21423,7 @@ var workerBlocksTransition = (transition, state) => transition === "pause" ? fal
|
|
|
21285
21423
|
import { createHash as createHash10 } from "node:crypto";
|
|
21286
21424
|
import * as fs13 from "node:fs";
|
|
21287
21425
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
21288
|
-
import
|
|
21426
|
+
import path17 from "node:path";
|
|
21289
21427
|
|
|
21290
21428
|
// packages/workit-core/src/check-config.ts
|
|
21291
21429
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
@@ -21505,14 +21643,757 @@ function checkCommand(args, version, onPath = workitAvailable()) {
|
|
|
21505
21643
|
}
|
|
21506
21644
|
|
|
21507
21645
|
// packages/workit-core/src/core/policy/derive.ts
|
|
21508
|
-
import { existsSync as
|
|
21509
|
-
import
|
|
21646
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
21647
|
+
import path16 from "node:path";
|
|
21510
21648
|
|
|
21511
21649
|
// packages/workit-core/src/ledger.ts
|
|
21512
21650
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
21513
21651
|
import { createHash as createHash9, randomBytes as randomBytes3 } from "node:crypto";
|
|
21514
21652
|
import fs12 from "node:fs";
|
|
21653
|
+
import path15 from "node:path";
|
|
21654
|
+
|
|
21655
|
+
// packages/workit-core/src/core/policy/lane.ts
|
|
21656
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
21515
21657
|
import path14 from "node:path";
|
|
21658
|
+
|
|
21659
|
+
// packages/workit-core/src/git/default-base.ts
|
|
21660
|
+
var safeRef = (value) => value.length > 0 && !value.startsWith("-");
|
|
21661
|
+
var trackTrunk = (cwd) => {
|
|
21662
|
+
try {
|
|
21663
|
+
const resolved = vcsConfig("resolve", cwd);
|
|
21664
|
+
if (resolved.ok === false || !resolved.releaseTrack || resolved.releaseTrack.blocking)
|
|
21665
|
+
return null;
|
|
21666
|
+
const target = String(resolved.defaultTargetBranch ?? "").trim();
|
|
21667
|
+
return target && safeRef(target) ? target : null;
|
|
21668
|
+
} catch {
|
|
21669
|
+
return null;
|
|
21670
|
+
}
|
|
21671
|
+
};
|
|
21672
|
+
function defaultBase(cwd) {
|
|
21673
|
+
const trunk = trackTrunk(cwd);
|
|
21674
|
+
if (trunk) {
|
|
21675
|
+
for (const candidate of [`origin/${trunk}`, trunk])
|
|
21676
|
+
if (resolveRef(cwd, candidate))
|
|
21677
|
+
return candidate;
|
|
21678
|
+
}
|
|
21679
|
+
const originHead = originHeadRef(cwd);
|
|
21680
|
+
if (originHead && resolveRef(cwd, originHead))
|
|
21681
|
+
return originHead;
|
|
21682
|
+
for (const candidate of [
|
|
21683
|
+
"origin/main",
|
|
21684
|
+
"origin/master",
|
|
21685
|
+
"main",
|
|
21686
|
+
"master",
|
|
21687
|
+
"origin/develop",
|
|
21688
|
+
"develop"
|
|
21689
|
+
])
|
|
21690
|
+
if (resolveRef(cwd, candidate))
|
|
21691
|
+
return candidate;
|
|
21692
|
+
return null;
|
|
21693
|
+
}
|
|
21694
|
+
|
|
21695
|
+
// packages/workit-core/src/core/policy/attributes.ts
|
|
21696
|
+
function patternRegex(dir, pattern) {
|
|
21697
|
+
if (!pattern || pattern.endsWith("/") || pattern.startsWith('"') || pattern.startsWith("!"))
|
|
21698
|
+
return null;
|
|
21699
|
+
const anchored = pattern.includes("/");
|
|
21700
|
+
const body = pattern.replace(/^\//u, "");
|
|
21701
|
+
let source = "";
|
|
21702
|
+
for (let index = 0;index < body.length; index += 1) {
|
|
21703
|
+
const char = body[index];
|
|
21704
|
+
if (char === "*" && body[index + 1] === "*") {
|
|
21705
|
+
const slash = body[index + 2] === "/";
|
|
21706
|
+
source += slash ? "(?:.*/)?" : ".*";
|
|
21707
|
+
index += slash ? 2 : 1;
|
|
21708
|
+
} else if (char === "*")
|
|
21709
|
+
source += "[^/]*";
|
|
21710
|
+
else if (char === "?")
|
|
21711
|
+
source += "[^/]";
|
|
21712
|
+
else if (char === "[") {
|
|
21713
|
+
const end = body.indexOf("]", index + 2);
|
|
21714
|
+
if (end < 0)
|
|
21715
|
+
return null;
|
|
21716
|
+
const set = body.slice(index + 1, end).replace(/^!/u, "^").replace(/\\/gu, "\\\\");
|
|
21717
|
+
source += `[${set}]`;
|
|
21718
|
+
index = end;
|
|
21719
|
+
} else if (char === "\\" && index + 1 < body.length) {
|
|
21720
|
+
source += body[index + 1].replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
|
|
21721
|
+
index += 1;
|
|
21722
|
+
} else
|
|
21723
|
+
source += char.replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
|
|
21724
|
+
}
|
|
21725
|
+
const prefix = dir ? `${dir.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}/` : "";
|
|
21726
|
+
try {
|
|
21727
|
+
return new RegExp(anchored ? `^${prefix}${source}$` : `^${prefix}(?:.*/)?${source}$`, "u");
|
|
21728
|
+
} catch {
|
|
21729
|
+
return null;
|
|
21730
|
+
}
|
|
21731
|
+
}
|
|
21732
|
+
function rulesOf(dir, text) {
|
|
21733
|
+
const out = [];
|
|
21734
|
+
for (const raw of text.split(`
|
|
21735
|
+
`)) {
|
|
21736
|
+
const line = raw.trim();
|
|
21737
|
+
if (!line || line.startsWith("#") || line.startsWith("[attr]"))
|
|
21738
|
+
continue;
|
|
21739
|
+
const [pattern, ...attributes] = line.split(/\s+/u);
|
|
21740
|
+
let generated = null;
|
|
21741
|
+
for (const attribute of attributes) {
|
|
21742
|
+
if (attribute === "linguist-generated" || attribute === "linguist-generated=true")
|
|
21743
|
+
generated = true;
|
|
21744
|
+
else if (attribute === "-linguist-generated" || attribute === "!linguist-generated" || attribute.startsWith("linguist-generated="))
|
|
21745
|
+
generated = false;
|
|
21746
|
+
}
|
|
21747
|
+
if (generated === null)
|
|
21748
|
+
continue;
|
|
21749
|
+
const regex = patternRegex(dir, pattern);
|
|
21750
|
+
if (regex)
|
|
21751
|
+
out.push({ regex, generated });
|
|
21752
|
+
}
|
|
21753
|
+
return out;
|
|
21754
|
+
}
|
|
21755
|
+
function generatedByAttributes(files, paths) {
|
|
21756
|
+
const rules = [...files].map(([file, text]) => {
|
|
21757
|
+
const dir = file.includes("/") ? file.slice(0, file.lastIndexOf("/")) : "";
|
|
21758
|
+
return {
|
|
21759
|
+
depth: dir ? dir.split("/").length : 0,
|
|
21760
|
+
rules: rulesOf(dir, text)
|
|
21761
|
+
};
|
|
21762
|
+
}).toSorted((left, right) => left.depth - right.depth).flatMap((entry) => entry.rules);
|
|
21763
|
+
const out = new Set;
|
|
21764
|
+
for (const file of paths) {
|
|
21765
|
+
const last = rules.findLast((rule) => rule.regex.test(file));
|
|
21766
|
+
if (last?.generated)
|
|
21767
|
+
out.add(file);
|
|
21768
|
+
}
|
|
21769
|
+
return out;
|
|
21770
|
+
}
|
|
21771
|
+
|
|
21772
|
+
// packages/workit-core/src/core/policy/substance.ts
|
|
21773
|
+
var SLASH_BLOCK = [["/*", "*/"]];
|
|
21774
|
+
var C_LIKE = { line: ["//"], block: SLASH_BLOCK, quotes: `"'` };
|
|
21775
|
+
var SYNTAXES = Object.fromEntries([
|
|
21776
|
+
...["ts", "mts", "cts", "js", "mjs", "cjs"].map((ext) => [ext, { ...C_LIKE, js: true }]),
|
|
21777
|
+
...["java", "kt", "kts", "scala", "swift", "dart", "groovy"].map((ext) => [
|
|
21778
|
+
ext,
|
|
21779
|
+
{ ...C_LIKE, triple: true }
|
|
21780
|
+
]),
|
|
21781
|
+
["go", { ...C_LIKE, rawBacktick: true }],
|
|
21782
|
+
...["css", "scss", "less"].map((ext) => [
|
|
21783
|
+
ext,
|
|
21784
|
+
{ line: [], block: SLASH_BLOCK, quotes: `"'`, cssUrl: true }
|
|
21785
|
+
]),
|
|
21786
|
+
...["py", "pyi"].map((ext) => [
|
|
21787
|
+
ext,
|
|
21788
|
+
{ line: ["#"], block: [], quotes: `"'`, triple: true, indented: true, fstring: true }
|
|
21789
|
+
]),
|
|
21790
|
+
["toml", { line: ["#"], block: [], quotes: `"`, literal: "'", triple: true }],
|
|
21791
|
+
...["html", "htm", "xml", "svg", "xhtml"].map((ext) => [
|
|
21792
|
+
ext,
|
|
21793
|
+
{ line: [], block: [["<!--", "-->"]], quotes: "", indented: true }
|
|
21794
|
+
])
|
|
21795
|
+
]);
|
|
21796
|
+
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;
|
|
21797
|
+
var extensionOf = (file) => {
|
|
21798
|
+
const name = file.slice(file.lastIndexOf("/") + 1);
|
|
21799
|
+
const dot = name.lastIndexOf(".");
|
|
21800
|
+
return dot > 0 ? name.slice(dot + 1).toLowerCase() : "";
|
|
21801
|
+
};
|
|
21802
|
+
var CI_PATH = /^\.github\/|(?:^|\/)(?:\.gitlab-ci\.ya?ml|Jenkinsfile|azure-pipelines\.ya?ml|\.pre-commit-config\.ya?ml|\.circleci\/.*)$/u;
|
|
21803
|
+
var syntaxOf = (file) => CI_PATH.test(file) ? null : SYNTAXES[extensionOf(file)] ?? null;
|
|
21804
|
+
var SPACE = /[ \t\r\f\v]/u;
|
|
21805
|
+
var WORD = /[\w$]/u;
|
|
21806
|
+
var NO_SPACE_AFTER = "([{,;";
|
|
21807
|
+
var NO_SPACE_BEFORE = ")]},;";
|
|
21808
|
+
var REGEX_AFTER = "(,=:[!&|?{};+-*%<>~^";
|
|
21809
|
+
var REGEX_KEYWORDS = new Set([
|
|
21810
|
+
"return",
|
|
21811
|
+
"typeof",
|
|
21812
|
+
"instanceof",
|
|
21813
|
+
"case",
|
|
21814
|
+
"do",
|
|
21815
|
+
"else",
|
|
21816
|
+
"in",
|
|
21817
|
+
"of",
|
|
21818
|
+
"new",
|
|
21819
|
+
"delete",
|
|
21820
|
+
"void",
|
|
21821
|
+
"throw",
|
|
21822
|
+
"yield",
|
|
21823
|
+
"await"
|
|
21824
|
+
]);
|
|
21825
|
+
function substanceOf(file, text) {
|
|
21826
|
+
const syntax = syntaxOf(file);
|
|
21827
|
+
if (!syntax)
|
|
21828
|
+
return plainSubstance(text);
|
|
21829
|
+
const markup = syntax.block.some(([open]) => open === "<!--");
|
|
21830
|
+
if (markup && (/<(?:script|style)\b|<!\[CDATA\[|<\?/iu.test(text) || /[^>\s][ \t]*<!--/u.test(text)))
|
|
21831
|
+
return plainSubstance(text);
|
|
21832
|
+
return lex(syntax, text);
|
|
21833
|
+
}
|
|
21834
|
+
function plainSubstance(text) {
|
|
21835
|
+
return text.split(`
|
|
21836
|
+
`).map((line) => line.replace(/[ \t\r\f\v]+$/u, "")).filter(Boolean).join(`
|
|
21837
|
+
`);
|
|
21838
|
+
}
|
|
21839
|
+
function lex(syntax, text) {
|
|
21840
|
+
const collapse = !syntax.indented;
|
|
21841
|
+
let out = "";
|
|
21842
|
+
let lineStart = 0;
|
|
21843
|
+
let kept = 0;
|
|
21844
|
+
let pendingSpace = false;
|
|
21845
|
+
const frames = [{ kind: "code", braces: 0 }];
|
|
21846
|
+
let index = 0;
|
|
21847
|
+
if (text.startsWith("#!")) {
|
|
21848
|
+
const end = text.indexOf(`
|
|
21849
|
+
`);
|
|
21850
|
+
out = end < 0 ? text : text.slice(0, end);
|
|
21851
|
+
kept = out.length;
|
|
21852
|
+
index = end < 0 ? text.length : end;
|
|
21853
|
+
}
|
|
21854
|
+
const emitCode = (chunk) => {
|
|
21855
|
+
if (collapse && pendingSpace && out.length > lineStart) {
|
|
21856
|
+
const before = out[out.length - 1];
|
|
21857
|
+
if (!NO_SPACE_AFTER.includes(before) && !NO_SPACE_BEFORE.includes(chunk[0]))
|
|
21858
|
+
out += " ";
|
|
21859
|
+
}
|
|
21860
|
+
pendingSpace = false;
|
|
21861
|
+
out += chunk;
|
|
21862
|
+
};
|
|
21863
|
+
const emitVerbatim = (chunk) => {
|
|
21864
|
+
emitCode(chunk);
|
|
21865
|
+
kept = out.length;
|
|
21866
|
+
};
|
|
21867
|
+
const newline = () => {
|
|
21868
|
+
if (!collapse) {
|
|
21869
|
+
let end = out.length;
|
|
21870
|
+
while (end > Math.max(lineStart, kept) && SPACE.test(out[end - 1]))
|
|
21871
|
+
end -= 1;
|
|
21872
|
+
out = out.slice(0, end);
|
|
21873
|
+
}
|
|
21874
|
+
pendingSpace = false;
|
|
21875
|
+
if (out.length > lineStart) {
|
|
21876
|
+
out += `
|
|
21877
|
+
`;
|
|
21878
|
+
lineStart = out.length;
|
|
21879
|
+
}
|
|
21880
|
+
};
|
|
21881
|
+
const regexAllowed = () => {
|
|
21882
|
+
let end = out.length;
|
|
21883
|
+
while (end > 0 && /\s/u.test(out[end - 1]))
|
|
21884
|
+
end -= 1;
|
|
21885
|
+
if (end === 0 || REGEX_AFTER.includes(out[end - 1]))
|
|
21886
|
+
return true;
|
|
21887
|
+
let start = end;
|
|
21888
|
+
while (start > 0 && WORD.test(out[start - 1]))
|
|
21889
|
+
start -= 1;
|
|
21890
|
+
return REGEX_KEYWORDS.has(out.slice(start, end));
|
|
21891
|
+
};
|
|
21892
|
+
const scanString = (quote, escapes, multiline) => {
|
|
21893
|
+
const prefix = text.slice(Math.max(0, index - 2), index).match(/[a-z]*$/iu)?.[0] ?? "";
|
|
21894
|
+
const fstring = syntax.fstring === true && /f/iu.test(prefix);
|
|
21895
|
+
let end = index + quote.length;
|
|
21896
|
+
while (end < text.length) {
|
|
21897
|
+
const char = text[end];
|
|
21898
|
+
if (escapes && char === "\\") {
|
|
21899
|
+
end += 2;
|
|
21900
|
+
continue;
|
|
21901
|
+
}
|
|
21902
|
+
if (text.startsWith(quote, end)) {
|
|
21903
|
+
if (fstring && unbalanced(text.slice(index + quote.length, end)))
|
|
21904
|
+
return false;
|
|
21905
|
+
emitVerbatim(text.slice(index, end + quote.length));
|
|
21906
|
+
index = end + quote.length;
|
|
21907
|
+
return true;
|
|
21908
|
+
}
|
|
21909
|
+
if (char === `
|
|
21910
|
+
` && !multiline)
|
|
21911
|
+
return false;
|
|
21912
|
+
end += 1;
|
|
21913
|
+
}
|
|
21914
|
+
return false;
|
|
21915
|
+
};
|
|
21916
|
+
while (index < text.length) {
|
|
21917
|
+
const frame = frames[frames.length - 1];
|
|
21918
|
+
const char = text[index];
|
|
21919
|
+
if (frame.kind === "template") {
|
|
21920
|
+
if (char === "\\") {
|
|
21921
|
+
emitVerbatim(text.slice(index, index + 2));
|
|
21922
|
+
index += 2;
|
|
21923
|
+
} else if (char === "`") {
|
|
21924
|
+
emitVerbatim(char);
|
|
21925
|
+
frames.pop();
|
|
21926
|
+
index += 1;
|
|
21927
|
+
} else if (text.startsWith("${", index)) {
|
|
21928
|
+
emitVerbatim("${");
|
|
21929
|
+
frames.push({ kind: "code", braces: 0 });
|
|
21930
|
+
index += 2;
|
|
21931
|
+
} else {
|
|
21932
|
+
out += char;
|
|
21933
|
+
kept = out.length;
|
|
21934
|
+
index += 1;
|
|
21935
|
+
}
|
|
21936
|
+
continue;
|
|
21937
|
+
}
|
|
21938
|
+
if (char === `
|
|
21939
|
+
`) {
|
|
21940
|
+
newline();
|
|
21941
|
+
index += 1;
|
|
21942
|
+
continue;
|
|
21943
|
+
}
|
|
21944
|
+
if (SPACE.test(char)) {
|
|
21945
|
+
if (collapse)
|
|
21946
|
+
pendingSpace = true;
|
|
21947
|
+
else
|
|
21948
|
+
out += char;
|
|
21949
|
+
index += 1;
|
|
21950
|
+
continue;
|
|
21951
|
+
}
|
|
21952
|
+
const lineOpener = syntax.line.find((opener) => text.startsWith(opener, index));
|
|
21953
|
+
if (lineOpener) {
|
|
21954
|
+
const end = text.indexOf(`
|
|
21955
|
+
`, index);
|
|
21956
|
+
const comment = text.slice(index, end < 0 ? text.length : end);
|
|
21957
|
+
if (DIRECTIVE.test(comment.slice(lineOpener.length)))
|
|
21958
|
+
emitVerbatim(comment);
|
|
21959
|
+
else
|
|
21960
|
+
pendingSpace = true;
|
|
21961
|
+
index = end < 0 ? text.length : end;
|
|
21962
|
+
continue;
|
|
21963
|
+
}
|
|
21964
|
+
const block = syntax.block.find(([open]) => text.startsWith(open, index));
|
|
21965
|
+
if (block) {
|
|
21966
|
+
const end = text.indexOf(block[1], index + block[0].length);
|
|
21967
|
+
if (end < 0)
|
|
21968
|
+
return null;
|
|
21969
|
+
const comment = text.slice(index, end + block[1].length);
|
|
21970
|
+
if (DIRECTIVE.test(comment.slice(block[0].length, -block[1].length)))
|
|
21971
|
+
emitVerbatim(comment);
|
|
21972
|
+
else
|
|
21973
|
+
pendingSpace = true;
|
|
21974
|
+
if (comment.includes(`
|
|
21975
|
+
`))
|
|
21976
|
+
newline();
|
|
21977
|
+
index = end + block[1].length;
|
|
21978
|
+
continue;
|
|
21979
|
+
}
|
|
21980
|
+
if (syntax.triple && (char === '"' || char === "'") && text.startsWith(char.repeat(3), index)) {
|
|
21981
|
+
if (!scanString(char.repeat(3), !syntax.literal?.includes(char), true))
|
|
21982
|
+
return null;
|
|
21983
|
+
continue;
|
|
21984
|
+
}
|
|
21985
|
+
if (syntax.quotes.includes(char)) {
|
|
21986
|
+
if (!scanString(char, true, Boolean(syntax.multiline)))
|
|
21987
|
+
return null;
|
|
21988
|
+
continue;
|
|
21989
|
+
}
|
|
21990
|
+
if (syntax.literal?.includes(char)) {
|
|
21991
|
+
if (!scanString(char, false, false))
|
|
21992
|
+
return null;
|
|
21993
|
+
continue;
|
|
21994
|
+
}
|
|
21995
|
+
if (syntax.rawBacktick && char === "`") {
|
|
21996
|
+
if (!scanString("`", false, true))
|
|
21997
|
+
return null;
|
|
21998
|
+
continue;
|
|
21999
|
+
}
|
|
22000
|
+
if (syntax.js && char === "`") {
|
|
22001
|
+
emitVerbatim(char);
|
|
22002
|
+
frames.push({ kind: "template" });
|
|
22003
|
+
index += 1;
|
|
22004
|
+
continue;
|
|
22005
|
+
}
|
|
22006
|
+
if (syntax.cssUrl && /^url\(\s*[^"')\s]/iu.test(text.slice(index, index + 64)))
|
|
22007
|
+
return null;
|
|
22008
|
+
if (syntax.js && char === "/" && !regexAllowed() && out.trimEnd().endsWith(")")) {
|
|
22009
|
+
const lineEnd = text.indexOf(`
|
|
22010
|
+
`, index);
|
|
22011
|
+
if (text.slice(index + 1, lineEnd < 0 ? text.length : lineEnd).includes("/"))
|
|
22012
|
+
return null;
|
|
22013
|
+
}
|
|
22014
|
+
if (syntax.js && char === "/" && regexAllowed()) {
|
|
22015
|
+
let end = index + 1;
|
|
22016
|
+
let inClass = false;
|
|
22017
|
+
while (end < text.length && (inClass || text[end] !== "/")) {
|
|
22018
|
+
if (text[end] === `
|
|
22019
|
+
`)
|
|
22020
|
+
return null;
|
|
22021
|
+
if (text[end] === "\\")
|
|
22022
|
+
end += 1;
|
|
22023
|
+
else if (text[end] === "[")
|
|
22024
|
+
inClass = true;
|
|
22025
|
+
else if (text[end] === "]")
|
|
22026
|
+
inClass = false;
|
|
22027
|
+
end += 1;
|
|
22028
|
+
}
|
|
22029
|
+
if (end >= text.length)
|
|
22030
|
+
return null;
|
|
22031
|
+
emitVerbatim(text.slice(index, end + 1));
|
|
22032
|
+
index = end + 1;
|
|
22033
|
+
continue;
|
|
22034
|
+
}
|
|
22035
|
+
if (frames.length > 1 && frame.kind === "code") {
|
|
22036
|
+
if (char === "{")
|
|
22037
|
+
frame.braces += 1;
|
|
22038
|
+
else if (char === "}") {
|
|
22039
|
+
if (frame.braces === 0) {
|
|
22040
|
+
emitVerbatim(char);
|
|
22041
|
+
frames.pop();
|
|
22042
|
+
index += 1;
|
|
22043
|
+
continue;
|
|
22044
|
+
}
|
|
22045
|
+
frame.braces -= 1;
|
|
22046
|
+
}
|
|
22047
|
+
}
|
|
22048
|
+
emitCode(char);
|
|
22049
|
+
index += 1;
|
|
22050
|
+
}
|
|
22051
|
+
if (frames.length !== 1)
|
|
22052
|
+
return null;
|
|
22053
|
+
newline();
|
|
22054
|
+
return out;
|
|
22055
|
+
}
|
|
22056
|
+
function unbalanced(body) {
|
|
22057
|
+
let depth = 0;
|
|
22058
|
+
for (const part of body.replaceAll("{{", "").replaceAll("}}", "")) {
|
|
22059
|
+
if (part === "{")
|
|
22060
|
+
depth += 1;
|
|
22061
|
+
else if (part === "}")
|
|
22062
|
+
depth = Math.max(0, depth - 1);
|
|
22063
|
+
}
|
|
22064
|
+
return depth > 0;
|
|
22065
|
+
}
|
|
22066
|
+
function hasOpaqueLineBreak(text) {
|
|
22067
|
+
return /\r(?!\n)|[\u2028\u2029]/u.test(text);
|
|
22068
|
+
}
|
|
22069
|
+
var decoder = new TextDecoder("utf-8", { fatal: true });
|
|
22070
|
+
function textOf(bytes) {
|
|
22071
|
+
if (bytes.includes(0))
|
|
22072
|
+
return null;
|
|
22073
|
+
try {
|
|
22074
|
+
return decoder.decode(bytes);
|
|
22075
|
+
} catch {
|
|
22076
|
+
return null;
|
|
22077
|
+
}
|
|
22078
|
+
}
|
|
22079
|
+
function cosmeticChange(file, before, after) {
|
|
22080
|
+
const left = textOf(before);
|
|
22081
|
+
const right = textOf(after);
|
|
22082
|
+
if (left === null || right === null)
|
|
22083
|
+
return false;
|
|
22084
|
+
if (hasOpaqueLineBreak(left) || hasOpaqueLineBreak(right))
|
|
22085
|
+
return false;
|
|
22086
|
+
const a = substanceOf(file, left);
|
|
22087
|
+
return a !== null && a === substanceOf(file, right);
|
|
22088
|
+
}
|
|
22089
|
+
|
|
22090
|
+
// packages/workit-core/src/core/policy/lane.ts
|
|
22091
|
+
var LANE_THRESHOLDS = {
|
|
22092
|
+
selfMaxLines: 100,
|
|
22093
|
+
selfMaxFiles: 5,
|
|
22094
|
+
fullMinLines: 500
|
|
22095
|
+
};
|
|
22096
|
+
var RISK_TOKENS = new Set([
|
|
22097
|
+
"auth",
|
|
22098
|
+
"authn",
|
|
22099
|
+
"authz",
|
|
22100
|
+
"oauth",
|
|
22101
|
+
"security",
|
|
22102
|
+
"permission",
|
|
22103
|
+
"permissions",
|
|
22104
|
+
"secret",
|
|
22105
|
+
"secrets",
|
|
22106
|
+
"crypto",
|
|
22107
|
+
"gate",
|
|
22108
|
+
"gates",
|
|
22109
|
+
"policy",
|
|
22110
|
+
"policies",
|
|
22111
|
+
"hook",
|
|
22112
|
+
"hooks",
|
|
22113
|
+
"husky",
|
|
22114
|
+
"lefthook",
|
|
22115
|
+
"release",
|
|
22116
|
+
"releases",
|
|
22117
|
+
"migration",
|
|
22118
|
+
"migrations",
|
|
22119
|
+
"migrate",
|
|
22120
|
+
"workflows"
|
|
22121
|
+
]);
|
|
22122
|
+
var RISK_FILES = new Set([
|
|
22123
|
+
".gitlab-ci.yml",
|
|
22124
|
+
"Jenkinsfile",
|
|
22125
|
+
"azure-pipelines.yml",
|
|
22126
|
+
".pre-commit-config.yaml",
|
|
22127
|
+
".workit/risk-paths"
|
|
22128
|
+
]);
|
|
22129
|
+
var RISK_NAMES = new Set([".gitattributes"]);
|
|
22130
|
+
var RISK_PATHS_FILE = ".workit/risk-paths";
|
|
22131
|
+
var LOCKFILES = new Set([
|
|
22132
|
+
"bun.lock",
|
|
22133
|
+
"bun.lockb",
|
|
22134
|
+
"package-lock.json",
|
|
22135
|
+
"npm-shrinkwrap.json",
|
|
22136
|
+
"yarn.lock",
|
|
22137
|
+
"pnpm-lock.yaml",
|
|
22138
|
+
"Cargo.lock",
|
|
22139
|
+
"go.sum",
|
|
22140
|
+
"poetry.lock",
|
|
22141
|
+
"uv.lock",
|
|
22142
|
+
"Pipfile.lock",
|
|
22143
|
+
"Gemfile.lock",
|
|
22144
|
+
"composer.lock"
|
|
22145
|
+
]);
|
|
22146
|
+
var DOC_EXT = /\.(?:md|mdx|markdown|rst|adoc)$/iu;
|
|
22147
|
+
var DOC_NAMES = /^(?:license|licence|notice|authors|changelog|changes|contributors)$/iu;
|
|
22148
|
+
var INSTRUCTIONS = /(?:^|\/)(?:AGENTS|CLAUDE|GEMINI|SKILL)\.md$|(?:^|\/)(?:skills|agents|commands|rules|prompts)\/[^/]+/iu;
|
|
22149
|
+
var TEST_PATH = /(?:^|\/)(?:test|tests|__tests__)\/|\.(?:test|spec)\.[^/]+$|_test\.[^/]+$/iu;
|
|
22150
|
+
var basename = (file) => file.slice(file.lastIndexOf("/") + 1);
|
|
22151
|
+
var isDoc = (file) => !INSTRUCTIONS.test(file) && (DOC_EXT.test(file) || DOC_NAMES.test(basename(file)));
|
|
22152
|
+
function kindOf(file) {
|
|
22153
|
+
if (file.binary)
|
|
22154
|
+
return "behavior";
|
|
22155
|
+
if (file.generated)
|
|
22156
|
+
return "generated";
|
|
22157
|
+
if (LOCKFILES.has(basename(file.path)))
|
|
22158
|
+
return "lockfile";
|
|
22159
|
+
if (isDoc(file.path))
|
|
22160
|
+
return "doc";
|
|
22161
|
+
if (file.cosmetic)
|
|
22162
|
+
return "cosmetic";
|
|
22163
|
+
return TEST_PATH.test(file.path) ? "test" : "behavior";
|
|
22164
|
+
}
|
|
22165
|
+
var globCache = new Map;
|
|
22166
|
+
function globMatch(pattern, file) {
|
|
22167
|
+
let regex = globCache.get(pattern);
|
|
22168
|
+
if (!regex) {
|
|
22169
|
+
let source = "";
|
|
22170
|
+
for (let index = 0;index < pattern.length; index += 1) {
|
|
22171
|
+
const char = pattern[index];
|
|
22172
|
+
if (char === "*" && pattern[index + 1] === "*") {
|
|
22173
|
+
source += pattern[index + 2] === "/" ? "(?:[^/]*/)*" : ".*";
|
|
22174
|
+
index += pattern[index + 2] === "/" ? 2 : 1;
|
|
22175
|
+
} else if (char === "*")
|
|
22176
|
+
source += "[^/]*";
|
|
22177
|
+
else if (char === "?")
|
|
22178
|
+
source += "[^/]";
|
|
22179
|
+
else
|
|
22180
|
+
source += char.replace(/[.+^${}()|[\]\\]/gu, "\\$&");
|
|
22181
|
+
}
|
|
22182
|
+
regex = new RegExp(`^${source}$`, "u");
|
|
22183
|
+
globCache.set(pattern, regex);
|
|
22184
|
+
}
|
|
22185
|
+
return regex.test(file) || file.startsWith(`${pattern.replace(/\/$/u, "")}/`);
|
|
22186
|
+
}
|
|
22187
|
+
function isRiskPath(file, extra = []) {
|
|
22188
|
+
if (extra.some((pattern) => globMatch(pattern, file)))
|
|
22189
|
+
return true;
|
|
22190
|
+
if (RISK_FILES.has(file) || RISK_NAMES.has(basename(file)))
|
|
22191
|
+
return true;
|
|
22192
|
+
if (TEST_PATH.test(file) || isDoc(file))
|
|
22193
|
+
return false;
|
|
22194
|
+
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)));
|
|
22195
|
+
}
|
|
22196
|
+
var parseRiskPaths = (text) => text.split(`
|
|
22197
|
+
`).map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.replace(/^\//u, ""));
|
|
22198
|
+
function computeLane(input) {
|
|
22199
|
+
const riskFiles = input.files.filter((file) => isRiskPath(file.path, input.riskPaths)).map((file) => file.path);
|
|
22200
|
+
const risky = new Set(riskFiles);
|
|
22201
|
+
const kinds = input.files.map((file) => ({
|
|
22202
|
+
file,
|
|
22203
|
+
kind: risky.has(file.path) ? "behavior" : kindOf(file)
|
|
22204
|
+
}));
|
|
22205
|
+
const behavior = kinds.filter((entry) => entry.kind === "behavior" || entry.kind === "test" || entry.kind === "lockfile");
|
|
22206
|
+
const lines = behavior.filter((entry) => entry.kind !== "lockfile").reduce((sum, entry) => sum + entry.file.added + entry.file.deleted, 0);
|
|
22207
|
+
const opaque = behavior.filter((entry) => entry.kind === "lockfile" || entry.file.binary);
|
|
22208
|
+
const result = (lane, reasons) => ({
|
|
22209
|
+
lane,
|
|
22210
|
+
reasons,
|
|
22211
|
+
lines,
|
|
22212
|
+
files: behavior.length,
|
|
22213
|
+
riskFiles
|
|
22214
|
+
});
|
|
22215
|
+
const { selfMaxLines, selfMaxFiles, fullMinLines } = LANE_THRESHOLDS;
|
|
22216
|
+
if (input.riskTier === "high")
|
|
22217
|
+
return result("full", ["the task judgment records high risk"]);
|
|
22218
|
+
if (riskFiles.length)
|
|
22219
|
+
return result("full", [
|
|
22220
|
+
`touches a risk path: ${riskFiles.slice(0, 3).join(", ")}${riskFiles.length > 3 ? ", …" : ""}`
|
|
22221
|
+
]);
|
|
22222
|
+
if (!behavior.length)
|
|
22223
|
+
return result("none", [
|
|
22224
|
+
input.files.length ? "only docs, comments, formatting or generated copies changed" : "no changes"
|
|
22225
|
+
]);
|
|
22226
|
+
if (lines >= fullMinLines)
|
|
22227
|
+
return result("full", [`large diff: ${lines} lines (≥ ${fullMinLines})`]);
|
|
22228
|
+
if (lines > selfMaxLines)
|
|
22229
|
+
return result("focused", [`${lines} lines changed (> ${selfMaxLines})`]);
|
|
22230
|
+
if (behavior.length > selfMaxFiles)
|
|
22231
|
+
return result("focused", [`${behavior.length} behavior files changed (> ${selfMaxFiles})`]);
|
|
22232
|
+
if (opaque.length)
|
|
22233
|
+
return result("focused", [
|
|
22234
|
+
`a lockfile or binary changed: ${opaque.slice(0, 3).map((entry) => entry.file.path).join(", ")}${opaque.length > 3 ? ", …" : ""}`
|
|
22235
|
+
]);
|
|
22236
|
+
return result("self", [
|
|
22237
|
+
`small change: ${lines} line${lines === 1 ? "" : "s"} in ${behavior.length} file${behavior.length === 1 ? "" : "s"}, no risk path`
|
|
22238
|
+
]);
|
|
22239
|
+
}
|
|
22240
|
+
function untrackedStat(cwd, file) {
|
|
22241
|
+
try {
|
|
22242
|
+
const bytes = readFileSync4(path14.join(cwd, file));
|
|
22243
|
+
if (bytes.includes(0))
|
|
22244
|
+
return { path: file, added: 0, deleted: 0, binary: true };
|
|
22245
|
+
const text = bytes.toString("utf8");
|
|
22246
|
+
if (hasOpaqueLineBreak(text))
|
|
22247
|
+
return { path: file, added: 0, deleted: 0, binary: true };
|
|
22248
|
+
const lines = text.split(`
|
|
22249
|
+
`).length - (text.endsWith(`
|
|
22250
|
+
`) ? 1 : 0);
|
|
22251
|
+
return { path: file, added: lines, deleted: 0 };
|
|
22252
|
+
} catch {
|
|
22253
|
+
return { path: file, added: 0, deleted: 0, binary: true };
|
|
22254
|
+
}
|
|
22255
|
+
}
|
|
22256
|
+
var REGULAR = new Set(["100644", "100755"]);
|
|
22257
|
+
var ABSENT = /^0+$/u;
|
|
22258
|
+
function cosmeticFiles(cwd, fork, head) {
|
|
22259
|
+
const raw = diffRaw(cwd, fork, head);
|
|
22260
|
+
if (!raw)
|
|
22261
|
+
return null;
|
|
22262
|
+
const candidates = raw.filter((entry) => REGULAR.has(entry.oldMode) && entry.oldMode === entry.newMode && !ABSENT.test(entry.oldBlob) && (head === null || !ABSENT.test(entry.newBlob)));
|
|
22263
|
+
const blobs = readBlobs(cwd, candidates.flatMap((entry) => [entry.oldBlob, entry.newBlob]));
|
|
22264
|
+
if (!blobs)
|
|
22265
|
+
return null;
|
|
22266
|
+
const out = new Set;
|
|
22267
|
+
const opaque = new Set;
|
|
22268
|
+
for (const entry of candidates) {
|
|
22269
|
+
const before = blobs.get(entry.oldBlob);
|
|
22270
|
+
let after = blobs.get(entry.newBlob);
|
|
22271
|
+
if (!after && head === null && ABSENT.test(entry.newBlob))
|
|
22272
|
+
try {
|
|
22273
|
+
after = readFileSync4(path14.join(cwd, entry.path));
|
|
22274
|
+
} catch {
|
|
22275
|
+
after = undefined;
|
|
22276
|
+
}
|
|
22277
|
+
if (before && after && cosmeticChange(entry.path, before, after))
|
|
22278
|
+
out.add(entry.path);
|
|
22279
|
+
else if ([before, after].some((bytes) => bytes && hasOpaqueLineBreak(bytes.toString("utf8"))))
|
|
22280
|
+
opaque.add(entry.path);
|
|
22281
|
+
}
|
|
22282
|
+
return { cosmetic: out, opaque };
|
|
22283
|
+
}
|
|
22284
|
+
function generatedAt(cwd, fork, paths) {
|
|
22285
|
+
const files = treeFilesNamed(cwd, fork, ".gitattributes");
|
|
22286
|
+
const blobs = files?.size ? readBlobs(cwd, [...files.values()]) : null;
|
|
22287
|
+
if (!files || !blobs)
|
|
22288
|
+
return new Set;
|
|
22289
|
+
const texts = new Map;
|
|
22290
|
+
for (const [file, id] of files) {
|
|
22291
|
+
const bytes = blobs.get(id);
|
|
22292
|
+
if (bytes)
|
|
22293
|
+
texts.set(file, bytes.toString("utf8"));
|
|
22294
|
+
}
|
|
22295
|
+
return generatedByAttributes(texts, paths);
|
|
22296
|
+
}
|
|
22297
|
+
var forkOf = (cwd, base, head) => mergeBase(cwd, base, head ?? "HEAD");
|
|
22298
|
+
function laneFiles(cwd, fork, head, attributesAt = fork) {
|
|
22299
|
+
const stats = diffNumstat(cwd, fork, head);
|
|
22300
|
+
const cosmetic = stats ? cosmeticFiles(cwd, fork, head) : null;
|
|
22301
|
+
if (!stats || !cosmetic)
|
|
22302
|
+
return null;
|
|
22303
|
+
const files = [
|
|
22304
|
+
...stats.map((entry) => ({
|
|
22305
|
+
...entry,
|
|
22306
|
+
...cosmetic.opaque.has(entry.path) ? { binary: true } : {},
|
|
22307
|
+
cosmetic: !entry.binary && cosmetic.cosmetic.has(entry.path)
|
|
22308
|
+
})),
|
|
22309
|
+
...head === null ? untrackedFiles(cwd).map((file) => untrackedStat(cwd, file)) : []
|
|
22310
|
+
];
|
|
22311
|
+
const generated = generatedAt(cwd, attributesAt, files.map((entry) => entry.path));
|
|
22312
|
+
return files.map((entry) => ({
|
|
22313
|
+
...entry,
|
|
22314
|
+
generated: generated.has(entry.path)
|
|
22315
|
+
}));
|
|
22316
|
+
}
|
|
22317
|
+
function driftFiles(cwd, range) {
|
|
22318
|
+
if (range.fromFork === range.toFork)
|
|
22319
|
+
return laneFiles(cwd, range.from, range.to, range.toFork);
|
|
22320
|
+
const drifted = ownChangeDrift(cwd, range);
|
|
22321
|
+
const stats = drifted ? diffNumstat(cwd, range.from, range.to) : null;
|
|
22322
|
+
if (!drifted || !stats)
|
|
22323
|
+
return null;
|
|
22324
|
+
const byPath = new Map(stats.map((entry) => [entry.path, entry]));
|
|
22325
|
+
const generated = generatedAt(cwd, range.toFork, drifted);
|
|
22326
|
+
return drifted.map((file) => ({
|
|
22327
|
+
path: file,
|
|
22328
|
+
added: byPath.get(file)?.added ?? 0,
|
|
22329
|
+
deleted: byPath.get(file)?.deleted ?? 0,
|
|
22330
|
+
...byPath.get(file)?.binary ? { binary: true } : {},
|
|
22331
|
+
cosmetic: false,
|
|
22332
|
+
generated: generated.has(file)
|
|
22333
|
+
}));
|
|
22334
|
+
}
|
|
22335
|
+
function branchLane(cwd, options) {
|
|
22336
|
+
const candidates = options.base ? [`origin/${options.base}`, options.base] : [];
|
|
22337
|
+
const base = candidates.find((ref) => resolveRef(cwd, ref) !== null) ?? defaultBase(cwd) ?? null;
|
|
22338
|
+
const head = options.workingTree ? null : options.head;
|
|
22339
|
+
const fork = base && (options.workingTree || options.head) ? forkOf(cwd, base, head) : null;
|
|
22340
|
+
const files = fork ? laneFiles(cwd, fork, head) : null;
|
|
22341
|
+
const riskTier = options.judgment?.riskTier ?? null;
|
|
22342
|
+
if (!fork || !files) {
|
|
22343
|
+
const high = riskTier === "high";
|
|
22344
|
+
return {
|
|
22345
|
+
lane: high ? "full" : "focused",
|
|
22346
|
+
reasons: [
|
|
22347
|
+
`the diff of ${options.head?.slice(0, 12) ?? "(no head)"} against ${base ?? "(no base)"} cannot be read`,
|
|
22348
|
+
...high ? ["the task judgment records high risk"] : []
|
|
22349
|
+
],
|
|
22350
|
+
lines: 0,
|
|
22351
|
+
files: 0,
|
|
22352
|
+
riskFiles: [],
|
|
22353
|
+
base,
|
|
22354
|
+
head: options.head
|
|
22355
|
+
};
|
|
22356
|
+
}
|
|
22357
|
+
const repoRisk = parseRiskPaths(fileAt(cwd, fork, RISK_PATHS_FILE) ?? "");
|
|
22358
|
+
return {
|
|
22359
|
+
...computeLane({
|
|
22360
|
+
files,
|
|
22361
|
+
riskTier,
|
|
22362
|
+
riskPaths: [...repoRisk, ...options.riskPaths ?? []]
|
|
22363
|
+
}),
|
|
22364
|
+
base,
|
|
22365
|
+
head: options.head
|
|
22366
|
+
};
|
|
22367
|
+
}
|
|
22368
|
+
var laneNeed = (lane) => lane === "none" ? "none" : lane === "self" ? "self" : "non-author";
|
|
22369
|
+
|
|
22370
|
+
// packages/workit-core/src/core/policy/carry.ts
|
|
22371
|
+
var TEST_ONLY_KINDS = new Set(["doc", "cosmetic", "generated", "test"]);
|
|
22372
|
+
function verdictDrift(cwd, input) {
|
|
22373
|
+
const since = input.from;
|
|
22374
|
+
const stale = (reason, files = null, focused = false) => ({
|
|
22375
|
+
carries: false,
|
|
22376
|
+
since,
|
|
22377
|
+
files,
|
|
22378
|
+
focused,
|
|
22379
|
+
reason
|
|
22380
|
+
});
|
|
22381
|
+
const fromFork = mergeBase(cwd, input.fromBase, input.from);
|
|
22382
|
+
const toFork = mergeBase(cwd, input.toBase, input.to);
|
|
22383
|
+
const files = fromFork && toFork ? driftFiles(cwd, { from: input.from, to: input.to, fromFork, toFork }) : null;
|
|
22384
|
+
if (!fromFork || !toFork || !files)
|
|
22385
|
+
return stale(`the change since ${since.slice(0, 12)} cannot be read`);
|
|
22386
|
+
const riskPaths = [fromFork, toFork].flatMap((fork) => parseRiskPaths(fileAt(cwd, fork, RISK_PATHS_FILE) ?? ""));
|
|
22387
|
+
const lane = computeLane({ files, riskPaths });
|
|
22388
|
+
const paths = files.map((file) => file.path);
|
|
22389
|
+
if (lane.lane === "none")
|
|
22390
|
+
return { carries: true, rule: "lane-none", since, files: paths };
|
|
22391
|
+
if (input.kind === "unit" && lane.lane === "self" && files.every((file) => TEST_ONLY_KINDS.has(kindOf(file))))
|
|
22392
|
+
return { carries: true, rule: "tests-only", since, files: paths };
|
|
22393
|
+
return stale(lane.reasons[0] ?? `lane ${lane.lane}`, paths, lane.lane === "self");
|
|
22394
|
+
}
|
|
22395
|
+
|
|
22396
|
+
// packages/workit-core/src/ledger.ts
|
|
21516
22397
|
var LEDGER_VERSION = 1;
|
|
21517
22398
|
var MAX_LINE_BYTES = 4096;
|
|
21518
22399
|
var PASSING = new Set(["verified", "tests-verified", "type-check-only"]);
|
|
@@ -21557,52 +22438,19 @@ var git4 = (cwd, args) => {
|
|
|
21557
22438
|
const value = run.ok ? run.stdout.trim() : "";
|
|
21558
22439
|
return value ? value : null;
|
|
21559
22440
|
};
|
|
21560
|
-
var
|
|
22441
|
+
var safeRef2 = (value) => value.length > 0 && !value.startsWith("-");
|
|
21561
22442
|
function resolveCommit(cwd, ref) {
|
|
21562
|
-
if (!
|
|
22443
|
+
if (!safeRef2(ref))
|
|
21563
22444
|
return null;
|
|
21564
22445
|
return git4(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]);
|
|
21565
22446
|
}
|
|
21566
22447
|
function branchHead(cwd, branch) {
|
|
21567
|
-
if (!
|
|
22448
|
+
if (!safeRef2(branch))
|
|
21568
22449
|
return null;
|
|
21569
22450
|
return resolveCommit(cwd, `refs/heads/${branch}`) ?? resolveCommit(cwd, `refs/remotes/origin/${branch}`);
|
|
21570
22451
|
}
|
|
21571
|
-
var trackTrunk = (cwd) => {
|
|
21572
|
-
try {
|
|
21573
|
-
const resolved = vcsConfig("resolve", cwd);
|
|
21574
|
-
if (resolved.ok === false || !resolved.releaseTrack || resolved.releaseTrack.blocking)
|
|
21575
|
-
return null;
|
|
21576
|
-
const target = String(resolved.defaultTargetBranch ?? "").trim();
|
|
21577
|
-
return target && safeRef(target) ? target : null;
|
|
21578
|
-
} catch {
|
|
21579
|
-
return null;
|
|
21580
|
-
}
|
|
21581
|
-
};
|
|
21582
|
-
function defaultBase(cwd) {
|
|
21583
|
-
const trunk = trackTrunk(cwd);
|
|
21584
|
-
if (trunk) {
|
|
21585
|
-
for (const candidate of [`origin/${trunk}`, trunk])
|
|
21586
|
-
if (resolveCommit(cwd, candidate))
|
|
21587
|
-
return candidate;
|
|
21588
|
-
}
|
|
21589
|
-
const originHead = git4(cwd, ["symbolic-ref", "-q", "--short", "refs/remotes/origin/HEAD"]);
|
|
21590
|
-
if (originHead && resolveCommit(cwd, originHead))
|
|
21591
|
-
return originHead;
|
|
21592
|
-
for (const candidate of [
|
|
21593
|
-
"origin/main",
|
|
21594
|
-
"origin/master",
|
|
21595
|
-
"main",
|
|
21596
|
-
"master",
|
|
21597
|
-
"origin/develop",
|
|
21598
|
-
"develop"
|
|
21599
|
-
])
|
|
21600
|
-
if (resolveCommit(cwd, candidate))
|
|
21601
|
-
return candidate;
|
|
21602
|
-
return null;
|
|
21603
|
-
}
|
|
21604
22452
|
function diffHash(cwd, base, head) {
|
|
21605
|
-
if (!
|
|
22453
|
+
if (!safeRef2(base) || !safeRef2(head))
|
|
21606
22454
|
return null;
|
|
21607
22455
|
const diff = gitRun2(cwd, [
|
|
21608
22456
|
"diff",
|
|
@@ -21634,14 +22482,14 @@ function diffHash(cwd, base, head) {
|
|
|
21634
22482
|
return `sha256:${hash.digest("hex")}`;
|
|
21635
22483
|
}
|
|
21636
22484
|
function storeRoot(cwd) {
|
|
21637
|
-
const location = resolveStore(
|
|
22485
|
+
const location = resolveStore(path15.resolve(cwd));
|
|
21638
22486
|
if (location instanceof Error)
|
|
21639
22487
|
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");
|
|
21640
22488
|
return { ok: true, value: { root: location.dir, shared: location.shared } };
|
|
21641
22489
|
}
|
|
21642
22490
|
function ledgerPath(cwd) {
|
|
21643
22491
|
const root = storeRoot(cwd);
|
|
21644
|
-
return root.ok ? { ok: true, value:
|
|
22492
|
+
return root.ok ? { ok: true, value: path15.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
21645
22493
|
}
|
|
21646
22494
|
var newId2 = () => `${Date.now().toString(36)}-${randomBytes3(6).toString("hex")}`;
|
|
21647
22495
|
var NETWORK_FS_TYPES = new Set([
|
|
@@ -21671,13 +22519,13 @@ var LOCK_STALE_MS = 30000;
|
|
|
21671
22519
|
var LOCK_OWNER = "owner";
|
|
21672
22520
|
var lockToken = (lock) => {
|
|
21673
22521
|
try {
|
|
21674
|
-
return fs12.readFileSync(
|
|
22522
|
+
return fs12.readFileSync(path15.join(lock, LOCK_OWNER), "utf8");
|
|
21675
22523
|
} catch {
|
|
21676
22524
|
return null;
|
|
21677
22525
|
}
|
|
21678
22526
|
};
|
|
21679
22527
|
var lockAgeMs = (lock) => {
|
|
21680
|
-
for (const target of [
|
|
22528
|
+
for (const target of [path15.join(lock, LOCK_OWNER), lock]) {
|
|
21681
22529
|
try {
|
|
21682
22530
|
return Date.now() - fs12.statSync(target).mtimeMs;
|
|
21683
22531
|
} catch {}
|
|
@@ -21694,7 +22542,7 @@ var ledgerLock = {
|
|
|
21694
22542
|
throw error;
|
|
21695
22543
|
}
|
|
21696
22544
|
const token = `${process.pid}-${randomBytes3(8).toString("hex")}`;
|
|
21697
|
-
fs12.writeFileSync(
|
|
22545
|
+
fs12.writeFileSync(path15.join(lock, LOCK_OWNER), token);
|
|
21698
22546
|
return token;
|
|
21699
22547
|
},
|
|
21700
22548
|
release(lock, token) {
|
|
@@ -21827,8 +22675,8 @@ function appendLine(file, build, options) {
|
|
|
21827
22675
|
}
|
|
21828
22676
|
};
|
|
21829
22677
|
try {
|
|
21830
|
-
fs12.mkdirSync(
|
|
21831
|
-
if (!options.forceLock && !onNetworkFs(
|
|
22678
|
+
fs12.mkdirSync(path15.dirname(file), { recursive: true });
|
|
22679
|
+
if (!options.forceLock && !onNetworkFs(path15.dirname(file)))
|
|
21832
22680
|
return write();
|
|
21833
22681
|
const locked = withLedgerLock(file, write);
|
|
21834
22682
|
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
@@ -22059,7 +22907,7 @@ function verdictBasis(verdict, current) {
|
|
|
22059
22907
|
}
|
|
22060
22908
|
var isLiveVerdict = (row, retired) => row.type === "verdict" && typeof row.result === "string" && !retired.has(row.id);
|
|
22061
22909
|
function trailerSessions(cwd, base, head) {
|
|
22062
|
-
if (!base || !head || !
|
|
22910
|
+
if (!base || !head || !safeRef2(base) || !safeRef2(head))
|
|
22063
22911
|
return [];
|
|
22064
22912
|
const out = git4(cwd, [
|
|
22065
22913
|
"log",
|
|
@@ -22072,7 +22920,7 @@ var RENAMED = /^branch: renamed refs\/heads\/(.+) to refs\/heads\/(.+)$/iu;
|
|
|
22072
22920
|
function branchScope(cwd, branch) {
|
|
22073
22921
|
const renamedAt = new Map;
|
|
22074
22922
|
let since = Number.NEGATIVE_INFINITY;
|
|
22075
|
-
if (
|
|
22923
|
+
if (safeRef2(branch)) {
|
|
22076
22924
|
const log = git4(cwd, [
|
|
22077
22925
|
"log",
|
|
22078
22926
|
"-g",
|
|
@@ -22217,12 +23065,29 @@ function effectiveOf(rows, reasonsOf, sameCode, isCurrent) {
|
|
|
22217
23065
|
}
|
|
22218
23066
|
return effective;
|
|
22219
23067
|
}
|
|
22220
|
-
|
|
23068
|
+
var restackExact = new WeakMap;
|
|
23069
|
+
function restackCarries(exactIn, rows, branch, from, to) {
|
|
22221
23070
|
if (!from || !to)
|
|
22222
23071
|
return false;
|
|
23072
|
+
const exact = (row, fromHead, head) => {
|
|
23073
|
+
if (exactIn === null)
|
|
23074
|
+
return true;
|
|
23075
|
+
const cwd = exactIn;
|
|
23076
|
+
let known = restackExact.get(row);
|
|
23077
|
+
if (known === undefined) {
|
|
23078
|
+
known = typeof row.fromBase === "string" && typeof row.toBase === "string" && sameOwnChange(cwd, {
|
|
23079
|
+
from: fromHead,
|
|
23080
|
+
to: head,
|
|
23081
|
+
fromBase: row.fromBase,
|
|
23082
|
+
toBase: row.toBase
|
|
23083
|
+
});
|
|
23084
|
+
restackExact.set(row, known);
|
|
23085
|
+
}
|
|
23086
|
+
return known;
|
|
23087
|
+
};
|
|
22223
23088
|
const edges = new Map;
|
|
22224
23089
|
for (const row of rows)
|
|
22225
|
-
if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.integrity === "verified" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
|
|
23090
|
+
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))
|
|
22226
23091
|
edges.set(row.fromHead, [...edges.get(row.fromHead) ?? [], row.head]);
|
|
22227
23092
|
const seen = new Set([from]);
|
|
22228
23093
|
const queue = [from];
|
|
@@ -22256,9 +23121,57 @@ function checkVerdicts(cwd, branch, ledgerRows) {
|
|
|
22256
23121
|
return key;
|
|
22257
23122
|
};
|
|
22258
23123
|
const keyFor = (base) => keysAt(base, head);
|
|
22259
|
-
const
|
|
23124
|
+
const driftCache = new Map;
|
|
23125
|
+
const driftOf = (row) => {
|
|
23126
|
+
if (driftCache.has(row))
|
|
23127
|
+
return driftCache.get(row) ?? null;
|
|
23128
|
+
let drift = null;
|
|
23129
|
+
const toBase = row.base ?? fallbackBase;
|
|
23130
|
+
const toBaseSha = toBase ? resolveCommit(cwd, toBase) : null;
|
|
23131
|
+
const fromBase = row.baseSha ?? toBaseSha;
|
|
23132
|
+
if (row.head && head && row.head !== head && toBaseSha && fromBase && !untrusted(reasonsOf(row)))
|
|
23133
|
+
drift = verdictDrift(cwd, {
|
|
23134
|
+
from: row.head,
|
|
23135
|
+
to: head,
|
|
23136
|
+
fromBase,
|
|
23137
|
+
toBase: toBaseSha,
|
|
23138
|
+
kind: typeof row.kind === "string" ? row.kind : "review"
|
|
23139
|
+
});
|
|
23140
|
+
driftCache.set(row, drift);
|
|
23141
|
+
return drift;
|
|
23142
|
+
};
|
|
23143
|
+
const exactCache = new Map;
|
|
23144
|
+
const exactCarry = (row) => {
|
|
23145
|
+
if (FAILING.has(String(row.result)))
|
|
23146
|
+
return true;
|
|
23147
|
+
let exact = exactCache.get(row);
|
|
23148
|
+
if (exact === undefined) {
|
|
23149
|
+
const toBase = row.base ?? fallbackBase;
|
|
23150
|
+
const toBaseSha = toBase ? resolveCommit(cwd, toBase) : null;
|
|
23151
|
+
const fromBase = row.baseSha ?? toBaseSha;
|
|
23152
|
+
exact = Boolean(row.head && head && toBaseSha && fromBase && sameOwnChange(cwd, { from: row.head, to: head, fromBase, toBase: toBaseSha }));
|
|
23153
|
+
exactCache.set(row, exact);
|
|
23154
|
+
}
|
|
23155
|
+
return exact;
|
|
23156
|
+
};
|
|
23157
|
+
const keyBasis = (row) => {
|
|
22260
23158
|
const basis = verdictBasis(row, { head, ...keyFor(row.base ?? fallbackBase) });
|
|
22261
|
-
return basis === "
|
|
23159
|
+
return basis === "carried" && !exactCarry(row) ? "stale" : basis;
|
|
23160
|
+
};
|
|
23161
|
+
const restacked = (row) => restackCarries(FAILING.has(String(row.result)) ? null : cwd, rows, branch, row.head, head);
|
|
23162
|
+
const carryOf = (row) => {
|
|
23163
|
+
if (keyBasis(row) !== "stale")
|
|
23164
|
+
return null;
|
|
23165
|
+
if (restacked(row))
|
|
23166
|
+
return null;
|
|
23167
|
+
const drift = driftOf(row);
|
|
23168
|
+
return drift?.carries ? { rule: drift.rule, since: drift.since, files: drift.files } : null;
|
|
23169
|
+
};
|
|
23170
|
+
const basisOf = (row) => {
|
|
23171
|
+
const basis = keyBasis(row);
|
|
23172
|
+
if (basis !== "stale")
|
|
23173
|
+
return basis;
|
|
23174
|
+
return restacked(row) || carryOf(row) ? "carried" : basis;
|
|
22262
23175
|
};
|
|
22263
23176
|
const sameCode = (failed, row) => {
|
|
22264
23177
|
if (failed.head && failed.head === row.head)
|
|
@@ -22266,7 +23179,7 @@ function checkVerdicts(cwd, branch, ledgerRows) {
|
|
|
22266
23179
|
const base = failed.base ?? fallbackBase;
|
|
22267
23180
|
const stored = (row.base ?? fallbackBase) === base && row.baseSha !== null && row.baseSha === failed.baseSha;
|
|
22268
23181
|
const keys = stored ? { patchId: row.patchId, diffHash: row.diffHash } : keysAt(base, row.head);
|
|
22269
|
-
return verdictBasis(failed, { head: row.head, ...keys }) !== "stale" || restackCarries(rows, branch, failed.head, row.head);
|
|
23182
|
+
return verdictBasis(failed, { head: row.head, ...keys }) !== "stale" || restackCarries(null, rows, branch, failed.head, row.head);
|
|
22270
23183
|
};
|
|
22271
23184
|
const authors = authorSessions(cwd, rows, branch, { base: fallbackBase, head }, scope);
|
|
22272
23185
|
const failureAuthorCache = new Map;
|
|
@@ -22322,6 +23235,7 @@ function checkVerdicts(cwd, branch, ledgerRows) {
|
|
|
22322
23235
|
independent: independence.length === 0,
|
|
22323
23236
|
accepted: reasons.length === 0,
|
|
22324
23237
|
reasons,
|
|
23238
|
+
carry: basis === "carried" ? carryOf(row) : null,
|
|
22325
23239
|
verdict: row
|
|
22326
23240
|
});
|
|
22327
23241
|
if (reasons.length === 0) {
|
|
@@ -22350,7 +23264,12 @@ function checkVerdicts(cwd, branch, ledgerRows) {
|
|
|
22350
23264
|
verdict: failing?.verdict ?? null,
|
|
22351
23265
|
reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
|
|
22352
23266
|
};
|
|
22353
|
-
const
|
|
23267
|
+
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))));
|
|
23268
|
+
const selfEntry = latestSelf && STRONG_RESULTS.has(String(latestSelf.verdict.result)) ? latestSelf : undefined;
|
|
23269
|
+
const carryEntry = verdicts.find((entry) => entry.verdict === accepted.verdict && entry.accepted) ?? newestCurrent;
|
|
23270
|
+
const lastPass = accepted.accepted || failing || tampered.length ? undefined : verdicts.findLast((entry) => !entry.current && !untrusted(entry.reasons) && STRONG_RESULTS.has(String(entry.verdict.result)));
|
|
23271
|
+
const drift = lastPass ? driftOf(lastPass.verdict) : null;
|
|
23272
|
+
const reverify = drift && !drift.carries && drift.focused && drift.files ? { scope: "focused", since: drift.since, files: drift.files } : null;
|
|
22354
23273
|
return {
|
|
22355
23274
|
branch,
|
|
22356
23275
|
head,
|
|
@@ -22359,6 +23278,8 @@ function checkVerdicts(cwd, branch, ledgerRows) {
|
|
|
22359
23278
|
base: newestCurrent?.verdict.base ?? fallbackBase,
|
|
22360
23279
|
patchId: keyFor(newestCurrent?.verdict.base ?? fallbackBase).patchId,
|
|
22361
23280
|
current: { basis: newestCurrent?.basis ?? "none", verdict: newestCurrent?.verdict ?? null },
|
|
23281
|
+
carry: carryEntry?.carry ?? null,
|
|
23282
|
+
reverify,
|
|
22362
23283
|
accepted,
|
|
22363
23284
|
verdicts,
|
|
22364
23285
|
authors: [...authors].toSorted(),
|
|
@@ -22378,6 +23299,7 @@ var RULES = {
|
|
|
22378
23299
|
self: "verdict:self",
|
|
22379
23300
|
nonAuthor: "verdict:non-author",
|
|
22380
23301
|
verified: "verdict:verified",
|
|
23302
|
+
lane: "verdict:lane",
|
|
22381
23303
|
product: "decision:product",
|
|
22382
23304
|
plan: "plan"
|
|
22383
23305
|
};
|
|
@@ -22400,6 +23322,7 @@ var normalizedScope = (scope) => ({
|
|
|
22400
23322
|
function deriveRequirements(judgment, scope, constraints, verification = "self") {
|
|
22401
23323
|
const out = [];
|
|
22402
23324
|
const base = { scope, dependentAction: null };
|
|
23325
|
+
const proportional = verification === "proportional";
|
|
22403
23326
|
if (judgment.behaviorChange)
|
|
22404
23327
|
out.push(derived2({
|
|
22405
23328
|
...base,
|
|
@@ -22410,7 +23333,17 @@ function deriveRequirements(judgment, scope, constraints, verification = "self")
|
|
|
22410
23333
|
before: "close",
|
|
22411
23334
|
acceptanceAllowed: false
|
|
22412
23335
|
}));
|
|
22413
|
-
if (
|
|
23336
|
+
if (proportional && judgment.riskTier === "normal")
|
|
23337
|
+
out.push(derived2({
|
|
23338
|
+
...base,
|
|
23339
|
+
ruleId: RULES.lane,
|
|
23340
|
+
dimension: "review",
|
|
23341
|
+
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.",
|
|
23342
|
+
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.",
|
|
23343
|
+
before: "close",
|
|
23344
|
+
acceptanceAllowed: false
|
|
23345
|
+
}));
|
|
23346
|
+
if (!proportional && judgment.behaviorChange && judgment.riskTier === "normal")
|
|
22414
23347
|
out.push(verification === "independent" ? derived2({
|
|
22415
23348
|
...base,
|
|
22416
23349
|
ruleId: RULES.nonAuthor,
|
|
@@ -22513,7 +23446,7 @@ var productDecision = (task, ledger) => {
|
|
|
22513
23446
|
};
|
|
22514
23447
|
};
|
|
22515
23448
|
var planRecorded = (task, root) => {
|
|
22516
|
-
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" &&
|
|
23449
|
+
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync5(path16.resolve(root, ref.path)));
|
|
22517
23450
|
if (cited)
|
|
22518
23451
|
return {
|
|
22519
23452
|
met: true,
|
|
@@ -22527,14 +23460,30 @@ var planRecorded = (task, root) => {
|
|
|
22527
23460
|
decisionIds: []
|
|
22528
23461
|
};
|
|
22529
23462
|
};
|
|
22530
|
-
var
|
|
23463
|
+
var workingLane = (task, root) => branchLane(root, { head: null, workingTree: true, judgment: latestJudgment(task) });
|
|
23464
|
+
var laneVerdict = (task, root, ledger) => {
|
|
23465
|
+
if (!ledger.branch() && latestJudgment(task)?.behaviorChange === false)
|
|
23466
|
+
return {
|
|
23467
|
+
met: true,
|
|
23468
|
+
reason: "no branch to read a lane from, and the judgment records no behavior change",
|
|
23469
|
+
decisionIds: []
|
|
23470
|
+
};
|
|
23471
|
+
const lane = workingLane(task, root);
|
|
23472
|
+
const label = `lane ${lane.lane} (${lane.reasons.join("; ")})`;
|
|
23473
|
+
const need = laneNeed(lane.lane);
|
|
23474
|
+
if (need === "none")
|
|
23475
|
+
return { met: true, reason: `${label}: no verdict needed`, decisionIds: [] };
|
|
23476
|
+
const status = verdict(need === "self" ? RULES.self : RULES.nonAuthor, root, ledger);
|
|
23477
|
+
return { ...status, reason: `${label}: ${status.reason}` };
|
|
23478
|
+
};
|
|
23479
|
+
var verdict = (ruleId, root, ledger) => {
|
|
22531
23480
|
const branch = ledger.branch();
|
|
22532
23481
|
if (!branch)
|
|
22533
23482
|
return { met: false, reason: "no branch is checked out to hold a verdict", decisionIds: [] };
|
|
22534
23483
|
const check = checkVerdicts(root, branch, ledger.rows());
|
|
22535
23484
|
const failing = check.accepted.reasons.includes("failing_verdict");
|
|
22536
23485
|
const strong = (entry) => STRONG_RESULTS.has(String(entry.verdict.result));
|
|
22537
|
-
const met = !failing && (
|
|
23486
|
+
const met = !failing && (ruleId === RULES.verified ? check.verdicts.find((entry) => entry.accepted && entry.kind === "live" && String(entry.verdict.result) === "verified") : ruleId === RULES.nonAuthor ? check.verdicts.find((entry) => entry.accepted && strong(entry)) : check.verdicts.find((entry) => entry.current && strong(entry)));
|
|
22538
23487
|
if (met)
|
|
22539
23488
|
return {
|
|
22540
23489
|
met: true,
|
|
@@ -22542,7 +23491,7 @@ var verdict = (requirement, root, ledger) => {
|
|
|
22542
23491
|
decisionIds: []
|
|
22543
23492
|
};
|
|
22544
23493
|
const why = failing ? "a current independent verdict fails" : check.verdicts.some((entry) => entry.current && entry.verdict.result === "type-check-only") ? "type-check-only does not prove a behavior change" : (check.accepted.reasons.join(", ") || "no_verdict").replace(/_/g, " ");
|
|
22545
|
-
const unblock =
|
|
23494
|
+
const unblock = ruleId === RULES.self ? "record your own verdict after an observed `workit check test`: `workit ledger verdict tests-verified --self --how <what you ran>` (shown as self-reviewed), or have a verifier record one" : `an independent session records \`workit ledger verdict verified${ruleId === RULES.verified ? " --kind live" : ""} --how <what it exercised>\``;
|
|
22546
23495
|
return { met: false, reason: `${why}: ${unblock}`, decisionIds: [] };
|
|
22547
23496
|
};
|
|
22548
23497
|
function derivedRuleStatus(task, requirement, root, ledger) {
|
|
@@ -22554,7 +23503,9 @@ function derivedRuleStatus(task, requirement, root, ledger) {
|
|
|
22554
23503
|
case RULES.self:
|
|
22555
23504
|
case RULES.nonAuthor:
|
|
22556
23505
|
case RULES.verified:
|
|
22557
|
-
return verdict(requirement, root, ledger);
|
|
23506
|
+
return verdict(requirement.ruleId, root, ledger);
|
|
23507
|
+
case RULES.lane:
|
|
23508
|
+
return laneVerdict(task, root, ledger);
|
|
22558
23509
|
default:
|
|
22559
23510
|
return null;
|
|
22560
23511
|
}
|
|
@@ -22562,14 +23513,14 @@ function derivedRuleStatus(task, requirement, root, ledger) {
|
|
|
22562
23513
|
|
|
22563
23514
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
22564
23515
|
var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
|
|
22565
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
22566
|
-
var relative = (root, candidate) =>
|
|
23516
|
+
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path17.sep}`);
|
|
23517
|
+
var relative = (root, candidate) => path17.relative(root, candidate).split(path17.sep).join("/") || ".";
|
|
22567
23518
|
var canonicalPath = (value) => {
|
|
22568
23519
|
if (typeof value !== "string" || !value)
|
|
22569
23520
|
return null;
|
|
22570
23521
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
22571
23522
|
return null;
|
|
22572
|
-
const normalized =
|
|
23523
|
+
const normalized = path17.posix.normalize(value);
|
|
22573
23524
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
22574
23525
|
return null;
|
|
22575
23526
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -22617,14 +23568,14 @@ var gitPaths = (root) => {
|
|
|
22617
23568
|
git: !/not a git repository/i.test(stderr)
|
|
22618
23569
|
};
|
|
22619
23570
|
}
|
|
22620
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
23571
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path17.sep).join("/")) : [];
|
|
22621
23572
|
const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
22622
23573
|
if (stagedDeleted.status !== 0) {
|
|
22623
23574
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
22624
23575
|
if (!/not a git repository/i.test(stderr))
|
|
22625
23576
|
return { paths, uncertain: true, git: true };
|
|
22626
23577
|
} else if (stagedDeleted.stdout) {
|
|
22627
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
23578
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path17.sep).join("/")));
|
|
22628
23579
|
}
|
|
22629
23580
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
22630
23581
|
};
|
|
@@ -22639,7 +23590,7 @@ var walk = (root, directory, output) => {
|
|
|
22639
23590
|
for (const name of names) {
|
|
22640
23591
|
if (name === ".git" || name === ".workit")
|
|
22641
23592
|
continue;
|
|
22642
|
-
const target =
|
|
23593
|
+
const target = path17.join(directory, name);
|
|
22643
23594
|
let stat;
|
|
22644
23595
|
try {
|
|
22645
23596
|
stat = fs13.lstatSync(target);
|
|
@@ -22657,12 +23608,12 @@ var walk = (root, directory, output) => {
|
|
|
22657
23608
|
var scopeRoots = (root, scope) => {
|
|
22658
23609
|
const roots = [];
|
|
22659
23610
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
22660
|
-
const target =
|
|
23611
|
+
const target = path17.resolve(root, item);
|
|
22661
23612
|
if (!inside(root, target))
|
|
22662
23613
|
return failure2("invalid_input", `candidate scope escapes checkout: ${item} — keep one task per repository and coordinate a separate linked task in the other checkout`, { fields: [{ path: "scope.paths", reason: `${item} is outside the checkout` }] });
|
|
22663
23614
|
let ancestor = target;
|
|
22664
23615
|
while (!fs13.existsSync(ancestor) && ancestor !== root)
|
|
22665
|
-
ancestor =
|
|
23616
|
+
ancestor = path17.dirname(ancestor);
|
|
22666
23617
|
try {
|
|
22667
23618
|
if (!inside(root, fs13.realpathSync(ancestor)))
|
|
22668
23619
|
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` }] });
|
|
@@ -22714,7 +23665,7 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
22714
23665
|
for (const item of [...names].toSorted()) {
|
|
22715
23666
|
if (!scopeMatches(item, normalizedScope))
|
|
22716
23667
|
continue;
|
|
22717
|
-
const target =
|
|
23668
|
+
const target = path17.join(checkout, item);
|
|
22718
23669
|
try {
|
|
22719
23670
|
const stat = fs13.lstatSync(target);
|
|
22720
23671
|
if (stat.isSymbolicLink()) {
|
|
@@ -22898,23 +23849,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
22898
23849
|
continue;
|
|
22899
23850
|
if (!reference.digest)
|
|
22900
23851
|
return failure2("invalid_input", "document references require a byte digest");
|
|
22901
|
-
const target =
|
|
22902
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
23852
|
+
const target = path17.resolve(root, reference.path);
|
|
23853
|
+
if (target !== root && !target.startsWith(`${root}${path17.sep}`))
|
|
22903
23854
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
22904
23855
|
fields: [
|
|
22905
23856
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
22906
23857
|
]
|
|
22907
23858
|
});
|
|
22908
23859
|
try {
|
|
22909
|
-
const below =
|
|
23860
|
+
const below = path17.relative(root, target);
|
|
22910
23861
|
let current = root;
|
|
22911
|
-
for (const segment of below.split(
|
|
23862
|
+
for (const segment of below.split(path17.sep)) {
|
|
22912
23863
|
if (!segment)
|
|
22913
23864
|
continue;
|
|
22914
|
-
current =
|
|
23865
|
+
current = path17.join(current, segment);
|
|
22915
23866
|
const stat = fs13.lstatSync(current);
|
|
22916
23867
|
const real = fs13.realpathSync(current);
|
|
22917
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
23868
|
+
if (real !== root && !real.startsWith(`${root}${path17.sep}`))
|
|
22918
23869
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
22919
23870
|
fields: [
|
|
22920
23871
|
{
|
|
@@ -23773,7 +24724,7 @@ var judgeInputSummary = (raw) => {
|
|
|
23773
24724
|
|
|
23774
24725
|
// packages/workit-core/src/autonomy.ts
|
|
23775
24726
|
import os4 from "node:os";
|
|
23776
|
-
import
|
|
24727
|
+
import path18 from "node:path";
|
|
23777
24728
|
var accountHome = () => {
|
|
23778
24729
|
try {
|
|
23779
24730
|
return os4.userInfo().homedir;
|
|
@@ -23782,10 +24733,10 @@ var accountHome = () => {
|
|
|
23782
24733
|
}
|
|
23783
24734
|
};
|
|
23784
24735
|
var grantsHome = { resolve: accountHome };
|
|
23785
|
-
var grantsDir = () =>
|
|
24736
|
+
var grantsDir = () => path18.join(grantsHome.resolve(), ".config", "workit");
|
|
23786
24737
|
var grantsOverride = () => {
|
|
23787
|
-
const configured =
|
|
23788
|
-
return configured ===
|
|
24738
|
+
const configured = path18.resolve(resolveConfigDir());
|
|
24739
|
+
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`;
|
|
23789
24740
|
};
|
|
23790
24741
|
var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
|
|
23791
24742
|
var DEFAULT_GRANTS = Object.freeze({
|
|
@@ -23838,8 +24789,16 @@ function endpointView(entry, context) {
|
|
|
23838
24789
|
...issue ? { endpointIssue: issue } : {}
|
|
23839
24790
|
};
|
|
23840
24791
|
}
|
|
23841
|
-
var
|
|
23842
|
-
|
|
24792
|
+
var VERIFICATION_MODES = [
|
|
24793
|
+
"proportional",
|
|
24794
|
+
"self",
|
|
24795
|
+
"independent"
|
|
24796
|
+
];
|
|
24797
|
+
var DEFAULT_VERIFICATION = "proportional";
|
|
24798
|
+
var verificationOf = (entry) => {
|
|
24799
|
+
const value = entry?.verification;
|
|
24800
|
+
return VERIFICATION_MODES.includes(value) ? value : DEFAULT_VERIFICATION;
|
|
24801
|
+
};
|
|
23843
24802
|
var isGrantValue = (value) => value === true || value === false || value === "verified";
|
|
23844
24803
|
var normalized = (kind, value) => value === "verified" && kind !== "merge" ? true : value;
|
|
23845
24804
|
var fromAutoApprove = (value) => {
|
|
@@ -25587,8 +26546,8 @@ class WorkitCore {
|
|
|
25587
26546
|
}
|
|
25588
26547
|
// packages/workit-core/src/core/repo-context.ts
|
|
25589
26548
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
25590
|
-
import { existsSync as
|
|
25591
|
-
import
|
|
26549
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "node:fs";
|
|
26550
|
+
import path19 from "node:path";
|
|
25592
26551
|
var isSafeContextRange = (value) => value.length <= 4096 && (() => {
|
|
25593
26552
|
try {
|
|
25594
26553
|
gitRevisionParts(value);
|
|
@@ -25722,7 +26681,7 @@ var findPrTemplate = (cwd) => {
|
|
|
25722
26681
|
]) {
|
|
25723
26682
|
const parts = rel.split("/");
|
|
25724
26683
|
const base = parts[parts.length - 1];
|
|
25725
|
-
const dir = parts.length > 1 ?
|
|
26684
|
+
const dir = parts.length > 1 ? path19.join(cwd, ...parts.slice(0, -1)) : cwd;
|
|
25726
26685
|
const actual = probeCaseInsensitive(dir, base);
|
|
25727
26686
|
if (actual)
|
|
25728
26687
|
return [...parts.slice(0, -1), actual].join("/");
|
|
@@ -25753,11 +26712,11 @@ var diffStatForRange = (cwd, range) => {
|
|
|
25753
26712
|
return runGit(cwd, ["diff", "--stat", "--"]).stdout;
|
|
25754
26713
|
};
|
|
25755
26714
|
var packageScripts = (cwd, keys) => {
|
|
25756
|
-
const pkgPath =
|
|
25757
|
-
if (!
|
|
26715
|
+
const pkgPath = path19.join(cwd, "package.json");
|
|
26716
|
+
if (!existsSync7(pkgPath))
|
|
25758
26717
|
return [];
|
|
25759
26718
|
try {
|
|
25760
|
-
const pkg = JSON.parse(
|
|
26719
|
+
const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
|
|
25761
26720
|
return keys.filter((k) => pkg.scripts && typeof pkg.scripts[k] === "string").map((k) => `${k}: ${pkg.scripts?.[k]}`);
|
|
25762
26721
|
} catch {
|
|
25763
26722
|
return [];
|
|
@@ -25779,9 +26738,9 @@ var documentationFiles = (cwd) => {
|
|
|
25779
26738
|
if (entry.isDirectory()) {
|
|
25780
26739
|
if (excluded.has(entry.name))
|
|
25781
26740
|
continue;
|
|
25782
|
-
walk(
|
|
26741
|
+
walk(path19.join(dir, entry.name), depth + 1);
|
|
25783
26742
|
} else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
|
|
25784
|
-
matches.push("./" +
|
|
26743
|
+
matches.push("./" + path19.relative(cwd, path19.join(dir, entry.name)).replaceAll("\\", "/"));
|
|
25785
26744
|
}
|
|
25786
26745
|
}
|
|
25787
26746
|
};
|
|
@@ -25789,15 +26748,15 @@ var documentationFiles = (cwd) => {
|
|
|
25789
26748
|
return matches.toSorted().slice(0, 200);
|
|
25790
26749
|
};
|
|
25791
26750
|
var readTrimmed2 = (file, maxLines) => {
|
|
25792
|
-
if (!
|
|
26751
|
+
if (!existsSync7(file))
|
|
25793
26752
|
return "";
|
|
25794
|
-
const lines =
|
|
26753
|
+
const lines = readFileSync6(file, "utf8").split(`
|
|
25795
26754
|
`);
|
|
25796
26755
|
return lines.slice(0, maxLines).join(`
|
|
25797
26756
|
`);
|
|
25798
26757
|
};
|
|
25799
26758
|
function prReadyContext(root, range) {
|
|
25800
|
-
const cwd =
|
|
26759
|
+
const cwd = path19.resolve(repoRoot(root));
|
|
25801
26760
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
25802
26761
|
return invalidRange(cwd);
|
|
25803
26762
|
let stdout = "";
|
|
@@ -25855,7 +26814,7 @@ ${status.stderr}` : "");
|
|
|
25855
26814
|
stdout += `template_path: ${template}
|
|
25856
26815
|
|
|
25857
26816
|
`;
|
|
25858
|
-
stdout += readTrimmed2(
|
|
26817
|
+
stdout += readTrimmed2(path19.join(cwd, template), 220);
|
|
25859
26818
|
} else {
|
|
25860
26819
|
stdout += `template_path: none
|
|
25861
26820
|
|
|
@@ -25865,7 +26824,7 @@ ${status.stderr}` : "");
|
|
|
25865
26824
|
stdout += `
|
|
25866
26825
|
`;
|
|
25867
26826
|
stdout += printSection("Recent Validation Signals");
|
|
25868
|
-
if (
|
|
26827
|
+
if (existsSync7(path19.join(cwd, "package.json"))) {
|
|
25869
26828
|
stdout += `package.json detected. Common scripts:
|
|
25870
26829
|
`;
|
|
25871
26830
|
const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
|
|
@@ -25874,7 +26833,7 @@ ${status.stderr}` : "");
|
|
|
25874
26833
|
`) + `
|
|
25875
26834
|
`;
|
|
25876
26835
|
}
|
|
25877
|
-
if (
|
|
26836
|
+
if (existsSync7(path19.join(cwd, "Cargo.toml")) || existsSync7(path19.join(cwd, "src-tauri/Cargo.toml"))) {
|
|
25878
26837
|
stdout += `Rust project detected.
|
|
25879
26838
|
`;
|
|
25880
26839
|
}
|
|
@@ -25907,7 +26866,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
|
|
|
25907
26866
|
- Apply with the host-native editor, preserving the repository changelog conventions.
|
|
25908
26867
|
- If Unreleased already has duplicate category headings, normalize_only first.`;
|
|
25909
26868
|
function changelogContext(root, range) {
|
|
25910
|
-
const cwd =
|
|
26869
|
+
const cwd = path19.resolve(repoRoot(root));
|
|
25911
26870
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
25912
26871
|
return invalidRange(cwd);
|
|
25913
26872
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -25925,8 +26884,8 @@ function changelogContext(root, range) {
|
|
|
25925
26884
|
stdout += CHANGELOG_RULES + `
|
|
25926
26885
|
`;
|
|
25927
26886
|
stdout += printSection("Existing CHANGELOG.md");
|
|
25928
|
-
const changelogPath =
|
|
25929
|
-
if (
|
|
26887
|
+
const changelogPath = path19.join(cwd, "CHANGELOG.md");
|
|
26888
|
+
if (existsSync7(changelogPath)) {
|
|
25930
26889
|
stdout += readTrimmed2(changelogPath, 260) + `
|
|
25931
26890
|
`;
|
|
25932
26891
|
} else {
|
|
@@ -25945,7 +26904,7 @@ function changelogContext(root, range) {
|
|
|
25945
26904
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
25946
26905
|
}
|
|
25947
26906
|
function docsRefreshContext(root, range) {
|
|
25948
|
-
const cwd =
|
|
26907
|
+
const cwd = path19.resolve(repoRoot(root));
|
|
25949
26908
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
25950
26909
|
return invalidRange(cwd);
|
|
25951
26910
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -25967,8 +26926,8 @@ function docsRefreshContext(root, range) {
|
|
|
25967
26926
|
`) + `
|
|
25968
26927
|
`;
|
|
25969
26928
|
stdout += printSection("README Preview");
|
|
25970
|
-
const readme =
|
|
25971
|
-
if (
|
|
26929
|
+
const readme = path19.join(cwd, "README.md");
|
|
26930
|
+
if (existsSync7(readme)) {
|
|
25972
26931
|
stdout += readTrimmed2(readme, 220) + `
|
|
25973
26932
|
`;
|
|
25974
26933
|
} else {
|
|
@@ -25976,10 +26935,10 @@ function docsRefreshContext(root, range) {
|
|
|
25976
26935
|
`;
|
|
25977
26936
|
}
|
|
25978
26937
|
stdout += printSection("Package Scripts");
|
|
25979
|
-
const pkgPath =
|
|
25980
|
-
if (
|
|
26938
|
+
const pkgPath = path19.join(cwd, "package.json");
|
|
26939
|
+
if (existsSync7(pkgPath)) {
|
|
25981
26940
|
try {
|
|
25982
|
-
const pkg = JSON.parse(
|
|
26941
|
+
const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
|
|
25983
26942
|
stdout += JSON.stringify({ name: pkg.name, version: pkg.version, scripts: pkg.scripts }, null, 2) + `
|
|
25984
26943
|
`;
|
|
25985
26944
|
} catch {}
|
|
@@ -25990,7 +26949,7 @@ function docsRefreshContext(root, range) {
|
|
|
25990
26949
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
25991
26950
|
}
|
|
25992
26951
|
function releaseNotesContext(root, rangeOrTag) {
|
|
25993
|
-
const cwd =
|
|
26952
|
+
const cwd = path19.resolve(repoRoot(root));
|
|
25994
26953
|
if (!rangeOrTag) {
|
|
25995
26954
|
return { stdout: "", stderr: `ERROR: release tag or range required
|
|
25996
26955
|
`, exitCode: 1, cwd };
|
|
@@ -26028,7 +26987,7 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
26028
26987
|
`;
|
|
26029
26988
|
stdout += printSection("Existing Release Files");
|
|
26030
26989
|
for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
|
|
26031
|
-
if (
|
|
26990
|
+
if (existsSync7(path19.join(cwd, rel)))
|
|
26032
26991
|
stdout += rel + `
|
|
26033
26992
|
`;
|
|
26034
26993
|
}
|
|
@@ -26060,7 +27019,7 @@ import { spawnSync as spawnSync13 } from "node:child_process";
|
|
|
26060
27019
|
|
|
26061
27020
|
// packages/workit-core/src/core/pr-create.ts
|
|
26062
27021
|
import fs14 from "node:fs";
|
|
26063
|
-
import
|
|
27022
|
+
import path20 from "node:path";
|
|
26064
27023
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
26065
27024
|
// packages/workit-core/src/forge/pr-body.ts
|
|
26066
27025
|
function parseGhIssue(value) {
|
|
@@ -26071,11 +27030,11 @@ function parseGhIssue(value) {
|
|
|
26071
27030
|
// packages/workit-core/src/core/pr-create.ts
|
|
26072
27031
|
function whichOnPath(tool) {
|
|
26073
27032
|
const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
|
|
26074
|
-
for (const dir of (process.env.PATH ?? "").split(
|
|
27033
|
+
for (const dir of (process.env.PATH ?? "").split(path20.delimiter)) {
|
|
26075
27034
|
if (!dir)
|
|
26076
27035
|
continue;
|
|
26077
27036
|
for (const name of names) {
|
|
26078
|
-
const candidate =
|
|
27037
|
+
const candidate = path20.join(dir, name);
|
|
26079
27038
|
try {
|
|
26080
27039
|
fs14.accessSync(candidate, fs14.constants.X_OK);
|
|
26081
27040
|
return candidate;
|
|
@@ -26196,7 +27155,7 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
|
|
|
26196
27155
|
|
|
26197
27156
|
// packages/workit-core/src/core/youtrack.ts
|
|
26198
27157
|
import fs15 from "node:fs";
|
|
26199
|
-
import
|
|
27158
|
+
import path21 from "node:path";
|
|
26200
27159
|
|
|
26201
27160
|
// packages/workit-core/src/core/templates.ts
|
|
26202
27161
|
var repoRoot2 = assetRoot();
|
|
@@ -26209,8 +27168,8 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
|
|
|
26209
27168
|
// packages/workit-core/src/core/youtrack.ts
|
|
26210
27169
|
var ISSUE_RE = /^[A-Z]+-\d+$/;
|
|
26211
27170
|
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
26212
|
-
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
26213
|
-
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
27171
|
+
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path21.join(configDir(), "youtrack.json");
|
|
27172
|
+
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path21.join(resolveConfigDir(), "youtrack.json");
|
|
26214
27173
|
var youTrackTokenModeOk = (p) => {
|
|
26215
27174
|
if (process.platform === "win32")
|
|
26216
27175
|
return true;
|
|
@@ -26278,7 +27237,7 @@ var youTrackToken = () => {
|
|
|
26278
27237
|
if ("error" in loaded)
|
|
26279
27238
|
return loaded;
|
|
26280
27239
|
const tokenFile = String(loaded.config.tokenFile ?? "");
|
|
26281
|
-
const tokenPath = tokenFile ?
|
|
27240
|
+
const tokenPath = tokenFile ? path21.isAbsolute(tokenFile) ? path21.resolve(tokenFile) : path21.resolve(process.cwd(), tokenFile) : "";
|
|
26282
27241
|
if (!tokenPath || !fs15.existsSync(tokenPath))
|
|
26283
27242
|
return { error: "missing youtrack.token" };
|
|
26284
27243
|
if (!youTrackTokenModeOk(tokenPath))
|
|
@@ -26620,15 +27579,15 @@ function resolveGitRevision(root, value) {
|
|
|
26620
27579
|
}
|
|
26621
27580
|
function resolveInside(root, candidate) {
|
|
26622
27581
|
const base = realpathSync5(root);
|
|
26623
|
-
const target =
|
|
26624
|
-
if (target !== base && !target.startsWith(base +
|
|
27582
|
+
const target = path22.resolve(base, candidate);
|
|
27583
|
+
if (target !== base && !target.startsWith(base + path22.sep)) {
|
|
26625
27584
|
throw new Error("path must stay inside repository root");
|
|
26626
27585
|
}
|
|
26627
27586
|
let ancestor = target;
|
|
26628
|
-
while (!
|
|
26629
|
-
ancestor =
|
|
27587
|
+
while (!existsSync8(ancestor))
|
|
27588
|
+
ancestor = path22.dirname(ancestor);
|
|
26630
27589
|
const canonicalAncestor = realpathSync5(ancestor);
|
|
26631
|
-
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base +
|
|
27590
|
+
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path22.sep)) {
|
|
26632
27591
|
throw new Error("path must stay inside repository root");
|
|
26633
27592
|
}
|
|
26634
27593
|
return target;
|
|
@@ -26676,7 +27635,7 @@ var safeCapability = (value, allowed) => allowed.includes(value) ? value : "cont
|
|
|
26676
27635
|
var TOOL_CAPABILITIES = [...CONTEXT_KINDS, "workspace", "native_caller_identity"];
|
|
26677
27636
|
var VERSION = (() => {
|
|
26678
27637
|
try {
|
|
26679
|
-
const packageJson = JSON.parse(
|
|
27638
|
+
const packageJson = JSON.parse(readFileSync7(new URL("../package.json", import.meta.url), "utf8"));
|
|
26680
27639
|
return typeof packageJson.version === "string" ? packageJson.version : "0.0.0";
|
|
26681
27640
|
} catch {
|
|
26682
27641
|
return "0.0.0";
|
|
@@ -26686,13 +27645,13 @@ var rootVariants = (workspaceRoot) => {
|
|
|
26686
27645
|
if (!workspaceRoot)
|
|
26687
27646
|
return [];
|
|
26688
27647
|
const roots = new Set;
|
|
26689
|
-
for (const candidate of [workspaceRoot,
|
|
26690
|
-
if (
|
|
27648
|
+
for (const candidate of [workspaceRoot, path23.resolve(workspaceRoot)]) {
|
|
27649
|
+
if (path23.isAbsolute(candidate) && candidate !== path23.parse(candidate).root)
|
|
26691
27650
|
roots.add(candidate);
|
|
26692
27651
|
}
|
|
26693
27652
|
try {
|
|
26694
27653
|
const canonical = realpathSync6(workspaceRoot);
|
|
26695
|
-
if (canonical !==
|
|
27654
|
+
if (canonical !== path23.parse(canonical).root)
|
|
26696
27655
|
roots.add(canonical);
|
|
26697
27656
|
} catch {}
|
|
26698
27657
|
return [...roots].toSorted((left, right) => right.length - left.length);
|
|
@@ -26774,12 +27733,12 @@ var thrownResult = (tool, error, workspaceRoot) => {
|
|
|
26774
27733
|
};
|
|
26775
27734
|
function createMcpServer(host, contextProvider) {
|
|
26776
27735
|
assertMcpHost(host);
|
|
26777
|
-
const here =
|
|
27736
|
+
const here = path23.dirname(fileURLToPath2(import.meta.url));
|
|
26778
27737
|
const sourceMarker = markSourcesLoaded([
|
|
26779
|
-
|
|
26780
|
-
|
|
26781
|
-
|
|
26782
|
-
].filter((file) =>
|
|
27738
|
+
path23.join(here, "server.ts"),
|
|
27739
|
+
path23.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
|
|
27740
|
+
path23.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
|
|
27741
|
+
].filter((file) => existsSync9(file)));
|
|
26783
27742
|
let staleWarned = false;
|
|
26784
27743
|
const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
|
|
26785
27744
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
@@ -26959,8 +27918,8 @@ var main = async () => {
|
|
|
26959
27918
|
process.exitCode = 2;
|
|
26960
27919
|
}
|
|
26961
27920
|
};
|
|
26962
|
-
var entryPath = process.argv[1] ?
|
|
26963
|
-
if (entryPath ===
|
|
27921
|
+
var entryPath = process.argv[1] ? path24.resolve(process.argv[1]) : "";
|
|
27922
|
+
if (entryPath === path24.resolve(fileURLToPath3(import.meta.url)))
|
|
26964
27923
|
await main();
|
|
26965
27924
|
export {
|
|
26966
27925
|
McpCapabilityUnavailableError,
|