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