@brainervirus/workit-codex 8.23.0 → 8.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex-plugin/plugin.json +1 -1
- package/dist/launch-mcp.js +986 -161
- package/dist/{workit-hook-hegafjtc.js → workit-hook-q465naq9.js} +1035 -188
- package/dist/workit-hook.js +2 -2
- package/package.json +3 -3
- package/skills/workit-fanout/SKILL.md +1 -1
- package/skills/workit-implement/SKILL.md +5 -5
- package/skills/workit-review/SKILL.md +3 -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,124 @@ function resolveRef(cwd, ref) {
|
|
|
15400
15400
|
return null;
|
|
15401
15401
|
return line(git(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]));
|
|
15402
15402
|
}
|
|
15403
|
+
var LANE_DIFF = [
|
|
15404
|
+
"-c",
|
|
15405
|
+
"core.quotePath=false",
|
|
15406
|
+
"diff",
|
|
15407
|
+
"--no-color",
|
|
15408
|
+
"--no-ext-diff",
|
|
15409
|
+
"--no-textconv",
|
|
15410
|
+
"--no-renames"
|
|
15411
|
+
];
|
|
15412
|
+
var laneRange = (fork, head) => {
|
|
15413
|
+
if (!safeArg(fork) || head !== null && !safeArg(head))
|
|
15414
|
+
return null;
|
|
15415
|
+
return head === null ? [fork] : [fork, head];
|
|
15416
|
+
};
|
|
15417
|
+
function diffNumstat(cwd, fork, head) {
|
|
15418
|
+
const range = laneRange(fork, head);
|
|
15419
|
+
if (!range)
|
|
15420
|
+
return null;
|
|
15421
|
+
const run = git(cwd, [...LANE_DIFF, "--numstat", "-z", ...range, "--"]);
|
|
15422
|
+
if (!run.ok)
|
|
15423
|
+
return null;
|
|
15424
|
+
const out = [];
|
|
15425
|
+
for (const record of run.stdout.split("\x00")) {
|
|
15426
|
+
const match = /^(-|\d+)\t(-|\d+)\t(.+)$/su.exec(record.replace(/^\n/u, ""));
|
|
15427
|
+
if (!match)
|
|
15428
|
+
continue;
|
|
15429
|
+
const binary = match[1] === "-";
|
|
15430
|
+
out.push({
|
|
15431
|
+
path: match[3],
|
|
15432
|
+
added: binary ? 0 : Number(match[1]),
|
|
15433
|
+
deleted: binary ? 0 : Number(match[2]),
|
|
15434
|
+
binary
|
|
15435
|
+
});
|
|
15436
|
+
}
|
|
15437
|
+
return out;
|
|
15438
|
+
}
|
|
15439
|
+
function diffRaw(cwd, fork, head) {
|
|
15440
|
+
const range = laneRange(fork, head);
|
|
15441
|
+
if (!range)
|
|
15442
|
+
return null;
|
|
15443
|
+
const run = git(cwd, [...LANE_DIFF, "--raw", "-z", "--no-abbrev", ...range, "--"]);
|
|
15444
|
+
if (!run.ok)
|
|
15445
|
+
return null;
|
|
15446
|
+
const fields = run.stdout.split("\x00");
|
|
15447
|
+
const out = [];
|
|
15448
|
+
for (let index = 0;index + 1 < fields.length; index += 2) {
|
|
15449
|
+
const meta = /^:(\d{6}) (\d{6}) ([0-9a-f]+) ([0-9a-f]+) [A-Z]\d*$/u.exec(fields[index].replace(/^\n/u, ""));
|
|
15450
|
+
if (!meta)
|
|
15451
|
+
return null;
|
|
15452
|
+
out.push({
|
|
15453
|
+
path: fields[index + 1],
|
|
15454
|
+
oldMode: meta[1],
|
|
15455
|
+
newMode: meta[2],
|
|
15456
|
+
oldBlob: meta[3],
|
|
15457
|
+
newBlob: meta[4]
|
|
15458
|
+
});
|
|
15459
|
+
}
|
|
15460
|
+
return out;
|
|
15461
|
+
}
|
|
15462
|
+
function readBlobs(cwd, ids) {
|
|
15463
|
+
const out = new Map;
|
|
15464
|
+
const wanted = [...new Set(ids)].filter((id) => /^[0-9a-f]{40,64}$/u.test(id));
|
|
15465
|
+
if (!wanted.length)
|
|
15466
|
+
return out;
|
|
15467
|
+
const run = spawnSync3("git", ["cat-file", "--batch"], {
|
|
15468
|
+
cwd,
|
|
15469
|
+
input: `${wanted.join(`
|
|
15470
|
+
`)}
|
|
15471
|
+
`,
|
|
15472
|
+
maxBuffer: MAX_BUFFER,
|
|
15473
|
+
timeout: GIT_TIMEOUTS.local,
|
|
15474
|
+
killSignal: "SIGKILL",
|
|
15475
|
+
windowsHide: true
|
|
15476
|
+
});
|
|
15477
|
+
if (run.status !== 0 || !run.stdout)
|
|
15478
|
+
return null;
|
|
15479
|
+
const bytes = run.stdout;
|
|
15480
|
+
let at = 0;
|
|
15481
|
+
for (const id of wanted) {
|
|
15482
|
+
const end = bytes.indexOf(10, at);
|
|
15483
|
+
if (end < 0)
|
|
15484
|
+
return null;
|
|
15485
|
+
const header = bytes.subarray(at, end).toString("utf8").split(" ");
|
|
15486
|
+
at = end + 1;
|
|
15487
|
+
if (header[1] === "missing")
|
|
15488
|
+
continue;
|
|
15489
|
+
const size = Number(header[2]);
|
|
15490
|
+
if (header[0] !== id || !Number.isSafeInteger(size))
|
|
15491
|
+
return null;
|
|
15492
|
+
out.set(id, bytes.subarray(at, at + size));
|
|
15493
|
+
at += size + 1;
|
|
15494
|
+
}
|
|
15495
|
+
return out;
|
|
15496
|
+
}
|
|
15497
|
+
function treeFilesNamed(cwd, rev, name) {
|
|
15498
|
+
if (!safeArg(rev))
|
|
15499
|
+
return null;
|
|
15500
|
+
const run = git(cwd, ["ls-tree", "-r", "-z", "--full-tree", rev]);
|
|
15501
|
+
if (!run.ok)
|
|
15502
|
+
return null;
|
|
15503
|
+
const out = new Map;
|
|
15504
|
+
for (const record of run.stdout.split("\x00")) {
|
|
15505
|
+
const match = /^\d{6} blob ([0-9a-f]+)\t(.+)$/su.exec(record);
|
|
15506
|
+
if (match && (match[2] === name || match[2].endsWith(`/${name}`)))
|
|
15507
|
+
out.set(match[2], match[1]);
|
|
15508
|
+
}
|
|
15509
|
+
return out;
|
|
15510
|
+
}
|
|
15511
|
+
function fileAt(cwd, rev, file) {
|
|
15512
|
+
if (!safeArg(rev))
|
|
15513
|
+
return null;
|
|
15514
|
+
const run = git(cwd, ["cat-file", "blob", `${rev}:${file}`]);
|
|
15515
|
+
return run.ok ? run.stdout : null;
|
|
15516
|
+
}
|
|
15517
|
+
function untrackedFiles(cwd) {
|
|
15518
|
+
const run = git(cwd, ["ls-files", "-z", "--others", "--exclude-standard"]);
|
|
15519
|
+
return run.ok ? run.stdout.split("\x00").filter(Boolean) : [];
|
|
15520
|
+
}
|
|
15403
15521
|
var config2 = (cwd, key) => line(git(cwd, ["config", "--get", key]));
|
|
15404
15522
|
function currentBranch(cwd) {
|
|
15405
15523
|
return line(git(cwd, ["symbolic-ref", "--short", "-q", "HEAD"]));
|
|
@@ -18908,9 +19026,9 @@ var workerBlocksTransition = (transition, state) => transition === "pause" ? fal
|
|
|
18908
19026
|
|
|
18909
19027
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
18910
19028
|
import { createHash as createHash10 } from "node:crypto";
|
|
18911
|
-
import * as
|
|
18912
|
-
import { spawnSync as
|
|
18913
|
-
import
|
|
19029
|
+
import * as fs14 from "node:fs";
|
|
19030
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
19031
|
+
import path18 from "node:path";
|
|
18914
19032
|
|
|
18915
19033
|
// packages/workit-core/src/check-config.ts
|
|
18916
19034
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
@@ -19130,8 +19248,8 @@ function checkCommand(args, version, onPath = workitAvailable()) {
|
|
|
19130
19248
|
}
|
|
19131
19249
|
|
|
19132
19250
|
// packages/workit-core/src/core/policy/derive.ts
|
|
19133
|
-
import { existsSync as
|
|
19134
|
-
import
|
|
19251
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
19252
|
+
import path17 from "node:path";
|
|
19135
19253
|
|
|
19136
19254
|
// packages/workit-core/src/ledger.ts
|
|
19137
19255
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
@@ -19975,7 +20093,8 @@ function checkVerdicts(cwd, branch, ledgerRows) {
|
|
|
19975
20093
|
verdict: failing?.verdict ?? null,
|
|
19976
20094
|
reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
|
|
19977
20095
|
};
|
|
19978
|
-
const
|
|
20096
|
+
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))));
|
|
20097
|
+
const selfEntry = latestSelf && STRONG_RESULTS.has(String(latestSelf.verdict.result)) ? latestSelf : undefined;
|
|
19979
20098
|
return {
|
|
19980
20099
|
branch,
|
|
19981
20100
|
head,
|
|
@@ -19997,12 +20116,721 @@ var OBSERVED_ONLY = new Set([
|
|
|
19997
20116
|
...PR_ROW_TYPES
|
|
19998
20117
|
]);
|
|
19999
20118
|
|
|
20119
|
+
// packages/workit-core/src/core/policy/lane.ts
|
|
20120
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
20121
|
+
import path16 from "node:path";
|
|
20122
|
+
|
|
20123
|
+
// packages/workit-core/src/core/pr-create.ts
|
|
20124
|
+
import fs13 from "node:fs";
|
|
20125
|
+
import path15 from "node:path";
|
|
20126
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
20127
|
+
// packages/workit-core/src/forge/pr-body.ts
|
|
20128
|
+
function parseGhIssue(value) {
|
|
20129
|
+
const m = /issues\/(\d+)/.exec(value);
|
|
20130
|
+
return m ? m[1] : String(value).trim().replace(/^#/, "");
|
|
20131
|
+
}
|
|
20132
|
+
|
|
20133
|
+
// packages/workit-core/src/core/pr-create.ts
|
|
20134
|
+
function whichOnPath(tool) {
|
|
20135
|
+
const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
|
|
20136
|
+
for (const dir of (process.env.PATH ?? "").split(path15.delimiter)) {
|
|
20137
|
+
if (!dir)
|
|
20138
|
+
continue;
|
|
20139
|
+
for (const name of names) {
|
|
20140
|
+
const candidate = path15.join(dir, name);
|
|
20141
|
+
try {
|
|
20142
|
+
fs13.accessSync(candidate, fs13.constants.X_OK);
|
|
20143
|
+
return candidate;
|
|
20144
|
+
} catch {}
|
|
20145
|
+
}
|
|
20146
|
+
}
|
|
20147
|
+
return null;
|
|
20148
|
+
}
|
|
20149
|
+
var hostingCliAvailable = (provider) => whichOnPath(provider === "gitlab" ? "glab" : "gh") !== null;
|
|
20150
|
+
var pushRemote = (cwd) => {
|
|
20151
|
+
const result = spawnSync10("git", ["remote", "get-url", "--push", "--all", "origin"], {
|
|
20152
|
+
cwd,
|
|
20153
|
+
encoding: "utf8"
|
|
20154
|
+
});
|
|
20155
|
+
if (result.status !== 0)
|
|
20156
|
+
return null;
|
|
20157
|
+
const urls = (result.stdout ?? "").split(/\r?\n/u).map((url) => url.trim()).filter(Boolean);
|
|
20158
|
+
return urls.length === 1 ? urls[0] : null;
|
|
20159
|
+
};
|
|
20160
|
+
|
|
20161
|
+
// packages/workit-core/src/forge/redact.ts
|
|
20162
|
+
var KEY = String.raw`[A-Za-z0-9_.-]*?(?:token|secret|password|passwd|pwd|api[_-]?key|access[_-]?key|account[_-]?key|private[_-]?key|client[_-]?secret|credentials?|authorization|cookie|signature)[A-Za-z0-9_.-]*`;
|
|
20163
|
+
var ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*["']?)((?:bearer|basic|token|digest)\s+)?([^\s"',;&]+)`, "giu");
|
|
20164
|
+
var QUOTED_ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*)(["'])([^"'\n]*[^\s"'][^"'\n]*)\2`, "giu");
|
|
20165
|
+
var ANSI = new RegExp(String.raw`\u001b\[[0-9;?]*[ -/]*[@-~]|\u001b\][^\u0007]*\u0007`, "gu");
|
|
20166
|
+
|
|
20167
|
+
// packages/workit-core/src/git/ops.ts
|
|
20168
|
+
var COMMIT_TIMEOUT_MS = 10 * 60000;
|
|
20169
|
+
|
|
20170
|
+
// packages/workit-core/src/core/policy/attributes.ts
|
|
20171
|
+
function patternRegex(dir, pattern) {
|
|
20172
|
+
if (!pattern || pattern.endsWith("/") || pattern.startsWith('"') || pattern.startsWith("!"))
|
|
20173
|
+
return null;
|
|
20174
|
+
const anchored = pattern.includes("/");
|
|
20175
|
+
const body = pattern.replace(/^\//u, "");
|
|
20176
|
+
let source = "";
|
|
20177
|
+
for (let index = 0;index < body.length; index += 1) {
|
|
20178
|
+
const char = body[index];
|
|
20179
|
+
if (char === "*" && body[index + 1] === "*") {
|
|
20180
|
+
const slash = body[index + 2] === "/";
|
|
20181
|
+
source += slash ? "(?:.*/)?" : ".*";
|
|
20182
|
+
index += slash ? 2 : 1;
|
|
20183
|
+
} else if (char === "*")
|
|
20184
|
+
source += "[^/]*";
|
|
20185
|
+
else if (char === "?")
|
|
20186
|
+
source += "[^/]";
|
|
20187
|
+
else if (char === "[") {
|
|
20188
|
+
const end = body.indexOf("]", index + 2);
|
|
20189
|
+
if (end < 0)
|
|
20190
|
+
return null;
|
|
20191
|
+
const set = body.slice(index + 1, end).replace(/^!/u, "^").replace(/\\/gu, "\\\\");
|
|
20192
|
+
source += `[${set}]`;
|
|
20193
|
+
index = end;
|
|
20194
|
+
} else if (char === "\\" && index + 1 < body.length) {
|
|
20195
|
+
source += body[index + 1].replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
|
|
20196
|
+
index += 1;
|
|
20197
|
+
} else
|
|
20198
|
+
source += char.replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
|
|
20199
|
+
}
|
|
20200
|
+
const prefix = dir ? `${dir.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}/` : "";
|
|
20201
|
+
try {
|
|
20202
|
+
return new RegExp(anchored ? `^${prefix}${source}$` : `^${prefix}(?:.*/)?${source}$`, "u");
|
|
20203
|
+
} catch {
|
|
20204
|
+
return null;
|
|
20205
|
+
}
|
|
20206
|
+
}
|
|
20207
|
+
function rulesOf(dir, text) {
|
|
20208
|
+
const out = [];
|
|
20209
|
+
for (const raw of text.split(`
|
|
20210
|
+
`)) {
|
|
20211
|
+
const line = raw.trim();
|
|
20212
|
+
if (!line || line.startsWith("#") || line.startsWith("[attr]"))
|
|
20213
|
+
continue;
|
|
20214
|
+
const [pattern, ...attributes] = line.split(/\s+/u);
|
|
20215
|
+
let generated = null;
|
|
20216
|
+
for (const attribute of attributes) {
|
|
20217
|
+
if (attribute === "linguist-generated" || attribute === "linguist-generated=true")
|
|
20218
|
+
generated = true;
|
|
20219
|
+
else if (attribute === "-linguist-generated" || attribute === "!linguist-generated" || attribute.startsWith("linguist-generated="))
|
|
20220
|
+
generated = false;
|
|
20221
|
+
}
|
|
20222
|
+
if (generated === null)
|
|
20223
|
+
continue;
|
|
20224
|
+
const regex = patternRegex(dir, pattern);
|
|
20225
|
+
if (regex)
|
|
20226
|
+
out.push({ regex, generated });
|
|
20227
|
+
}
|
|
20228
|
+
return out;
|
|
20229
|
+
}
|
|
20230
|
+
function generatedByAttributes(files, paths) {
|
|
20231
|
+
const rules = [...files].map(([file, text]) => {
|
|
20232
|
+
const dir = file.includes("/") ? file.slice(0, file.lastIndexOf("/")) : "";
|
|
20233
|
+
return {
|
|
20234
|
+
depth: dir ? dir.split("/").length : 0,
|
|
20235
|
+
rules: rulesOf(dir, text)
|
|
20236
|
+
};
|
|
20237
|
+
}).toSorted((left, right) => left.depth - right.depth).flatMap((entry) => entry.rules);
|
|
20238
|
+
const out = new Set;
|
|
20239
|
+
for (const file of paths) {
|
|
20240
|
+
const last = rules.findLast((rule) => rule.regex.test(file));
|
|
20241
|
+
if (last?.generated)
|
|
20242
|
+
out.add(file);
|
|
20243
|
+
}
|
|
20244
|
+
return out;
|
|
20245
|
+
}
|
|
20246
|
+
|
|
20247
|
+
// packages/workit-core/src/core/policy/substance.ts
|
|
20248
|
+
var SLASH_BLOCK = [["/*", "*/"]];
|
|
20249
|
+
var C_LIKE = { line: ["//"], block: SLASH_BLOCK, quotes: `"'` };
|
|
20250
|
+
var SYNTAXES = Object.fromEntries([
|
|
20251
|
+
...["ts", "mts", "cts", "js", "mjs", "cjs"].map((ext) => [ext, { ...C_LIKE, js: true }]),
|
|
20252
|
+
...["java", "kt", "kts", "scala", "swift", "dart", "groovy"].map((ext) => [
|
|
20253
|
+
ext,
|
|
20254
|
+
{ ...C_LIKE, triple: true }
|
|
20255
|
+
]),
|
|
20256
|
+
["go", { ...C_LIKE, rawBacktick: true }],
|
|
20257
|
+
...["css", "scss", "less"].map((ext) => [
|
|
20258
|
+
ext,
|
|
20259
|
+
{ line: [], block: SLASH_BLOCK, quotes: `"'`, cssUrl: true }
|
|
20260
|
+
]),
|
|
20261
|
+
...["py", "pyi"].map((ext) => [
|
|
20262
|
+
ext,
|
|
20263
|
+
{ line: ["#"], block: [], quotes: `"'`, triple: true, indented: true, fstring: true }
|
|
20264
|
+
]),
|
|
20265
|
+
["toml", { line: ["#"], block: [], quotes: `"`, literal: "'", triple: true }],
|
|
20266
|
+
...["html", "htm", "xml", "svg", "xhtml"].map((ext) => [
|
|
20267
|
+
ext,
|
|
20268
|
+
{ line: [], block: [["<!--", "-->"]], quotes: "", indented: true }
|
|
20269
|
+
])
|
|
20270
|
+
]);
|
|
20271
|
+
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;
|
|
20272
|
+
var extensionOf = (file) => {
|
|
20273
|
+
const name = file.slice(file.lastIndexOf("/") + 1);
|
|
20274
|
+
const dot = name.lastIndexOf(".");
|
|
20275
|
+
return dot > 0 ? name.slice(dot + 1).toLowerCase() : "";
|
|
20276
|
+
};
|
|
20277
|
+
var CI_PATH = /^\.github\/|(?:^|\/)(?:\.gitlab-ci\.ya?ml|Jenkinsfile|azure-pipelines\.ya?ml|\.pre-commit-config\.ya?ml|\.circleci\/.*)$/u;
|
|
20278
|
+
var syntaxOf = (file) => CI_PATH.test(file) ? null : SYNTAXES[extensionOf(file)] ?? null;
|
|
20279
|
+
var SPACE = /[ \t\r\f\v]/u;
|
|
20280
|
+
var WORD = /[\w$]/u;
|
|
20281
|
+
var NO_SPACE_AFTER = "([{,;";
|
|
20282
|
+
var NO_SPACE_BEFORE = ")]},;";
|
|
20283
|
+
var REGEX_AFTER = "(,=:[!&|?{};+-*%<>~^";
|
|
20284
|
+
var REGEX_KEYWORDS = new Set([
|
|
20285
|
+
"return",
|
|
20286
|
+
"typeof",
|
|
20287
|
+
"instanceof",
|
|
20288
|
+
"case",
|
|
20289
|
+
"do",
|
|
20290
|
+
"else",
|
|
20291
|
+
"in",
|
|
20292
|
+
"of",
|
|
20293
|
+
"new",
|
|
20294
|
+
"delete",
|
|
20295
|
+
"void",
|
|
20296
|
+
"throw",
|
|
20297
|
+
"yield",
|
|
20298
|
+
"await"
|
|
20299
|
+
]);
|
|
20300
|
+
function substanceOf(file, text) {
|
|
20301
|
+
const syntax = syntaxOf(file);
|
|
20302
|
+
if (!syntax)
|
|
20303
|
+
return plainSubstance(text);
|
|
20304
|
+
const markup = syntax.block.some(([open]) => open === "<!--");
|
|
20305
|
+
if (markup && (/<(?:script|style)\b|<!\[CDATA\[|<\?/iu.test(text) || /[^>\s][ \t]*<!--/u.test(text)))
|
|
20306
|
+
return plainSubstance(text);
|
|
20307
|
+
return lex(syntax, text);
|
|
20308
|
+
}
|
|
20309
|
+
function plainSubstance(text) {
|
|
20310
|
+
return text.split(`
|
|
20311
|
+
`).map((line) => line.replace(/[ \t\r\f\v]+$/u, "")).filter(Boolean).join(`
|
|
20312
|
+
`);
|
|
20313
|
+
}
|
|
20314
|
+
function lex(syntax, text) {
|
|
20315
|
+
const collapse = !syntax.indented;
|
|
20316
|
+
let out = "";
|
|
20317
|
+
let lineStart = 0;
|
|
20318
|
+
let kept = 0;
|
|
20319
|
+
let pendingSpace = false;
|
|
20320
|
+
const frames = [{ kind: "code", braces: 0 }];
|
|
20321
|
+
let index = 0;
|
|
20322
|
+
if (text.startsWith("#!")) {
|
|
20323
|
+
const end = text.indexOf(`
|
|
20324
|
+
`);
|
|
20325
|
+
out = end < 0 ? text : text.slice(0, end);
|
|
20326
|
+
kept = out.length;
|
|
20327
|
+
index = end < 0 ? text.length : end;
|
|
20328
|
+
}
|
|
20329
|
+
const emitCode = (chunk) => {
|
|
20330
|
+
if (collapse && pendingSpace && out.length > lineStart) {
|
|
20331
|
+
const before = out[out.length - 1];
|
|
20332
|
+
if (!NO_SPACE_AFTER.includes(before) && !NO_SPACE_BEFORE.includes(chunk[0]))
|
|
20333
|
+
out += " ";
|
|
20334
|
+
}
|
|
20335
|
+
pendingSpace = false;
|
|
20336
|
+
out += chunk;
|
|
20337
|
+
};
|
|
20338
|
+
const emitVerbatim = (chunk) => {
|
|
20339
|
+
emitCode(chunk);
|
|
20340
|
+
kept = out.length;
|
|
20341
|
+
};
|
|
20342
|
+
const newline = () => {
|
|
20343
|
+
if (!collapse) {
|
|
20344
|
+
let end = out.length;
|
|
20345
|
+
while (end > Math.max(lineStart, kept) && SPACE.test(out[end - 1]))
|
|
20346
|
+
end -= 1;
|
|
20347
|
+
out = out.slice(0, end);
|
|
20348
|
+
}
|
|
20349
|
+
pendingSpace = false;
|
|
20350
|
+
if (out.length > lineStart) {
|
|
20351
|
+
out += `
|
|
20352
|
+
`;
|
|
20353
|
+
lineStart = out.length;
|
|
20354
|
+
}
|
|
20355
|
+
};
|
|
20356
|
+
const regexAllowed = () => {
|
|
20357
|
+
let end = out.length;
|
|
20358
|
+
while (end > 0 && /\s/u.test(out[end - 1]))
|
|
20359
|
+
end -= 1;
|
|
20360
|
+
if (end === 0 || REGEX_AFTER.includes(out[end - 1]))
|
|
20361
|
+
return true;
|
|
20362
|
+
let start = end;
|
|
20363
|
+
while (start > 0 && WORD.test(out[start - 1]))
|
|
20364
|
+
start -= 1;
|
|
20365
|
+
return REGEX_KEYWORDS.has(out.slice(start, end));
|
|
20366
|
+
};
|
|
20367
|
+
const scanString = (quote, escapes, multiline) => {
|
|
20368
|
+
const prefix = text.slice(Math.max(0, index - 2), index).match(/[a-z]*$/iu)?.[0] ?? "";
|
|
20369
|
+
const fstring = syntax.fstring === true && /f/iu.test(prefix);
|
|
20370
|
+
let end = index + quote.length;
|
|
20371
|
+
while (end < text.length) {
|
|
20372
|
+
const char = text[end];
|
|
20373
|
+
if (escapes && char === "\\") {
|
|
20374
|
+
end += 2;
|
|
20375
|
+
continue;
|
|
20376
|
+
}
|
|
20377
|
+
if (text.startsWith(quote, end)) {
|
|
20378
|
+
if (fstring && unbalanced(text.slice(index + quote.length, end)))
|
|
20379
|
+
return false;
|
|
20380
|
+
emitVerbatim(text.slice(index, end + quote.length));
|
|
20381
|
+
index = end + quote.length;
|
|
20382
|
+
return true;
|
|
20383
|
+
}
|
|
20384
|
+
if (char === `
|
|
20385
|
+
` && !multiline)
|
|
20386
|
+
return false;
|
|
20387
|
+
end += 1;
|
|
20388
|
+
}
|
|
20389
|
+
return false;
|
|
20390
|
+
};
|
|
20391
|
+
while (index < text.length) {
|
|
20392
|
+
const frame = frames[frames.length - 1];
|
|
20393
|
+
const char = text[index];
|
|
20394
|
+
if (frame.kind === "template") {
|
|
20395
|
+
if (char === "\\") {
|
|
20396
|
+
emitVerbatim(text.slice(index, index + 2));
|
|
20397
|
+
index += 2;
|
|
20398
|
+
} else if (char === "`") {
|
|
20399
|
+
emitVerbatim(char);
|
|
20400
|
+
frames.pop();
|
|
20401
|
+
index += 1;
|
|
20402
|
+
} else if (text.startsWith("${", index)) {
|
|
20403
|
+
emitVerbatim("${");
|
|
20404
|
+
frames.push({ kind: "code", braces: 0 });
|
|
20405
|
+
index += 2;
|
|
20406
|
+
} else {
|
|
20407
|
+
out += char;
|
|
20408
|
+
kept = out.length;
|
|
20409
|
+
index += 1;
|
|
20410
|
+
}
|
|
20411
|
+
continue;
|
|
20412
|
+
}
|
|
20413
|
+
if (char === `
|
|
20414
|
+
`) {
|
|
20415
|
+
newline();
|
|
20416
|
+
index += 1;
|
|
20417
|
+
continue;
|
|
20418
|
+
}
|
|
20419
|
+
if (SPACE.test(char)) {
|
|
20420
|
+
if (collapse)
|
|
20421
|
+
pendingSpace = true;
|
|
20422
|
+
else
|
|
20423
|
+
out += char;
|
|
20424
|
+
index += 1;
|
|
20425
|
+
continue;
|
|
20426
|
+
}
|
|
20427
|
+
const lineOpener = syntax.line.find((opener) => text.startsWith(opener, index));
|
|
20428
|
+
if (lineOpener) {
|
|
20429
|
+
const end = text.indexOf(`
|
|
20430
|
+
`, index);
|
|
20431
|
+
const comment = text.slice(index, end < 0 ? text.length : end);
|
|
20432
|
+
if (DIRECTIVE.test(comment.slice(lineOpener.length)))
|
|
20433
|
+
emitVerbatim(comment);
|
|
20434
|
+
else
|
|
20435
|
+
pendingSpace = true;
|
|
20436
|
+
index = end < 0 ? text.length : end;
|
|
20437
|
+
continue;
|
|
20438
|
+
}
|
|
20439
|
+
const block = syntax.block.find(([open]) => text.startsWith(open, index));
|
|
20440
|
+
if (block) {
|
|
20441
|
+
const end = text.indexOf(block[1], index + block[0].length);
|
|
20442
|
+
if (end < 0)
|
|
20443
|
+
return null;
|
|
20444
|
+
const comment = text.slice(index, end + block[1].length);
|
|
20445
|
+
if (DIRECTIVE.test(comment.slice(block[0].length, -block[1].length)))
|
|
20446
|
+
emitVerbatim(comment);
|
|
20447
|
+
else
|
|
20448
|
+
pendingSpace = true;
|
|
20449
|
+
if (comment.includes(`
|
|
20450
|
+
`))
|
|
20451
|
+
newline();
|
|
20452
|
+
index = end + block[1].length;
|
|
20453
|
+
continue;
|
|
20454
|
+
}
|
|
20455
|
+
if (syntax.triple && (char === '"' || char === "'") && text.startsWith(char.repeat(3), index)) {
|
|
20456
|
+
if (!scanString(char.repeat(3), !syntax.literal?.includes(char), true))
|
|
20457
|
+
return null;
|
|
20458
|
+
continue;
|
|
20459
|
+
}
|
|
20460
|
+
if (syntax.quotes.includes(char)) {
|
|
20461
|
+
if (!scanString(char, true, Boolean(syntax.multiline)))
|
|
20462
|
+
return null;
|
|
20463
|
+
continue;
|
|
20464
|
+
}
|
|
20465
|
+
if (syntax.literal?.includes(char)) {
|
|
20466
|
+
if (!scanString(char, false, false))
|
|
20467
|
+
return null;
|
|
20468
|
+
continue;
|
|
20469
|
+
}
|
|
20470
|
+
if (syntax.rawBacktick && char === "`") {
|
|
20471
|
+
if (!scanString("`", false, true))
|
|
20472
|
+
return null;
|
|
20473
|
+
continue;
|
|
20474
|
+
}
|
|
20475
|
+
if (syntax.js && char === "`") {
|
|
20476
|
+
emitVerbatim(char);
|
|
20477
|
+
frames.push({ kind: "template" });
|
|
20478
|
+
index += 1;
|
|
20479
|
+
continue;
|
|
20480
|
+
}
|
|
20481
|
+
if (syntax.cssUrl && /^url\(\s*[^"')\s]/iu.test(text.slice(index, index + 64)))
|
|
20482
|
+
return null;
|
|
20483
|
+
if (syntax.js && char === "/" && !regexAllowed() && out.trimEnd().endsWith(")")) {
|
|
20484
|
+
const lineEnd = text.indexOf(`
|
|
20485
|
+
`, index);
|
|
20486
|
+
if (text.slice(index + 1, lineEnd < 0 ? text.length : lineEnd).includes("/"))
|
|
20487
|
+
return null;
|
|
20488
|
+
}
|
|
20489
|
+
if (syntax.js && char === "/" && regexAllowed()) {
|
|
20490
|
+
let end = index + 1;
|
|
20491
|
+
let inClass = false;
|
|
20492
|
+
while (end < text.length && (inClass || text[end] !== "/")) {
|
|
20493
|
+
if (text[end] === `
|
|
20494
|
+
`)
|
|
20495
|
+
return null;
|
|
20496
|
+
if (text[end] === "\\")
|
|
20497
|
+
end += 1;
|
|
20498
|
+
else if (text[end] === "[")
|
|
20499
|
+
inClass = true;
|
|
20500
|
+
else if (text[end] === "]")
|
|
20501
|
+
inClass = false;
|
|
20502
|
+
end += 1;
|
|
20503
|
+
}
|
|
20504
|
+
if (end >= text.length)
|
|
20505
|
+
return null;
|
|
20506
|
+
emitVerbatim(text.slice(index, end + 1));
|
|
20507
|
+
index = end + 1;
|
|
20508
|
+
continue;
|
|
20509
|
+
}
|
|
20510
|
+
if (frames.length > 1 && frame.kind === "code") {
|
|
20511
|
+
if (char === "{")
|
|
20512
|
+
frame.braces += 1;
|
|
20513
|
+
else if (char === "}") {
|
|
20514
|
+
if (frame.braces === 0) {
|
|
20515
|
+
emitVerbatim(char);
|
|
20516
|
+
frames.pop();
|
|
20517
|
+
index += 1;
|
|
20518
|
+
continue;
|
|
20519
|
+
}
|
|
20520
|
+
frame.braces -= 1;
|
|
20521
|
+
}
|
|
20522
|
+
}
|
|
20523
|
+
emitCode(char);
|
|
20524
|
+
index += 1;
|
|
20525
|
+
}
|
|
20526
|
+
if (frames.length !== 1)
|
|
20527
|
+
return null;
|
|
20528
|
+
newline();
|
|
20529
|
+
return out;
|
|
20530
|
+
}
|
|
20531
|
+
function unbalanced(body) {
|
|
20532
|
+
let depth = 0;
|
|
20533
|
+
for (const part of body.replaceAll("{{", "").replaceAll("}}", "")) {
|
|
20534
|
+
if (part === "{")
|
|
20535
|
+
depth += 1;
|
|
20536
|
+
else if (part === "}")
|
|
20537
|
+
depth = Math.max(0, depth - 1);
|
|
20538
|
+
}
|
|
20539
|
+
return depth > 0;
|
|
20540
|
+
}
|
|
20541
|
+
function hasOpaqueLineBreak(text) {
|
|
20542
|
+
return /\r(?!\n)|[\u2028\u2029]/u.test(text);
|
|
20543
|
+
}
|
|
20544
|
+
var decoder = new TextDecoder("utf-8", { fatal: true });
|
|
20545
|
+
function textOf(bytes) {
|
|
20546
|
+
if (bytes.includes(0))
|
|
20547
|
+
return null;
|
|
20548
|
+
try {
|
|
20549
|
+
return decoder.decode(bytes);
|
|
20550
|
+
} catch {
|
|
20551
|
+
return null;
|
|
20552
|
+
}
|
|
20553
|
+
}
|
|
20554
|
+
function cosmeticChange(file, before, after) {
|
|
20555
|
+
const left = textOf(before);
|
|
20556
|
+
const right = textOf(after);
|
|
20557
|
+
if (left === null || right === null)
|
|
20558
|
+
return false;
|
|
20559
|
+
if (hasOpaqueLineBreak(left) || hasOpaqueLineBreak(right))
|
|
20560
|
+
return false;
|
|
20561
|
+
const a = substanceOf(file, left);
|
|
20562
|
+
return a !== null && a === substanceOf(file, right);
|
|
20563
|
+
}
|
|
20564
|
+
|
|
20565
|
+
// packages/workit-core/src/core/policy/lane.ts
|
|
20566
|
+
var LANE_THRESHOLDS = {
|
|
20567
|
+
selfMaxLines: 100,
|
|
20568
|
+
selfMaxFiles: 5,
|
|
20569
|
+
fullMinLines: 500
|
|
20570
|
+
};
|
|
20571
|
+
var RISK_TOKENS = new Set([
|
|
20572
|
+
"auth",
|
|
20573
|
+
"authn",
|
|
20574
|
+
"authz",
|
|
20575
|
+
"oauth",
|
|
20576
|
+
"security",
|
|
20577
|
+
"permission",
|
|
20578
|
+
"permissions",
|
|
20579
|
+
"secret",
|
|
20580
|
+
"secrets",
|
|
20581
|
+
"crypto",
|
|
20582
|
+
"gate",
|
|
20583
|
+
"gates",
|
|
20584
|
+
"policy",
|
|
20585
|
+
"policies",
|
|
20586
|
+
"hook",
|
|
20587
|
+
"hooks",
|
|
20588
|
+
"husky",
|
|
20589
|
+
"lefthook",
|
|
20590
|
+
"release",
|
|
20591
|
+
"releases",
|
|
20592
|
+
"migration",
|
|
20593
|
+
"migrations",
|
|
20594
|
+
"migrate",
|
|
20595
|
+
"workflows"
|
|
20596
|
+
]);
|
|
20597
|
+
var RISK_FILES = new Set([
|
|
20598
|
+
".gitlab-ci.yml",
|
|
20599
|
+
"Jenkinsfile",
|
|
20600
|
+
"azure-pipelines.yml",
|
|
20601
|
+
".pre-commit-config.yaml",
|
|
20602
|
+
".workit/risk-paths"
|
|
20603
|
+
]);
|
|
20604
|
+
var RISK_NAMES = new Set([".gitattributes"]);
|
|
20605
|
+
var RISK_PATHS_FILE = ".workit/risk-paths";
|
|
20606
|
+
var LOCKFILES = new Set([
|
|
20607
|
+
"bun.lock",
|
|
20608
|
+
"bun.lockb",
|
|
20609
|
+
"package-lock.json",
|
|
20610
|
+
"npm-shrinkwrap.json",
|
|
20611
|
+
"yarn.lock",
|
|
20612
|
+
"pnpm-lock.yaml",
|
|
20613
|
+
"Cargo.lock",
|
|
20614
|
+
"go.sum",
|
|
20615
|
+
"poetry.lock",
|
|
20616
|
+
"uv.lock",
|
|
20617
|
+
"Pipfile.lock",
|
|
20618
|
+
"Gemfile.lock",
|
|
20619
|
+
"composer.lock"
|
|
20620
|
+
]);
|
|
20621
|
+
var DOC_EXT = /\.(?:md|mdx|markdown|rst|adoc|txt)$/iu;
|
|
20622
|
+
var DOC_NAMES = /^(?:license|licence|notice|authors|changelog|changes|contributors)$/iu;
|
|
20623
|
+
var INSTRUCTIONS = /(?:^|\/)(?:AGENTS|CLAUDE|GEMINI|SKILL)\.md$|(?:^|\/)(?:skills|agents|commands|rules|prompts)\/[^/]+/iu;
|
|
20624
|
+
var TEST_PATH = /(?:^|\/)(?:test|tests|__tests__|spec|specs|fixtures)\/|\.(?:test|spec)\.[^/]+$/iu;
|
|
20625
|
+
var basename = (file) => file.slice(file.lastIndexOf("/") + 1);
|
|
20626
|
+
var isDoc = (file) => !INSTRUCTIONS.test(file) && (DOC_EXT.test(file) || DOC_NAMES.test(basename(file)));
|
|
20627
|
+
function kindOf(file) {
|
|
20628
|
+
if (file.binary)
|
|
20629
|
+
return "behavior";
|
|
20630
|
+
if (file.generated)
|
|
20631
|
+
return "generated";
|
|
20632
|
+
if (LOCKFILES.has(basename(file.path)))
|
|
20633
|
+
return "lockfile";
|
|
20634
|
+
if (isDoc(file.path))
|
|
20635
|
+
return "doc";
|
|
20636
|
+
if (file.cosmetic)
|
|
20637
|
+
return "cosmetic";
|
|
20638
|
+
return TEST_PATH.test(file.path) ? "test" : "behavior";
|
|
20639
|
+
}
|
|
20640
|
+
var globCache = new Map;
|
|
20641
|
+
function globMatch(pattern, file) {
|
|
20642
|
+
let regex = globCache.get(pattern);
|
|
20643
|
+
if (!regex) {
|
|
20644
|
+
let source = "";
|
|
20645
|
+
for (let index = 0;index < pattern.length; index += 1) {
|
|
20646
|
+
const char = pattern[index];
|
|
20647
|
+
if (char === "*" && pattern[index + 1] === "*") {
|
|
20648
|
+
source += pattern[index + 2] === "/" ? "(?:[^/]*/)*" : ".*";
|
|
20649
|
+
index += pattern[index + 2] === "/" ? 2 : 1;
|
|
20650
|
+
} else if (char === "*")
|
|
20651
|
+
source += "[^/]*";
|
|
20652
|
+
else if (char === "?")
|
|
20653
|
+
source += "[^/]";
|
|
20654
|
+
else
|
|
20655
|
+
source += char.replace(/[.+^${}()|[\]\\]/gu, "\\$&");
|
|
20656
|
+
}
|
|
20657
|
+
regex = new RegExp(`^${source}$`, "u");
|
|
20658
|
+
globCache.set(pattern, regex);
|
|
20659
|
+
}
|
|
20660
|
+
return regex.test(file) || file.startsWith(`${pattern.replace(/\/$/u, "")}/`);
|
|
20661
|
+
}
|
|
20662
|
+
function isRiskPath(file, extra = []) {
|
|
20663
|
+
if (extra.some((pattern) => globMatch(pattern, file)))
|
|
20664
|
+
return true;
|
|
20665
|
+
if (RISK_FILES.has(file) || RISK_NAMES.has(basename(file)))
|
|
20666
|
+
return true;
|
|
20667
|
+
if (TEST_PATH.test(file) || isDoc(file))
|
|
20668
|
+
return false;
|
|
20669
|
+
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)));
|
|
20670
|
+
}
|
|
20671
|
+
var parseRiskPaths = (text) => text.split(`
|
|
20672
|
+
`).map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.replace(/^\//u, ""));
|
|
20673
|
+
function computeLane(input) {
|
|
20674
|
+
const riskFiles = input.files.filter((file) => isRiskPath(file.path, input.riskPaths)).map((file) => file.path);
|
|
20675
|
+
const risky = new Set(riskFiles);
|
|
20676
|
+
const kinds = input.files.map((file) => ({
|
|
20677
|
+
file,
|
|
20678
|
+
kind: risky.has(file.path) ? "behavior" : kindOf(file)
|
|
20679
|
+
}));
|
|
20680
|
+
const behavior = kinds.filter((entry) => entry.kind === "behavior" || entry.kind === "test" || entry.kind === "lockfile");
|
|
20681
|
+
const lines = behavior.filter((entry) => entry.kind !== "lockfile").reduce((sum, entry) => sum + entry.file.added + entry.file.deleted, 0);
|
|
20682
|
+
const opaque = behavior.filter((entry) => entry.kind === "lockfile" || entry.file.binary);
|
|
20683
|
+
const result = (lane, reasons) => ({
|
|
20684
|
+
lane,
|
|
20685
|
+
reasons,
|
|
20686
|
+
lines,
|
|
20687
|
+
files: behavior.length,
|
|
20688
|
+
riskFiles
|
|
20689
|
+
});
|
|
20690
|
+
const { selfMaxLines, selfMaxFiles, fullMinLines } = LANE_THRESHOLDS;
|
|
20691
|
+
if (input.riskTier === "high")
|
|
20692
|
+
return result("full", ["the task judgment records high risk"]);
|
|
20693
|
+
if (riskFiles.length)
|
|
20694
|
+
return result("full", [
|
|
20695
|
+
`touches a risk path: ${riskFiles.slice(0, 3).join(", ")}${riskFiles.length > 3 ? ", …" : ""}`
|
|
20696
|
+
]);
|
|
20697
|
+
if (!behavior.length)
|
|
20698
|
+
return result("none", [
|
|
20699
|
+
input.files.length ? "only docs, comments, formatting or generated copies changed" : "no changes"
|
|
20700
|
+
]);
|
|
20701
|
+
if (lines >= fullMinLines)
|
|
20702
|
+
return result("full", [`large diff: ${lines} lines (≥ ${fullMinLines})`]);
|
|
20703
|
+
if (lines > selfMaxLines)
|
|
20704
|
+
return result("focused", [`${lines} lines changed (> ${selfMaxLines})`]);
|
|
20705
|
+
if (behavior.length > selfMaxFiles)
|
|
20706
|
+
return result("focused", [`${behavior.length} behavior files changed (> ${selfMaxFiles})`]);
|
|
20707
|
+
if (opaque.length)
|
|
20708
|
+
return result("focused", [
|
|
20709
|
+
`a lockfile or binary changed: ${opaque.slice(0, 3).map((entry) => entry.file.path).join(", ")}${opaque.length > 3 ? ", …" : ""}`
|
|
20710
|
+
]);
|
|
20711
|
+
return result("self", [
|
|
20712
|
+
`small change: ${lines} line${lines === 1 ? "" : "s"} in ${behavior.length} file${behavior.length === 1 ? "" : "s"}, no risk path`
|
|
20713
|
+
]);
|
|
20714
|
+
}
|
|
20715
|
+
function untrackedStat(cwd, file) {
|
|
20716
|
+
try {
|
|
20717
|
+
const bytes = readFileSync4(path16.join(cwd, file));
|
|
20718
|
+
if (bytes.includes(0))
|
|
20719
|
+
return { path: file, added: 0, deleted: 0, binary: true };
|
|
20720
|
+
const text = bytes.toString("utf8");
|
|
20721
|
+
if (hasOpaqueLineBreak(text))
|
|
20722
|
+
return { path: file, added: 0, deleted: 0, binary: true };
|
|
20723
|
+
const lines = text.split(`
|
|
20724
|
+
`).length - (text.endsWith(`
|
|
20725
|
+
`) ? 1 : 0);
|
|
20726
|
+
return { path: file, added: lines, deleted: 0 };
|
|
20727
|
+
} catch {
|
|
20728
|
+
return { path: file, added: 0, deleted: 0, binary: true };
|
|
20729
|
+
}
|
|
20730
|
+
}
|
|
20731
|
+
var REGULAR = new Set(["100644", "100755"]);
|
|
20732
|
+
var ABSENT = /^0+$/u;
|
|
20733
|
+
function cosmeticFiles(cwd, fork, head) {
|
|
20734
|
+
const raw = diffRaw(cwd, fork, head);
|
|
20735
|
+
if (!raw)
|
|
20736
|
+
return null;
|
|
20737
|
+
const candidates = raw.filter((entry) => REGULAR.has(entry.oldMode) && entry.oldMode === entry.newMode && !ABSENT.test(entry.oldBlob) && (head === null || !ABSENT.test(entry.newBlob)));
|
|
20738
|
+
const blobs = readBlobs(cwd, candidates.flatMap((entry) => [entry.oldBlob, entry.newBlob]));
|
|
20739
|
+
if (!blobs)
|
|
20740
|
+
return null;
|
|
20741
|
+
const out = new Set;
|
|
20742
|
+
const opaque = new Set;
|
|
20743
|
+
for (const entry of candidates) {
|
|
20744
|
+
const before = blobs.get(entry.oldBlob);
|
|
20745
|
+
let after = blobs.get(entry.newBlob);
|
|
20746
|
+
if (!after && head === null && ABSENT.test(entry.newBlob))
|
|
20747
|
+
try {
|
|
20748
|
+
after = readFileSync4(path16.join(cwd, entry.path));
|
|
20749
|
+
} catch {
|
|
20750
|
+
after = undefined;
|
|
20751
|
+
}
|
|
20752
|
+
if (before && after && cosmeticChange(entry.path, before, after))
|
|
20753
|
+
out.add(entry.path);
|
|
20754
|
+
else if ([before, after].some((bytes) => bytes && hasOpaqueLineBreak(bytes.toString("utf8"))))
|
|
20755
|
+
opaque.add(entry.path);
|
|
20756
|
+
}
|
|
20757
|
+
return { cosmetic: out, opaque };
|
|
20758
|
+
}
|
|
20759
|
+
function generatedAt(cwd, fork, paths) {
|
|
20760
|
+
const files = treeFilesNamed(cwd, fork, ".gitattributes");
|
|
20761
|
+
const blobs = files?.size ? readBlobs(cwd, [...files.values()]) : null;
|
|
20762
|
+
if (!files || !blobs)
|
|
20763
|
+
return new Set;
|
|
20764
|
+
const texts = new Map;
|
|
20765
|
+
for (const [file, id] of files) {
|
|
20766
|
+
const bytes = blobs.get(id);
|
|
20767
|
+
if (bytes)
|
|
20768
|
+
texts.set(file, bytes.toString("utf8"));
|
|
20769
|
+
}
|
|
20770
|
+
return generatedByAttributes(texts, paths);
|
|
20771
|
+
}
|
|
20772
|
+
var forkOf = (cwd, base, head) => mergeBase(cwd, base, head ?? "HEAD");
|
|
20773
|
+
function laneFiles(cwd, fork, head) {
|
|
20774
|
+
const stats = diffNumstat(cwd, fork, head);
|
|
20775
|
+
const cosmetic = stats ? cosmeticFiles(cwd, fork, head) : null;
|
|
20776
|
+
if (!stats || !cosmetic)
|
|
20777
|
+
return null;
|
|
20778
|
+
const files = [
|
|
20779
|
+
...stats.map((entry) => ({
|
|
20780
|
+
...entry,
|
|
20781
|
+
...cosmetic.opaque.has(entry.path) ? { binary: true } : {},
|
|
20782
|
+
cosmetic: !entry.binary && cosmetic.cosmetic.has(entry.path)
|
|
20783
|
+
})),
|
|
20784
|
+
...head === null ? untrackedFiles(cwd).map((file) => untrackedStat(cwd, file)) : []
|
|
20785
|
+
];
|
|
20786
|
+
const generated = generatedAt(cwd, fork, files.map((entry) => entry.path));
|
|
20787
|
+
return files.map((entry) => ({
|
|
20788
|
+
...entry,
|
|
20789
|
+
generated: generated.has(entry.path)
|
|
20790
|
+
}));
|
|
20791
|
+
}
|
|
20792
|
+
function branchLane(cwd, options) {
|
|
20793
|
+
const candidates = options.base ? [`origin/${options.base}`, options.base] : [];
|
|
20794
|
+
const base = candidates.find((ref) => resolveRef(cwd, ref) !== null) ?? defaultBase(cwd) ?? null;
|
|
20795
|
+
const head = options.workingTree ? null : options.head;
|
|
20796
|
+
const fork = base && (options.workingTree || options.head) ? forkOf(cwd, base, head) : null;
|
|
20797
|
+
const files = fork ? laneFiles(cwd, fork, head) : null;
|
|
20798
|
+
const riskTier = options.judgment?.riskTier ?? null;
|
|
20799
|
+
if (!fork || !files) {
|
|
20800
|
+
const high = riskTier === "high";
|
|
20801
|
+
return {
|
|
20802
|
+
lane: high ? "full" : "focused",
|
|
20803
|
+
reasons: [
|
|
20804
|
+
`the diff of ${options.head?.slice(0, 12) ?? "(no head)"} against ${base ?? "(no base)"} cannot be read`,
|
|
20805
|
+
...high ? ["the task judgment records high risk"] : []
|
|
20806
|
+
],
|
|
20807
|
+
lines: 0,
|
|
20808
|
+
files: 0,
|
|
20809
|
+
riskFiles: [],
|
|
20810
|
+
base,
|
|
20811
|
+
head: options.head
|
|
20812
|
+
};
|
|
20813
|
+
}
|
|
20814
|
+
const repoRisk = parseRiskPaths(fileAt(cwd, fork, RISK_PATHS_FILE) ?? "");
|
|
20815
|
+
return {
|
|
20816
|
+
...computeLane({
|
|
20817
|
+
files,
|
|
20818
|
+
riskTier,
|
|
20819
|
+
riskPaths: [...repoRisk, ...options.riskPaths ?? []]
|
|
20820
|
+
}),
|
|
20821
|
+
base,
|
|
20822
|
+
head: options.head
|
|
20823
|
+
};
|
|
20824
|
+
}
|
|
20825
|
+
var laneNeed = (lane) => lane === "none" ? "none" : lane === "self" ? "self" : "non-author";
|
|
20826
|
+
|
|
20000
20827
|
// packages/workit-core/src/core/policy/derive.ts
|
|
20001
20828
|
var RULES = {
|
|
20002
20829
|
test: "check:test",
|
|
20003
20830
|
self: "verdict:self",
|
|
20004
20831
|
nonAuthor: "verdict:non-author",
|
|
20005
20832
|
verified: "verdict:verified",
|
|
20833
|
+
lane: "verdict:lane",
|
|
20006
20834
|
product: "decision:product",
|
|
20007
20835
|
plan: "plan"
|
|
20008
20836
|
};
|
|
@@ -20025,6 +20853,7 @@ var normalizedScope = (scope) => ({
|
|
|
20025
20853
|
function deriveRequirements(judgment, scope, constraints, verification = "self") {
|
|
20026
20854
|
const out = [];
|
|
20027
20855
|
const base = { scope, dependentAction: null };
|
|
20856
|
+
const proportional = verification === "proportional";
|
|
20028
20857
|
if (judgment.behaviorChange)
|
|
20029
20858
|
out.push(derived2({
|
|
20030
20859
|
...base,
|
|
@@ -20035,7 +20864,17 @@ function deriveRequirements(judgment, scope, constraints, verification = "self")
|
|
|
20035
20864
|
before: "close",
|
|
20036
20865
|
acceptanceAllowed: false
|
|
20037
20866
|
}));
|
|
20038
|
-
if (
|
|
20867
|
+
if (proportional && judgment.riskTier === "normal")
|
|
20868
|
+
out.push(derived2({
|
|
20869
|
+
...base,
|
|
20870
|
+
ruleId: RULES.lane,
|
|
20871
|
+
dimension: "review",
|
|
20872
|
+
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.",
|
|
20873
|
+
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.",
|
|
20874
|
+
before: "close",
|
|
20875
|
+
acceptanceAllowed: false
|
|
20876
|
+
}));
|
|
20877
|
+
if (!proportional && judgment.behaviorChange && judgment.riskTier === "normal")
|
|
20039
20878
|
out.push(verification === "independent" ? derived2({
|
|
20040
20879
|
...base,
|
|
20041
20880
|
ruleId: RULES.nonAuthor,
|
|
@@ -20138,7 +20977,7 @@ var productDecision = (task, ledger) => {
|
|
|
20138
20977
|
};
|
|
20139
20978
|
};
|
|
20140
20979
|
var planRecorded = (task, root) => {
|
|
20141
|
-
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" &&
|
|
20980
|
+
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync5(path17.resolve(root, ref.path)));
|
|
20142
20981
|
if (cited)
|
|
20143
20982
|
return {
|
|
20144
20983
|
met: true,
|
|
@@ -20152,14 +20991,30 @@ var planRecorded = (task, root) => {
|
|
|
20152
20991
|
decisionIds: []
|
|
20153
20992
|
};
|
|
20154
20993
|
};
|
|
20155
|
-
var
|
|
20994
|
+
var workingLane = (task, root) => branchLane(root, { head: null, workingTree: true, judgment: latestJudgment(task) });
|
|
20995
|
+
var laneVerdict = (task, root, ledger) => {
|
|
20996
|
+
if (!ledger.branch() && latestJudgment(task)?.behaviorChange === false)
|
|
20997
|
+
return {
|
|
20998
|
+
met: true,
|
|
20999
|
+
reason: "no branch to read a lane from, and the judgment records no behavior change",
|
|
21000
|
+
decisionIds: []
|
|
21001
|
+
};
|
|
21002
|
+
const lane = workingLane(task, root);
|
|
21003
|
+
const label = `lane ${lane.lane} (${lane.reasons.join("; ")})`;
|
|
21004
|
+
const need = laneNeed(lane.lane);
|
|
21005
|
+
if (need === "none")
|
|
21006
|
+
return { met: true, reason: `${label}: no verdict needed`, decisionIds: [] };
|
|
21007
|
+
const status = verdict(need === "self" ? RULES.self : RULES.nonAuthor, root, ledger);
|
|
21008
|
+
return { ...status, reason: `${label}: ${status.reason}` };
|
|
21009
|
+
};
|
|
21010
|
+
var verdict = (ruleId, root, ledger) => {
|
|
20156
21011
|
const branch = ledger.branch();
|
|
20157
21012
|
if (!branch)
|
|
20158
21013
|
return { met: false, reason: "no branch is checked out to hold a verdict", decisionIds: [] };
|
|
20159
21014
|
const check = checkVerdicts(root, branch, ledger.rows());
|
|
20160
21015
|
const failing = check.accepted.reasons.includes("failing_verdict");
|
|
20161
21016
|
const strong = (entry) => STRONG_RESULTS.has(String(entry.verdict.result));
|
|
20162
|
-
const met = !failing && (
|
|
21017
|
+
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
21018
|
if (met)
|
|
20164
21019
|
return {
|
|
20165
21020
|
met: true,
|
|
@@ -20167,7 +21022,7 @@ var verdict = (requirement, root, ledger) => {
|
|
|
20167
21022
|
decisionIds: []
|
|
20168
21023
|
};
|
|
20169
21024
|
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 =
|
|
21025
|
+
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
21026
|
return { met: false, reason: `${why}: ${unblock}`, decisionIds: [] };
|
|
20172
21027
|
};
|
|
20173
21028
|
function derivedRuleStatus(task, requirement, root, ledger) {
|
|
@@ -20179,7 +21034,9 @@ function derivedRuleStatus(task, requirement, root, ledger) {
|
|
|
20179
21034
|
case RULES.self:
|
|
20180
21035
|
case RULES.nonAuthor:
|
|
20181
21036
|
case RULES.verified:
|
|
20182
|
-
return verdict(requirement, root, ledger);
|
|
21037
|
+
return verdict(requirement.ruleId, root, ledger);
|
|
21038
|
+
case RULES.lane:
|
|
21039
|
+
return laneVerdict(task, root, ledger);
|
|
20183
21040
|
default:
|
|
20184
21041
|
return null;
|
|
20185
21042
|
}
|
|
@@ -20187,14 +21044,14 @@ function derivedRuleStatus(task, requirement, root, ledger) {
|
|
|
20187
21044
|
|
|
20188
21045
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
20189
21046
|
var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
|
|
20190
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
20191
|
-
var relative = (root, candidate) =>
|
|
21047
|
+
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path18.sep}`);
|
|
21048
|
+
var relative = (root, candidate) => path18.relative(root, candidate).split(path18.sep).join("/") || ".";
|
|
20192
21049
|
var canonicalPath = (value) => {
|
|
20193
21050
|
if (typeof value !== "string" || !value)
|
|
20194
21051
|
return null;
|
|
20195
21052
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
20196
21053
|
return null;
|
|
20197
|
-
const normalized =
|
|
21054
|
+
const normalized = path18.posix.normalize(value);
|
|
20198
21055
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
20199
21056
|
return null;
|
|
20200
21057
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -20230,7 +21087,7 @@ var compareCodeUnits2 = (left, right) => {
|
|
|
20230
21087
|
return left.length - right.length;
|
|
20231
21088
|
};
|
|
20232
21089
|
var gitPaths = (root) => {
|
|
20233
|
-
const result =
|
|
21090
|
+
const result = spawnSync11("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
|
|
20234
21091
|
cwd: root,
|
|
20235
21092
|
encoding: "buffer"
|
|
20236
21093
|
});
|
|
@@ -20242,21 +21099,21 @@ var gitPaths = (root) => {
|
|
|
20242
21099
|
git: !/not a git repository/i.test(stderr)
|
|
20243
21100
|
};
|
|
20244
21101
|
}
|
|
20245
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
20246
|
-
const stagedDeleted =
|
|
21102
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path18.sep).join("/")) : [];
|
|
21103
|
+
const stagedDeleted = spawnSync11("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
20247
21104
|
if (stagedDeleted.status !== 0) {
|
|
20248
21105
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
20249
21106
|
if (!/not a git repository/i.test(stderr))
|
|
20250
21107
|
return { paths, uncertain: true, git: true };
|
|
20251
21108
|
} else if (stagedDeleted.stdout) {
|
|
20252
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
21109
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path18.sep).join("/")));
|
|
20253
21110
|
}
|
|
20254
21111
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
20255
21112
|
};
|
|
20256
21113
|
var walk = (root, directory, output) => {
|
|
20257
21114
|
let names;
|
|
20258
21115
|
try {
|
|
20259
|
-
names =
|
|
21116
|
+
names = fs14.readdirSync(directory);
|
|
20260
21117
|
} catch {
|
|
20261
21118
|
return true;
|
|
20262
21119
|
}
|
|
@@ -20264,10 +21121,10 @@ var walk = (root, directory, output) => {
|
|
|
20264
21121
|
for (const name of names) {
|
|
20265
21122
|
if (name === ".git" || name === ".workit")
|
|
20266
21123
|
continue;
|
|
20267
|
-
const target =
|
|
21124
|
+
const target = path18.join(directory, name);
|
|
20268
21125
|
let stat;
|
|
20269
21126
|
try {
|
|
20270
|
-
stat =
|
|
21127
|
+
stat = fs14.lstatSync(target);
|
|
20271
21128
|
} catch {
|
|
20272
21129
|
uncertain = true;
|
|
20273
21130
|
continue;
|
|
@@ -20282,14 +21139,14 @@ var walk = (root, directory, output) => {
|
|
|
20282
21139
|
var scopeRoots = (root, scope) => {
|
|
20283
21140
|
const roots = [];
|
|
20284
21141
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
20285
|
-
const target =
|
|
21142
|
+
const target = path18.resolve(root, item);
|
|
20286
21143
|
if (!inside(root, target))
|
|
20287
21144
|
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
21145
|
let ancestor = target;
|
|
20289
|
-
while (!
|
|
20290
|
-
ancestor =
|
|
21146
|
+
while (!fs14.existsSync(ancestor) && ancestor !== root)
|
|
21147
|
+
ancestor = path18.dirname(ancestor);
|
|
20291
21148
|
try {
|
|
20292
|
-
if (!inside(root,
|
|
21149
|
+
if (!inside(root, fs14.realpathSync(ancestor)))
|
|
20293
21150
|
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` }] });
|
|
20294
21151
|
} catch {
|
|
20295
21152
|
return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
|
|
@@ -20301,7 +21158,7 @@ var scopeRoots = (root, scope) => {
|
|
|
20301
21158
|
function captureCandidate(root, scope, environment = []) {
|
|
20302
21159
|
let checkout;
|
|
20303
21160
|
try {
|
|
20304
|
-
checkout =
|
|
21161
|
+
checkout = fs14.realpathSync(root);
|
|
20305
21162
|
} catch {
|
|
20306
21163
|
return failure2("invalid_input", "candidate root does not exist");
|
|
20307
21164
|
}
|
|
@@ -20319,11 +21176,11 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
20319
21176
|
if (item === ".git" || item === ".workit")
|
|
20320
21177
|
continue;
|
|
20321
21178
|
names.add(item);
|
|
20322
|
-
if (!
|
|
21179
|
+
if (!fs14.existsSync(target))
|
|
20323
21180
|
continue;
|
|
20324
21181
|
let stat;
|
|
20325
21182
|
try {
|
|
20326
|
-
stat =
|
|
21183
|
+
stat = fs14.lstatSync(target);
|
|
20327
21184
|
} catch {
|
|
20328
21185
|
uncertain = true;
|
|
20329
21186
|
continue;
|
|
@@ -20339,17 +21196,17 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
20339
21196
|
for (const item of [...names].toSorted()) {
|
|
20340
21197
|
if (!scopeMatches(item, normalizedScope))
|
|
20341
21198
|
continue;
|
|
20342
|
-
const target =
|
|
21199
|
+
const target = path18.join(checkout, item);
|
|
20343
21200
|
try {
|
|
20344
|
-
const stat =
|
|
21201
|
+
const stat = fs14.lstatSync(target);
|
|
20345
21202
|
if (stat.isSymbolicLink()) {
|
|
20346
|
-
const link =
|
|
21203
|
+
const link = fs14.readlinkSync(target);
|
|
20347
21204
|
files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
|
|
20348
21205
|
} else if (stat.isFile()) {
|
|
20349
21206
|
files.push({
|
|
20350
21207
|
path: item,
|
|
20351
21208
|
kind: "file",
|
|
20352
|
-
digest: digestBytes(
|
|
21209
|
+
digest: digestBytes(fs14.readFileSync(target)),
|
|
20353
21210
|
executable: (stat.mode & 73) !== 0
|
|
20354
21211
|
});
|
|
20355
21212
|
} else if (!stat.isDirectory()) {
|
|
@@ -20374,7 +21231,7 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
20374
21231
|
const values = supplied.toSorted((left, right) => compareCodeUnits2(left.name, right.name)).map(({ name, value }) => ({ name, value, refs: [] }));
|
|
20375
21232
|
if (values.some(({ value }) => value === null))
|
|
20376
21233
|
completeness = "uncertain";
|
|
20377
|
-
const headResult =
|
|
21234
|
+
const headResult = spawnSync11("git", ["rev-parse", "HEAD"], { cwd: checkout, encoding: "utf8" });
|
|
20378
21235
|
if (headResult.status !== 0 && !/not a git repository/i.test(headResult.stderr ?? ""))
|
|
20379
21236
|
completeness = "uncertain";
|
|
20380
21237
|
const head = headResult.status === 0 ? headResult.stdout.trim() : null;
|
|
@@ -20514,7 +21371,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
|
|
|
20514
21371
|
var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
20515
21372
|
let root;
|
|
20516
21373
|
try {
|
|
20517
|
-
root =
|
|
21374
|
+
root = fs14.realpathSync(checkoutRoot);
|
|
20518
21375
|
} catch {
|
|
20519
21376
|
return failure2("permission_denied", "checkout root is unavailable");
|
|
20520
21377
|
}
|
|
@@ -20523,23 +21380,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
20523
21380
|
continue;
|
|
20524
21381
|
if (!reference.digest)
|
|
20525
21382
|
return failure2("invalid_input", "document references require a byte digest");
|
|
20526
|
-
const target =
|
|
20527
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
21383
|
+
const target = path18.resolve(root, reference.path);
|
|
21384
|
+
if (target !== root && !target.startsWith(`${root}${path18.sep}`))
|
|
20528
21385
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
20529
21386
|
fields: [
|
|
20530
21387
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
20531
21388
|
]
|
|
20532
21389
|
});
|
|
20533
21390
|
try {
|
|
20534
|
-
const below =
|
|
21391
|
+
const below = path18.relative(root, target);
|
|
20535
21392
|
let current = root;
|
|
20536
|
-
for (const segment of below.split(
|
|
21393
|
+
for (const segment of below.split(path18.sep)) {
|
|
20537
21394
|
if (!segment)
|
|
20538
21395
|
continue;
|
|
20539
|
-
current =
|
|
20540
|
-
const stat =
|
|
20541
|
-
const real =
|
|
20542
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
21396
|
+
current = path18.join(current, segment);
|
|
21397
|
+
const stat = fs14.lstatSync(current);
|
|
21398
|
+
const real = fs14.realpathSync(current);
|
|
21399
|
+
if (real !== root && !real.startsWith(`${root}${path18.sep}`))
|
|
20543
21400
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
20544
21401
|
fields: [
|
|
20545
21402
|
{
|
|
@@ -20555,7 +21412,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
20555
21412
|
if (current !== target && !stat.isDirectory())
|
|
20556
21413
|
return failure2("invalid_input", "document reference ancestor is not a directory");
|
|
20557
21414
|
}
|
|
20558
|
-
if (digestBytes(
|
|
21415
|
+
if (digestBytes(fs14.readFileSync(target)) !== reference.digest)
|
|
20559
21416
|
return failure2("permission_denied", "decision document bytes have changed");
|
|
20560
21417
|
} catch {
|
|
20561
21418
|
return failure2("invalid_input", "decision document is unavailable");
|
|
@@ -21398,7 +22255,7 @@ var judgeInputSummary = (raw) => {
|
|
|
21398
22255
|
|
|
21399
22256
|
// packages/workit-core/src/autonomy.ts
|
|
21400
22257
|
import os4 from "node:os";
|
|
21401
|
-
import
|
|
22258
|
+
import path19 from "node:path";
|
|
21402
22259
|
var accountHome = () => {
|
|
21403
22260
|
try {
|
|
21404
22261
|
return os4.userInfo().homedir;
|
|
@@ -21407,10 +22264,10 @@ var accountHome = () => {
|
|
|
21407
22264
|
}
|
|
21408
22265
|
};
|
|
21409
22266
|
var grantsHome = { resolve: accountHome };
|
|
21410
|
-
var grantsDir = () =>
|
|
22267
|
+
var grantsDir = () => path19.join(grantsHome.resolve(), ".config", "workit");
|
|
21411
22268
|
var grantsOverride = () => {
|
|
21412
|
-
const configured =
|
|
21413
|
-
return configured ===
|
|
22269
|
+
const configured = path19.resolve(resolveConfigDir());
|
|
22270
|
+
return configured === path19.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path19.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
|
|
21414
22271
|
};
|
|
21415
22272
|
var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
|
|
21416
22273
|
var DEFAULT_GRANTS = Object.freeze({
|
|
@@ -21463,8 +22320,16 @@ function endpointView(entry, context) {
|
|
|
21463
22320
|
...issue ? { endpointIssue: issue } : {}
|
|
21464
22321
|
};
|
|
21465
22322
|
}
|
|
21466
|
-
var
|
|
21467
|
-
|
|
22323
|
+
var VERIFICATION_MODES = [
|
|
22324
|
+
"proportional",
|
|
22325
|
+
"self",
|
|
22326
|
+
"independent"
|
|
22327
|
+
];
|
|
22328
|
+
var DEFAULT_VERIFICATION = "proportional";
|
|
22329
|
+
var verificationOf = (entry) => {
|
|
22330
|
+
const value = entry?.verification;
|
|
22331
|
+
return VERIFICATION_MODES.includes(value) ? value : DEFAULT_VERIFICATION;
|
|
22332
|
+
};
|
|
21468
22333
|
var isGrantValue = (value) => value === true || value === false || value === "verified";
|
|
21469
22334
|
var normalized = (kind, value) => value === "verified" && kind !== "merge" ? true : value;
|
|
21470
22335
|
var fromAutoApprove = (value) => {
|
|
@@ -23211,9 +24076,9 @@ class WorkitCore {
|
|
|
23211
24076
|
}
|
|
23212
24077
|
}
|
|
23213
24078
|
// packages/workit-core/src/core/repo-context.ts
|
|
23214
|
-
import { spawnSync as
|
|
23215
|
-
import { existsSync as
|
|
23216
|
-
import
|
|
24079
|
+
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
24080
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "node:fs";
|
|
24081
|
+
import path20 from "node:path";
|
|
23217
24082
|
var isSafeContextRange = (value) => value.length <= 4096 && (() => {
|
|
23218
24083
|
try {
|
|
23219
24084
|
gitRevisionParts(value);
|
|
@@ -23240,7 +24105,7 @@ var invalidRange = (cwd) => ({
|
|
|
23240
24105
|
cwd
|
|
23241
24106
|
});
|
|
23242
24107
|
var runGit = (cwd, args) => {
|
|
23243
|
-
const result =
|
|
24108
|
+
const result = spawnSync12("git", args, { cwd, encoding: "utf8" });
|
|
23244
24109
|
return {
|
|
23245
24110
|
stdout: (result.stdout ?? "").trimEnd(),
|
|
23246
24111
|
stderr: (result.stderr ?? "").trimEnd(),
|
|
@@ -23347,7 +24212,7 @@ var findPrTemplate = (cwd) => {
|
|
|
23347
24212
|
]) {
|
|
23348
24213
|
const parts = rel.split("/");
|
|
23349
24214
|
const base = parts[parts.length - 1];
|
|
23350
|
-
const dir = parts.length > 1 ?
|
|
24215
|
+
const dir = parts.length > 1 ? path20.join(cwd, ...parts.slice(0, -1)) : cwd;
|
|
23351
24216
|
const actual = probeCaseInsensitive(dir, base);
|
|
23352
24217
|
if (actual)
|
|
23353
24218
|
return [...parts.slice(0, -1), actual].join("/");
|
|
@@ -23378,11 +24243,11 @@ var diffStatForRange = (cwd, range) => {
|
|
|
23378
24243
|
return runGit(cwd, ["diff", "--stat", "--"]).stdout;
|
|
23379
24244
|
};
|
|
23380
24245
|
var packageScripts = (cwd, keys) => {
|
|
23381
|
-
const pkgPath =
|
|
23382
|
-
if (!
|
|
24246
|
+
const pkgPath = path20.join(cwd, "package.json");
|
|
24247
|
+
if (!existsSync7(pkgPath))
|
|
23383
24248
|
return [];
|
|
23384
24249
|
try {
|
|
23385
|
-
const pkg = JSON.parse(
|
|
24250
|
+
const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
|
|
23386
24251
|
return keys.filter((k) => pkg.scripts && typeof pkg.scripts[k] === "string").map((k) => `${k}: ${pkg.scripts?.[k]}`);
|
|
23387
24252
|
} catch {
|
|
23388
24253
|
return [];
|
|
@@ -23404,9 +24269,9 @@ var documentationFiles = (cwd) => {
|
|
|
23404
24269
|
if (entry.isDirectory()) {
|
|
23405
24270
|
if (excluded.has(entry.name))
|
|
23406
24271
|
continue;
|
|
23407
|
-
walk(
|
|
24272
|
+
walk(path20.join(dir, entry.name), depth + 1);
|
|
23408
24273
|
} else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
|
|
23409
|
-
matches.push("./" +
|
|
24274
|
+
matches.push("./" + path20.relative(cwd, path20.join(dir, entry.name)).replaceAll("\\", "/"));
|
|
23410
24275
|
}
|
|
23411
24276
|
}
|
|
23412
24277
|
};
|
|
@@ -23414,15 +24279,15 @@ var documentationFiles = (cwd) => {
|
|
|
23414
24279
|
return matches.toSorted().slice(0, 200);
|
|
23415
24280
|
};
|
|
23416
24281
|
var readTrimmed2 = (file, maxLines) => {
|
|
23417
|
-
if (!
|
|
24282
|
+
if (!existsSync7(file))
|
|
23418
24283
|
return "";
|
|
23419
|
-
const lines =
|
|
24284
|
+
const lines = readFileSync6(file, "utf8").split(`
|
|
23420
24285
|
`);
|
|
23421
24286
|
return lines.slice(0, maxLines).join(`
|
|
23422
24287
|
`);
|
|
23423
24288
|
};
|
|
23424
24289
|
function prReadyContext(root, range) {
|
|
23425
|
-
const cwd =
|
|
24290
|
+
const cwd = path20.resolve(repoRoot(root));
|
|
23426
24291
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
23427
24292
|
return invalidRange(cwd);
|
|
23428
24293
|
let stdout = "";
|
|
@@ -23480,7 +24345,7 @@ ${status.stderr}` : "");
|
|
|
23480
24345
|
stdout += `template_path: ${template}
|
|
23481
24346
|
|
|
23482
24347
|
`;
|
|
23483
|
-
stdout += readTrimmed2(
|
|
24348
|
+
stdout += readTrimmed2(path20.join(cwd, template), 220);
|
|
23484
24349
|
} else {
|
|
23485
24350
|
stdout += `template_path: none
|
|
23486
24351
|
|
|
@@ -23490,7 +24355,7 @@ ${status.stderr}` : "");
|
|
|
23490
24355
|
stdout += `
|
|
23491
24356
|
`;
|
|
23492
24357
|
stdout += printSection("Recent Validation Signals");
|
|
23493
|
-
if (
|
|
24358
|
+
if (existsSync7(path20.join(cwd, "package.json"))) {
|
|
23494
24359
|
stdout += `package.json detected. Common scripts:
|
|
23495
24360
|
`;
|
|
23496
24361
|
const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
|
|
@@ -23499,7 +24364,7 @@ ${status.stderr}` : "");
|
|
|
23499
24364
|
`) + `
|
|
23500
24365
|
`;
|
|
23501
24366
|
}
|
|
23502
|
-
if (
|
|
24367
|
+
if (existsSync7(path20.join(cwd, "Cargo.toml")) || existsSync7(path20.join(cwd, "src-tauri/Cargo.toml"))) {
|
|
23503
24368
|
stdout += `Rust project detected.
|
|
23504
24369
|
`;
|
|
23505
24370
|
}
|
|
@@ -23532,7 +24397,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
|
|
|
23532
24397
|
- Apply with the host-native editor, preserving the repository changelog conventions.
|
|
23533
24398
|
- If Unreleased already has duplicate category headings, normalize_only first.`;
|
|
23534
24399
|
function changelogContext(root, range) {
|
|
23535
|
-
const cwd =
|
|
24400
|
+
const cwd = path20.resolve(repoRoot(root));
|
|
23536
24401
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
23537
24402
|
return invalidRange(cwd);
|
|
23538
24403
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -23550,8 +24415,8 @@ function changelogContext(root, range) {
|
|
|
23550
24415
|
stdout += CHANGELOG_RULES + `
|
|
23551
24416
|
`;
|
|
23552
24417
|
stdout += printSection("Existing CHANGELOG.md");
|
|
23553
|
-
const changelogPath =
|
|
23554
|
-
if (
|
|
24418
|
+
const changelogPath = path20.join(cwd, "CHANGELOG.md");
|
|
24419
|
+
if (existsSync7(changelogPath)) {
|
|
23555
24420
|
stdout += readTrimmed2(changelogPath, 260) + `
|
|
23556
24421
|
`;
|
|
23557
24422
|
} else {
|
|
@@ -23570,7 +24435,7 @@ function changelogContext(root, range) {
|
|
|
23570
24435
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
23571
24436
|
}
|
|
23572
24437
|
function docsRefreshContext(root, range) {
|
|
23573
|
-
const cwd =
|
|
24438
|
+
const cwd = path20.resolve(repoRoot(root));
|
|
23574
24439
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
23575
24440
|
return invalidRange(cwd);
|
|
23576
24441
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -23592,8 +24457,8 @@ function docsRefreshContext(root, range) {
|
|
|
23592
24457
|
`) + `
|
|
23593
24458
|
`;
|
|
23594
24459
|
stdout += printSection("README Preview");
|
|
23595
|
-
const readme =
|
|
23596
|
-
if (
|
|
24460
|
+
const readme = path20.join(cwd, "README.md");
|
|
24461
|
+
if (existsSync7(readme)) {
|
|
23597
24462
|
stdout += readTrimmed2(readme, 220) + `
|
|
23598
24463
|
`;
|
|
23599
24464
|
} else {
|
|
@@ -23601,10 +24466,10 @@ function docsRefreshContext(root, range) {
|
|
|
23601
24466
|
`;
|
|
23602
24467
|
}
|
|
23603
24468
|
stdout += printSection("Package Scripts");
|
|
23604
|
-
const pkgPath =
|
|
23605
|
-
if (
|
|
24469
|
+
const pkgPath = path20.join(cwd, "package.json");
|
|
24470
|
+
if (existsSync7(pkgPath)) {
|
|
23606
24471
|
try {
|
|
23607
|
-
const pkg = JSON.parse(
|
|
24472
|
+
const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
|
|
23608
24473
|
stdout += JSON.stringify({ name: pkg.name, version: pkg.version, scripts: pkg.scripts }, null, 2) + `
|
|
23609
24474
|
`;
|
|
23610
24475
|
} catch {}
|
|
@@ -23615,7 +24480,7 @@ function docsRefreshContext(root, range) {
|
|
|
23615
24480
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
23616
24481
|
}
|
|
23617
24482
|
function releaseNotesContext(root, rangeOrTag) {
|
|
23618
|
-
const cwd =
|
|
24483
|
+
const cwd = path20.resolve(repoRoot(root));
|
|
23619
24484
|
if (!rangeOrTag) {
|
|
23620
24485
|
return { stdout: "", stderr: `ERROR: release tag or range required
|
|
23621
24486
|
`, exitCode: 1, cwd };
|
|
@@ -23653,7 +24518,7 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
23653
24518
|
`;
|
|
23654
24519
|
stdout += printSection("Existing Release Files");
|
|
23655
24520
|
for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
|
|
23656
|
-
if (
|
|
24521
|
+
if (existsSync7(path20.join(cwd, rel)))
|
|
23657
24522
|
stdout += rel + `
|
|
23658
24523
|
`;
|
|
23659
24524
|
}
|
|
@@ -23682,46 +24547,6 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
23682
24547
|
|
|
23683
24548
|
// packages/workit-core/src/core/tracker-issues.ts
|
|
23684
24549
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
23685
|
-
|
|
23686
|
-
// packages/workit-core/src/core/pr-create.ts
|
|
23687
|
-
import fs14 from "node:fs";
|
|
23688
|
-
import path19 from "node:path";
|
|
23689
|
-
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
23690
|
-
// packages/workit-core/src/forge/pr-body.ts
|
|
23691
|
-
function parseGhIssue(value) {
|
|
23692
|
-
const m = /issues\/(\d+)/.exec(value);
|
|
23693
|
-
return m ? m[1] : String(value).trim().replace(/^#/, "");
|
|
23694
|
-
}
|
|
23695
|
-
|
|
23696
|
-
// packages/workit-core/src/core/pr-create.ts
|
|
23697
|
-
function whichOnPath(tool) {
|
|
23698
|
-
const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
|
|
23699
|
-
for (const dir of (process.env.PATH ?? "").split(path19.delimiter)) {
|
|
23700
|
-
if (!dir)
|
|
23701
|
-
continue;
|
|
23702
|
-
for (const name of names) {
|
|
23703
|
-
const candidate = path19.join(dir, name);
|
|
23704
|
-
try {
|
|
23705
|
-
fs14.accessSync(candidate, fs14.constants.X_OK);
|
|
23706
|
-
return candidate;
|
|
23707
|
-
} catch {}
|
|
23708
|
-
}
|
|
23709
|
-
}
|
|
23710
|
-
return null;
|
|
23711
|
-
}
|
|
23712
|
-
var hostingCliAvailable = (provider) => whichOnPath(provider === "gitlab" ? "glab" : "gh") !== null;
|
|
23713
|
-
var pushRemote = (cwd) => {
|
|
23714
|
-
const result = spawnSync12("git", ["remote", "get-url", "--push", "--all", "origin"], {
|
|
23715
|
-
cwd,
|
|
23716
|
-
encoding: "utf8"
|
|
23717
|
-
});
|
|
23718
|
-
if (result.status !== 0)
|
|
23719
|
-
return null;
|
|
23720
|
-
const urls = (result.stdout ?? "").split(/\r?\n/u).map((url) => url.trim()).filter(Boolean);
|
|
23721
|
-
return urls.length === 1 ? urls[0] : null;
|
|
23722
|
-
};
|
|
23723
|
-
|
|
23724
|
-
// packages/workit-core/src/core/tracker-issues.ts
|
|
23725
24550
|
var repoPathFromRemote = (remote) => {
|
|
23726
24551
|
let rest = (remote || "").trim().replace(/\/+$/, "");
|
|
23727
24552
|
if (!rest)
|
|
@@ -23821,7 +24646,7 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
|
|
|
23821
24646
|
|
|
23822
24647
|
// packages/workit-core/src/core/youtrack.ts
|
|
23823
24648
|
import fs15 from "node:fs";
|
|
23824
|
-
import
|
|
24649
|
+
import path21 from "node:path";
|
|
23825
24650
|
|
|
23826
24651
|
// packages/workit-core/src/core/templates.ts
|
|
23827
24652
|
var repoRoot2 = assetRoot();
|
|
@@ -23834,8 +24659,8 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
|
|
|
23834
24659
|
// packages/workit-core/src/core/youtrack.ts
|
|
23835
24660
|
var ISSUE_RE = /^[A-Z]+-\d+$/;
|
|
23836
24661
|
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
23837
|
-
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
23838
|
-
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
24662
|
+
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path21.join(configDir(), "youtrack.json");
|
|
24663
|
+
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path21.join(resolveConfigDir(), "youtrack.json");
|
|
23839
24664
|
var youTrackTokenModeOk = (p) => {
|
|
23840
24665
|
if (process.platform === "win32")
|
|
23841
24666
|
return true;
|
|
@@ -23903,7 +24728,7 @@ var youTrackToken = () => {
|
|
|
23903
24728
|
if ("error" in loaded)
|
|
23904
24729
|
return loaded;
|
|
23905
24730
|
const tokenFile = String(loaded.config.tokenFile ?? "");
|
|
23906
|
-
const tokenPath = tokenFile ?
|
|
24731
|
+
const tokenPath = tokenFile ? path21.isAbsolute(tokenFile) ? path21.resolve(tokenFile) : path21.resolve(process.cwd(), tokenFile) : "";
|
|
23907
24732
|
if (!tokenPath || !fs15.existsSync(tokenPath))
|
|
23908
24733
|
return { error: "missing youtrack.token" };
|
|
23909
24734
|
if (!youTrackTokenModeOk(tokenPath))
|
|
@@ -24245,15 +25070,15 @@ function resolveGitRevision(root, value) {
|
|
|
24245
25070
|
}
|
|
24246
25071
|
function resolveInside(root, candidate) {
|
|
24247
25072
|
const base = realpathSync5(root);
|
|
24248
|
-
const target =
|
|
24249
|
-
if (target !== base && !target.startsWith(base +
|
|
25073
|
+
const target = path22.resolve(base, candidate);
|
|
25074
|
+
if (target !== base && !target.startsWith(base + path22.sep)) {
|
|
24250
25075
|
throw new Error("path must stay inside repository root");
|
|
24251
25076
|
}
|
|
24252
25077
|
let ancestor = target;
|
|
24253
|
-
while (!
|
|
24254
|
-
ancestor =
|
|
25078
|
+
while (!existsSync8(ancestor))
|
|
25079
|
+
ancestor = path22.dirname(ancestor);
|
|
24255
25080
|
const canonicalAncestor = realpathSync5(ancestor);
|
|
24256
|
-
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base +
|
|
25081
|
+
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path22.sep)) {
|
|
24257
25082
|
throw new Error("path must stay inside repository root");
|
|
24258
25083
|
}
|
|
24259
25084
|
return target;
|
|
@@ -24284,8 +25109,8 @@ var SUPPORT_MATRIX = {
|
|
|
24284
25109
|
};
|
|
24285
25110
|
|
|
24286
25111
|
// packages/workit-mcp/src/server.ts
|
|
24287
|
-
import { existsSync as
|
|
24288
|
-
import
|
|
25112
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, realpathSync as realpathSync6 } from "node:fs";
|
|
25113
|
+
import path23 from "node:path";
|
|
24289
25114
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
24290
25115
|
function isZ4Schema(s) {
|
|
24291
25116
|
const schema = s;
|
|
@@ -26689,7 +27514,7 @@ var safeCapability = (value, allowed) => allowed.includes(value) ? value : "cont
|
|
|
26689
27514
|
var TOOL_CAPABILITIES = [...CONTEXT_KINDS, "workspace", "native_caller_identity"];
|
|
26690
27515
|
var VERSION = (() => {
|
|
26691
27516
|
try {
|
|
26692
|
-
const packageJson = JSON.parse(
|
|
27517
|
+
const packageJson = JSON.parse(readFileSync7(new URL("../package.json", import.meta.url), "utf8"));
|
|
26693
27518
|
return typeof packageJson.version === "string" ? packageJson.version : "0.0.0";
|
|
26694
27519
|
} catch {
|
|
26695
27520
|
return "0.0.0";
|
|
@@ -26699,13 +27524,13 @@ var rootVariants = (workspaceRoot) => {
|
|
|
26699
27524
|
if (!workspaceRoot)
|
|
26700
27525
|
return [];
|
|
26701
27526
|
const roots = new Set;
|
|
26702
|
-
for (const candidate of [workspaceRoot,
|
|
26703
|
-
if (
|
|
27527
|
+
for (const candidate of [workspaceRoot, path23.resolve(workspaceRoot)]) {
|
|
27528
|
+
if (path23.isAbsolute(candidate) && candidate !== path23.parse(candidate).root)
|
|
26704
27529
|
roots.add(candidate);
|
|
26705
27530
|
}
|
|
26706
27531
|
try {
|
|
26707
27532
|
const canonical = realpathSync6(workspaceRoot);
|
|
26708
|
-
if (canonical !==
|
|
27533
|
+
if (canonical !== path23.parse(canonical).root)
|
|
26709
27534
|
roots.add(canonical);
|
|
26710
27535
|
} catch {}
|
|
26711
27536
|
return [...roots].toSorted((left, right) => right.length - left.length);
|
|
@@ -26787,12 +27612,12 @@ var thrownResult = (tool, error, workspaceRoot) => {
|
|
|
26787
27612
|
};
|
|
26788
27613
|
function createMcpServer(host, contextProvider) {
|
|
26789
27614
|
assertMcpHost(host);
|
|
26790
|
-
const here =
|
|
27615
|
+
const here = path23.dirname(fileURLToPath2(import.meta.url));
|
|
26791
27616
|
const sourceMarker = markSourcesLoaded([
|
|
26792
|
-
|
|
26793
|
-
|
|
26794
|
-
|
|
26795
|
-
].filter((file) =>
|
|
27617
|
+
path23.join(here, "server.ts"),
|
|
27618
|
+
path23.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
|
|
27619
|
+
path23.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
|
|
27620
|
+
].filter((file) => existsSync9(file)));
|
|
26796
27621
|
let staleWarned = false;
|
|
26797
27622
|
const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
|
|
26798
27623
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
@@ -27109,7 +27934,7 @@ var EXEC = new Set(["exec", "x", "dlx"]);
|
|
|
27109
27934
|
// packages/workit-core/src/core/heavy-words.ts
|
|
27110
27935
|
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
27936
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
27112
|
-
import
|
|
27937
|
+
import path24 from "node:path";
|
|
27113
27938
|
|
|
27114
27939
|
// packages/workit-core/src/core/live-session.ts
|
|
27115
27940
|
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
@@ -27150,7 +27975,7 @@ var MUTATING_WORKIT_GIT = new Set(["commit", "branch"]);
|
|
|
27150
27975
|
var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
|
|
27151
27976
|
var PUSHD2 = new Set(["pushd", "push-location"]);
|
|
27152
27977
|
var POPD2 = new Set(["popd", "pop-location"]);
|
|
27153
|
-
var UNKNOWN_DIR =
|
|
27978
|
+
var UNKNOWN_DIR = path24.resolve(path24.parse(process.cwd()).root, ".workit-unknown-dir");
|
|
27154
27979
|
// packages/workit-core/src/core/skill-manifests.ts
|
|
27155
27980
|
if (false) {}
|
|
27156
27981
|
|
|
@@ -27363,24 +28188,24 @@ if (false)
|
|
|
27363
28188
|
|
|
27364
28189
|
// packages/workit-codex/scripts/agents.ts
|
|
27365
28190
|
import {
|
|
27366
|
-
existsSync as
|
|
28191
|
+
existsSync as existsSync10,
|
|
27367
28192
|
lstatSync as lstatSync3,
|
|
27368
28193
|
mkdirSync as mkdirSync3,
|
|
27369
28194
|
readdirSync as readdirSync5,
|
|
27370
|
-
readFileSync as
|
|
28195
|
+
readFileSync as readFileSync8,
|
|
27371
28196
|
renameSync as renameSync2,
|
|
27372
28197
|
rmSync as rmSync2,
|
|
27373
28198
|
writeFileSync as writeFileSync3
|
|
27374
28199
|
} from "node:fs";
|
|
27375
28200
|
import os5 from "node:os";
|
|
27376
|
-
import
|
|
28201
|
+
import path25 from "node:path";
|
|
27377
28202
|
var CODEX_AGENT_MARKER = "# Generated by Workit";
|
|
27378
28203
|
var codexHomeOfInstall = (pluginRoot) => {
|
|
27379
|
-
const parts =
|
|
28204
|
+
const parts = path25.resolve(pluginRoot).split(path25.sep);
|
|
27380
28205
|
const cache = parts.length - 4;
|
|
27381
|
-
return cache >= 2 && parts[cache] === "cache" && parts[cache - 1] === "plugins" ? parts.slice(0, cache - 1).join(
|
|
28206
|
+
return cache >= 2 && parts[cache] === "cache" && parts[cache - 1] === "plugins" ? parts.slice(0, cache - 1).join(path25.sep) || path25.sep : null;
|
|
27382
28207
|
};
|
|
27383
|
-
var codexHomeFor = (pluginRoot, env) => codexHomeOfInstall(pluginRoot) ?? (env.CODEX_HOME ||
|
|
28208
|
+
var codexHomeFor = (pluginRoot, env) => codexHomeOfInstall(pluginRoot) ?? (env.CODEX_HOME || path25.join(env.HOME || os5.homedir(), ".codex"));
|
|
27384
28209
|
var MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
|
|
27385
28210
|
var agentMarkerVersion = (text) => MARKER_VERSION.exec(text)?.[1] ?? null;
|
|
27386
28211
|
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 +28219,7 @@ var versionAtLeast = (version, min) => {
|
|
|
27394
28219
|
};
|
|
27395
28220
|
var pluginVersion = (pluginRoot) => {
|
|
27396
28221
|
try {
|
|
27397
|
-
const version = JSON.parse(
|
|
28222
|
+
const version = JSON.parse(readFileSync8(path25.join(pluginRoot, "package.json"), "utf8")).version;
|
|
27398
28223
|
return typeof version === "string" && /^\d+\.\d+\.\d+/.test(version) ? version.match(/^\d+\.\d+\.\d+/)[0] : null;
|
|
27399
28224
|
} catch {
|
|
27400
28225
|
return null;
|
|
@@ -27408,15 +28233,15 @@ var lstatOrNull = (file) => {
|
|
|
27408
28233
|
}
|
|
27409
28234
|
};
|
|
27410
28235
|
var installCodexAgents = (pluginRoot, codexHome) => {
|
|
27411
|
-
const source =
|
|
27412
|
-
if (!
|
|
28236
|
+
const source = path25.join(pluginRoot, "agents");
|
|
28237
|
+
if (!existsSync10(source))
|
|
27413
28238
|
return [];
|
|
27414
28239
|
const version = pluginVersion(pluginRoot);
|
|
27415
|
-
const target =
|
|
28240
|
+
const target = path25.join(codexHome, "agents");
|
|
27416
28241
|
const results = [];
|
|
27417
28242
|
for (const file of readdirSync5(source).filter((name) => name.endsWith(".toml")).toSorted()) {
|
|
27418
|
-
const content = stampCodexAgent(
|
|
27419
|
-
const dest =
|
|
28243
|
+
const content = stampCodexAgent(readFileSync8(path25.join(source, file), "utf8"), version);
|
|
28244
|
+
const dest = path25.join(target, file);
|
|
27420
28245
|
const stat = lstatOrNull(dest);
|
|
27421
28246
|
if (stat?.isSymbolicLink()) {
|
|
27422
28247
|
results.push({ file: dest, action: "skipped-symlink" });
|
|
@@ -27438,7 +28263,7 @@ var installCodexAgents = (pluginRoot, codexHome) => {
|
|
|
27438
28263
|
results.push({ file: dest, action: "kept-user-file" });
|
|
27439
28264
|
continue;
|
|
27440
28265
|
}
|
|
27441
|
-
const current =
|
|
28266
|
+
const current = readFileSync8(dest, "utf8");
|
|
27442
28267
|
if (current === content) {
|
|
27443
28268
|
results.push({ file: dest, action: "current" });
|
|
27444
28269
|
continue;
|
|
@@ -27452,7 +28277,7 @@ var installCodexAgents = (pluginRoot, codexHome) => {
|
|
|
27452
28277
|
results.push({ file: dest, action: "kept-newer-version" });
|
|
27453
28278
|
continue;
|
|
27454
28279
|
}
|
|
27455
|
-
const temp =
|
|
28280
|
+
const temp = path25.join(target, `.${file}.${process.pid}.${Date.now()}.tmp`);
|
|
27456
28281
|
writeFileSync3(temp, content, { flag: "wx" });
|
|
27457
28282
|
try {
|
|
27458
28283
|
renameSync2(temp, dest);
|
|
@@ -27474,8 +28299,8 @@ var codexQualification = (host) => host === "codex_cli" ? { surface: host, cli:
|
|
|
27474
28299
|
var resolveCodexWorkspaceRoot = (pluginRoot, env) => {
|
|
27475
28300
|
const explicit = env.WORKFLOW_WORKSPACE_ROOT;
|
|
27476
28301
|
const inherited = env.PWD;
|
|
27477
|
-
const candidate = explicit ?? (inherited &&
|
|
27478
|
-
if (!candidate || !
|
|
28302
|
+
const candidate = explicit ?? (inherited && path26.resolve(inherited) !== path26.resolve(pluginRoot) ? inherited : undefined);
|
|
28303
|
+
if (!candidate || !path26.isAbsolute(candidate) || !existsSync11(candidate))
|
|
27479
28304
|
return null;
|
|
27480
28305
|
try {
|
|
27481
28306
|
if (!statSync3(candidate).isDirectory())
|
|
@@ -27514,7 +28339,7 @@ var codexContextProvider = (host = detectCodexSurface(process.env), root) => ({
|
|
|
27514
28339
|
};
|
|
27515
28340
|
}
|
|
27516
28341
|
});
|
|
27517
|
-
var pluginRoot = () =>
|
|
28342
|
+
var pluginRoot = () => path26.resolve(path26.dirname(fileURLToPath3(import.meta.url)), "..");
|
|
27518
28343
|
var syncCodexAgents = (root) => {
|
|
27519
28344
|
const codexHome = codexHomeOfInstall(root);
|
|
27520
28345
|
if (!codexHome)
|