@brainervirus/workit-opencode 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/plugin.js
CHANGED
|
@@ -4,9 +4,9 @@ function define(plugin) {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
// packages/workit-core/src/core.ts
|
|
7
|
-
import { spawnSync as
|
|
8
|
-
import { existsSync as
|
|
9
|
-
import
|
|
7
|
+
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
8
|
+
import { existsSync as existsSync10, realpathSync as realpathSync5 } from "node:fs";
|
|
9
|
+
import path27 from "node:path";
|
|
10
10
|
|
|
11
11
|
// packages/workit-core/src/core/task-contract.ts
|
|
12
12
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -8430,7 +8430,7 @@ var workspaceConfigSchema = object({
|
|
|
8430
8430
|
}).passthrough().optional(),
|
|
8431
8431
|
autoApprove: union([boolean2(), array(nonBlank)]).optional(),
|
|
8432
8432
|
defaultEndpoint: unknown().optional(),
|
|
8433
|
-
verification: _enum(["self", "independent"]).optional(),
|
|
8433
|
+
verification: _enum(["proportional", "self", "independent"]).optional(),
|
|
8434
8434
|
delegation: unknown().optional(),
|
|
8435
8435
|
trailers: boolean2().optional(),
|
|
8436
8436
|
liveSessionGuard: boolean2().optional(),
|
|
@@ -9015,6 +9015,124 @@ function resolveRef(cwd, ref) {
|
|
|
9015
9015
|
return null;
|
|
9016
9016
|
return line(git(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]));
|
|
9017
9017
|
}
|
|
9018
|
+
var LANE_DIFF = [
|
|
9019
|
+
"-c",
|
|
9020
|
+
"core.quotePath=false",
|
|
9021
|
+
"diff",
|
|
9022
|
+
"--no-color",
|
|
9023
|
+
"--no-ext-diff",
|
|
9024
|
+
"--no-textconv",
|
|
9025
|
+
"--no-renames"
|
|
9026
|
+
];
|
|
9027
|
+
var laneRange = (fork, head) => {
|
|
9028
|
+
if (!safeArg(fork) || head !== null && !safeArg(head))
|
|
9029
|
+
return null;
|
|
9030
|
+
return head === null ? [fork] : [fork, head];
|
|
9031
|
+
};
|
|
9032
|
+
function diffNumstat(cwd, fork, head) {
|
|
9033
|
+
const range = laneRange(fork, head);
|
|
9034
|
+
if (!range)
|
|
9035
|
+
return null;
|
|
9036
|
+
const run = git(cwd, [...LANE_DIFF, "--numstat", "-z", ...range, "--"]);
|
|
9037
|
+
if (!run.ok)
|
|
9038
|
+
return null;
|
|
9039
|
+
const out = [];
|
|
9040
|
+
for (const record of run.stdout.split("\x00")) {
|
|
9041
|
+
const match = /^(-|\d+)\t(-|\d+)\t(.+)$/su.exec(record.replace(/^\n/u, ""));
|
|
9042
|
+
if (!match)
|
|
9043
|
+
continue;
|
|
9044
|
+
const binary = match[1] === "-";
|
|
9045
|
+
out.push({
|
|
9046
|
+
path: match[3],
|
|
9047
|
+
added: binary ? 0 : Number(match[1]),
|
|
9048
|
+
deleted: binary ? 0 : Number(match[2]),
|
|
9049
|
+
binary
|
|
9050
|
+
});
|
|
9051
|
+
}
|
|
9052
|
+
return out;
|
|
9053
|
+
}
|
|
9054
|
+
function diffRaw(cwd, fork, head) {
|
|
9055
|
+
const range = laneRange(fork, head);
|
|
9056
|
+
if (!range)
|
|
9057
|
+
return null;
|
|
9058
|
+
const run = git(cwd, [...LANE_DIFF, "--raw", "-z", "--no-abbrev", ...range, "--"]);
|
|
9059
|
+
if (!run.ok)
|
|
9060
|
+
return null;
|
|
9061
|
+
const fields = run.stdout.split("\x00");
|
|
9062
|
+
const out = [];
|
|
9063
|
+
for (let index = 0;index + 1 < fields.length; index += 2) {
|
|
9064
|
+
const meta = /^:(\d{6}) (\d{6}) ([0-9a-f]+) ([0-9a-f]+) [A-Z]\d*$/u.exec(fields[index].replace(/^\n/u, ""));
|
|
9065
|
+
if (!meta)
|
|
9066
|
+
return null;
|
|
9067
|
+
out.push({
|
|
9068
|
+
path: fields[index + 1],
|
|
9069
|
+
oldMode: meta[1],
|
|
9070
|
+
newMode: meta[2],
|
|
9071
|
+
oldBlob: meta[3],
|
|
9072
|
+
newBlob: meta[4]
|
|
9073
|
+
});
|
|
9074
|
+
}
|
|
9075
|
+
return out;
|
|
9076
|
+
}
|
|
9077
|
+
function readBlobs(cwd, ids) {
|
|
9078
|
+
const out = new Map;
|
|
9079
|
+
const wanted = [...new Set(ids)].filter((id) => /^[0-9a-f]{40,64}$/u.test(id));
|
|
9080
|
+
if (!wanted.length)
|
|
9081
|
+
return out;
|
|
9082
|
+
const run = spawnSync3("git", ["cat-file", "--batch"], {
|
|
9083
|
+
cwd,
|
|
9084
|
+
input: `${wanted.join(`
|
|
9085
|
+
`)}
|
|
9086
|
+
`,
|
|
9087
|
+
maxBuffer: MAX_BUFFER,
|
|
9088
|
+
timeout: GIT_TIMEOUTS.local,
|
|
9089
|
+
killSignal: "SIGKILL",
|
|
9090
|
+
windowsHide: true
|
|
9091
|
+
});
|
|
9092
|
+
if (run.status !== 0 || !run.stdout)
|
|
9093
|
+
return null;
|
|
9094
|
+
const bytes = run.stdout;
|
|
9095
|
+
let at = 0;
|
|
9096
|
+
for (const id of wanted) {
|
|
9097
|
+
const end = bytes.indexOf(10, at);
|
|
9098
|
+
if (end < 0)
|
|
9099
|
+
return null;
|
|
9100
|
+
const header = bytes.subarray(at, end).toString("utf8").split(" ");
|
|
9101
|
+
at = end + 1;
|
|
9102
|
+
if (header[1] === "missing")
|
|
9103
|
+
continue;
|
|
9104
|
+
const size = Number(header[2]);
|
|
9105
|
+
if (header[0] !== id || !Number.isSafeInteger(size))
|
|
9106
|
+
return null;
|
|
9107
|
+
out.set(id, bytes.subarray(at, at + size));
|
|
9108
|
+
at += size + 1;
|
|
9109
|
+
}
|
|
9110
|
+
return out;
|
|
9111
|
+
}
|
|
9112
|
+
function treeFilesNamed(cwd, rev, name) {
|
|
9113
|
+
if (!safeArg(rev))
|
|
9114
|
+
return null;
|
|
9115
|
+
const run = git(cwd, ["ls-tree", "-r", "-z", "--full-tree", rev]);
|
|
9116
|
+
if (!run.ok)
|
|
9117
|
+
return null;
|
|
9118
|
+
const out = new Map;
|
|
9119
|
+
for (const record of run.stdout.split("\x00")) {
|
|
9120
|
+
const match = /^\d{6} blob ([0-9a-f]+)\t(.+)$/su.exec(record);
|
|
9121
|
+
if (match && (match[2] === name || match[2].endsWith(`/${name}`)))
|
|
9122
|
+
out.set(match[2], match[1]);
|
|
9123
|
+
}
|
|
9124
|
+
return out;
|
|
9125
|
+
}
|
|
9126
|
+
function fileAt(cwd, rev, file) {
|
|
9127
|
+
if (!safeArg(rev))
|
|
9128
|
+
return null;
|
|
9129
|
+
const run = git(cwd, ["cat-file", "blob", `${rev}:${file}`]);
|
|
9130
|
+
return run.ok ? run.stdout : null;
|
|
9131
|
+
}
|
|
9132
|
+
function untrackedFiles(cwd) {
|
|
9133
|
+
const run = git(cwd, ["ls-files", "-z", "--others", "--exclude-standard"]);
|
|
9134
|
+
return run.ok ? run.stdout.split("\x00").filter(Boolean) : [];
|
|
9135
|
+
}
|
|
9018
9136
|
var config2 = (cwd, key) => line(git(cwd, ["config", "--get", key]));
|
|
9019
9137
|
function currentBranch(cwd) {
|
|
9020
9138
|
return line(git(cwd, ["symbolic-ref", "--short", "-q", "HEAD"]));
|
|
@@ -12775,9 +12893,9 @@ var holdsLiveState = (state, dirty) => state === "running" || dirty === true;
|
|
|
12775
12893
|
|
|
12776
12894
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
12777
12895
|
import { createHash as createHash12 } from "node:crypto";
|
|
12778
|
-
import * as
|
|
12779
|
-
import { spawnSync as
|
|
12780
|
-
import
|
|
12896
|
+
import * as fs15 from "node:fs";
|
|
12897
|
+
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
12898
|
+
import path20 from "node:path";
|
|
12781
12899
|
|
|
12782
12900
|
// packages/workit-core/src/check-config.ts
|
|
12783
12901
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
@@ -13007,8 +13125,8 @@ function checkCommand(args, version, onPath = workitAvailable()) {
|
|
|
13007
13125
|
}
|
|
13008
13126
|
|
|
13009
13127
|
// packages/workit-core/src/core/policy/derive.ts
|
|
13010
|
-
import { existsSync as
|
|
13011
|
-
import
|
|
13128
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
13129
|
+
import path19 from "node:path";
|
|
13012
13130
|
|
|
13013
13131
|
// packages/workit-core/src/ledger.ts
|
|
13014
13132
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
@@ -13912,7 +14030,8 @@ function checkVerdicts(cwd, branch, ledgerRows) {
|
|
|
13912
14030
|
verdict: failing?.verdict ?? null,
|
|
13913
14031
|
reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
|
|
13914
14032
|
};
|
|
13915
|
-
const
|
|
14033
|
+
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))));
|
|
14034
|
+
const selfEntry = latestSelf && STRONG_RESULTS.has(String(latestSelf.verdict.result)) ? latestSelf : undefined;
|
|
13916
14035
|
return {
|
|
13917
14036
|
branch,
|
|
13918
14037
|
head,
|
|
@@ -13956,151 +14075,1001 @@ var OBSERVED_ONLY = new Set([
|
|
|
13956
14075
|
...PR_ROW_TYPES
|
|
13957
14076
|
]);
|
|
13958
14077
|
|
|
13959
|
-
// packages/workit-core/src/core/policy/
|
|
13960
|
-
|
|
13961
|
-
|
|
13962
|
-
|
|
13963
|
-
|
|
13964
|
-
|
|
13965
|
-
|
|
13966
|
-
|
|
13967
|
-
|
|
13968
|
-
|
|
13969
|
-
|
|
13970
|
-
|
|
13971
|
-
|
|
13972
|
-
|
|
13973
|
-
|
|
13974
|
-
|
|
13975
|
-
|
|
13976
|
-
|
|
13977
|
-
});
|
|
13978
|
-
var sorted = (values) => [...new Set(values)].toSorted();
|
|
13979
|
-
var normalizedScope = (scope) => ({
|
|
13980
|
-
description: scope.description,
|
|
13981
|
-
paths: sorted(scope.paths),
|
|
13982
|
-
exclusions: sorted(scope.exclusions)
|
|
13983
|
-
});
|
|
13984
|
-
function deriveRequirements(judgment, scope, constraints, verification = "self") {
|
|
13985
|
-
const out = [];
|
|
13986
|
-
const base = { scope, dependentAction: null };
|
|
13987
|
-
if (judgment.behaviorChange)
|
|
13988
|
-
out.push(derived2({
|
|
13989
|
-
...base,
|
|
13990
|
-
ruleId: RULES.test,
|
|
13991
|
-
dimension: "testing",
|
|
13992
|
-
reason: "Behavior changes: the configured test check must pass on the final tree.",
|
|
13993
|
-
satisfaction: "Run `workit check test` on the final tree.",
|
|
13994
|
-
before: "close",
|
|
13995
|
-
acceptanceAllowed: false
|
|
13996
|
-
}));
|
|
13997
|
-
if (judgment.behaviorChange && judgment.riskTier === "normal")
|
|
13998
|
-
out.push(verification === "independent" ? derived2({
|
|
13999
|
-
...base,
|
|
14000
|
-
ruleId: RULES.nonAuthor,
|
|
14001
|
-
dimension: "review",
|
|
14002
|
-
reason: "This workspace requires independent verification: a session that did not author the change records the verdict.",
|
|
14003
|
-
satisfaction: "An independent session records a passing verdict: `workit ledger verdict verified --how <what it exercised>`.",
|
|
14004
|
-
before: "close",
|
|
14005
|
-
acceptanceAllowed: false
|
|
14006
|
-
}) : derived2({
|
|
14007
|
-
...base,
|
|
14008
|
-
ruleId: RULES.self,
|
|
14009
|
-
dimension: "review",
|
|
14010
|
-
reason: "A behavior change needs a recorded verdict; the author's own is allowed and is shown as self-reviewed, never verified.",
|
|
14011
|
-
satisfaction: "After an observed passing `workit check test`, record `workit ledger verdict tests-verified --self --how <what you ran>` (or have a verifier record one).",
|
|
14012
|
-
before: "close",
|
|
14013
|
-
acceptanceAllowed: false
|
|
14014
|
-
}));
|
|
14015
|
-
if (judgment.riskTier === "high")
|
|
14016
|
-
out.push(derived2({
|
|
14017
|
-
...base,
|
|
14018
|
-
ruleId: RULES.verified,
|
|
14019
|
-
dimension: "review",
|
|
14020
|
-
reason: "High risk: an independent verifier must exercise the live surface.",
|
|
14021
|
-
satisfaction: "An independent verifier runs the real surface and records `workit ledger verdict verified --kind live --how <what it exercised>`.",
|
|
14022
|
-
before: "close",
|
|
14023
|
-
acceptanceAllowed: false
|
|
14024
|
-
}));
|
|
14025
|
-
if (judgment.productChoiceOpen)
|
|
14026
|
-
out.push(derived2({
|
|
14027
|
-
...base,
|
|
14028
|
-
ruleId: RULES.product,
|
|
14029
|
-
dimension: "decisions",
|
|
14030
|
-
reason: "A product or preference choice is open; the user decides it before code is written.",
|
|
14031
|
-
satisfaction: 'Ask the user (with your recommendation), then record the answer: `workit ledger decision "<choice>" --why "<reason>"`.',
|
|
14032
|
-
before: "write",
|
|
14033
|
-
acceptanceAllowed: false
|
|
14034
|
-
}));
|
|
14035
|
-
if (judgment.needsPlan || judgment.riskTier === "high")
|
|
14036
|
-
out.push(derived2({
|
|
14037
|
-
...base,
|
|
14038
|
-
ruleId: RULES.plan,
|
|
14039
|
-
dimension: "artifacts",
|
|
14040
|
-
reason: judgment.needsPlan ? "The work needs a written plan or spec before implementation." : "High-risk work needs a written plan before implementation.",
|
|
14041
|
-
satisfaction: "Write the plan or spec (e.g. docs/plans/<slug>.md; docs and Markdown writes stay allowed), then record it: `workit policy assess --ref <path>`.",
|
|
14042
|
-
before: "write",
|
|
14043
|
-
acceptanceAllowed: true
|
|
14044
|
-
}));
|
|
14045
|
-
for (const constraint of constraints)
|
|
14046
|
-
for (const obligation of constraint.requires)
|
|
14047
|
-
out.push(derived2({
|
|
14048
|
-
ruleId: `project-constraint:${constraint.id}:${obligation.kind}:${sha256({
|
|
14049
|
-
kind: obligation.kind,
|
|
14050
|
-
scope: normalizedScope(obligation.scope),
|
|
14051
|
-
refs: obligation.refs.map((ref) => JSON.stringify(ref)).toSorted(),
|
|
14052
|
-
method: obligation.method,
|
|
14053
|
-
before: obligation.before,
|
|
14054
|
-
dependentAction: obligation.dependentAction
|
|
14055
|
-
})}`,
|
|
14056
|
-
dimension: obligation.method ?? (obligation.kind === "check" ? "verification" : obligation.kind === "decision" ? "decisions" : "challenge"),
|
|
14057
|
-
scope: obligation.scope,
|
|
14058
|
-
reason: `${constraint.kind} constraint requires ${obligation.kind}: ${constraint.statement}`,
|
|
14059
|
-
satisfaction: `Satisfy the constraint obligation using its referenced ${obligation.kind}.`,
|
|
14060
|
-
before: obligation.before,
|
|
14061
|
-
dependentAction: obligation.dependentAction,
|
|
14062
|
-
acceptanceAllowed: constraint.acceptanceAllowed && obligation.kind !== "decision"
|
|
14063
|
-
}));
|
|
14064
|
-
const seen = new Set;
|
|
14065
|
-
return out.filter((item) => seen.has(item.id) ? false : (seen.add(item.id), true));
|
|
14078
|
+
// packages/workit-core/src/core/policy/lane.ts
|
|
14079
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
|
|
14080
|
+
import path18 from "node:path";
|
|
14081
|
+
|
|
14082
|
+
// packages/workit-core/src/git/ops.ts
|
|
14083
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
14084
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
14085
|
+
import path17 from "node:path";
|
|
14086
|
+
|
|
14087
|
+
// packages/workit-core/src/core/pr-create.ts
|
|
14088
|
+
import fs14 from "node:fs";
|
|
14089
|
+
import path16 from "node:path";
|
|
14090
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
14091
|
+
import { pathToFileURL } from "node:url";
|
|
14092
|
+
// packages/workit-core/src/forge/pr-body.ts
|
|
14093
|
+
function parseGhIssue(value) {
|
|
14094
|
+
const m = /issues\/(\d+)/.exec(value);
|
|
14095
|
+
return m ? m[1] : String(value).trim().replace(/^#/, "");
|
|
14066
14096
|
}
|
|
14067
|
-
|
|
14068
|
-
|
|
14069
|
-
|
|
14070
|
-
|
|
14071
|
-
|
|
14072
|
-
|
|
14073
|
-
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
|
|
14078
|
-
|
|
14097
|
+
|
|
14098
|
+
// packages/workit-core/src/core/pr-create.ts
|
|
14099
|
+
function whichOnPath(tool) {
|
|
14100
|
+
const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
|
|
14101
|
+
for (const dir of (process.env.PATH ?? "").split(path16.delimiter)) {
|
|
14102
|
+
if (!dir)
|
|
14103
|
+
continue;
|
|
14104
|
+
for (const name of names) {
|
|
14105
|
+
const candidate = path16.join(dir, name);
|
|
14106
|
+
try {
|
|
14107
|
+
fs14.accessSync(candidate, fs14.constants.X_OK);
|
|
14108
|
+
return candidate;
|
|
14109
|
+
} catch {}
|
|
14079
14110
|
}
|
|
14080
|
-
}
|
|
14111
|
+
}
|
|
14112
|
+
return null;
|
|
14113
|
+
}
|
|
14114
|
+
var hostingCliAvailable = (provider) => whichOnPath(provider === "gitlab" ? "glab" : "gh") !== null;
|
|
14115
|
+
var pushRemote = (cwd) => {
|
|
14116
|
+
const result = spawnSync10("git", ["remote", "get-url", "--push", "--all", "origin"], {
|
|
14117
|
+
cwd,
|
|
14118
|
+
encoding: "utf8"
|
|
14119
|
+
});
|
|
14120
|
+
if (result.status !== 0)
|
|
14121
|
+
return null;
|
|
14122
|
+
const urls = (result.stdout ?? "").split(/\r?\n/u).map((url) => url.trim()).filter(Boolean);
|
|
14123
|
+
return urls.length === 1 ? urls[0] : null;
|
|
14081
14124
|
};
|
|
14082
|
-
var
|
|
14083
|
-
const
|
|
14084
|
-
if (
|
|
14085
|
-
return
|
|
14086
|
-
|
|
14087
|
-
|
|
14088
|
-
|
|
14089
|
-
|
|
14090
|
-
|
|
14091
|
-
|
|
14092
|
-
|
|
14093
|
-
|
|
14094
|
-
|
|
14095
|
-
|
|
14096
|
-
|
|
14097
|
-
|
|
14125
|
+
var safePushUrl = (remote) => {
|
|
14126
|
+
const raw = remote.trim();
|
|
14127
|
+
if (path16.isAbsolute(raw))
|
|
14128
|
+
return pathToFileURL(raw).href;
|
|
14129
|
+
if (!raw.includes("://")) {
|
|
14130
|
+
const scp = /^(?:([^@\s]+)@)?([^:]+):(.+)$/u.exec(raw);
|
|
14131
|
+
if (scp)
|
|
14132
|
+
return `${scp[1] || "git"}@${scp[2]}:${scp[3]}`;
|
|
14133
|
+
}
|
|
14134
|
+
try {
|
|
14135
|
+
const url = new URL(raw);
|
|
14136
|
+
if (!["file:", "git:", "http:", "https:", "ssh:"].includes(url.protocol))
|
|
14137
|
+
return null;
|
|
14138
|
+
url.password = "";
|
|
14139
|
+
if (url.protocol !== "ssh:")
|
|
14140
|
+
url.username = "";
|
|
14141
|
+
url.search = "";
|
|
14142
|
+
url.hash = "";
|
|
14143
|
+
return url.toString();
|
|
14144
|
+
} catch {
|
|
14145
|
+
return null;
|
|
14146
|
+
}
|
|
14098
14147
|
};
|
|
14099
|
-
var
|
|
14100
|
-
const
|
|
14101
|
-
if (
|
|
14102
|
-
return
|
|
14103
|
-
|
|
14148
|
+
var pushTargetIsStable = (cwd, remote) => {
|
|
14149
|
+
const target = safePushUrl(remote);
|
|
14150
|
+
if (!target)
|
|
14151
|
+
return false;
|
|
14152
|
+
const result = spawnSync10("git", ["config", "--get-regexp", "^url\\..*\\.(insteadof|pushinsteadof)$"], { cwd, encoding: "utf8" });
|
|
14153
|
+
if (result.status !== 0 && result.status !== 1)
|
|
14154
|
+
return false;
|
|
14155
|
+
const prefixes = (result.stdout ?? "").split(/\r?\n/u).map((line) => line.trim().slice(line.trim().indexOf(" ") + 1)).filter(Boolean);
|
|
14156
|
+
return !prefixes.some((prefix) => target.startsWith(prefix));
|
|
14157
|
+
};
|
|
14158
|
+
|
|
14159
|
+
// packages/workit-core/src/forge/redact.ts
|
|
14160
|
+
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_.-]*`;
|
|
14161
|
+
var ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*["']?)((?:bearer|basic|token|digest)\s+)?([^\s"',;&]+)`, "giu");
|
|
14162
|
+
var QUOTED_ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*)(["'])([^"'\n]*[^\s"'][^"'\n]*)\2`, "giu");
|
|
14163
|
+
var ANSI = new RegExp(String.raw`\u001b\[[0-9;?]*[ -/]*[@-~]|\u001b\][^\u0007]*\u0007`, "gu");
|
|
14164
|
+
|
|
14165
|
+
// packages/workit-core/src/forge/types.ts
|
|
14166
|
+
var success2 = (data) => ({ ok: true, data });
|
|
14167
|
+
var failure3 = (code, error, unblock) => ({ ok: false, code, error, ...unblock ? { unblock } : {} });
|
|
14168
|
+
|
|
14169
|
+
// packages/workit-core/src/git/ops.ts
|
|
14170
|
+
var COMMIT_TIMEOUT_MS = 10 * 60000;
|
|
14171
|
+
var git5 = (cwd, args, options = {}) => {
|
|
14172
|
+
const result = spawnSync11("git", args, {
|
|
14173
|
+
cwd,
|
|
14174
|
+
encoding: "utf8",
|
|
14175
|
+
env: { ...options.env ?? process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
14176
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
14177
|
+
timeout: options.timeoutMs ?? GIT_TIMEOUTS.local,
|
|
14178
|
+
killSignal: "SIGKILL",
|
|
14179
|
+
windowsHide: true,
|
|
14180
|
+
...options.input === undefined ? { stdio: ["ignore", "pipe", "pipe"] } : { input: options.input, stdio: ["pipe", "pipe", "pipe"] }
|
|
14181
|
+
});
|
|
14182
|
+
return {
|
|
14183
|
+
ok: result.status === 0,
|
|
14184
|
+
status: result.status,
|
|
14185
|
+
stdout: result.stdout ?? "",
|
|
14186
|
+
stderr: result.stderr ?? ""
|
|
14187
|
+
};
|
|
14188
|
+
};
|
|
14189
|
+
function operationInProgress(cwd) {
|
|
14190
|
+
const markers = [
|
|
14191
|
+
["rebase-merge", "rebase"],
|
|
14192
|
+
["rebase-apply", "rebase"],
|
|
14193
|
+
["MERGE_HEAD", "merge"],
|
|
14194
|
+
["CHERRY_PICK_HEAD", "cherry-pick"],
|
|
14195
|
+
["REVERT_HEAD", "revert"]
|
|
14196
|
+
];
|
|
14197
|
+
const run = git5(cwd, ["rev-parse", ...markers.flatMap(([name]) => ["--git-path", name])]);
|
|
14198
|
+
if (!run.ok)
|
|
14199
|
+
return null;
|
|
14200
|
+
const found = run.stdout.split(`
|
|
14201
|
+
`).map((line) => path17.resolve(cwd, line.trim()));
|
|
14202
|
+
const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
|
|
14203
|
+
for (const [index, [, operation]] of markers.entries()) {
|
|
14204
|
+
const marker = found[index];
|
|
14205
|
+
if (!marker || !existsSync4(marker))
|
|
14206
|
+
continue;
|
|
14207
|
+
if (index === 1 && existsSync4(path17.join(marker, "applying")))
|
|
14208
|
+
return { operation: "am", commitAllowed: false, branch: null };
|
|
14209
|
+
if (index === 0 && existsSync4(path17.join(marker, "amend")) && !conflicted()) {
|
|
14210
|
+
let headName = "";
|
|
14211
|
+
try {
|
|
14212
|
+
headName = readFileSync4(path17.join(marker, "head-name"), "utf8").trim();
|
|
14213
|
+
} catch {}
|
|
14214
|
+
const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
|
|
14215
|
+
return { operation, commitAllowed: branch !== null, branch };
|
|
14216
|
+
}
|
|
14217
|
+
if ((operation === "revert" || operation === "merge") && !conflicted())
|
|
14218
|
+
return { operation, commitAllowed: true, branch: null };
|
|
14219
|
+
return { operation, commitAllowed: false, branch: null };
|
|
14220
|
+
}
|
|
14221
|
+
return null;
|
|
14222
|
+
}
|
|
14223
|
+
function inProgressFailure(operation, verb) {
|
|
14224
|
+
const command = operation === "am" ? "git am" : `git ${operation}`;
|
|
14225
|
+
return failure3("blocked", `${operation.replace("-", "_")}_in_progress: a ${operation === "am" ? "git am" : operation} is in progress; finish or abort it before workit can ${verb}`, `resolve the conflicts, git add <files>, then ${command} --continue # or ${command} --abort to return to where you started`);
|
|
14226
|
+
}
|
|
14227
|
+
function pushPreflight(cwd, options = {}) {
|
|
14228
|
+
const progress = operationInProgress(cwd);
|
|
14229
|
+
if (progress)
|
|
14230
|
+
return inProgressFailure(progress.operation, "push");
|
|
14231
|
+
const branch = options.branch ?? currentBranch(cwd);
|
|
14232
|
+
if (!branch)
|
|
14233
|
+
return failure3("invalid_input", "HEAD is detached; push a branch");
|
|
14234
|
+
if (isProtectedTarget(cwd, branch))
|
|
14235
|
+
return failure3("blocked", `protected_branch: ${branch} is protected by the workspace branch policy; workit git push never pushes to it`, releaseBranch(cwd, branch) ? `workit git push --release ${branch} # finishing a release or hotfix; needs the release grant` : "workit git branch <feature/name> # push a feature branch and open a PR");
|
|
14236
|
+
const sha = resolveRef(cwd, `refs/heads/${branch}`);
|
|
14237
|
+
if (!sha)
|
|
14238
|
+
return failure3("not_found", `branch ${branch} has no commit to push`);
|
|
14239
|
+
const remote = pushRemoteName(cwd, branch);
|
|
14240
|
+
if (!remote)
|
|
14241
|
+
return failure3("not_found", "no push remote is configured for this branch", "git remote add origin <url>");
|
|
14242
|
+
const raw = pushUrl(cwd, remote);
|
|
14243
|
+
if (!raw)
|
|
14244
|
+
return failure3("blocked", `remote "${remote}" has no single push URL`, `git remote get-url --push --all ${remote} # keep exactly one push URL`);
|
|
14245
|
+
const parsed = parseRemoteUrl(raw);
|
|
14246
|
+
const local = parsed?.protocol === "file";
|
|
14247
|
+
if (!local && !pushTargetIsStable(cwd, raw))
|
|
14248
|
+
return failure3("blocked", `push_target_rewritten: the push URL of "${remote}" is rewritten by a url.*.insteadOf rule, so the destination is not the one checked`, "git config --get-regexp '^url\\.' # remove the rewrite for this remote");
|
|
14249
|
+
return success2({
|
|
14250
|
+
branch,
|
|
14251
|
+
sha,
|
|
14252
|
+
remote,
|
|
14253
|
+
url: redactRemote(raw),
|
|
14254
|
+
rawUrl: raw,
|
|
14255
|
+
local
|
|
14256
|
+
});
|
|
14257
|
+
}
|
|
14258
|
+
|
|
14259
|
+
// packages/workit-core/src/core/policy/attributes.ts
|
|
14260
|
+
function patternRegex(dir, pattern) {
|
|
14261
|
+
if (!pattern || pattern.endsWith("/") || pattern.startsWith('"') || pattern.startsWith("!"))
|
|
14262
|
+
return null;
|
|
14263
|
+
const anchored = pattern.includes("/");
|
|
14264
|
+
const body = pattern.replace(/^\//u, "");
|
|
14265
|
+
let source = "";
|
|
14266
|
+
for (let index = 0;index < body.length; index += 1) {
|
|
14267
|
+
const char = body[index];
|
|
14268
|
+
if (char === "*" && body[index + 1] === "*") {
|
|
14269
|
+
const slash = body[index + 2] === "/";
|
|
14270
|
+
source += slash ? "(?:.*/)?" : ".*";
|
|
14271
|
+
index += slash ? 2 : 1;
|
|
14272
|
+
} else if (char === "*")
|
|
14273
|
+
source += "[^/]*";
|
|
14274
|
+
else if (char === "?")
|
|
14275
|
+
source += "[^/]";
|
|
14276
|
+
else if (char === "[") {
|
|
14277
|
+
const end = body.indexOf("]", index + 2);
|
|
14278
|
+
if (end < 0)
|
|
14279
|
+
return null;
|
|
14280
|
+
const set = body.slice(index + 1, end).replace(/^!/u, "^").replace(/\\/gu, "\\\\");
|
|
14281
|
+
source += `[${set}]`;
|
|
14282
|
+
index = end;
|
|
14283
|
+
} else if (char === "\\" && index + 1 < body.length) {
|
|
14284
|
+
source += body[index + 1].replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
|
|
14285
|
+
index += 1;
|
|
14286
|
+
} else
|
|
14287
|
+
source += char.replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
|
|
14288
|
+
}
|
|
14289
|
+
const prefix = dir ? `${dir.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}/` : "";
|
|
14290
|
+
try {
|
|
14291
|
+
return new RegExp(anchored ? `^${prefix}${source}$` : `^${prefix}(?:.*/)?${source}$`, "u");
|
|
14292
|
+
} catch {
|
|
14293
|
+
return null;
|
|
14294
|
+
}
|
|
14295
|
+
}
|
|
14296
|
+
function rulesOf(dir, text) {
|
|
14297
|
+
const out = [];
|
|
14298
|
+
for (const raw of text.split(`
|
|
14299
|
+
`)) {
|
|
14300
|
+
const line = raw.trim();
|
|
14301
|
+
if (!line || line.startsWith("#") || line.startsWith("[attr]"))
|
|
14302
|
+
continue;
|
|
14303
|
+
const [pattern, ...attributes] = line.split(/\s+/u);
|
|
14304
|
+
let generated = null;
|
|
14305
|
+
for (const attribute of attributes) {
|
|
14306
|
+
if (attribute === "linguist-generated" || attribute === "linguist-generated=true")
|
|
14307
|
+
generated = true;
|
|
14308
|
+
else if (attribute === "-linguist-generated" || attribute === "!linguist-generated" || attribute.startsWith("linguist-generated="))
|
|
14309
|
+
generated = false;
|
|
14310
|
+
}
|
|
14311
|
+
if (generated === null)
|
|
14312
|
+
continue;
|
|
14313
|
+
const regex = patternRegex(dir, pattern);
|
|
14314
|
+
if (regex)
|
|
14315
|
+
out.push({ regex, generated });
|
|
14316
|
+
}
|
|
14317
|
+
return out;
|
|
14318
|
+
}
|
|
14319
|
+
function generatedByAttributes(files, paths) {
|
|
14320
|
+
const rules = [...files].map(([file, text]) => {
|
|
14321
|
+
const dir = file.includes("/") ? file.slice(0, file.lastIndexOf("/")) : "";
|
|
14322
|
+
return {
|
|
14323
|
+
depth: dir ? dir.split("/").length : 0,
|
|
14324
|
+
rules: rulesOf(dir, text)
|
|
14325
|
+
};
|
|
14326
|
+
}).toSorted((left, right) => left.depth - right.depth).flatMap((entry) => entry.rules);
|
|
14327
|
+
const out = new Set;
|
|
14328
|
+
for (const file of paths) {
|
|
14329
|
+
const last = rules.findLast((rule) => rule.regex.test(file));
|
|
14330
|
+
if (last?.generated)
|
|
14331
|
+
out.add(file);
|
|
14332
|
+
}
|
|
14333
|
+
return out;
|
|
14334
|
+
}
|
|
14335
|
+
|
|
14336
|
+
// packages/workit-core/src/core/policy/substance.ts
|
|
14337
|
+
var SLASH_BLOCK = [["/*", "*/"]];
|
|
14338
|
+
var C_LIKE = { line: ["//"], block: SLASH_BLOCK, quotes: `"'` };
|
|
14339
|
+
var SYNTAXES = Object.fromEntries([
|
|
14340
|
+
...["ts", "mts", "cts", "js", "mjs", "cjs"].map((ext) => [ext, { ...C_LIKE, js: true }]),
|
|
14341
|
+
...["java", "kt", "kts", "scala", "swift", "dart", "groovy"].map((ext) => [
|
|
14342
|
+
ext,
|
|
14343
|
+
{ ...C_LIKE, triple: true }
|
|
14344
|
+
]),
|
|
14345
|
+
["go", { ...C_LIKE, rawBacktick: true }],
|
|
14346
|
+
...["css", "scss", "less"].map((ext) => [
|
|
14347
|
+
ext,
|
|
14348
|
+
{ line: [], block: SLASH_BLOCK, quotes: `"'`, cssUrl: true }
|
|
14349
|
+
]),
|
|
14350
|
+
...["py", "pyi"].map((ext) => [
|
|
14351
|
+
ext,
|
|
14352
|
+
{ line: ["#"], block: [], quotes: `"'`, triple: true, indented: true, fstring: true }
|
|
14353
|
+
]),
|
|
14354
|
+
["toml", { line: ["#"], block: [], quotes: `"`, literal: "'", triple: true }],
|
|
14355
|
+
...["html", "htm", "xml", "svg", "xhtml"].map((ext) => [
|
|
14356
|
+
ext,
|
|
14357
|
+
{ line: [], block: [["<!--", "-->"]], quotes: "", indented: true }
|
|
14358
|
+
])
|
|
14359
|
+
]);
|
|
14360
|
+
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;
|
|
14361
|
+
var extensionOf = (file) => {
|
|
14362
|
+
const name = file.slice(file.lastIndexOf("/") + 1);
|
|
14363
|
+
const dot = name.lastIndexOf(".");
|
|
14364
|
+
return dot > 0 ? name.slice(dot + 1).toLowerCase() : "";
|
|
14365
|
+
};
|
|
14366
|
+
var CI_PATH = /^\.github\/|(?:^|\/)(?:\.gitlab-ci\.ya?ml|Jenkinsfile|azure-pipelines\.ya?ml|\.pre-commit-config\.ya?ml|\.circleci\/.*)$/u;
|
|
14367
|
+
var syntaxOf = (file) => CI_PATH.test(file) ? null : SYNTAXES[extensionOf(file)] ?? null;
|
|
14368
|
+
var SPACE = /[ \t\r\f\v]/u;
|
|
14369
|
+
var WORD = /[\w$]/u;
|
|
14370
|
+
var NO_SPACE_AFTER = "([{,;";
|
|
14371
|
+
var NO_SPACE_BEFORE = ")]},;";
|
|
14372
|
+
var REGEX_AFTER = "(,=:[!&|?{};+-*%<>~^";
|
|
14373
|
+
var REGEX_KEYWORDS = new Set([
|
|
14374
|
+
"return",
|
|
14375
|
+
"typeof",
|
|
14376
|
+
"instanceof",
|
|
14377
|
+
"case",
|
|
14378
|
+
"do",
|
|
14379
|
+
"else",
|
|
14380
|
+
"in",
|
|
14381
|
+
"of",
|
|
14382
|
+
"new",
|
|
14383
|
+
"delete",
|
|
14384
|
+
"void",
|
|
14385
|
+
"throw",
|
|
14386
|
+
"yield",
|
|
14387
|
+
"await"
|
|
14388
|
+
]);
|
|
14389
|
+
function substanceOf(file, text) {
|
|
14390
|
+
const syntax = syntaxOf(file);
|
|
14391
|
+
if (!syntax)
|
|
14392
|
+
return plainSubstance(text);
|
|
14393
|
+
const markup = syntax.block.some(([open]) => open === "<!--");
|
|
14394
|
+
if (markup && (/<(?:script|style)\b|<!\[CDATA\[|<\?/iu.test(text) || /[^>\s][ \t]*<!--/u.test(text)))
|
|
14395
|
+
return plainSubstance(text);
|
|
14396
|
+
return lex(syntax, text);
|
|
14397
|
+
}
|
|
14398
|
+
function plainSubstance(text) {
|
|
14399
|
+
return text.split(`
|
|
14400
|
+
`).map((line) => line.replace(/[ \t\r\f\v]+$/u, "")).filter(Boolean).join(`
|
|
14401
|
+
`);
|
|
14402
|
+
}
|
|
14403
|
+
function lex(syntax, text) {
|
|
14404
|
+
const collapse = !syntax.indented;
|
|
14405
|
+
let out = "";
|
|
14406
|
+
let lineStart = 0;
|
|
14407
|
+
let kept = 0;
|
|
14408
|
+
let pendingSpace = false;
|
|
14409
|
+
const frames = [{ kind: "code", braces: 0 }];
|
|
14410
|
+
let index = 0;
|
|
14411
|
+
if (text.startsWith("#!")) {
|
|
14412
|
+
const end = text.indexOf(`
|
|
14413
|
+
`);
|
|
14414
|
+
out = end < 0 ? text : text.slice(0, end);
|
|
14415
|
+
kept = out.length;
|
|
14416
|
+
index = end < 0 ? text.length : end;
|
|
14417
|
+
}
|
|
14418
|
+
const emitCode = (chunk) => {
|
|
14419
|
+
if (collapse && pendingSpace && out.length > lineStart) {
|
|
14420
|
+
const before = out[out.length - 1];
|
|
14421
|
+
if (!NO_SPACE_AFTER.includes(before) && !NO_SPACE_BEFORE.includes(chunk[0]))
|
|
14422
|
+
out += " ";
|
|
14423
|
+
}
|
|
14424
|
+
pendingSpace = false;
|
|
14425
|
+
out += chunk;
|
|
14426
|
+
};
|
|
14427
|
+
const emitVerbatim = (chunk) => {
|
|
14428
|
+
emitCode(chunk);
|
|
14429
|
+
kept = out.length;
|
|
14430
|
+
};
|
|
14431
|
+
const newline = () => {
|
|
14432
|
+
if (!collapse) {
|
|
14433
|
+
let end = out.length;
|
|
14434
|
+
while (end > Math.max(lineStart, kept) && SPACE.test(out[end - 1]))
|
|
14435
|
+
end -= 1;
|
|
14436
|
+
out = out.slice(0, end);
|
|
14437
|
+
}
|
|
14438
|
+
pendingSpace = false;
|
|
14439
|
+
if (out.length > lineStart) {
|
|
14440
|
+
out += `
|
|
14441
|
+
`;
|
|
14442
|
+
lineStart = out.length;
|
|
14443
|
+
}
|
|
14444
|
+
};
|
|
14445
|
+
const regexAllowed = () => {
|
|
14446
|
+
let end = out.length;
|
|
14447
|
+
while (end > 0 && /\s/u.test(out[end - 1]))
|
|
14448
|
+
end -= 1;
|
|
14449
|
+
if (end === 0 || REGEX_AFTER.includes(out[end - 1]))
|
|
14450
|
+
return true;
|
|
14451
|
+
let start = end;
|
|
14452
|
+
while (start > 0 && WORD.test(out[start - 1]))
|
|
14453
|
+
start -= 1;
|
|
14454
|
+
return REGEX_KEYWORDS.has(out.slice(start, end));
|
|
14455
|
+
};
|
|
14456
|
+
const scanString = (quote, escapes, multiline) => {
|
|
14457
|
+
const prefix = text.slice(Math.max(0, index - 2), index).match(/[a-z]*$/iu)?.[0] ?? "";
|
|
14458
|
+
const fstring = syntax.fstring === true && /f/iu.test(prefix);
|
|
14459
|
+
let end = index + quote.length;
|
|
14460
|
+
while (end < text.length) {
|
|
14461
|
+
const char = text[end];
|
|
14462
|
+
if (escapes && char === "\\") {
|
|
14463
|
+
end += 2;
|
|
14464
|
+
continue;
|
|
14465
|
+
}
|
|
14466
|
+
if (text.startsWith(quote, end)) {
|
|
14467
|
+
if (fstring && unbalanced(text.slice(index + quote.length, end)))
|
|
14468
|
+
return false;
|
|
14469
|
+
emitVerbatim(text.slice(index, end + quote.length));
|
|
14470
|
+
index = end + quote.length;
|
|
14471
|
+
return true;
|
|
14472
|
+
}
|
|
14473
|
+
if (char === `
|
|
14474
|
+
` && !multiline)
|
|
14475
|
+
return false;
|
|
14476
|
+
end += 1;
|
|
14477
|
+
}
|
|
14478
|
+
return false;
|
|
14479
|
+
};
|
|
14480
|
+
while (index < text.length) {
|
|
14481
|
+
const frame = frames[frames.length - 1];
|
|
14482
|
+
const char = text[index];
|
|
14483
|
+
if (frame.kind === "template") {
|
|
14484
|
+
if (char === "\\") {
|
|
14485
|
+
emitVerbatim(text.slice(index, index + 2));
|
|
14486
|
+
index += 2;
|
|
14487
|
+
} else if (char === "`") {
|
|
14488
|
+
emitVerbatim(char);
|
|
14489
|
+
frames.pop();
|
|
14490
|
+
index += 1;
|
|
14491
|
+
} else if (text.startsWith("${", index)) {
|
|
14492
|
+
emitVerbatim("${");
|
|
14493
|
+
frames.push({ kind: "code", braces: 0 });
|
|
14494
|
+
index += 2;
|
|
14495
|
+
} else {
|
|
14496
|
+
out += char;
|
|
14497
|
+
kept = out.length;
|
|
14498
|
+
index += 1;
|
|
14499
|
+
}
|
|
14500
|
+
continue;
|
|
14501
|
+
}
|
|
14502
|
+
if (char === `
|
|
14503
|
+
`) {
|
|
14504
|
+
newline();
|
|
14505
|
+
index += 1;
|
|
14506
|
+
continue;
|
|
14507
|
+
}
|
|
14508
|
+
if (SPACE.test(char)) {
|
|
14509
|
+
if (collapse)
|
|
14510
|
+
pendingSpace = true;
|
|
14511
|
+
else
|
|
14512
|
+
out += char;
|
|
14513
|
+
index += 1;
|
|
14514
|
+
continue;
|
|
14515
|
+
}
|
|
14516
|
+
const lineOpener = syntax.line.find((opener) => text.startsWith(opener, index));
|
|
14517
|
+
if (lineOpener) {
|
|
14518
|
+
const end = text.indexOf(`
|
|
14519
|
+
`, index);
|
|
14520
|
+
const comment = text.slice(index, end < 0 ? text.length : end);
|
|
14521
|
+
if (DIRECTIVE.test(comment.slice(lineOpener.length)))
|
|
14522
|
+
emitVerbatim(comment);
|
|
14523
|
+
else
|
|
14524
|
+
pendingSpace = true;
|
|
14525
|
+
index = end < 0 ? text.length : end;
|
|
14526
|
+
continue;
|
|
14527
|
+
}
|
|
14528
|
+
const block = syntax.block.find(([open]) => text.startsWith(open, index));
|
|
14529
|
+
if (block) {
|
|
14530
|
+
const end = text.indexOf(block[1], index + block[0].length);
|
|
14531
|
+
if (end < 0)
|
|
14532
|
+
return null;
|
|
14533
|
+
const comment = text.slice(index, end + block[1].length);
|
|
14534
|
+
if (DIRECTIVE.test(comment.slice(block[0].length, -block[1].length)))
|
|
14535
|
+
emitVerbatim(comment);
|
|
14536
|
+
else
|
|
14537
|
+
pendingSpace = true;
|
|
14538
|
+
if (comment.includes(`
|
|
14539
|
+
`))
|
|
14540
|
+
newline();
|
|
14541
|
+
index = end + block[1].length;
|
|
14542
|
+
continue;
|
|
14543
|
+
}
|
|
14544
|
+
if (syntax.triple && (char === '"' || char === "'") && text.startsWith(char.repeat(3), index)) {
|
|
14545
|
+
if (!scanString(char.repeat(3), !syntax.literal?.includes(char), true))
|
|
14546
|
+
return null;
|
|
14547
|
+
continue;
|
|
14548
|
+
}
|
|
14549
|
+
if (syntax.quotes.includes(char)) {
|
|
14550
|
+
if (!scanString(char, true, Boolean(syntax.multiline)))
|
|
14551
|
+
return null;
|
|
14552
|
+
continue;
|
|
14553
|
+
}
|
|
14554
|
+
if (syntax.literal?.includes(char)) {
|
|
14555
|
+
if (!scanString(char, false, false))
|
|
14556
|
+
return null;
|
|
14557
|
+
continue;
|
|
14558
|
+
}
|
|
14559
|
+
if (syntax.rawBacktick && char === "`") {
|
|
14560
|
+
if (!scanString("`", false, true))
|
|
14561
|
+
return null;
|
|
14562
|
+
continue;
|
|
14563
|
+
}
|
|
14564
|
+
if (syntax.js && char === "`") {
|
|
14565
|
+
emitVerbatim(char);
|
|
14566
|
+
frames.push({ kind: "template" });
|
|
14567
|
+
index += 1;
|
|
14568
|
+
continue;
|
|
14569
|
+
}
|
|
14570
|
+
if (syntax.cssUrl && /^url\(\s*[^"')\s]/iu.test(text.slice(index, index + 64)))
|
|
14571
|
+
return null;
|
|
14572
|
+
if (syntax.js && char === "/" && !regexAllowed() && out.trimEnd().endsWith(")")) {
|
|
14573
|
+
const lineEnd = text.indexOf(`
|
|
14574
|
+
`, index);
|
|
14575
|
+
if (text.slice(index + 1, lineEnd < 0 ? text.length : lineEnd).includes("/"))
|
|
14576
|
+
return null;
|
|
14577
|
+
}
|
|
14578
|
+
if (syntax.js && char === "/" && regexAllowed()) {
|
|
14579
|
+
let end = index + 1;
|
|
14580
|
+
let inClass = false;
|
|
14581
|
+
while (end < text.length && (inClass || text[end] !== "/")) {
|
|
14582
|
+
if (text[end] === `
|
|
14583
|
+
`)
|
|
14584
|
+
return null;
|
|
14585
|
+
if (text[end] === "\\")
|
|
14586
|
+
end += 1;
|
|
14587
|
+
else if (text[end] === "[")
|
|
14588
|
+
inClass = true;
|
|
14589
|
+
else if (text[end] === "]")
|
|
14590
|
+
inClass = false;
|
|
14591
|
+
end += 1;
|
|
14592
|
+
}
|
|
14593
|
+
if (end >= text.length)
|
|
14594
|
+
return null;
|
|
14595
|
+
emitVerbatim(text.slice(index, end + 1));
|
|
14596
|
+
index = end + 1;
|
|
14597
|
+
continue;
|
|
14598
|
+
}
|
|
14599
|
+
if (frames.length > 1 && frame.kind === "code") {
|
|
14600
|
+
if (char === "{")
|
|
14601
|
+
frame.braces += 1;
|
|
14602
|
+
else if (char === "}") {
|
|
14603
|
+
if (frame.braces === 0) {
|
|
14604
|
+
emitVerbatim(char);
|
|
14605
|
+
frames.pop();
|
|
14606
|
+
index += 1;
|
|
14607
|
+
continue;
|
|
14608
|
+
}
|
|
14609
|
+
frame.braces -= 1;
|
|
14610
|
+
}
|
|
14611
|
+
}
|
|
14612
|
+
emitCode(char);
|
|
14613
|
+
index += 1;
|
|
14614
|
+
}
|
|
14615
|
+
if (frames.length !== 1)
|
|
14616
|
+
return null;
|
|
14617
|
+
newline();
|
|
14618
|
+
return out;
|
|
14619
|
+
}
|
|
14620
|
+
function unbalanced(body) {
|
|
14621
|
+
let depth = 0;
|
|
14622
|
+
for (const part of body.replaceAll("{{", "").replaceAll("}}", "")) {
|
|
14623
|
+
if (part === "{")
|
|
14624
|
+
depth += 1;
|
|
14625
|
+
else if (part === "}")
|
|
14626
|
+
depth = Math.max(0, depth - 1);
|
|
14627
|
+
}
|
|
14628
|
+
return depth > 0;
|
|
14629
|
+
}
|
|
14630
|
+
function hasOpaqueLineBreak(text) {
|
|
14631
|
+
return /\r(?!\n)|[\u2028\u2029]/u.test(text);
|
|
14632
|
+
}
|
|
14633
|
+
var decoder = new TextDecoder("utf-8", { fatal: true });
|
|
14634
|
+
function textOf(bytes) {
|
|
14635
|
+
if (bytes.includes(0))
|
|
14636
|
+
return null;
|
|
14637
|
+
try {
|
|
14638
|
+
return decoder.decode(bytes);
|
|
14639
|
+
} catch {
|
|
14640
|
+
return null;
|
|
14641
|
+
}
|
|
14642
|
+
}
|
|
14643
|
+
function cosmeticChange(file, before, after) {
|
|
14644
|
+
const left = textOf(before);
|
|
14645
|
+
const right = textOf(after);
|
|
14646
|
+
if (left === null || right === null)
|
|
14647
|
+
return false;
|
|
14648
|
+
if (hasOpaqueLineBreak(left) || hasOpaqueLineBreak(right))
|
|
14649
|
+
return false;
|
|
14650
|
+
const a = substanceOf(file, left);
|
|
14651
|
+
return a !== null && a === substanceOf(file, right);
|
|
14652
|
+
}
|
|
14653
|
+
|
|
14654
|
+
// packages/workit-core/src/core/policy/lane.ts
|
|
14655
|
+
var LANE_THRESHOLDS = {
|
|
14656
|
+
selfMaxLines: 100,
|
|
14657
|
+
selfMaxFiles: 5,
|
|
14658
|
+
fullMinLines: 500
|
|
14659
|
+
};
|
|
14660
|
+
var RISK_TOKENS = new Set([
|
|
14661
|
+
"auth",
|
|
14662
|
+
"authn",
|
|
14663
|
+
"authz",
|
|
14664
|
+
"oauth",
|
|
14665
|
+
"security",
|
|
14666
|
+
"permission",
|
|
14667
|
+
"permissions",
|
|
14668
|
+
"secret",
|
|
14669
|
+
"secrets",
|
|
14670
|
+
"crypto",
|
|
14671
|
+
"gate",
|
|
14672
|
+
"gates",
|
|
14673
|
+
"policy",
|
|
14674
|
+
"policies",
|
|
14675
|
+
"hook",
|
|
14676
|
+
"hooks",
|
|
14677
|
+
"husky",
|
|
14678
|
+
"lefthook",
|
|
14679
|
+
"release",
|
|
14680
|
+
"releases",
|
|
14681
|
+
"migration",
|
|
14682
|
+
"migrations",
|
|
14683
|
+
"migrate",
|
|
14684
|
+
"workflows"
|
|
14685
|
+
]);
|
|
14686
|
+
var RISK_FILES = new Set([
|
|
14687
|
+
".gitlab-ci.yml",
|
|
14688
|
+
"Jenkinsfile",
|
|
14689
|
+
"azure-pipelines.yml",
|
|
14690
|
+
".pre-commit-config.yaml",
|
|
14691
|
+
".workit/risk-paths"
|
|
14692
|
+
]);
|
|
14693
|
+
var RISK_NAMES = new Set([".gitattributes"]);
|
|
14694
|
+
var RISK_PATHS_FILE = ".workit/risk-paths";
|
|
14695
|
+
var LOCKFILES = new Set([
|
|
14696
|
+
"bun.lock",
|
|
14697
|
+
"bun.lockb",
|
|
14698
|
+
"package-lock.json",
|
|
14699
|
+
"npm-shrinkwrap.json",
|
|
14700
|
+
"yarn.lock",
|
|
14701
|
+
"pnpm-lock.yaml",
|
|
14702
|
+
"Cargo.lock",
|
|
14703
|
+
"go.sum",
|
|
14704
|
+
"poetry.lock",
|
|
14705
|
+
"uv.lock",
|
|
14706
|
+
"Pipfile.lock",
|
|
14707
|
+
"Gemfile.lock",
|
|
14708
|
+
"composer.lock"
|
|
14709
|
+
]);
|
|
14710
|
+
var DOC_EXT = /\.(?:md|mdx|markdown|rst|adoc|txt)$/iu;
|
|
14711
|
+
var DOC_NAMES = /^(?:license|licence|notice|authors|changelog|changes|contributors)$/iu;
|
|
14712
|
+
var INSTRUCTIONS = /(?:^|\/)(?:AGENTS|CLAUDE|GEMINI|SKILL)\.md$|(?:^|\/)(?:skills|agents|commands|rules|prompts)\/[^/]+/iu;
|
|
14713
|
+
var TEST_PATH = /(?:^|\/)(?:test|tests|__tests__|spec|specs|fixtures)\/|\.(?:test|spec)\.[^/]+$/iu;
|
|
14714
|
+
var basename = (file) => file.slice(file.lastIndexOf("/") + 1);
|
|
14715
|
+
var isDoc = (file) => !INSTRUCTIONS.test(file) && (DOC_EXT.test(file) || DOC_NAMES.test(basename(file)));
|
|
14716
|
+
function kindOf(file) {
|
|
14717
|
+
if (file.binary)
|
|
14718
|
+
return "behavior";
|
|
14719
|
+
if (file.generated)
|
|
14720
|
+
return "generated";
|
|
14721
|
+
if (LOCKFILES.has(basename(file.path)))
|
|
14722
|
+
return "lockfile";
|
|
14723
|
+
if (isDoc(file.path))
|
|
14724
|
+
return "doc";
|
|
14725
|
+
if (file.cosmetic)
|
|
14726
|
+
return "cosmetic";
|
|
14727
|
+
return TEST_PATH.test(file.path) ? "test" : "behavior";
|
|
14728
|
+
}
|
|
14729
|
+
var globCache = new Map;
|
|
14730
|
+
function globMatch(pattern, file) {
|
|
14731
|
+
let regex = globCache.get(pattern);
|
|
14732
|
+
if (!regex) {
|
|
14733
|
+
let source = "";
|
|
14734
|
+
for (let index = 0;index < pattern.length; index += 1) {
|
|
14735
|
+
const char = pattern[index];
|
|
14736
|
+
if (char === "*" && pattern[index + 1] === "*") {
|
|
14737
|
+
source += pattern[index + 2] === "/" ? "(?:[^/]*/)*" : ".*";
|
|
14738
|
+
index += pattern[index + 2] === "/" ? 2 : 1;
|
|
14739
|
+
} else if (char === "*")
|
|
14740
|
+
source += "[^/]*";
|
|
14741
|
+
else if (char === "?")
|
|
14742
|
+
source += "[^/]";
|
|
14743
|
+
else
|
|
14744
|
+
source += char.replace(/[.+^${}()|[\]\\]/gu, "\\$&");
|
|
14745
|
+
}
|
|
14746
|
+
regex = new RegExp(`^${source}$`, "u");
|
|
14747
|
+
globCache.set(pattern, regex);
|
|
14748
|
+
}
|
|
14749
|
+
return regex.test(file) || file.startsWith(`${pattern.replace(/\/$/u, "")}/`);
|
|
14750
|
+
}
|
|
14751
|
+
function isRiskPath(file, extra = []) {
|
|
14752
|
+
if (extra.some((pattern) => globMatch(pattern, file)))
|
|
14753
|
+
return true;
|
|
14754
|
+
if (RISK_FILES.has(file) || RISK_NAMES.has(basename(file)))
|
|
14755
|
+
return true;
|
|
14756
|
+
if (TEST_PATH.test(file) || isDoc(file))
|
|
14757
|
+
return false;
|
|
14758
|
+
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)));
|
|
14759
|
+
}
|
|
14760
|
+
var parseRiskPaths = (text) => text.split(`
|
|
14761
|
+
`).map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.replace(/^\//u, ""));
|
|
14762
|
+
function computeLane(input) {
|
|
14763
|
+
const riskFiles = input.files.filter((file) => isRiskPath(file.path, input.riskPaths)).map((file) => file.path);
|
|
14764
|
+
const risky = new Set(riskFiles);
|
|
14765
|
+
const kinds = input.files.map((file) => ({
|
|
14766
|
+
file,
|
|
14767
|
+
kind: risky.has(file.path) ? "behavior" : kindOf(file)
|
|
14768
|
+
}));
|
|
14769
|
+
const behavior = kinds.filter((entry) => entry.kind === "behavior" || entry.kind === "test" || entry.kind === "lockfile");
|
|
14770
|
+
const lines = behavior.filter((entry) => entry.kind !== "lockfile").reduce((sum, entry) => sum + entry.file.added + entry.file.deleted, 0);
|
|
14771
|
+
const opaque = behavior.filter((entry) => entry.kind === "lockfile" || entry.file.binary);
|
|
14772
|
+
const result = (lane, reasons) => ({
|
|
14773
|
+
lane,
|
|
14774
|
+
reasons,
|
|
14775
|
+
lines,
|
|
14776
|
+
files: behavior.length,
|
|
14777
|
+
riskFiles
|
|
14778
|
+
});
|
|
14779
|
+
const { selfMaxLines, selfMaxFiles, fullMinLines } = LANE_THRESHOLDS;
|
|
14780
|
+
if (input.riskTier === "high")
|
|
14781
|
+
return result("full", ["the task judgment records high risk"]);
|
|
14782
|
+
if (riskFiles.length)
|
|
14783
|
+
return result("full", [
|
|
14784
|
+
`touches a risk path: ${riskFiles.slice(0, 3).join(", ")}${riskFiles.length > 3 ? ", …" : ""}`
|
|
14785
|
+
]);
|
|
14786
|
+
if (!behavior.length)
|
|
14787
|
+
return result("none", [
|
|
14788
|
+
input.files.length ? "only docs, comments, formatting or generated copies changed" : "no changes"
|
|
14789
|
+
]);
|
|
14790
|
+
if (lines >= fullMinLines)
|
|
14791
|
+
return result("full", [`large diff: ${lines} lines (≥ ${fullMinLines})`]);
|
|
14792
|
+
if (lines > selfMaxLines)
|
|
14793
|
+
return result("focused", [`${lines} lines changed (> ${selfMaxLines})`]);
|
|
14794
|
+
if (behavior.length > selfMaxFiles)
|
|
14795
|
+
return result("focused", [`${behavior.length} behavior files changed (> ${selfMaxFiles})`]);
|
|
14796
|
+
if (opaque.length)
|
|
14797
|
+
return result("focused", [
|
|
14798
|
+
`a lockfile or binary changed: ${opaque.slice(0, 3).map((entry) => entry.file.path).join(", ")}${opaque.length > 3 ? ", …" : ""}`
|
|
14799
|
+
]);
|
|
14800
|
+
return result("self", [
|
|
14801
|
+
`small change: ${lines} line${lines === 1 ? "" : "s"} in ${behavior.length} file${behavior.length === 1 ? "" : "s"}, no risk path`
|
|
14802
|
+
]);
|
|
14803
|
+
}
|
|
14804
|
+
function untrackedStat(cwd, file) {
|
|
14805
|
+
try {
|
|
14806
|
+
const bytes = readFileSync5(path18.join(cwd, file));
|
|
14807
|
+
if (bytes.includes(0))
|
|
14808
|
+
return { path: file, added: 0, deleted: 0, binary: true };
|
|
14809
|
+
const text = bytes.toString("utf8");
|
|
14810
|
+
if (hasOpaqueLineBreak(text))
|
|
14811
|
+
return { path: file, added: 0, deleted: 0, binary: true };
|
|
14812
|
+
const lines = text.split(`
|
|
14813
|
+
`).length - (text.endsWith(`
|
|
14814
|
+
`) ? 1 : 0);
|
|
14815
|
+
return { path: file, added: lines, deleted: 0 };
|
|
14816
|
+
} catch {
|
|
14817
|
+
return { path: file, added: 0, deleted: 0, binary: true };
|
|
14818
|
+
}
|
|
14819
|
+
}
|
|
14820
|
+
var REGULAR = new Set(["100644", "100755"]);
|
|
14821
|
+
var ABSENT = /^0+$/u;
|
|
14822
|
+
function cosmeticFiles(cwd, fork, head) {
|
|
14823
|
+
const raw = diffRaw(cwd, fork, head);
|
|
14824
|
+
if (!raw)
|
|
14825
|
+
return null;
|
|
14826
|
+
const candidates = raw.filter((entry) => REGULAR.has(entry.oldMode) && entry.oldMode === entry.newMode && !ABSENT.test(entry.oldBlob) && (head === null || !ABSENT.test(entry.newBlob)));
|
|
14827
|
+
const blobs = readBlobs(cwd, candidates.flatMap((entry) => [entry.oldBlob, entry.newBlob]));
|
|
14828
|
+
if (!blobs)
|
|
14829
|
+
return null;
|
|
14830
|
+
const out = new Set;
|
|
14831
|
+
const opaque = new Set;
|
|
14832
|
+
for (const entry of candidates) {
|
|
14833
|
+
const before = blobs.get(entry.oldBlob);
|
|
14834
|
+
let after = blobs.get(entry.newBlob);
|
|
14835
|
+
if (!after && head === null && ABSENT.test(entry.newBlob))
|
|
14836
|
+
try {
|
|
14837
|
+
after = readFileSync5(path18.join(cwd, entry.path));
|
|
14838
|
+
} catch {
|
|
14839
|
+
after = undefined;
|
|
14840
|
+
}
|
|
14841
|
+
if (before && after && cosmeticChange(entry.path, before, after))
|
|
14842
|
+
out.add(entry.path);
|
|
14843
|
+
else if ([before, after].some((bytes) => bytes && hasOpaqueLineBreak(bytes.toString("utf8"))))
|
|
14844
|
+
opaque.add(entry.path);
|
|
14845
|
+
}
|
|
14846
|
+
return { cosmetic: out, opaque };
|
|
14847
|
+
}
|
|
14848
|
+
function generatedAt(cwd, fork, paths) {
|
|
14849
|
+
const files = treeFilesNamed(cwd, fork, ".gitattributes");
|
|
14850
|
+
const blobs = files?.size ? readBlobs(cwd, [...files.values()]) : null;
|
|
14851
|
+
if (!files || !blobs)
|
|
14852
|
+
return new Set;
|
|
14853
|
+
const texts = new Map;
|
|
14854
|
+
for (const [file, id] of files) {
|
|
14855
|
+
const bytes = blobs.get(id);
|
|
14856
|
+
if (bytes)
|
|
14857
|
+
texts.set(file, bytes.toString("utf8"));
|
|
14858
|
+
}
|
|
14859
|
+
return generatedByAttributes(texts, paths);
|
|
14860
|
+
}
|
|
14861
|
+
var forkOf = (cwd, base, head) => mergeBase(cwd, base, head ?? "HEAD");
|
|
14862
|
+
function laneFiles(cwd, fork, head) {
|
|
14863
|
+
const stats = diffNumstat(cwd, fork, head);
|
|
14864
|
+
const cosmetic = stats ? cosmeticFiles(cwd, fork, head) : null;
|
|
14865
|
+
if (!stats || !cosmetic)
|
|
14866
|
+
return null;
|
|
14867
|
+
const files = [
|
|
14868
|
+
...stats.map((entry) => ({
|
|
14869
|
+
...entry,
|
|
14870
|
+
...cosmetic.opaque.has(entry.path) ? { binary: true } : {},
|
|
14871
|
+
cosmetic: !entry.binary && cosmetic.cosmetic.has(entry.path)
|
|
14872
|
+
})),
|
|
14873
|
+
...head === null ? untrackedFiles(cwd).map((file) => untrackedStat(cwd, file)) : []
|
|
14874
|
+
];
|
|
14875
|
+
const generated = generatedAt(cwd, fork, files.map((entry) => entry.path));
|
|
14876
|
+
return files.map((entry) => ({
|
|
14877
|
+
...entry,
|
|
14878
|
+
generated: generated.has(entry.path)
|
|
14879
|
+
}));
|
|
14880
|
+
}
|
|
14881
|
+
function branchLane(cwd, options) {
|
|
14882
|
+
const candidates = options.base ? [`origin/${options.base}`, options.base] : [];
|
|
14883
|
+
const base = candidates.find((ref) => resolveRef(cwd, ref) !== null) ?? defaultBase(cwd) ?? null;
|
|
14884
|
+
const head = options.workingTree ? null : options.head;
|
|
14885
|
+
const fork = base && (options.workingTree || options.head) ? forkOf(cwd, base, head) : null;
|
|
14886
|
+
const files = fork ? laneFiles(cwd, fork, head) : null;
|
|
14887
|
+
const riskTier = options.judgment?.riskTier ?? null;
|
|
14888
|
+
if (!fork || !files) {
|
|
14889
|
+
const high = riskTier === "high";
|
|
14890
|
+
return {
|
|
14891
|
+
lane: high ? "full" : "focused",
|
|
14892
|
+
reasons: [
|
|
14893
|
+
`the diff of ${options.head?.slice(0, 12) ?? "(no head)"} against ${base ?? "(no base)"} cannot be read`,
|
|
14894
|
+
...high ? ["the task judgment records high risk"] : []
|
|
14895
|
+
],
|
|
14896
|
+
lines: 0,
|
|
14897
|
+
files: 0,
|
|
14898
|
+
riskFiles: [],
|
|
14899
|
+
base,
|
|
14900
|
+
head: options.head
|
|
14901
|
+
};
|
|
14902
|
+
}
|
|
14903
|
+
const repoRisk = parseRiskPaths(fileAt(cwd, fork, RISK_PATHS_FILE) ?? "");
|
|
14904
|
+
return {
|
|
14905
|
+
...computeLane({
|
|
14906
|
+
files,
|
|
14907
|
+
riskTier,
|
|
14908
|
+
riskPaths: [...repoRisk, ...options.riskPaths ?? []]
|
|
14909
|
+
}),
|
|
14910
|
+
base,
|
|
14911
|
+
head: options.head
|
|
14912
|
+
};
|
|
14913
|
+
}
|
|
14914
|
+
var laneNeed = (lane) => lane === "none" ? "none" : lane === "self" ? "self" : "non-author";
|
|
14915
|
+
|
|
14916
|
+
// packages/workit-core/src/core/policy/derive.ts
|
|
14917
|
+
var RULES = {
|
|
14918
|
+
test: "check:test",
|
|
14919
|
+
self: "verdict:self",
|
|
14920
|
+
nonAuthor: "verdict:non-author",
|
|
14921
|
+
verified: "verdict:verified",
|
|
14922
|
+
lane: "verdict:lane",
|
|
14923
|
+
product: "decision:product",
|
|
14924
|
+
plan: "plan"
|
|
14925
|
+
};
|
|
14926
|
+
var derived2 = (spec) => ({
|
|
14927
|
+
...spec,
|
|
14928
|
+
id: requirementId({
|
|
14929
|
+
ruleId: spec.ruleId,
|
|
14930
|
+
scope: spec.scope,
|
|
14931
|
+
satisfaction: spec.satisfaction,
|
|
14932
|
+
before: spec.before,
|
|
14933
|
+
dependentAction: spec.dependentAction
|
|
14934
|
+
})
|
|
14935
|
+
});
|
|
14936
|
+
var sorted = (values) => [...new Set(values)].toSorted();
|
|
14937
|
+
var normalizedScope = (scope) => ({
|
|
14938
|
+
description: scope.description,
|
|
14939
|
+
paths: sorted(scope.paths),
|
|
14940
|
+
exclusions: sorted(scope.exclusions)
|
|
14941
|
+
});
|
|
14942
|
+
function deriveRequirements(judgment, scope, constraints, verification = "self") {
|
|
14943
|
+
const out = [];
|
|
14944
|
+
const base = { scope, dependentAction: null };
|
|
14945
|
+
const proportional = verification === "proportional";
|
|
14946
|
+
if (judgment.behaviorChange)
|
|
14947
|
+
out.push(derived2({
|
|
14948
|
+
...base,
|
|
14949
|
+
ruleId: RULES.test,
|
|
14950
|
+
dimension: "testing",
|
|
14951
|
+
reason: "Behavior changes: the configured test check must pass on the final tree.",
|
|
14952
|
+
satisfaction: "Run `workit check test` on the final tree.",
|
|
14953
|
+
before: "close",
|
|
14954
|
+
acceptanceAllowed: false
|
|
14955
|
+
}));
|
|
14956
|
+
if (proportional && judgment.riskTier === "normal")
|
|
14957
|
+
out.push(derived2({
|
|
14958
|
+
...base,
|
|
14959
|
+
ruleId: RULES.lane,
|
|
14960
|
+
dimension: "review",
|
|
14961
|
+
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.",
|
|
14962
|
+
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.",
|
|
14963
|
+
before: "close",
|
|
14964
|
+
acceptanceAllowed: false
|
|
14965
|
+
}));
|
|
14966
|
+
if (!proportional && judgment.behaviorChange && judgment.riskTier === "normal")
|
|
14967
|
+
out.push(verification === "independent" ? derived2({
|
|
14968
|
+
...base,
|
|
14969
|
+
ruleId: RULES.nonAuthor,
|
|
14970
|
+
dimension: "review",
|
|
14971
|
+
reason: "This workspace requires independent verification: a session that did not author the change records the verdict.",
|
|
14972
|
+
satisfaction: "An independent session records a passing verdict: `workit ledger verdict verified --how <what it exercised>`.",
|
|
14973
|
+
before: "close",
|
|
14974
|
+
acceptanceAllowed: false
|
|
14975
|
+
}) : derived2({
|
|
14976
|
+
...base,
|
|
14977
|
+
ruleId: RULES.self,
|
|
14978
|
+
dimension: "review",
|
|
14979
|
+
reason: "A behavior change needs a recorded verdict; the author's own is allowed and is shown as self-reviewed, never verified.",
|
|
14980
|
+
satisfaction: "After an observed passing `workit check test`, record `workit ledger verdict tests-verified --self --how <what you ran>` (or have a verifier record one).",
|
|
14981
|
+
before: "close",
|
|
14982
|
+
acceptanceAllowed: false
|
|
14983
|
+
}));
|
|
14984
|
+
if (judgment.riskTier === "high")
|
|
14985
|
+
out.push(derived2({
|
|
14986
|
+
...base,
|
|
14987
|
+
ruleId: RULES.verified,
|
|
14988
|
+
dimension: "review",
|
|
14989
|
+
reason: "High risk: an independent verifier must exercise the live surface.",
|
|
14990
|
+
satisfaction: "An independent verifier runs the real surface and records `workit ledger verdict verified --kind live --how <what it exercised>`.",
|
|
14991
|
+
before: "close",
|
|
14992
|
+
acceptanceAllowed: false
|
|
14993
|
+
}));
|
|
14994
|
+
if (judgment.productChoiceOpen)
|
|
14995
|
+
out.push(derived2({
|
|
14996
|
+
...base,
|
|
14997
|
+
ruleId: RULES.product,
|
|
14998
|
+
dimension: "decisions",
|
|
14999
|
+
reason: "A product or preference choice is open; the user decides it before code is written.",
|
|
15000
|
+
satisfaction: 'Ask the user (with your recommendation), then record the answer: `workit ledger decision "<choice>" --why "<reason>"`.',
|
|
15001
|
+
before: "write",
|
|
15002
|
+
acceptanceAllowed: false
|
|
15003
|
+
}));
|
|
15004
|
+
if (judgment.needsPlan || judgment.riskTier === "high")
|
|
15005
|
+
out.push(derived2({
|
|
15006
|
+
...base,
|
|
15007
|
+
ruleId: RULES.plan,
|
|
15008
|
+
dimension: "artifacts",
|
|
15009
|
+
reason: judgment.needsPlan ? "The work needs a written plan or spec before implementation." : "High-risk work needs a written plan before implementation.",
|
|
15010
|
+
satisfaction: "Write the plan or spec (e.g. docs/plans/<slug>.md; docs and Markdown writes stay allowed), then record it: `workit policy assess --ref <path>`.",
|
|
15011
|
+
before: "write",
|
|
15012
|
+
acceptanceAllowed: true
|
|
15013
|
+
}));
|
|
15014
|
+
for (const constraint of constraints)
|
|
15015
|
+
for (const obligation of constraint.requires)
|
|
15016
|
+
out.push(derived2({
|
|
15017
|
+
ruleId: `project-constraint:${constraint.id}:${obligation.kind}:${sha256({
|
|
15018
|
+
kind: obligation.kind,
|
|
15019
|
+
scope: normalizedScope(obligation.scope),
|
|
15020
|
+
refs: obligation.refs.map((ref) => JSON.stringify(ref)).toSorted(),
|
|
15021
|
+
method: obligation.method,
|
|
15022
|
+
before: obligation.before,
|
|
15023
|
+
dependentAction: obligation.dependentAction
|
|
15024
|
+
})}`,
|
|
15025
|
+
dimension: obligation.method ?? (obligation.kind === "check" ? "verification" : obligation.kind === "decision" ? "decisions" : "challenge"),
|
|
15026
|
+
scope: obligation.scope,
|
|
15027
|
+
reason: `${constraint.kind} constraint requires ${obligation.kind}: ${constraint.statement}`,
|
|
15028
|
+
satisfaction: `Satisfy the constraint obligation using its referenced ${obligation.kind}.`,
|
|
15029
|
+
before: obligation.before,
|
|
15030
|
+
dependentAction: obligation.dependentAction,
|
|
15031
|
+
acceptanceAllowed: constraint.acceptanceAllowed && obligation.kind !== "decision"
|
|
15032
|
+
}));
|
|
15033
|
+
const seen = new Set;
|
|
15034
|
+
return out.filter((item) => seen.has(item.id) ? false : (seen.add(item.id), true));
|
|
15035
|
+
}
|
|
15036
|
+
var latestJudgment = (task) => task.judgments?.at(-1)?.data ?? null;
|
|
15037
|
+
var ledgerView = (root) => {
|
|
15038
|
+
let branch;
|
|
15039
|
+
let rows;
|
|
15040
|
+
return {
|
|
15041
|
+
branch: () => branch === undefined ? branch = currentBranch(root) : branch,
|
|
15042
|
+
rows: () => {
|
|
15043
|
+
if (rows === undefined) {
|
|
15044
|
+
const read = readLedger(root);
|
|
15045
|
+
rows = read.ok ? read.value.rows : [];
|
|
15046
|
+
}
|
|
15047
|
+
return rows;
|
|
15048
|
+
}
|
|
15049
|
+
};
|
|
15050
|
+
};
|
|
15051
|
+
var productDecision = (task, ledger) => {
|
|
15052
|
+
const decisions = task.decisions.filter((entry) => entry.data.revoked === null && (entry.data.response === "approved" || entry.data.response === "stated") && entry.data.purpose !== "limitation");
|
|
15053
|
+
if (decisions.length)
|
|
15054
|
+
return {
|
|
15055
|
+
met: true,
|
|
15056
|
+
reason: "the user's decision is recorded on the task",
|
|
15057
|
+
decisionIds: decisions.map((entry) => entry.id)
|
|
15058
|
+
};
|
|
15059
|
+
const since = Date.parse(task.createdAt);
|
|
15060
|
+
const branch = ledger.branch();
|
|
15061
|
+
const row = ledger.rows().findLast((item) => item.type === "decision" && item.by !== "decider" && !item.superseded && (item.branch ?? null) === branch && Date.parse(item.at) >= since);
|
|
15062
|
+
return row ? { met: true, reason: `ledger decision ${row.id} records the choice`, decisionIds: [] } : {
|
|
15063
|
+
met: false,
|
|
15064
|
+
reason: 'open product choice: ask the user, then `workit ledger decision "<choice>" --why "<reason>"` (or, if it is not open, `workit policy assess --judge product-choice=no --why "<reason>"`)',
|
|
15065
|
+
decisionIds: []
|
|
15066
|
+
};
|
|
15067
|
+
};
|
|
15068
|
+
var planRecorded = (task, root) => {
|
|
15069
|
+
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync6(path19.resolve(root, ref.path)));
|
|
15070
|
+
if (cited)
|
|
15071
|
+
return {
|
|
15072
|
+
met: true,
|
|
14104
15073
|
reason: `plan recorded: ${cited.kind === "file" ? cited.path : cited.kind === "external" ? cited.url : ""}`,
|
|
14105
15074
|
decisionIds: []
|
|
14106
15075
|
};
|
|
@@ -14111,14 +15080,30 @@ var planRecorded = (task, root) => {
|
|
|
14111
15080
|
decisionIds: []
|
|
14112
15081
|
};
|
|
14113
15082
|
};
|
|
14114
|
-
var
|
|
15083
|
+
var workingLane = (task, root) => branchLane(root, { head: null, workingTree: true, judgment: latestJudgment(task) });
|
|
15084
|
+
var laneVerdict = (task, root, ledger) => {
|
|
15085
|
+
if (!ledger.branch() && latestJudgment(task)?.behaviorChange === false)
|
|
15086
|
+
return {
|
|
15087
|
+
met: true,
|
|
15088
|
+
reason: "no branch to read a lane from, and the judgment records no behavior change",
|
|
15089
|
+
decisionIds: []
|
|
15090
|
+
};
|
|
15091
|
+
const lane = workingLane(task, root);
|
|
15092
|
+
const label = `lane ${lane.lane} (${lane.reasons.join("; ")})`;
|
|
15093
|
+
const need = laneNeed(lane.lane);
|
|
15094
|
+
if (need === "none")
|
|
15095
|
+
return { met: true, reason: `${label}: no verdict needed`, decisionIds: [] };
|
|
15096
|
+
const status = verdict(need === "self" ? RULES.self : RULES.nonAuthor, root, ledger);
|
|
15097
|
+
return { ...status, reason: `${label}: ${status.reason}` };
|
|
15098
|
+
};
|
|
15099
|
+
var verdict = (ruleId, root, ledger) => {
|
|
14115
15100
|
const branch = ledger.branch();
|
|
14116
15101
|
if (!branch)
|
|
14117
15102
|
return { met: false, reason: "no branch is checked out to hold a verdict", decisionIds: [] };
|
|
14118
15103
|
const check = checkVerdicts(root, branch, ledger.rows());
|
|
14119
15104
|
const failing = check.accepted.reasons.includes("failing_verdict");
|
|
14120
15105
|
const strong = (entry) => STRONG_RESULTS.has(String(entry.verdict.result));
|
|
14121
|
-
const met = !failing && (
|
|
15106
|
+
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)));
|
|
14122
15107
|
if (met)
|
|
14123
15108
|
return {
|
|
14124
15109
|
met: true,
|
|
@@ -14126,7 +15111,7 @@ var verdict = (requirement, root, ledger) => {
|
|
|
14126
15111
|
decisionIds: []
|
|
14127
15112
|
};
|
|
14128
15113
|
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, " ");
|
|
14129
|
-
const unblock =
|
|
15114
|
+
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>\``;
|
|
14130
15115
|
return { met: false, reason: `${why}: ${unblock}`, decisionIds: [] };
|
|
14131
15116
|
};
|
|
14132
15117
|
function derivedRuleStatus(task, requirement, root, ledger) {
|
|
@@ -14138,7 +15123,9 @@ function derivedRuleStatus(task, requirement, root, ledger) {
|
|
|
14138
15123
|
case RULES.self:
|
|
14139
15124
|
case RULES.nonAuthor:
|
|
14140
15125
|
case RULES.verified:
|
|
14141
|
-
return verdict(requirement, root, ledger);
|
|
15126
|
+
return verdict(requirement.ruleId, root, ledger);
|
|
15127
|
+
case RULES.lane:
|
|
15128
|
+
return laneVerdict(task, root, ledger);
|
|
14142
15129
|
default:
|
|
14143
15130
|
return null;
|
|
14144
15131
|
}
|
|
@@ -14157,14 +15144,14 @@ function writeBlockers(task, root) {
|
|
|
14157
15144
|
|
|
14158
15145
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
14159
15146
|
var digestBytes = (value) => createHash12("sha256").update(value).digest("hex");
|
|
14160
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
14161
|
-
var relative = (root, candidate) =>
|
|
15147
|
+
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path20.sep}`);
|
|
15148
|
+
var relative = (root, candidate) => path20.relative(root, candidate).split(path20.sep).join("/") || ".";
|
|
14162
15149
|
var canonicalPath = (value) => {
|
|
14163
15150
|
if (typeof value !== "string" || !value)
|
|
14164
15151
|
return null;
|
|
14165
15152
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
14166
15153
|
return null;
|
|
14167
|
-
const normalized =
|
|
15154
|
+
const normalized = path20.posix.normalize(value);
|
|
14168
15155
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
14169
15156
|
return null;
|
|
14170
15157
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -14200,7 +15187,7 @@ var compareCodeUnits2 = (left, right) => {
|
|
|
14200
15187
|
return left.length - right.length;
|
|
14201
15188
|
};
|
|
14202
15189
|
var gitPaths = (root) => {
|
|
14203
|
-
const result =
|
|
15190
|
+
const result = spawnSync12("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
|
|
14204
15191
|
cwd: root,
|
|
14205
15192
|
encoding: "buffer"
|
|
14206
15193
|
});
|
|
@@ -14212,21 +15199,21 @@ var gitPaths = (root) => {
|
|
|
14212
15199
|
git: !/not a git repository/i.test(stderr)
|
|
14213
15200
|
};
|
|
14214
15201
|
}
|
|
14215
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
14216
|
-
const stagedDeleted =
|
|
15202
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path20.sep).join("/")) : [];
|
|
15203
|
+
const stagedDeleted = spawnSync12("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
14217
15204
|
if (stagedDeleted.status !== 0) {
|
|
14218
15205
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
14219
15206
|
if (!/not a git repository/i.test(stderr))
|
|
14220
15207
|
return { paths, uncertain: true, git: true };
|
|
14221
15208
|
} else if (stagedDeleted.stdout) {
|
|
14222
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
15209
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path20.sep).join("/")));
|
|
14223
15210
|
}
|
|
14224
15211
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
14225
15212
|
};
|
|
14226
15213
|
var walk = (root, directory, output) => {
|
|
14227
15214
|
let names;
|
|
14228
15215
|
try {
|
|
14229
|
-
names =
|
|
15216
|
+
names = fs15.readdirSync(directory);
|
|
14230
15217
|
} catch {
|
|
14231
15218
|
return true;
|
|
14232
15219
|
}
|
|
@@ -14234,10 +15221,10 @@ var walk = (root, directory, output) => {
|
|
|
14234
15221
|
for (const name of names) {
|
|
14235
15222
|
if (name === ".git" || name === ".workit")
|
|
14236
15223
|
continue;
|
|
14237
|
-
const target =
|
|
15224
|
+
const target = path20.join(directory, name);
|
|
14238
15225
|
let stat;
|
|
14239
15226
|
try {
|
|
14240
|
-
stat =
|
|
15227
|
+
stat = fs15.lstatSync(target);
|
|
14241
15228
|
} catch {
|
|
14242
15229
|
uncertain = true;
|
|
14243
15230
|
continue;
|
|
@@ -14252,14 +15239,14 @@ var walk = (root, directory, output) => {
|
|
|
14252
15239
|
var scopeRoots = (root, scope) => {
|
|
14253
15240
|
const roots = [];
|
|
14254
15241
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
14255
|
-
const target =
|
|
15242
|
+
const target = path20.resolve(root, item);
|
|
14256
15243
|
if (!inside(root, target))
|
|
14257
15244
|
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` }] });
|
|
14258
15245
|
let ancestor = target;
|
|
14259
|
-
while (!
|
|
14260
|
-
ancestor =
|
|
15246
|
+
while (!fs15.existsSync(ancestor) && ancestor !== root)
|
|
15247
|
+
ancestor = path20.dirname(ancestor);
|
|
14261
15248
|
try {
|
|
14262
|
-
if (!inside(root,
|
|
15249
|
+
if (!inside(root, fs15.realpathSync(ancestor)))
|
|
14263
15250
|
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` }] });
|
|
14264
15251
|
} catch {
|
|
14265
15252
|
return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
|
|
@@ -14271,7 +15258,7 @@ var scopeRoots = (root, scope) => {
|
|
|
14271
15258
|
function captureCandidate(root, scope, environment = []) {
|
|
14272
15259
|
let checkout;
|
|
14273
15260
|
try {
|
|
14274
|
-
checkout =
|
|
15261
|
+
checkout = fs15.realpathSync(root);
|
|
14275
15262
|
} catch {
|
|
14276
15263
|
return failure2("invalid_input", "candidate root does not exist");
|
|
14277
15264
|
}
|
|
@@ -14289,11 +15276,11 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
14289
15276
|
if (item === ".git" || item === ".workit")
|
|
14290
15277
|
continue;
|
|
14291
15278
|
names.add(item);
|
|
14292
|
-
if (!
|
|
15279
|
+
if (!fs15.existsSync(target))
|
|
14293
15280
|
continue;
|
|
14294
15281
|
let stat;
|
|
14295
15282
|
try {
|
|
14296
|
-
stat =
|
|
15283
|
+
stat = fs15.lstatSync(target);
|
|
14297
15284
|
} catch {
|
|
14298
15285
|
uncertain = true;
|
|
14299
15286
|
continue;
|
|
@@ -14309,17 +15296,17 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
14309
15296
|
for (const item of [...names].toSorted()) {
|
|
14310
15297
|
if (!scopeMatches(item, normalizedScope))
|
|
14311
15298
|
continue;
|
|
14312
|
-
const target =
|
|
15299
|
+
const target = path20.join(checkout, item);
|
|
14313
15300
|
try {
|
|
14314
|
-
const stat =
|
|
15301
|
+
const stat = fs15.lstatSync(target);
|
|
14315
15302
|
if (stat.isSymbolicLink()) {
|
|
14316
|
-
const link =
|
|
15303
|
+
const link = fs15.readlinkSync(target);
|
|
14317
15304
|
files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
|
|
14318
15305
|
} else if (stat.isFile()) {
|
|
14319
15306
|
files.push({
|
|
14320
15307
|
path: item,
|
|
14321
15308
|
kind: "file",
|
|
14322
|
-
digest: digestBytes(
|
|
15309
|
+
digest: digestBytes(fs15.readFileSync(target)),
|
|
14323
15310
|
executable: (stat.mode & 73) !== 0
|
|
14324
15311
|
});
|
|
14325
15312
|
} else if (!stat.isDirectory()) {
|
|
@@ -14344,7 +15331,7 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
14344
15331
|
const values = supplied.toSorted((left, right) => compareCodeUnits2(left.name, right.name)).map(({ name, value }) => ({ name, value, refs: [] }));
|
|
14345
15332
|
if (values.some(({ value }) => value === null))
|
|
14346
15333
|
completeness = "uncertain";
|
|
14347
|
-
const headResult =
|
|
15334
|
+
const headResult = spawnSync12("git", ["rev-parse", "HEAD"], { cwd: checkout, encoding: "utf8" });
|
|
14348
15335
|
if (headResult.status !== 0 && !/not a git repository/i.test(headResult.stderr ?? ""))
|
|
14349
15336
|
completeness = "uncertain";
|
|
14350
15337
|
const head = headResult.status === 0 ? headResult.stdout.trim() : null;
|
|
@@ -14484,7 +15471,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
|
|
|
14484
15471
|
var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
14485
15472
|
let root;
|
|
14486
15473
|
try {
|
|
14487
|
-
root =
|
|
15474
|
+
root = fs15.realpathSync(checkoutRoot);
|
|
14488
15475
|
} catch {
|
|
14489
15476
|
return failure2("permission_denied", "checkout root is unavailable");
|
|
14490
15477
|
}
|
|
@@ -14493,23 +15480,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
14493
15480
|
continue;
|
|
14494
15481
|
if (!reference.digest)
|
|
14495
15482
|
return failure2("invalid_input", "document references require a byte digest");
|
|
14496
|
-
const target =
|
|
14497
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
15483
|
+
const target = path20.resolve(root, reference.path);
|
|
15484
|
+
if (target !== root && !target.startsWith(`${root}${path20.sep}`))
|
|
14498
15485
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
14499
15486
|
fields: [
|
|
14500
15487
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
14501
15488
|
]
|
|
14502
15489
|
});
|
|
14503
15490
|
try {
|
|
14504
|
-
const below =
|
|
15491
|
+
const below = path20.relative(root, target);
|
|
14505
15492
|
let current = root;
|
|
14506
|
-
for (const segment of below.split(
|
|
15493
|
+
for (const segment of below.split(path20.sep)) {
|
|
14507
15494
|
if (!segment)
|
|
14508
15495
|
continue;
|
|
14509
|
-
current =
|
|
14510
|
-
const stat =
|
|
14511
|
-
const real =
|
|
14512
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
15496
|
+
current = path20.join(current, segment);
|
|
15497
|
+
const stat = fs15.lstatSync(current);
|
|
15498
|
+
const real = fs15.realpathSync(current);
|
|
15499
|
+
if (real !== root && !real.startsWith(`${root}${path20.sep}`))
|
|
14513
15500
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
14514
15501
|
fields: [
|
|
14515
15502
|
{
|
|
@@ -14525,7 +15512,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
14525
15512
|
if (current !== target && !stat.isDirectory())
|
|
14526
15513
|
return failure2("invalid_input", "document reference ancestor is not a directory");
|
|
14527
15514
|
}
|
|
14528
|
-
if (digestBytes(
|
|
15515
|
+
if (digestBytes(fs15.readFileSync(target)) !== reference.digest)
|
|
14529
15516
|
return failure2("permission_denied", "decision document bytes have changed");
|
|
14530
15517
|
} catch {
|
|
14531
15518
|
return failure2("invalid_input", "decision document is unavailable");
|
|
@@ -14942,9 +15929,9 @@ Autonomy contract:
|
|
|
14942
15929
|
Prose is a note: only a configured check the CLI ran (\`workit check <name>\`)
|
|
14943
15930
|
satisfies a gate; an ad-hoc \`workit check -- <cmd>\` never does.
|
|
14944
15931
|
- Author is not verifier: your own verdict is \`--self\`, shown as
|
|
14945
|
-
self-reviewed, never verified. High risk,
|
|
14946
|
-
merge need a verifier with its
|
|
14947
|
-
\`<lead>:<child>\`); never hand-mint one (\`<lead>-v1\`).
|
|
15932
|
+
self-reviewed, never verified. High risk, a focused or full lane and
|
|
15933
|
+
merge under \`verification: self|independent\` need a verifier with its
|
|
15934
|
+
own host-derived session (a subagent's \`<lead>:<child>\`); never hand-mint one (\`<lead>-v1\`).
|
|
14948
15935
|
- A local-commit endpoint does not imply PR readiness, and a local commit alone
|
|
14949
15936
|
is not evidence of a requested remote push. Before reporting delivery,
|
|
14950
15937
|
reconcile every requested item and observe it (\`workit verify-delivery\`).
|
|
@@ -15106,21 +16093,21 @@ var exportDigest = (bundle) => sha256({
|
|
|
15106
16093
|
task: bundle.task
|
|
15107
16094
|
});
|
|
15108
16095
|
// packages/workit-core/src/core/route-intent.ts
|
|
15109
|
-
import { spawnSync as
|
|
15110
|
-
import { existsSync as
|
|
15111
|
-
import
|
|
16096
|
+
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
16097
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
16098
|
+
import path23 from "node:path";
|
|
15112
16099
|
|
|
15113
16100
|
// packages/workit-core/src/hooks/raw-git.ts
|
|
15114
|
-
import { spawnSync as
|
|
16101
|
+
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
15115
16102
|
import { createHash as createHash14 } from "node:crypto";
|
|
15116
|
-
import
|
|
16103
|
+
import fs17 from "node:fs";
|
|
15117
16104
|
import os4 from "node:os";
|
|
15118
|
-
import
|
|
16105
|
+
import path22 from "node:path";
|
|
15119
16106
|
|
|
15120
16107
|
// packages/workit-core/src/hooks/session-marker.ts
|
|
15121
16108
|
import { createHash as createHash13 } from "node:crypto";
|
|
15122
|
-
import
|
|
15123
|
-
import
|
|
16109
|
+
import fs16 from "node:fs";
|
|
16110
|
+
import path21 from "node:path";
|
|
15124
16111
|
var sessionMarkerFile = (input, session, store) => {
|
|
15125
16112
|
let dir = store;
|
|
15126
16113
|
if (dir === undefined) {
|
|
@@ -15130,13 +16117,13 @@ var sessionMarkerFile = (input, session, store) => {
|
|
|
15130
16117
|
dir = location.dir;
|
|
15131
16118
|
}
|
|
15132
16119
|
const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
|
|
15133
|
-
return
|
|
16120
|
+
return path21.join(dir, "hooks", `skills-${name}.json`);
|
|
15134
16121
|
};
|
|
15135
16122
|
var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
15136
16123
|
var EMPTY = { nudged: [], loaded: [], raw: [], stops: [], judges: [] };
|
|
15137
16124
|
var readRaw = (file) => {
|
|
15138
16125
|
try {
|
|
15139
|
-
return
|
|
16126
|
+
return fs16.readFileSync(file, "utf8");
|
|
15140
16127
|
} catch {
|
|
15141
16128
|
return "";
|
|
15142
16129
|
}
|
|
@@ -15157,13 +16144,13 @@ var parseMarker = (text) => {
|
|
|
15157
16144
|
};
|
|
15158
16145
|
var readSessionMarker = (file) => parseMarker(readRaw(file));
|
|
15159
16146
|
var writeAtomic = (file, marker) => {
|
|
15160
|
-
|
|
16147
|
+
fs16.mkdirSync(path21.dirname(file), { recursive: true });
|
|
15161
16148
|
const temp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
15162
16149
|
try {
|
|
15163
|
-
|
|
15164
|
-
|
|
16150
|
+
fs16.writeFileSync(temp, JSON.stringify(marker));
|
|
16151
|
+
fs16.renameSync(temp, file);
|
|
15165
16152
|
} catch (error) {
|
|
15166
|
-
|
|
16153
|
+
fs16.rmSync(temp, { force: true });
|
|
15167
16154
|
throw error;
|
|
15168
16155
|
}
|
|
15169
16156
|
};
|
|
@@ -15675,17 +16662,17 @@ var GIT_VALUE_OPTIONS = new Set([
|
|
|
15675
16662
|
]);
|
|
15676
16663
|
var GIT_CONFIG_OPTIONS = new Set(["-c", "--config-env", "--git-dir"]);
|
|
15677
16664
|
var GIT_CONFIG_ENV = /^GIT_(?:CONFIG\w*|DIR|COMMON_DIR|WORK_TREE)$/;
|
|
15678
|
-
var
|
|
16665
|
+
var ASSIGNMENT2 = /^([A-Za-z_]\w*)=([\s\S]*)$/;
|
|
15679
16666
|
var MAX_DEPTH = 4;
|
|
15680
16667
|
var MAX_EXPANSIONS = 16;
|
|
15681
|
-
var isAbsolute = (value) =>
|
|
16668
|
+
var isAbsolute = (value) => path22.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
|
|
15682
16669
|
var HERE = /^(?:\$PWD|\$\{PWD\}|\$\(\s*pwd\s*\)|`pwd`|\$\(\s*git\s+rev-parse\s+--show-toplevel\s*\))(?=$|[\\/])/;
|
|
15683
16670
|
var joinDir = (base, raw) => {
|
|
15684
16671
|
const next = raw.replace(HERE, ".");
|
|
15685
16672
|
if (base === undefined || /[$`*?]/.test(next) || next === "-")
|
|
15686
16673
|
return;
|
|
15687
|
-
const expanded = next === "~" || next.startsWith("~/") ?
|
|
15688
|
-
return base === null || isAbsolute(expanded) ? expanded :
|
|
16674
|
+
const expanded = next === "~" || next.startsWith("~/") ? path22.join(os4.homedir(), next.slice(1)) : next;
|
|
16675
|
+
return base === null || isAbsolute(expanded) ? expanded : path22.join(base, expanded);
|
|
15689
16676
|
};
|
|
15690
16677
|
var rebase = (base, inner) => inner === null ? base : inner === undefined ? undefined : joinDir(base, inner);
|
|
15691
16678
|
var cdTarget = (words) => {
|
|
@@ -15702,7 +16689,7 @@ var stripPrefixes = (input) => {
|
|
|
15702
16689
|
const first = words[0];
|
|
15703
16690
|
if (first === undefined)
|
|
15704
16691
|
return { words, env };
|
|
15705
|
-
const assignment =
|
|
16692
|
+
const assignment = ASSIGNMENT2.exec(first);
|
|
15706
16693
|
if (assignment) {
|
|
15707
16694
|
if (GIT_CONFIG_ENV.test(assignment[1]))
|
|
15708
16695
|
env[assignment[1]] = assignment[2];
|
|
@@ -15761,10 +16748,10 @@ var assignments = (words, vars) => {
|
|
|
15761
16748
|
while (rest[0]?.startsWith("-"))
|
|
15762
16749
|
rest = rest.slice(1);
|
|
15763
16750
|
}
|
|
15764
|
-
if (rest.length === 0 || !rest.every((word) =>
|
|
16751
|
+
if (rest.length === 0 || !rest.every((word) => ASSIGNMENT2.test(word)))
|
|
15765
16752
|
return null;
|
|
15766
16753
|
return rest.map((word) => {
|
|
15767
|
-
const [, name, value] =
|
|
16754
|
+
const [, name, value] = ASSIGNMENT2.exec(word);
|
|
15768
16755
|
return [name, expandWord(value, vars)];
|
|
15769
16756
|
});
|
|
15770
16757
|
};
|
|
@@ -15952,7 +16939,7 @@ var splitString = (line) => {
|
|
|
15952
16939
|
return line.slice(index).join(" ").slice(15);
|
|
15953
16940
|
if (/^-S./.test(word))
|
|
15954
16941
|
return [word.slice(2), ...line.slice(index + 1)].join(" ");
|
|
15955
|
-
if (!word.startsWith("-") && !
|
|
16942
|
+
if (!word.startsWith("-") && !ASSIGNMENT2.test(word))
|
|
15956
16943
|
return null;
|
|
15957
16944
|
}
|
|
15958
16945
|
return null;
|
|
@@ -16515,7 +17502,7 @@ var repoAt = (dir) => {
|
|
|
16515
17502
|
return { location, dir, branch: resolveTaskKey(dir, location).branch };
|
|
16516
17503
|
};
|
|
16517
17504
|
var isWorkitWorkspace = (repo) => {
|
|
16518
|
-
if (
|
|
17505
|
+
if (fs17.existsSync(repo.location.dir))
|
|
16519
17506
|
return true;
|
|
16520
17507
|
try {
|
|
16521
17508
|
return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
|
|
@@ -16536,17 +17523,17 @@ var headSha2 = (repo) => {
|
|
|
16536
17523
|
if (!git || git.reftable)
|
|
16537
17524
|
return null;
|
|
16538
17525
|
try {
|
|
16539
|
-
const head =
|
|
17526
|
+
const head = fs17.readFileSync(path22.join(git.gitDir, "HEAD"), "utf8").trim();
|
|
16540
17527
|
if (/^[0-9a-f]{40,64}$/.test(head))
|
|
16541
17528
|
return head;
|
|
16542
17529
|
const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
|
|
16543
17530
|
if (!ref)
|
|
16544
17531
|
return null;
|
|
16545
|
-
const common =
|
|
17532
|
+
const common = path22.dirname(repo.location.dir);
|
|
16546
17533
|
try {
|
|
16547
|
-
return
|
|
17534
|
+
return fs17.readFileSync(path22.join(common, ref), "utf8").trim() || null;
|
|
16548
17535
|
} catch {}
|
|
16549
|
-
const packed =
|
|
17536
|
+
const packed = fs17.readFileSync(path22.join(common, "packed-refs"), "utf8");
|
|
16550
17537
|
return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
|
|
16551
17538
|
} catch {
|
|
16552
17539
|
return null;
|
|
@@ -16558,7 +17545,7 @@ var gitConfig = (dir, invocation, cache) => {
|
|
|
16558
17545
|
if (cached)
|
|
16559
17546
|
return cached;
|
|
16560
17547
|
const config = new Map;
|
|
16561
|
-
const listed =
|
|
17548
|
+
const listed = spawnSync13("git", [...invocation.config ?? [], "config", "-z", "--list"], {
|
|
16562
17549
|
cwd: dir,
|
|
16563
17550
|
encoding: "utf8",
|
|
16564
17551
|
timeout: 3000,
|
|
@@ -16634,8 +17621,8 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
|
|
|
16634
17621
|
const sub = invocation.args[0];
|
|
16635
17622
|
if (invocation.tool !== "git" || invocation.dir === undefined || !sub || sub.startsWith("-") || GIT_COMMANDS.has(sub) || depth >= MAX_DEPTH)
|
|
16636
17623
|
return [invocation];
|
|
16637
|
-
const dir =
|
|
16638
|
-
if (!
|
|
17624
|
+
const dir = path22.resolve(root, invocation.dir ?? ".");
|
|
17625
|
+
if (!fs17.existsSync(dir))
|
|
16639
17626
|
return [invocation];
|
|
16640
17627
|
const config = gitConfig(dir, invocation, cache);
|
|
16641
17628
|
const alias = configValue(config, `alias.${sub.toLowerCase()}`);
|
|
@@ -16657,11 +17644,11 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
|
|
|
16657
17644
|
var normalizedUrl = (url, dir) => {
|
|
16658
17645
|
const trimmed = url.trim();
|
|
16659
17646
|
if (/^file:\/\//i.test(trimmed))
|
|
16660
|
-
return
|
|
17647
|
+
return path22.resolve(dir, trimmed.slice(7)).replace(/\/+$/, "").replace(/\.git$/, "");
|
|
16661
17648
|
const scheme = /^[a-z][a-z0-9+.-]*:\/\//i.exec(trimmed);
|
|
16662
17649
|
const scp = !scheme && /^(?:[^@/\\]+@)?[^/\\:]{2,}:/.test(trimmed);
|
|
16663
17650
|
if (!scheme && !scp)
|
|
16664
|
-
return
|
|
17651
|
+
return path22.resolve(dir, trimmed).replace(/\/+$/, "").replace(/\.git$/, "");
|
|
16665
17652
|
const value = scheme ? trimmed.slice(scheme[0].length).replace(/^[^@/]*@/, "").replace(/^([^/:]+):\d+(?=\/)/, "$1") : trimmed.replace(/^[^@/]*@/, "").replace(":", "/");
|
|
16666
17653
|
return value.toLowerCase().replace(/\/{2,}/g, "/").replace(/^www\./, "").replace(/\/+$/, "").replace(/\.git$/, "");
|
|
16667
17654
|
};
|
|
@@ -16722,7 +17709,7 @@ var refusal = (action, branch, dir) => {
|
|
|
16722
17709
|
};
|
|
16723
17710
|
var refFacts = (repo, remote) => {
|
|
16724
17711
|
const facts = { heads: new Set, tags: new Set, remoteHeads: new Set };
|
|
16725
|
-
const listed =
|
|
17712
|
+
const listed = spawnSync13("git", ["for-each-ref", "--format=%(refname)", "refs/heads", "refs/tags", `refs/remotes/${remote}`], { cwd: repo.dir, encoding: "utf8", timeout: 5000 });
|
|
16726
17713
|
const remotePrefix = `refs/remotes/${remote}/`;
|
|
16727
17714
|
for (const ref of (listed.stdout ?? "").split(`
|
|
16728
17715
|
`)) {
|
|
@@ -16739,7 +17726,7 @@ var globBranches = (repo, glob) => {
|
|
|
16739
17726
|
const source = glob.source.startsWith("refs/") ? glob.source : `refs/heads/${glob.source}`;
|
|
16740
17727
|
const [sourcePrefix, sourceSuffix = ""] = source.split("*");
|
|
16741
17728
|
const [destinationPrefix, destinationSuffix = ""] = glob.destination.split("*");
|
|
16742
|
-
const listed =
|
|
17729
|
+
const listed = spawnSync13("git", [
|
|
16743
17730
|
"for-each-ref",
|
|
16744
17731
|
"--format=%(refname)",
|
|
16745
17732
|
sourcePrefix.slice(0, sourcePrefix.lastIndexOf("/") + 1)
|
|
@@ -16816,7 +17803,7 @@ var tagRefusal = (action, facts, dir) => {
|
|
|
16816
17803
|
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")}).`;
|
|
16817
17804
|
};
|
|
16818
17805
|
var remoteHeads = (repo, remote) => {
|
|
16819
|
-
const listed =
|
|
17806
|
+
const listed = spawnSync13("git", ["ls-remote", "--heads", remote], {
|
|
16820
17807
|
cwd: repo.dir,
|
|
16821
17808
|
encoding: "utf8",
|
|
16822
17809
|
timeout: 3000,
|
|
@@ -16885,7 +17872,7 @@ var actionsIn = (cwd, command, dialect, cache = new Map) => {
|
|
|
16885
17872
|
const out = [];
|
|
16886
17873
|
const repos = new Map;
|
|
16887
17874
|
const repoFor = (relative) => {
|
|
16888
|
-
const dir =
|
|
17875
|
+
const dir = path22.resolve(cwd, relative ?? ".");
|
|
16889
17876
|
if (!repos.has(dir)) {
|
|
16890
17877
|
const repo = repoAt(dir);
|
|
16891
17878
|
repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
|
|
@@ -16970,7 +17957,7 @@ var analysisDenial = (error) => ({
|
|
|
16970
17957
|
unblock: SPLIT_IT
|
|
16971
17958
|
});
|
|
16972
17959
|
var MARKER_TTL_SECONDS = 3600;
|
|
16973
|
-
var markerFile = (repo, session, key) =>
|
|
17960
|
+
var markerFile = (repo, session, key) => path22.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
|
|
16974
17961
|
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash14("sha256").update(command).digest("hex")}`;
|
|
16975
17962
|
function noteRawCommit(input, command, key) {
|
|
16976
17963
|
try {
|
|
@@ -16981,14 +17968,14 @@ function noteRawCommit(input, command, key) {
|
|
|
16981
17968
|
if (action.kind !== "commit")
|
|
16982
17969
|
continue;
|
|
16983
17970
|
const file = markerFile(repo, input.session.id, key);
|
|
16984
|
-
|
|
16985
|
-
|
|
17971
|
+
fs17.mkdirSync(path22.dirname(file), { recursive: true });
|
|
17972
|
+
fs17.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
|
|
16986
17973
|
`);
|
|
16987
17974
|
}
|
|
16988
17975
|
} catch {}
|
|
16989
17976
|
}
|
|
16990
17977
|
var headCommit = (dir) => {
|
|
16991
|
-
const run =
|
|
17978
|
+
const run = spawnSync13("git", [
|
|
16992
17979
|
"log",
|
|
16993
17980
|
"-1",
|
|
16994
17981
|
"--format=%H%x1f%ct%x1f%s%x1f%(trailers:key=Workit-Session,valueonly,separator=%x2c)"
|
|
@@ -17005,11 +17992,11 @@ var headCommit = (dir) => {
|
|
|
17005
17992
|
var settle2 = (input, repo, file) => {
|
|
17006
17993
|
let marker;
|
|
17007
17994
|
try {
|
|
17008
|
-
marker = JSON.parse(
|
|
17995
|
+
marker = JSON.parse(fs17.readFileSync(file, "utf8"));
|
|
17009
17996
|
} catch {
|
|
17010
17997
|
return;
|
|
17011
17998
|
}
|
|
17012
|
-
|
|
17999
|
+
fs17.rmSync(file, { force: true });
|
|
17013
18000
|
const session = input.session.id;
|
|
17014
18001
|
const now = Date.now() / 1000;
|
|
17015
18002
|
if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
|
|
@@ -17190,7 +18177,7 @@ var targetsOf = (invocations) => invocations.flatMap((invocation) => invocation.
|
|
|
17190
18177
|
branch,
|
|
17191
18178
|
dir: invocation.dir
|
|
17192
18179
|
})) : []);
|
|
17193
|
-
var localBranchExists = (dir, branch) =>
|
|
18180
|
+
var localBranchExists = (dir, branch) => spawnSync14("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`], {
|
|
17194
18181
|
cwd: dir,
|
|
17195
18182
|
stdio: "ignore",
|
|
17196
18183
|
timeout: 5000
|
|
@@ -17200,8 +18187,8 @@ var judgedDir = (root, dir) => {
|
|
|
17200
18187
|
return null;
|
|
17201
18188
|
if (dir === null)
|
|
17202
18189
|
return root;
|
|
17203
|
-
const resolved =
|
|
17204
|
-
return
|
|
18190
|
+
const resolved = path23.resolve(root, dir);
|
|
18191
|
+
return existsSync8(resolved) && inWorkitWorkspace(resolved) ? resolved : null;
|
|
17205
18192
|
};
|
|
17206
18193
|
var shellBranchPolicyViolation = (root, command, dialect = "posix") => {
|
|
17207
18194
|
let judged = false;
|
|
@@ -17436,7 +18423,7 @@ var judgeInputSummary = (raw) => {
|
|
|
17436
18423
|
|
|
17437
18424
|
// packages/workit-core/src/autonomy.ts
|
|
17438
18425
|
import os5 from "node:os";
|
|
17439
|
-
import
|
|
18426
|
+
import path24 from "node:path";
|
|
17440
18427
|
|
|
17441
18428
|
// packages/workit-core/src/core/safe-write.ts
|
|
17442
18429
|
import {
|
|
@@ -17470,10 +18457,10 @@ var accountHome = () => {
|
|
|
17470
18457
|
}
|
|
17471
18458
|
};
|
|
17472
18459
|
var grantsHome = { resolve: accountHome };
|
|
17473
|
-
var grantsDir = () =>
|
|
18460
|
+
var grantsDir = () => path24.join(grantsHome.resolve(), ".config", "workit");
|
|
17474
18461
|
var grantsOverride = () => {
|
|
17475
|
-
const configured =
|
|
17476
|
-
return configured ===
|
|
18462
|
+
const configured = path24.resolve(resolveConfigDir());
|
|
18463
|
+
return configured === path24.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 ${path24.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
|
|
17477
18464
|
};
|
|
17478
18465
|
var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
|
|
17479
18466
|
var DEFAULT_GRANTS = Object.freeze({
|
|
@@ -17526,8 +18513,16 @@ function endpointView(entry, context) {
|
|
|
17526
18513
|
...issue ? { endpointIssue: issue } : {}
|
|
17527
18514
|
};
|
|
17528
18515
|
}
|
|
17529
|
-
var
|
|
17530
|
-
|
|
18516
|
+
var VERIFICATION_MODES = [
|
|
18517
|
+
"proportional",
|
|
18518
|
+
"self",
|
|
18519
|
+
"independent"
|
|
18520
|
+
];
|
|
18521
|
+
var DEFAULT_VERIFICATION = "proportional";
|
|
18522
|
+
var verificationOf = (entry) => {
|
|
18523
|
+
const value = entry?.verification;
|
|
18524
|
+
return VERIFICATION_MODES.includes(value) ? value : DEFAULT_VERIFICATION;
|
|
18525
|
+
};
|
|
17531
18526
|
var isGrantValue = (value) => value === true || value === false || value === "verified";
|
|
17532
18527
|
var normalized = (kind, value) => value === "verified" && kind !== "merge" ? true : value;
|
|
17533
18528
|
var fromAutoApprove = (value) => {
|
|
@@ -19273,10 +20268,10 @@ class WorkitCore {
|
|
|
19273
20268
|
return this.summary(changed.data.task);
|
|
19274
20269
|
}
|
|
19275
20270
|
}
|
|
19276
|
-
// packages/workit-core/src/core/repo-context.ts
|
|
19277
|
-
import { spawnSync as
|
|
19278
|
-
import { existsSync as
|
|
19279
|
-
import
|
|
20271
|
+
// packages/workit-core/src/core/repo-context.ts
|
|
20272
|
+
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
20273
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, readdirSync as readdirSync4 } from "node:fs";
|
|
20274
|
+
import path25 from "node:path";
|
|
19280
20275
|
var isSafeContextRange = (value) => value.length <= 4096 && (() => {
|
|
19281
20276
|
try {
|
|
19282
20277
|
gitRevisionParts(value);
|
|
@@ -19303,7 +20298,7 @@ var invalidRange = (cwd) => ({
|
|
|
19303
20298
|
cwd
|
|
19304
20299
|
});
|
|
19305
20300
|
var runGit = (cwd, args) => {
|
|
19306
|
-
const result =
|
|
20301
|
+
const result = spawnSync15("git", args, { cwd, encoding: "utf8" });
|
|
19307
20302
|
return {
|
|
19308
20303
|
stdout: (result.stdout ?? "").trimEnd(),
|
|
19309
20304
|
stderr: (result.stderr ?? "").trimEnd(),
|
|
@@ -19410,7 +20405,7 @@ var findPrTemplate = (cwd) => {
|
|
|
19410
20405
|
]) {
|
|
19411
20406
|
const parts = rel.split("/");
|
|
19412
20407
|
const base = parts[parts.length - 1];
|
|
19413
|
-
const dir = parts.length > 1 ?
|
|
20408
|
+
const dir = parts.length > 1 ? path25.join(cwd, ...parts.slice(0, -1)) : cwd;
|
|
19414
20409
|
const actual = probeCaseInsensitive(dir, base);
|
|
19415
20410
|
if (actual)
|
|
19416
20411
|
return [...parts.slice(0, -1), actual].join("/");
|
|
@@ -19441,11 +20436,11 @@ var diffStatForRange = (cwd, range) => {
|
|
|
19441
20436
|
return runGit(cwd, ["diff", "--stat", "--"]).stdout;
|
|
19442
20437
|
};
|
|
19443
20438
|
var packageScripts = (cwd, keys) => {
|
|
19444
|
-
const pkgPath =
|
|
19445
|
-
if (!
|
|
20439
|
+
const pkgPath = path25.join(cwd, "package.json");
|
|
20440
|
+
if (!existsSync9(pkgPath))
|
|
19446
20441
|
return [];
|
|
19447
20442
|
try {
|
|
19448
|
-
const pkg = JSON.parse(
|
|
20443
|
+
const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
19449
20444
|
return keys.filter((k) => pkg.scripts && typeof pkg.scripts[k] === "string").map((k) => `${k}: ${pkg.scripts?.[k]}`);
|
|
19450
20445
|
} catch {
|
|
19451
20446
|
return [];
|
|
@@ -19467,9 +20462,9 @@ var documentationFiles = (cwd) => {
|
|
|
19467
20462
|
if (entry.isDirectory()) {
|
|
19468
20463
|
if (excluded.has(entry.name))
|
|
19469
20464
|
continue;
|
|
19470
|
-
walk(
|
|
20465
|
+
walk(path25.join(dir, entry.name), depth + 1);
|
|
19471
20466
|
} else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
|
|
19472
|
-
matches.push("./" +
|
|
20467
|
+
matches.push("./" + path25.relative(cwd, path25.join(dir, entry.name)).replaceAll("\\", "/"));
|
|
19473
20468
|
}
|
|
19474
20469
|
}
|
|
19475
20470
|
};
|
|
@@ -19477,15 +20472,15 @@ var documentationFiles = (cwd) => {
|
|
|
19477
20472
|
return matches.toSorted().slice(0, 200);
|
|
19478
20473
|
};
|
|
19479
20474
|
var readTrimmed2 = (file, maxLines) => {
|
|
19480
|
-
if (!
|
|
20475
|
+
if (!existsSync9(file))
|
|
19481
20476
|
return "";
|
|
19482
|
-
const lines =
|
|
20477
|
+
const lines = readFileSync7(file, "utf8").split(`
|
|
19483
20478
|
`);
|
|
19484
20479
|
return lines.slice(0, maxLines).join(`
|
|
19485
20480
|
`);
|
|
19486
20481
|
};
|
|
19487
20482
|
function prReadyContext(root, range) {
|
|
19488
|
-
const cwd =
|
|
20483
|
+
const cwd = path25.resolve(repoRoot(root));
|
|
19489
20484
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
19490
20485
|
return invalidRange(cwd);
|
|
19491
20486
|
let stdout = "";
|
|
@@ -19543,7 +20538,7 @@ ${status.stderr}` : "");
|
|
|
19543
20538
|
stdout += `template_path: ${template}
|
|
19544
20539
|
|
|
19545
20540
|
`;
|
|
19546
|
-
stdout += readTrimmed2(
|
|
20541
|
+
stdout += readTrimmed2(path25.join(cwd, template), 220);
|
|
19547
20542
|
} else {
|
|
19548
20543
|
stdout += `template_path: none
|
|
19549
20544
|
|
|
@@ -19553,7 +20548,7 @@ ${status.stderr}` : "");
|
|
|
19553
20548
|
stdout += `
|
|
19554
20549
|
`;
|
|
19555
20550
|
stdout += printSection("Recent Validation Signals");
|
|
19556
|
-
if (
|
|
20551
|
+
if (existsSync9(path25.join(cwd, "package.json"))) {
|
|
19557
20552
|
stdout += `package.json detected. Common scripts:
|
|
19558
20553
|
`;
|
|
19559
20554
|
const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
|
|
@@ -19562,7 +20557,7 @@ ${status.stderr}` : "");
|
|
|
19562
20557
|
`) + `
|
|
19563
20558
|
`;
|
|
19564
20559
|
}
|
|
19565
|
-
if (
|
|
20560
|
+
if (existsSync9(path25.join(cwd, "Cargo.toml")) || existsSync9(path25.join(cwd, "src-tauri/Cargo.toml"))) {
|
|
19566
20561
|
stdout += `Rust project detected.
|
|
19567
20562
|
`;
|
|
19568
20563
|
}
|
|
@@ -19595,7 +20590,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
|
|
|
19595
20590
|
- Apply with the host-native editor, preserving the repository changelog conventions.
|
|
19596
20591
|
- If Unreleased already has duplicate category headings, normalize_only first.`;
|
|
19597
20592
|
function changelogContext(root, range) {
|
|
19598
|
-
const cwd =
|
|
20593
|
+
const cwd = path25.resolve(repoRoot(root));
|
|
19599
20594
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
19600
20595
|
return invalidRange(cwd);
|
|
19601
20596
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -19613,8 +20608,8 @@ function changelogContext(root, range) {
|
|
|
19613
20608
|
stdout += CHANGELOG_RULES + `
|
|
19614
20609
|
`;
|
|
19615
20610
|
stdout += printSection("Existing CHANGELOG.md");
|
|
19616
|
-
const changelogPath =
|
|
19617
|
-
if (
|
|
20611
|
+
const changelogPath = path25.join(cwd, "CHANGELOG.md");
|
|
20612
|
+
if (existsSync9(changelogPath)) {
|
|
19618
20613
|
stdout += readTrimmed2(changelogPath, 260) + `
|
|
19619
20614
|
`;
|
|
19620
20615
|
} else {
|
|
@@ -19633,7 +20628,7 @@ function changelogContext(root, range) {
|
|
|
19633
20628
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
19634
20629
|
}
|
|
19635
20630
|
function docsRefreshContext(root, range) {
|
|
19636
|
-
const cwd =
|
|
20631
|
+
const cwd = path25.resolve(repoRoot(root));
|
|
19637
20632
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
19638
20633
|
return invalidRange(cwd);
|
|
19639
20634
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -19655,8 +20650,8 @@ function docsRefreshContext(root, range) {
|
|
|
19655
20650
|
`) + `
|
|
19656
20651
|
`;
|
|
19657
20652
|
stdout += printSection("README Preview");
|
|
19658
|
-
const readme =
|
|
19659
|
-
if (
|
|
20653
|
+
const readme = path25.join(cwd, "README.md");
|
|
20654
|
+
if (existsSync9(readme)) {
|
|
19660
20655
|
stdout += readTrimmed2(readme, 220) + `
|
|
19661
20656
|
`;
|
|
19662
20657
|
} else {
|
|
@@ -19664,10 +20659,10 @@ function docsRefreshContext(root, range) {
|
|
|
19664
20659
|
`;
|
|
19665
20660
|
}
|
|
19666
20661
|
stdout += printSection("Package Scripts");
|
|
19667
|
-
const pkgPath =
|
|
19668
|
-
if (
|
|
20662
|
+
const pkgPath = path25.join(cwd, "package.json");
|
|
20663
|
+
if (existsSync9(pkgPath)) {
|
|
19669
20664
|
try {
|
|
19670
|
-
const pkg = JSON.parse(
|
|
20665
|
+
const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
19671
20666
|
stdout += JSON.stringify({ name: pkg.name, version: pkg.version, scripts: pkg.scripts }, null, 2) + `
|
|
19672
20667
|
`;
|
|
19673
20668
|
} catch {}
|
|
@@ -19678,7 +20673,7 @@ function docsRefreshContext(root, range) {
|
|
|
19678
20673
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
19679
20674
|
}
|
|
19680
20675
|
function releaseNotesContext(root, rangeOrTag) {
|
|
19681
|
-
const cwd =
|
|
20676
|
+
const cwd = path25.resolve(repoRoot(root));
|
|
19682
20677
|
if (!rangeOrTag) {
|
|
19683
20678
|
return { stdout: "", stderr: `ERROR: release tag or range required
|
|
19684
20679
|
`, exitCode: 1, cwd };
|
|
@@ -19716,7 +20711,7 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
19716
20711
|
`;
|
|
19717
20712
|
stdout += printSection("Existing Release Files");
|
|
19718
20713
|
for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
|
|
19719
|
-
if (
|
|
20714
|
+
if (existsSync9(path25.join(cwd, rel)))
|
|
19720
20715
|
stdout += rel + `
|
|
19721
20716
|
`;
|
|
19722
20717
|
}
|
|
@@ -19744,81 +20739,7 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
19744
20739
|
}
|
|
19745
20740
|
|
|
19746
20741
|
// packages/workit-core/src/core/tracker-issues.ts
|
|
19747
|
-
import { spawnSync as
|
|
19748
|
-
|
|
19749
|
-
// packages/workit-core/src/core/pr-create.ts
|
|
19750
|
-
import fs17 from "node:fs";
|
|
19751
|
-
import path23 from "node:path";
|
|
19752
|
-
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
19753
|
-
import { pathToFileURL } from "node:url";
|
|
19754
|
-
// packages/workit-core/src/forge/pr-body.ts
|
|
19755
|
-
function parseGhIssue(value) {
|
|
19756
|
-
const m = /issues\/(\d+)/.exec(value);
|
|
19757
|
-
return m ? m[1] : String(value).trim().replace(/^#/, "");
|
|
19758
|
-
}
|
|
19759
|
-
|
|
19760
|
-
// packages/workit-core/src/core/pr-create.ts
|
|
19761
|
-
function whichOnPath(tool) {
|
|
19762
|
-
const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
|
|
19763
|
-
for (const dir of (process.env.PATH ?? "").split(path23.delimiter)) {
|
|
19764
|
-
if (!dir)
|
|
19765
|
-
continue;
|
|
19766
|
-
for (const name of names) {
|
|
19767
|
-
const candidate = path23.join(dir, name);
|
|
19768
|
-
try {
|
|
19769
|
-
fs17.accessSync(candidate, fs17.constants.X_OK);
|
|
19770
|
-
return candidate;
|
|
19771
|
-
} catch {}
|
|
19772
|
-
}
|
|
19773
|
-
}
|
|
19774
|
-
return null;
|
|
19775
|
-
}
|
|
19776
|
-
var hostingCliAvailable = (provider) => whichOnPath(provider === "gitlab" ? "glab" : "gh") !== null;
|
|
19777
|
-
var pushRemote = (cwd) => {
|
|
19778
|
-
const result = spawnSync14("git", ["remote", "get-url", "--push", "--all", "origin"], {
|
|
19779
|
-
cwd,
|
|
19780
|
-
encoding: "utf8"
|
|
19781
|
-
});
|
|
19782
|
-
if (result.status !== 0)
|
|
19783
|
-
return null;
|
|
19784
|
-
const urls = (result.stdout ?? "").split(/\r?\n/u).map((url) => url.trim()).filter(Boolean);
|
|
19785
|
-
return urls.length === 1 ? urls[0] : null;
|
|
19786
|
-
};
|
|
19787
|
-
var safePushUrl = (remote) => {
|
|
19788
|
-
const raw = remote.trim();
|
|
19789
|
-
if (path23.isAbsolute(raw))
|
|
19790
|
-
return pathToFileURL(raw).href;
|
|
19791
|
-
if (!raw.includes("://")) {
|
|
19792
|
-
const scp = /^(?:([^@\s]+)@)?([^:]+):(.+)$/u.exec(raw);
|
|
19793
|
-
if (scp)
|
|
19794
|
-
return `${scp[1] || "git"}@${scp[2]}:${scp[3]}`;
|
|
19795
|
-
}
|
|
19796
|
-
try {
|
|
19797
|
-
const url = new URL(raw);
|
|
19798
|
-
if (!["file:", "git:", "http:", "https:", "ssh:"].includes(url.protocol))
|
|
19799
|
-
return null;
|
|
19800
|
-
url.password = "";
|
|
19801
|
-
if (url.protocol !== "ssh:")
|
|
19802
|
-
url.username = "";
|
|
19803
|
-
url.search = "";
|
|
19804
|
-
url.hash = "";
|
|
19805
|
-
return url.toString();
|
|
19806
|
-
} catch {
|
|
19807
|
-
return null;
|
|
19808
|
-
}
|
|
19809
|
-
};
|
|
19810
|
-
var pushTargetIsStable = (cwd, remote) => {
|
|
19811
|
-
const target = safePushUrl(remote);
|
|
19812
|
-
if (!target)
|
|
19813
|
-
return false;
|
|
19814
|
-
const result = spawnSync14("git", ["config", "--get-regexp", "^url\\..*\\.(insteadof|pushinsteadof)$"], { cwd, encoding: "utf8" });
|
|
19815
|
-
if (result.status !== 0 && result.status !== 1)
|
|
19816
|
-
return false;
|
|
19817
|
-
const prefixes = (result.stdout ?? "").split(/\r?\n/u).map((line) => line.trim().slice(line.trim().indexOf(" ") + 1)).filter(Boolean);
|
|
19818
|
-
return !prefixes.some((prefix) => target.startsWith(prefix));
|
|
19819
|
-
};
|
|
19820
|
-
|
|
19821
|
-
// packages/workit-core/src/core/tracker-issues.ts
|
|
20742
|
+
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
19822
20743
|
var repoPathFromRemote = (remote) => {
|
|
19823
20744
|
let rest = (remote || "").trim().replace(/\/+$/, "");
|
|
19824
20745
|
if (!rest)
|
|
@@ -19839,7 +20760,7 @@ var defaultCli = (bin, available) => {
|
|
|
19839
20760
|
if (!available)
|
|
19840
20761
|
return null;
|
|
19841
20762
|
return (args, root) => {
|
|
19842
|
-
const out =
|
|
20763
|
+
const out = spawnSync16(bin, args, {
|
|
19843
20764
|
cwd: root,
|
|
19844
20765
|
encoding: "utf8",
|
|
19845
20766
|
env: { ...process.env, PATH: process.env.PATH ?? "" }
|
|
@@ -19918,7 +20839,7 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
|
|
|
19918
20839
|
|
|
19919
20840
|
// packages/workit-core/src/core/youtrack.ts
|
|
19920
20841
|
import fs18 from "node:fs";
|
|
19921
|
-
import
|
|
20842
|
+
import path26 from "node:path";
|
|
19922
20843
|
|
|
19923
20844
|
// packages/workit-core/src/core/templates.ts
|
|
19924
20845
|
var repoRoot2 = assetRoot();
|
|
@@ -19931,8 +20852,8 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
|
|
|
19931
20852
|
// packages/workit-core/src/core/youtrack.ts
|
|
19932
20853
|
var ISSUE_RE = /^[A-Z]+-\d+$/;
|
|
19933
20854
|
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
19934
|
-
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
19935
|
-
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
20855
|
+
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path26.join(configDir(), "youtrack.json");
|
|
20856
|
+
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path26.join(resolveConfigDir(), "youtrack.json");
|
|
19936
20857
|
var youTrackTokenModeOk = (p) => {
|
|
19937
20858
|
if (process.platform === "win32")
|
|
19938
20859
|
return true;
|
|
@@ -20000,7 +20921,7 @@ var youTrackToken = () => {
|
|
|
20000
20921
|
if ("error" in loaded)
|
|
20001
20922
|
return loaded;
|
|
20002
20923
|
const tokenFile = String(loaded.config.tokenFile ?? "");
|
|
20003
|
-
const tokenPath = tokenFile ?
|
|
20924
|
+
const tokenPath = tokenFile ? path26.isAbsolute(tokenFile) ? path26.resolve(tokenFile) : path26.resolve(process.cwd(), tokenFile) : "";
|
|
20004
20925
|
if (!tokenPath || !fs18.existsSync(tokenPath))
|
|
20005
20926
|
return { error: "missing youtrack.token" };
|
|
20006
20927
|
if (!youTrackTokenModeOk(tokenPath))
|
|
@@ -20051,7 +20972,7 @@ function youTrackTokenCreateUrl() {
|
|
|
20051
20972
|
const desc = String(defaults.description ?? "OpenCode workit — /wk-issue-update and /wk-meetings");
|
|
20052
20973
|
const scopes = Array.isArray(defaults.scopes) ? defaults.scopes : ["YouTrack"];
|
|
20053
20974
|
const base = String(config.baseUrl ?? "").replace(/\/+$/, "");
|
|
20054
|
-
const tokenFile = String(config.tokenFile ??
|
|
20975
|
+
const tokenFile = String(config.tokenFile ?? path26.join(path26.dirname(loaded.path), "youtrack.token"));
|
|
20055
20976
|
const tab = String(defaults.profileTab ?? "account-security");
|
|
20056
20977
|
const createUrl = base ? `${base}/users/me?${new URLSearchParams({ tab })}` : null;
|
|
20057
20978
|
const docsUrl = "https://www.jetbrains.com/help/youtrack/cloud/manage-permanent-token.html";
|
|
@@ -20060,7 +20981,7 @@ function youTrackTokenCreateUrl() {
|
|
|
20060
20981
|
tokenName: name,
|
|
20061
20982
|
tokenDescription: desc,
|
|
20062
20983
|
scopes,
|
|
20063
|
-
tokenFile:
|
|
20984
|
+
tokenFile: path26.resolve(tokenFile),
|
|
20064
20985
|
createUrl,
|
|
20065
20986
|
docsUrl,
|
|
20066
20987
|
prefillSupported: false,
|
|
@@ -20400,22 +21321,22 @@ function resolveGitRevision(root, value) {
|
|
|
20400
21321
|
}
|
|
20401
21322
|
function resolveInside(root, candidate) {
|
|
20402
21323
|
const base = realpathSync5(root);
|
|
20403
|
-
const target =
|
|
20404
|
-
if (target !== base && !target.startsWith(base +
|
|
21324
|
+
const target = path27.resolve(base, candidate);
|
|
21325
|
+
if (target !== base && !target.startsWith(base + path27.sep)) {
|
|
20405
21326
|
throw new Error("path must stay inside repository root");
|
|
20406
21327
|
}
|
|
20407
21328
|
let ancestor = target;
|
|
20408
|
-
while (!
|
|
20409
|
-
ancestor =
|
|
21329
|
+
while (!existsSync10(ancestor))
|
|
21330
|
+
ancestor = path27.dirname(ancestor);
|
|
20410
21331
|
const canonicalAncestor = realpathSync5(ancestor);
|
|
20411
|
-
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base +
|
|
21332
|
+
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path27.sep)) {
|
|
20412
21333
|
throw new Error("path must stay inside repository root");
|
|
20413
21334
|
}
|
|
20414
21335
|
return target;
|
|
20415
21336
|
}
|
|
20416
21337
|
function run2(root, executable, args, env = {}) {
|
|
20417
21338
|
const cwd = realpathSync5(root);
|
|
20418
|
-
const result =
|
|
21339
|
+
const result = spawnSync17(executable, args, {
|
|
20419
21340
|
cwd,
|
|
20420
21341
|
encoding: "utf8",
|
|
20421
21342
|
env: { ...process.env, ...env }
|
|
@@ -20452,7 +21373,7 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
|
|
|
20452
21373
|
};
|
|
20453
21374
|
});
|
|
20454
21375
|
// packages/workit-core/src/hooks/context.ts
|
|
20455
|
-
import
|
|
21376
|
+
import path28 from "node:path";
|
|
20456
21377
|
var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
|
|
20457
21378
|
var migrationPending = (result) => !result.ok && result.code === "needs_input" && (result.error ?? "").startsWith(MIGRATION_PENDING);
|
|
20458
21379
|
var boundTo = (entry, session) => entry.sessions.some((item) => item.host === session.host && item.handle === session.handle);
|
|
@@ -20537,7 +21458,7 @@ function entryCompactContext(store, entry, session, context) {
|
|
|
20537
21458
|
return null;
|
|
20538
21459
|
const freshness = { mode: "signal", current: () => recentSignal(store.root) };
|
|
20539
21460
|
const observed = task?.data.evidence.some(isObservedCheck) ?? false;
|
|
20540
|
-
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [
|
|
21461
|
+
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path28.resolve(store.root, ref.path)] : []));
|
|
20541
21462
|
const observedFiles = filesKey(files);
|
|
20542
21463
|
const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
|
|
20543
21464
|
if (!compact.ok || !compact.data)
|
|
@@ -20570,7 +21491,7 @@ var shellPolicy = (cwd, command, dialect = "posix") => {
|
|
|
20570
21491
|
// packages/workit-core/src/core/heavy-rules.ts
|
|
20571
21492
|
import fs19 from "node:fs";
|
|
20572
21493
|
import os6 from "node:os";
|
|
20573
|
-
import
|
|
21494
|
+
import path29 from "node:path";
|
|
20574
21495
|
var EMPTY2 = () => ({ deny: [], allow: [] });
|
|
20575
21496
|
var readText2 = (file) => {
|
|
20576
21497
|
try {
|
|
@@ -20611,19 +21532,19 @@ function parseJsonc(text) {
|
|
|
20611
21532
|
return JSON.parse(out.replace(/,(\s*[}\]])/gu, "$1"));
|
|
20612
21533
|
}
|
|
20613
21534
|
function gitTop(cwd) {
|
|
20614
|
-
for (let dir =
|
|
20615
|
-
if (fs19.existsSync(
|
|
21535
|
+
for (let dir = path29.resolve(cwd);; dir = path29.dirname(dir)) {
|
|
21536
|
+
if (fs19.existsSync(path29.join(dir, ".git")))
|
|
20616
21537
|
return dir;
|
|
20617
|
-
if (
|
|
21538
|
+
if (path29.dirname(dir) === dir)
|
|
20618
21539
|
return null;
|
|
20619
21540
|
}
|
|
20620
21541
|
}
|
|
20621
21542
|
var projectDirs = (cwd) => {
|
|
20622
21543
|
const top = gitTop(cwd);
|
|
20623
21544
|
const dirs = [];
|
|
20624
|
-
for (let dir =
|
|
21545
|
+
for (let dir = path29.resolve(cwd);; dir = path29.dirname(dir)) {
|
|
20625
21546
|
dirs.push(dir);
|
|
20626
|
-
if (!top || dir === top ||
|
|
21547
|
+
if (!top || dir === top || path29.dirname(dir) === dir)
|
|
20627
21548
|
return dirs;
|
|
20628
21549
|
}
|
|
20629
21550
|
};
|
|
@@ -20635,12 +21556,12 @@ var CLAUDE_MANAGED = {
|
|
|
20635
21556
|
};
|
|
20636
21557
|
function claudeSettingsFiles(cwd, env, platform = process.platform) {
|
|
20637
21558
|
const project = env.CLAUDE_PROJECT_DIR || gitTop(cwd) || cwd;
|
|
20638
|
-
const user = env.CLAUDE_CONFIG_DIR ||
|
|
21559
|
+
const user = env.CLAUDE_CONFIG_DIR || path29.join(homeOf(env), ".claude");
|
|
20639
21560
|
return [
|
|
20640
21561
|
...CLAUDE_MANAGED[platform] ? [CLAUDE_MANAGED[platform]] : [],
|
|
20641
|
-
|
|
20642
|
-
|
|
20643
|
-
|
|
21562
|
+
path29.join(user, "settings.json"),
|
|
21563
|
+
path29.join(project, ".claude", "settings.json"),
|
|
21564
|
+
path29.join(project, ".claude", "settings.local.json")
|
|
20644
21565
|
];
|
|
20645
21566
|
}
|
|
20646
21567
|
var bashPattern = (entry) => {
|
|
@@ -20730,10 +21651,10 @@ var opencodeConfig = (value, rules) => {
|
|
|
20730
21651
|
function opencodeRules(cwd, env = process.env) {
|
|
20731
21652
|
const rules = EMPTY2();
|
|
20732
21653
|
try {
|
|
20733
|
-
const config = env.XDG_CONFIG_HOME ||
|
|
21654
|
+
const config = env.XDG_CONFIG_HOME || path29.join(homeOf(env), ".config");
|
|
20734
21655
|
const files = [
|
|
20735
|
-
...OPENCODE_NAMES.map((name) =>
|
|
20736
|
-
...projectDirs(cwd).flatMap((dir) => OPENCODE_NAMES.flatMap((name) => [
|
|
21656
|
+
...OPENCODE_NAMES.map((name) => path29.join(config, "opencode", name)),
|
|
21657
|
+
...projectDirs(cwd).flatMap((dir) => OPENCODE_NAMES.flatMap((name) => [path29.join(dir, name), path29.join(dir, ".opencode", name)])),
|
|
20737
21658
|
...env.OPENCODE_CONFIG ? [env.OPENCODE_CONFIG] : []
|
|
20738
21659
|
];
|
|
20739
21660
|
for (const file of files) {
|
|
@@ -20777,9 +21698,9 @@ var codexRule = (body) => {
|
|
|
20777
21698
|
function codexRules(cwd, env = process.env) {
|
|
20778
21699
|
const rules = EMPTY2();
|
|
20779
21700
|
try {
|
|
20780
|
-
const home = env.CODEX_HOME ||
|
|
21701
|
+
const home = env.CODEX_HOME || path29.join(homeOf(env), ".codex");
|
|
20781
21702
|
const top = gitTop(cwd) ?? cwd;
|
|
20782
|
-
for (const dir of [
|
|
21703
|
+
for (const dir of [path29.join(home, "rules"), path29.join(top, ".codex", "rules")]) {
|
|
20783
21704
|
let files;
|
|
20784
21705
|
try {
|
|
20785
21706
|
files = fs19.readdirSync(dir).filter((name) => name.endsWith(".rules"));
|
|
@@ -20789,7 +21710,7 @@ function codexRules(cwd, env = process.env) {
|
|
|
20789
21710
|
return "unreadable";
|
|
20790
21711
|
}
|
|
20791
21712
|
for (const name of files) {
|
|
20792
|
-
const text = readText2(
|
|
21713
|
+
const text = readText2(path29.join(dir, name)) ?? "";
|
|
20793
21714
|
for (const part of text.split(/\bprefix_rule\s*\(/u).slice(1)) {
|
|
20794
21715
|
const rule = codexRule(part);
|
|
20795
21716
|
if (!rule)
|
|
@@ -20808,8 +21729,8 @@ function cursorRules(cwd, env = process.env) {
|
|
|
20808
21729
|
try {
|
|
20809
21730
|
const top = gitTop(cwd) ?? cwd;
|
|
20810
21731
|
for (const file of [
|
|
20811
|
-
|
|
20812
|
-
|
|
21732
|
+
path29.join(homeOf(env), ".cursor", "cli-config.json"),
|
|
21733
|
+
path29.join(top, ".cursor", "cli.json")
|
|
20813
21734
|
]) {
|
|
20814
21735
|
const text = readText2(file);
|
|
20815
21736
|
if (text === null)
|
|
@@ -20885,21 +21806,21 @@ function wrapAllowed(read, words, command, options = {}) {
|
|
|
20885
21806
|
// packages/workit-core/src/core/heavy.ts
|
|
20886
21807
|
import fs20 from "node:fs";
|
|
20887
21808
|
import os7 from "node:os";
|
|
20888
|
-
import
|
|
21809
|
+
import path30 from "node:path";
|
|
20889
21810
|
function stateDir(env, platform = process.platform) {
|
|
20890
21811
|
if (env.WORKFLOW_TOOLKIT_STATE)
|
|
20891
21812
|
return env.WORKFLOW_TOOLKIT_STATE;
|
|
20892
21813
|
if (env.XDG_STATE_HOME)
|
|
20893
|
-
return
|
|
21814
|
+
return path30.join(env.XDG_STATE_HOME, "workit");
|
|
20894
21815
|
const home = env.HOME || os7.homedir();
|
|
20895
21816
|
if (platform === "darwin")
|
|
20896
|
-
return
|
|
21817
|
+
return path30.join(home, "Library", "Application Support", "workit");
|
|
20897
21818
|
if (platform === "win32")
|
|
20898
|
-
return
|
|
20899
|
-
return
|
|
21819
|
+
return path30.join(env.LOCALAPPDATA ?? path30.join(home, "AppData", "Local"), "workit");
|
|
21820
|
+
return path30.join(home, ".local", "state", "workit");
|
|
20900
21821
|
}
|
|
20901
21822
|
var HEAVY_COMMANDS_FILE = "heavy-commands.json";
|
|
20902
|
-
var heavyCommandsFile = (env) =>
|
|
21823
|
+
var heavyCommandsFile = (env) => path30.join(stateDir(env), HEAVY_COMMANDS_FILE);
|
|
20903
21824
|
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;
|
|
20904
21825
|
var INFO_FLAGS = new Set(["--version", "-v", "-V", "--help", "-h", "help", "version"]);
|
|
20905
21826
|
var WATCH_FLAG = /^(?:--watch(?:All)?(?:=.*)?|-w|--serve)$/u;
|
|
@@ -21174,7 +22095,7 @@ function machinePatterns(env) {
|
|
|
21174
22095
|
return isRecord5(value) ? stringList(value.patterns) : [];
|
|
21175
22096
|
}
|
|
21176
22097
|
function repoPatterns(cwd) {
|
|
21177
|
-
return repoHeavyCommands(gitTop(cwd) ??
|
|
22098
|
+
return repoHeavyCommands(gitTop(cwd) ?? path30.resolve(cwd));
|
|
21178
22099
|
}
|
|
21179
22100
|
function heavyLines(lines, options) {
|
|
21180
22101
|
const found = [];
|
|
@@ -21252,12 +22173,12 @@ function heavyPlan(command, options) {
|
|
|
21252
22173
|
}
|
|
21253
22174
|
function workitOnPath2(env = process.env) {
|
|
21254
22175
|
const names = process.platform === "win32" ? ["workit.exe", "workit.cmd", "workit"] : ["workit"];
|
|
21255
|
-
for (const dir of (env.PATH ?? "").split(
|
|
22176
|
+
for (const dir of (env.PATH ?? "").split(path30.delimiter))
|
|
21256
22177
|
for (const name of names) {
|
|
21257
22178
|
if (!dir)
|
|
21258
22179
|
continue;
|
|
21259
22180
|
try {
|
|
21260
|
-
fs20.accessSync(
|
|
22181
|
+
fs20.accessSync(path30.join(dir, name), fs20.constants.X_OK);
|
|
21261
22182
|
return true;
|
|
21262
22183
|
} catch {}
|
|
21263
22184
|
}
|
|
@@ -21276,20 +22197,20 @@ function leaseRewrite(command) {
|
|
|
21276
22197
|
// packages/workit-core/src/core/heavy-words.ts
|
|
21277
22198
|
import fs21 from "node:fs";
|
|
21278
22199
|
import os8 from "node:os";
|
|
21279
|
-
import
|
|
22200
|
+
import path31 from "node:path";
|
|
21280
22201
|
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(" "));
|
|
21281
22202
|
var wordsOf = (command) => command.split(/[\s;&|()<>`'"]+/u).map((word) => (word.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat)$/u, "")).filter(Boolean);
|
|
21282
22203
|
var stateDir2 = (env) => {
|
|
21283
22204
|
if (env.WORKFLOW_TOOLKIT_STATE)
|
|
21284
22205
|
return env.WORKFLOW_TOOLKIT_STATE;
|
|
21285
22206
|
if (env.XDG_STATE_HOME)
|
|
21286
|
-
return
|
|
22207
|
+
return path31.join(env.XDG_STATE_HOME, "workit");
|
|
21287
22208
|
const home = env.HOME || os8.homedir();
|
|
21288
22209
|
if (process.platform === "darwin")
|
|
21289
|
-
return
|
|
22210
|
+
return path31.join(home, "Library", "Application Support", "workit");
|
|
21290
22211
|
if (process.platform === "win32")
|
|
21291
|
-
return
|
|
21292
|
-
return
|
|
22212
|
+
return path31.join(env.LOCALAPPDATA ?? path31.join(home, "AppData", "Local"), "workit");
|
|
22213
|
+
return path31.join(home, ".local", "state", "workit");
|
|
21293
22214
|
};
|
|
21294
22215
|
var readJson2 = (file) => {
|
|
21295
22216
|
try {
|
|
@@ -21300,15 +22221,15 @@ var readJson2 = (file) => {
|
|
|
21300
22221
|
};
|
|
21301
22222
|
var patternWords = (cwd, env) => {
|
|
21302
22223
|
const patterns = [];
|
|
21303
|
-
const machine = readJson2(
|
|
22224
|
+
const machine = readJson2(path31.join(stateDir2(env), "heavy-commands.json"));
|
|
21304
22225
|
if (Array.isArray(machine?.patterns))
|
|
21305
22226
|
patterns.push(...machine.patterns);
|
|
21306
|
-
for (let dir =
|
|
21307
|
-
if (fs21.existsSync(
|
|
22227
|
+
for (let dir = path31.resolve(cwd);; dir = path31.dirname(dir)) {
|
|
22228
|
+
if (fs21.existsSync(path31.join(dir, ".git"))) {
|
|
21308
22229
|
patterns.push(...repoHeavyCommands(dir));
|
|
21309
22230
|
break;
|
|
21310
22231
|
}
|
|
21311
|
-
if (
|
|
22232
|
+
if (path31.dirname(dir) === dir)
|
|
21312
22233
|
break;
|
|
21313
22234
|
}
|
|
21314
22235
|
const words = new Set;
|
|
@@ -21367,21 +22288,21 @@ function heavyGate(cwd, command, options) {
|
|
|
21367
22288
|
}
|
|
21368
22289
|
}
|
|
21369
22290
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
21370
|
-
import { existsSync as
|
|
22291
|
+
import { existsSync as existsSync11, realpathSync as realpathSync6 } from "node:fs";
|
|
21371
22292
|
import os10 from "node:os";
|
|
21372
|
-
import
|
|
22293
|
+
import path33 from "node:path";
|
|
21373
22294
|
|
|
21374
22295
|
// packages/workit-core/src/core/live-session.ts
|
|
21375
|
-
import { spawnSync as
|
|
22296
|
+
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
21376
22297
|
import { createHash as createHash15 } from "node:crypto";
|
|
21377
22298
|
import fs22 from "node:fs";
|
|
21378
22299
|
import os9 from "node:os";
|
|
21379
|
-
import
|
|
22300
|
+
import path32 from "node:path";
|
|
21380
22301
|
var LIVE_SESSION_TTL_MS = 15 * 60000;
|
|
21381
22302
|
var HEARTBEAT_EVERY_MS = 30000;
|
|
21382
22303
|
var liveProbe = {
|
|
21383
22304
|
platform: process.platform,
|
|
21384
|
-
run: (args) =>
|
|
22305
|
+
run: (args) => spawnSync18("ps", args, { encoding: "utf8", timeout: 2000 }).stdout ?? "",
|
|
21385
22306
|
start: (pid) => processStartOf(pid)
|
|
21386
22307
|
};
|
|
21387
22308
|
var leadOf = (session) => session.split(":")[0].replace(/-w-.*$/su, "") || session;
|
|
@@ -21450,15 +22371,15 @@ var liveOwner = (input, transport, env = process.env) => {
|
|
|
21450
22371
|
};
|
|
21451
22372
|
};
|
|
21452
22373
|
var checkoutOf = (target) => {
|
|
21453
|
-
let dir =
|
|
21454
|
-
while (!fs22.existsSync(dir) &&
|
|
21455
|
-
dir =
|
|
22374
|
+
let dir = path32.resolve(target);
|
|
22375
|
+
while (!fs22.existsSync(dir) && path32.dirname(dir) !== dir)
|
|
22376
|
+
dir = path32.dirname(dir);
|
|
21456
22377
|
if (fs22.existsSync(dir) && !fs22.statSync(dir).isDirectory())
|
|
21457
|
-
dir =
|
|
21458
|
-
const parts = dir.split(
|
|
22378
|
+
dir = path32.dirname(dir);
|
|
22379
|
+
const parts = dir.split(path32.sep);
|
|
21459
22380
|
const dotGit = parts.lastIndexOf(".git");
|
|
21460
22381
|
if (dotGit > 0)
|
|
21461
|
-
dir = parts.slice(0, dotGit).join(
|
|
22382
|
+
dir = parts.slice(0, dotGit).join(path32.sep) || path32.sep;
|
|
21462
22383
|
const location = resolveStore(dir);
|
|
21463
22384
|
if (location instanceof Error || !location.shared || !location.top)
|
|
21464
22385
|
return null;
|
|
@@ -21468,9 +22389,9 @@ var checkoutOf = (target) => {
|
|
|
21468
22389
|
} catch {}
|
|
21469
22390
|
return top;
|
|
21470
22391
|
};
|
|
21471
|
-
var markerFile2 = (top) =>
|
|
22392
|
+
var markerFile2 = (top) => path32.join(resolveStateDir(), "live-sessions", `${createHash15("sha256").update(checkoutKey(top)).digest("hex").slice(0, 32)}.json`);
|
|
21472
22393
|
var checkoutKey = (top, platform = process.platform) => {
|
|
21473
|
-
let key =
|
|
22394
|
+
let key = path32.resolve(top);
|
|
21474
22395
|
try {
|
|
21475
22396
|
key = fs22.realpathSync.native(key);
|
|
21476
22397
|
} catch {}
|
|
@@ -21565,7 +22486,7 @@ var claimLiveSession = (target, owner, deps = {}) => {
|
|
|
21565
22486
|
checkout,
|
|
21566
22487
|
heartbeatAt: now.toISOString()
|
|
21567
22488
|
};
|
|
21568
|
-
fs22.mkdirSync(
|
|
22489
|
+
fs22.mkdirSync(path32.dirname(file), { recursive: true });
|
|
21569
22490
|
const temp = `${file}.${process.pid}.tmp`;
|
|
21570
22491
|
fs22.writeFileSync(temp, JSON.stringify(marker));
|
|
21571
22492
|
fs22.renameSync(temp, file);
|
|
@@ -21577,22 +22498,22 @@ var NONE3 = { kind: "none" };
|
|
|
21577
22498
|
var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
|
|
21578
22499
|
var canonical2 = (file) => {
|
|
21579
22500
|
let rest = "";
|
|
21580
|
-
for (let dir =
|
|
22501
|
+
for (let dir = path33.resolve(file);; dir = path33.dirname(dir)) {
|
|
21581
22502
|
try {
|
|
21582
|
-
return
|
|
22503
|
+
return path33.join(realpathSync6.native(dir), rest);
|
|
21583
22504
|
} catch {
|
|
21584
|
-
if (
|
|
21585
|
-
return
|
|
21586
|
-
rest = rest ?
|
|
22505
|
+
if (path33.dirname(dir) === dir)
|
|
22506
|
+
return path33.resolve(file);
|
|
22507
|
+
rest = rest ? path33.join(path33.basename(dir), rest) : path33.basename(dir);
|
|
21587
22508
|
}
|
|
21588
22509
|
}
|
|
21589
22510
|
};
|
|
21590
22511
|
var exempt = (cwd, root, file, plans) => {
|
|
21591
22512
|
const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
|
|
21592
|
-
const relative =
|
|
21593
|
-
if (relative.startsWith("..") ||
|
|
22513
|
+
const relative = path33.relative(fold(canonical2(root)), fold(canonical2(path33.resolve(cwd, file))));
|
|
22514
|
+
if (relative.startsWith("..") || path33.isAbsolute(relative))
|
|
21594
22515
|
return true;
|
|
21595
|
-
const posix = relative.split(
|
|
22516
|
+
const posix = relative.split(path33.sep).join("/");
|
|
21596
22517
|
const segments = posix.split("/");
|
|
21597
22518
|
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
21598
22519
|
};
|
|
@@ -21769,10 +22690,10 @@ var linkSources = (args, at) => {
|
|
|
21769
22690
|
const sources = names.filter((name, index) => into >= 0 ? name !== dest : index < names.length - 1 || names.length === 1);
|
|
21770
22691
|
const target = dest === undefined ? null : at(dest);
|
|
21771
22692
|
const symbolic = args.some((arg) => /^-[a-zA-Z]*s|^--symbolic$/.test(arg));
|
|
21772
|
-
const base = target === null ? null : into >= 0 || sources.length > 1 ||
|
|
22693
|
+
const base = target === null ? null : into >= 0 || sources.length > 1 || existsSync11(target) || /[\\/]$/.test(dest ?? "") ? target : path33.dirname(target);
|
|
21773
22694
|
return sources.flatMap((source) => {
|
|
21774
|
-
if (symbolic && base !== null && !
|
|
21775
|
-
return [
|
|
22695
|
+
if (symbolic && base !== null && !path33.isAbsolute(homeExpanded(source)))
|
|
22696
|
+
return [path33.resolve(base, source)];
|
|
21776
22697
|
const resolved = at(source);
|
|
21777
22698
|
return resolved ? [resolved] : [];
|
|
21778
22699
|
});
|
|
@@ -21801,7 +22722,7 @@ var shellWrites = (command, depth = 0) => {
|
|
|
21801
22722
|
return { writes: true, targets: unknown ? null : targets };
|
|
21802
22723
|
};
|
|
21803
22724
|
var cache2 = new Map;
|
|
21804
|
-
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(
|
|
22725
|
+
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path33.resolve(root, file)) ?? "-").join("\x00");
|
|
21805
22726
|
var gateFor = (cwd) => {
|
|
21806
22727
|
const store = new TaskStore(cwd);
|
|
21807
22728
|
const listed = store.listTaskIndex();
|
|
@@ -21880,13 +22801,13 @@ var gitMutationDirs = (cwd, command, dialect) => {
|
|
|
21880
22801
|
return [];
|
|
21881
22802
|
if (sub === "stash" && ["list", "show"].includes(rest[0] ?? ""))
|
|
21882
22803
|
return [];
|
|
21883
|
-
return [
|
|
22804
|
+
return [path33.resolve(cwd, invocation.dir ?? ".")];
|
|
21884
22805
|
});
|
|
21885
22806
|
};
|
|
21886
22807
|
var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
|
|
21887
22808
|
var PUSHD2 = new Set(["pushd", "push-location"]);
|
|
21888
22809
|
var POPD2 = new Set(["popd", "pop-location"]);
|
|
21889
|
-
var UNKNOWN_DIR =
|
|
22810
|
+
var UNKNOWN_DIR = path33.resolve(path33.parse(process.cwd()).root, ".workit-unknown-dir");
|
|
21890
22811
|
var cdInto = (dir, words, strict = false) => {
|
|
21891
22812
|
const lost = strict ? UNKNOWN_DIR : undefined;
|
|
21892
22813
|
const named = words.slice(1).find((word) => !word.startsWith("-") || word === "-");
|
|
@@ -21895,7 +22816,7 @@ var cdInto = (dir, words, strict = false) => {
|
|
|
21895
22816
|
return lost;
|
|
21896
22817
|
if (dir === undefined)
|
|
21897
22818
|
return lost;
|
|
21898
|
-
return target === undefined ? os10.homedir() :
|
|
22819
|
+
return target === undefined ? os10.homedir() : path33.resolve(dir, target);
|
|
21899
22820
|
};
|
|
21900
22821
|
var quoteWord2 = (word) => /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`;
|
|
21901
22822
|
var homeExpanded = (file) => {
|
|
@@ -21909,7 +22830,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
|
|
|
21909
22830
|
const groups = [];
|
|
21910
22831
|
const at = (file) => {
|
|
21911
22832
|
const home = homeExpanded(file);
|
|
21912
|
-
return
|
|
22833
|
+
return path33.isAbsolute(home) ? home : dir === undefined ? null : path33.resolve(dir, home);
|
|
21913
22834
|
};
|
|
21914
22835
|
for (const segment of segmentsOf(command, dialect)) {
|
|
21915
22836
|
if (segment.group === "open") {
|
|
@@ -21949,7 +22870,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
|
|
|
21949
22870
|
for (const file of opaque ?? []) {
|
|
21950
22871
|
const resolved = at(file);
|
|
21951
22872
|
if (resolved)
|
|
21952
|
-
targets.push(file === "." ?
|
|
22873
|
+
targets.push(file === "." ? path33.join(resolved, DIR_TARGET) : resolved);
|
|
21953
22874
|
}
|
|
21954
22875
|
const ln = words.findIndex((word) => /^ln$/i.test(word.split(/[\\/]/).at(-1) ?? ""));
|
|
21955
22876
|
if (ln >= 0 && words.slice(0, ln).every((word) => PREFIXES2.has(word)))
|
|
@@ -21964,7 +22885,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
|
|
|
21964
22885
|
const edits = editsOf(segment.words);
|
|
21965
22886
|
if (edits === null) {
|
|
21966
22887
|
if (dir !== undefined)
|
|
21967
|
-
targets.push(
|
|
22888
|
+
targets.push(path33.join(dir, DIR_TARGET));
|
|
21968
22889
|
} else
|
|
21969
22890
|
for (const file of edits) {
|
|
21970
22891
|
const resolved = at(file);
|
|
@@ -21975,20 +22896,20 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
|
|
|
21975
22896
|
for (const invocation of workitInvocations(segment.words.map(quoteWord2).join(" "), "posix")) {
|
|
21976
22897
|
const { at: runsIn, args } = workitCwd(dir, invocation);
|
|
21977
22898
|
if (args[0] === "git" && MUTATING_WORKIT_GIT.has(args[1] ?? "") && !inert(args.slice(2), ""))
|
|
21978
|
-
targets.push(
|
|
22899
|
+
targets.push(path33.join(runsIn, DIR_TARGET));
|
|
21979
22900
|
}
|
|
21980
22901
|
}
|
|
21981
22902
|
return targets;
|
|
21982
22903
|
};
|
|
21983
22904
|
var workitCwd = (dir, args) => {
|
|
21984
22905
|
const { rest, cwd } = skipWorkitGlobals(args);
|
|
21985
|
-
return { at: cwd === null ? dir :
|
|
22906
|
+
return { at: cwd === null ? dir : path33.resolve(dir, homeExpanded(cwd)), args: rest };
|
|
21986
22907
|
};
|
|
21987
22908
|
var shellMutationTargets = (cwd, command, dialect = "posix", strict = false) => {
|
|
21988
22909
|
try {
|
|
21989
22910
|
return [
|
|
21990
22911
|
...segmentTargets(cwd, command, dialect, 0, strict),
|
|
21991
|
-
...gitMutationDirs(cwd, command, dialect).map((dir) =>
|
|
22912
|
+
...gitMutationDirs(cwd, command, dialect).map((dir) => path33.join(dir, DIR_TARGET))
|
|
21992
22913
|
];
|
|
21993
22914
|
} catch {
|
|
21994
22915
|
return [];
|
|
@@ -22025,7 +22946,7 @@ var liveDeny = ({ marker, checkout, ageMs, file }) => {
|
|
|
22025
22946
|
var guarded = (targets) => {
|
|
22026
22947
|
const seen = new Set;
|
|
22027
22948
|
return targets.filter((target) => {
|
|
22028
|
-
const dir =
|
|
22949
|
+
const dir = path33.dirname(target);
|
|
22029
22950
|
if (seen.has(dir))
|
|
22030
22951
|
return false;
|
|
22031
22952
|
seen.add(dir);
|
|
@@ -22046,7 +22967,7 @@ var claimAll = (owner, targets, deps) => {
|
|
|
22046
22967
|
for (const target of guarded(targets))
|
|
22047
22968
|
claimLiveSession(target, owner, deps);
|
|
22048
22969
|
};
|
|
22049
|
-
var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) =>
|
|
22970
|
+
var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) => path33.resolve(cwd, file)) : [path33.join(cwd, DIR_TARGET)];
|
|
22050
22971
|
var issuedTarget = (cwd, targets) => {
|
|
22051
22972
|
const state = resolveStateDir();
|
|
22052
22973
|
const found = targets.find((target) => underIssued(state, cwd, homeExpanded(target), process.platform, canonical2));
|
|
@@ -22054,7 +22975,7 @@ var issuedTarget = (cwd, targets) => {
|
|
|
22054
22975
|
};
|
|
22055
22976
|
var underIssued = (state, cwd, target, platform = process.platform, real = (file) => file) => {
|
|
22056
22977
|
const win = platform === "win32";
|
|
22057
|
-
const p = win ?
|
|
22978
|
+
const p = win ? path33.win32 : path33.posix;
|
|
22058
22979
|
const fold = (value) => win || platform === "darwin" ? value.toLowerCase() : value;
|
|
22059
22980
|
const named = win ? target.replace(/^\/([a-zA-Z])(?=\/|$)/, "$1:") : target;
|
|
22060
22981
|
const relative = p.relative(fold(real(p.resolve(state))), fold(real(p.resolve(cwd, named))));
|
|
@@ -22144,7 +23065,25 @@ function beforeWriteGate(cwd, paths) {
|
|
|
22144
23065
|
}
|
|
22145
23066
|
}
|
|
22146
23067
|
// packages/workit-core/src/hooks/stop.ts
|
|
22147
|
-
import { spawnSync as
|
|
23068
|
+
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
23069
|
+
|
|
23070
|
+
// packages/workit-core/src/core/policy/current-judgment.ts
|
|
23071
|
+
function currentJudgment(cwd) {
|
|
23072
|
+
try {
|
|
23073
|
+
const store = new TaskStore(cwd);
|
|
23074
|
+
const listed = store.listTaskIndex();
|
|
23075
|
+
const key = store.currentKey();
|
|
23076
|
+
if (!listed.ok || !key.ok)
|
|
23077
|
+
return null;
|
|
23078
|
+
const entry = listed.data.filter((item) => item.key === key.data.key && item.status !== "closed").toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt))[0];
|
|
23079
|
+
const task = entry ? store.readTask(entry.id) : null;
|
|
23080
|
+
return task?.ok === true ? latestJudgment(task.data) : null;
|
|
23081
|
+
} catch {
|
|
23082
|
+
return null;
|
|
23083
|
+
}
|
|
23084
|
+
}
|
|
23085
|
+
|
|
23086
|
+
// packages/workit-core/src/hooks/stop.ts
|
|
22148
23087
|
var NONE4 = { kind: "none" };
|
|
22149
23088
|
var QUESTION = /[??؟](?=[\s*_`"')\]>]*(?:\s|$))|¿/;
|
|
22150
23089
|
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;
|
|
@@ -22165,7 +23104,7 @@ var asksUser = (message) => {
|
|
|
22165
23104
|
};
|
|
22166
23105
|
var short = (sha) => (sha ?? "?").slice(0, 12);
|
|
22167
23106
|
var gitList = (cwd, args) => {
|
|
22168
|
-
const run =
|
|
23107
|
+
const run = spawnSync19("git", args, {
|
|
22169
23108
|
cwd,
|
|
22170
23109
|
encoding: "utf8",
|
|
22171
23110
|
timeout: 3000,
|
|
@@ -22237,29 +23176,32 @@ var redChecks = (rows, pr, head, endpoint) => {
|
|
|
22237
23176
|
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)" : ""}.`
|
|
22238
23177
|
};
|
|
22239
23178
|
};
|
|
22240
|
-
var
|
|
22241
|
-
|
|
22242
|
-
|
|
22243
|
-
const listed = store.listTaskIndex();
|
|
22244
|
-
const key = store.currentKey();
|
|
22245
|
-
if (!listed.ok || !key.ok)
|
|
22246
|
-
return null;
|
|
22247
|
-
const entry = listed.data.filter((item) => item.key === key.data.key && item.status !== "closed").toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt))[0];
|
|
22248
|
-
const task = entry ? store.readTask(entry.id) : null;
|
|
22249
|
-
return task?.ok === true ? latestJudgment(task.data) : null;
|
|
22250
|
-
} catch {
|
|
22251
|
-
return null;
|
|
22252
|
-
}
|
|
23179
|
+
var prBase = (rows) => {
|
|
23180
|
+
const seen = rows.findLast((row) => (row.type === "pr.status" || row.type === "pr.created") && row.observer === "workit_cli" && typeof row.base === "string");
|
|
23181
|
+
return typeof seen?.base === "string" ? seen.base : null;
|
|
22253
23182
|
};
|
|
22254
|
-
var unverified = (cwd, branch, all, descriptor, verification) => {
|
|
23183
|
+
var unverified = (cwd, branch, all, descriptor, verification, head) => {
|
|
22255
23184
|
const check = checkVerdicts(cwd, branch, all);
|
|
22256
23185
|
if (check.accepted.accepted || check.accepted.reasons.includes("failing_verdict"))
|
|
22257
23186
|
return null;
|
|
22258
|
-
const judgment =
|
|
23187
|
+
const judgment = currentJudgment(cwd);
|
|
22259
23188
|
const high = judgment?.riskTier === "high";
|
|
22260
|
-
|
|
22261
|
-
|
|
22262
|
-
|
|
23189
|
+
let independent;
|
|
23190
|
+
if (verification === "proportional") {
|
|
23191
|
+
const lane = branchLane(cwd, {
|
|
23192
|
+
base: prBase(all.filter((row) => row.branch === branch)),
|
|
23193
|
+
head,
|
|
23194
|
+
judgment
|
|
23195
|
+
});
|
|
23196
|
+
const need = laneNeed(lane.lane);
|
|
23197
|
+
if (need === "none")
|
|
23198
|
+
return null;
|
|
23199
|
+
independent = need === "non-author";
|
|
23200
|
+
} else {
|
|
23201
|
+
if (judgment && !judgment.behaviorChange && !high)
|
|
23202
|
+
return null;
|
|
23203
|
+
independent = verification === "independent" || high;
|
|
23204
|
+
}
|
|
22263
23205
|
if (!independent && check.review === "self-reviewed")
|
|
22264
23206
|
return null;
|
|
22265
23207
|
const has = check.review === "self-reviewed" ? "only a self verdict" : "no current verdict";
|
|
@@ -22306,7 +23248,7 @@ function stopObligation(input, descriptor) {
|
|
|
22306
23248
|
}
|
|
22307
23249
|
if (!delivered || endpoint !== "green" && endpoint !== "merged")
|
|
22308
23250
|
return null;
|
|
22309
|
-
const left = unverified(input.cwd, branch, all, descriptor, autonomy.verification);
|
|
23251
|
+
const left = unverified(input.cwd, branch, all, descriptor, autonomy.verification, head);
|
|
22310
23252
|
return left ? { ...left, head } : null;
|
|
22311
23253
|
} catch {
|
|
22312
23254
|
return null;
|
|
@@ -22576,9 +23518,9 @@ var WRITE_TOOLS = new Set([
|
|
|
22576
23518
|
]);
|
|
22577
23519
|
// packages/workit-core/src/hooks/standing.ts
|
|
22578
23520
|
import fs23 from "node:fs";
|
|
22579
|
-
import
|
|
23521
|
+
import path34 from "node:path";
|
|
22580
23522
|
var readPlans = (store) => {
|
|
22581
|
-
const dir =
|
|
23523
|
+
const dir = path34.join(store, "fanouts");
|
|
22582
23524
|
let names;
|
|
22583
23525
|
try {
|
|
22584
23526
|
names = fs23.readdirSync(dir).filter((name) => name.endsWith(".json"));
|
|
@@ -22588,7 +23530,7 @@ var readPlans = (store) => {
|
|
|
22588
23530
|
const plans = [];
|
|
22589
23531
|
for (const name of names) {
|
|
22590
23532
|
try {
|
|
22591
|
-
const raw = JSON.parse(fs23.readFileSync(
|
|
23533
|
+
const raw = JSON.parse(fs23.readFileSync(path34.join(dir, name), "utf8"));
|
|
22592
23534
|
if (typeof raw.name !== "string" || !Array.isArray(raw.slices))
|
|
22593
23535
|
continue;
|
|
22594
23536
|
const texts = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string" && item !== "") : [];
|
|
@@ -22796,11 +23738,11 @@ var OPENCODE_DESCRIPTOR = {
|
|
|
22796
23738
|
]
|
|
22797
23739
|
};
|
|
22798
23740
|
// packages/workit-opencode/src/shared/init-apply.ts
|
|
22799
|
-
import
|
|
23741
|
+
import path39 from "node:path";
|
|
22800
23742
|
|
|
22801
23743
|
// packages/workit-core/src/core/gitignore.ts
|
|
22802
|
-
import { existsSync as
|
|
22803
|
-
import
|
|
23744
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
|
|
23745
|
+
import path35 from "node:path";
|
|
22804
23746
|
var GITIGNORE_ENTRIES = [
|
|
22805
23747
|
"# workit: SDD working state (never commit)",
|
|
22806
23748
|
"docs/*/sdd/",
|
|
@@ -22820,8 +23762,8 @@ var GITIGNORE_ENTRIES = [
|
|
|
22820
23762
|
var ensureProjectGitignore = (workspaceRoot, confirmed) => {
|
|
22821
23763
|
if (!confirmed)
|
|
22822
23764
|
return { ok: false, error: "confirmed: true required" };
|
|
22823
|
-
const file =
|
|
22824
|
-
const existing =
|
|
23765
|
+
const file = path35.join(workspaceRoot, ".gitignore");
|
|
23766
|
+
const existing = existsSync12(file) ? readFileSync8(file, "utf8") : "";
|
|
22825
23767
|
const existingLines = new Set(existing.split(`
|
|
22826
23768
|
`).map((l) => l.trim()).filter(Boolean));
|
|
22827
23769
|
const added = [];
|
|
@@ -22840,33 +23782,33 @@ var ensureProjectGitignore = (workspaceRoot, confirmed) => {
|
|
|
22840
23782
|
` : "") + append.join(`
|
|
22841
23783
|
`) + `
|
|
22842
23784
|
`, "utf8");
|
|
22843
|
-
} else if (!
|
|
23785
|
+
} else if (!existsSync12(file)) {
|
|
22844
23786
|
writeFileSync4(file, "", "utf8");
|
|
22845
23787
|
}
|
|
22846
23788
|
return { ok: true, path: file, added };
|
|
22847
23789
|
};
|
|
22848
23790
|
|
|
22849
23791
|
// packages/workit-core/src/core/hygiene.ts
|
|
22850
|
-
import { existsSync as
|
|
22851
|
-
import
|
|
23792
|
+
import { existsSync as existsSync13, readFileSync as readFileSync9, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
23793
|
+
import path36 from "node:path";
|
|
22852
23794
|
var repoRoot3 = assetRoot();
|
|
22853
|
-
var templatesDir = () =>
|
|
23795
|
+
var templatesDir = () => path36.join(repoRoot3, "templates", "hygiene");
|
|
22854
23796
|
var packageJson = (root) => {
|
|
22855
|
-
if (!
|
|
23797
|
+
if (!existsSync13(path36.join(root, "package.json")))
|
|
22856
23798
|
return null;
|
|
22857
23799
|
try {
|
|
22858
|
-
return JSON.parse(
|
|
23800
|
+
return JSON.parse(readFileSync9(path36.join(root, "package.json"), "utf8"));
|
|
22859
23801
|
} catch {
|
|
22860
23802
|
return null;
|
|
22861
23803
|
}
|
|
22862
23804
|
};
|
|
22863
23805
|
var isOpenSource = (root) => {
|
|
22864
|
-
if (
|
|
23806
|
+
if (existsSync13(path36.join(root, "LICENSE")))
|
|
22865
23807
|
return true;
|
|
22866
23808
|
const pkg = packageJson(root);
|
|
22867
23809
|
if (pkg && !pkg.private)
|
|
22868
23810
|
return true;
|
|
22869
|
-
return
|
|
23811
|
+
return path36.basename(root) === "workflow-toolkit";
|
|
22870
23812
|
};
|
|
22871
23813
|
var licenseHolder = (root) => {
|
|
22872
23814
|
const pkg = packageJson(root);
|
|
@@ -22889,13 +23831,13 @@ var planHygieneFiles = (root, opts = {}) => {
|
|
|
22889
23831
|
files.push("LICENSE", "CONTRIBUTING.md");
|
|
22890
23832
|
const planned = [];
|
|
22891
23833
|
for (const file of files) {
|
|
22892
|
-
if (
|
|
23834
|
+
if (existsSync13(path36.join(root, file)))
|
|
22893
23835
|
continue;
|
|
22894
|
-
const tpl =
|
|
22895
|
-
if (!
|
|
23836
|
+
const tpl = path36.join(templatesDir(), file);
|
|
23837
|
+
if (!existsSync13(tpl))
|
|
22896
23838
|
continue;
|
|
22897
|
-
const content =
|
|
22898
|
-
planned.push({ path:
|
|
23839
|
+
const content = readFileSync9(tpl, "utf8").replace(/<PROJECT>/g, path36.basename(root)).replace(/<YEAR>/g, String(new Date().getFullYear())).replace(/<HOLDER>\s*/g, licenseHolder(root));
|
|
23840
|
+
planned.push({ path: path36.join(root, file), content });
|
|
22899
23841
|
}
|
|
22900
23842
|
return planned;
|
|
22901
23843
|
};
|
|
@@ -22905,30 +23847,30 @@ var ensureHygieneFiles = (root, opts) => {
|
|
|
22905
23847
|
const created = [];
|
|
22906
23848
|
for (const planned of planHygieneFiles(root, opts)) {
|
|
22907
23849
|
writeFileSync5(planned.path, planned.content, "utf8");
|
|
22908
|
-
created.push(
|
|
23850
|
+
created.push(path36.basename(planned.path));
|
|
22909
23851
|
}
|
|
22910
23852
|
return { ok: true, created };
|
|
22911
23853
|
};
|
|
22912
23854
|
|
|
22913
23855
|
// packages/workit-core/src/core/init.ts
|
|
22914
23856
|
import fs24 from "node:fs";
|
|
22915
|
-
import
|
|
22916
|
-
import { spawnSync as
|
|
23857
|
+
import path38 from "node:path";
|
|
23858
|
+
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
22917
23859
|
|
|
22918
23860
|
// packages/workit-core/src/core/workspace-branch-policy.ts
|
|
22919
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
22920
|
-
import
|
|
23861
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync10, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23862
|
+
import path37 from "node:path";
|
|
22921
23863
|
import { isDeepStrictEqual } from "node:util";
|
|
22922
23864
|
var readFileSafe = (p) => {
|
|
22923
23865
|
try {
|
|
22924
|
-
return
|
|
23866
|
+
return readFileSync10(p, "utf8");
|
|
22925
23867
|
} catch {
|
|
22926
23868
|
return null;
|
|
22927
23869
|
}
|
|
22928
23870
|
};
|
|
22929
23871
|
function applyWorkspaceBranchPolicy(opts) {
|
|
22930
23872
|
const { workspace_root, env = process.env } = opts;
|
|
22931
|
-
const dir =
|
|
23873
|
+
const dir = path37.join(env.WORKFLOW_TOOLKIT_CONFIG ?? configDir());
|
|
22932
23874
|
const {
|
|
22933
23875
|
status,
|
|
22934
23876
|
path: wsPath,
|
|
@@ -22940,7 +23882,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
22940
23882
|
if (status === "malformed" || status === "invalid")
|
|
22941
23883
|
return { ok: false, error: workspacesError ?? `invalid workspaces.json: ${wsPath}` };
|
|
22942
23884
|
const detection = detectBranchPolicy(workspace_root);
|
|
22943
|
-
const name = String(env.WORKFLOW_BP_NAME ??
|
|
23885
|
+
const name = String(env.WORKFLOW_BP_NAME ?? path37.basename(workspace_root));
|
|
22944
23886
|
const integration = env.WORKFLOW_BP_INTEGRATION ?? detection.integration;
|
|
22945
23887
|
const policy = {
|
|
22946
23888
|
preset: detection.preset,
|
|
@@ -22989,7 +23931,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
22989
23931
|
ok: false,
|
|
22990
23932
|
error: `workspaces.json changed while applying the branch policy: ${wsPath}`
|
|
22991
23933
|
};
|
|
22992
|
-
mkdirSync4(
|
|
23934
|
+
mkdirSync4(path37.dirname(wsPath), { recursive: true });
|
|
22993
23935
|
const tmp = `${wsPath}.${process.pid}.tmp`;
|
|
22994
23936
|
try {
|
|
22995
23937
|
writeFileSync6(tmp, JSON.stringify({ ...document, workspaces: next }, null, 2) + `
|
|
@@ -23036,7 +23978,7 @@ var resolveInitProvider = (cwd) => {
|
|
|
23036
23978
|
return env.toLowerCase();
|
|
23037
23979
|
const root = cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
23038
23980
|
try {
|
|
23039
|
-
const out =
|
|
23981
|
+
const out = spawnSync20("git", ["remote", "get-url", "origin"], {
|
|
23040
23982
|
cwd: root,
|
|
23041
23983
|
encoding: "utf8"
|
|
23042
23984
|
});
|
|
@@ -23054,7 +23996,7 @@ var youtrackJsonContent = (dir) => {
|
|
|
23054
23996
|
const meetingIssue = process.env.WORKFLOW_YT_MEETING_ISSUE;
|
|
23055
23997
|
return {
|
|
23056
23998
|
baseUrl: process.env.WORKFLOW_YT_BASE_URL ?? "https://youtrack.example.com",
|
|
23057
|
-
tokenFile: process.env.WORKFLOW_YT_TOKEN_FILE ??
|
|
23999
|
+
tokenFile: process.env.WORKFLOW_YT_TOKEN_FILE ?? path38.join(dir, "youtrack.token"),
|
|
23058
24000
|
...meetingIssue ? {
|
|
23059
24001
|
meetingIssue,
|
|
23060
24002
|
meetingIssues: { general: { issue: meetingIssue, label: "General meetings" } }
|
|
@@ -23087,16 +24029,16 @@ function initApplyData(action, env = process.env) {
|
|
|
23087
24029
|
fs24.mkdirSync(dir, { recursive: true });
|
|
23088
24030
|
switch (action) {
|
|
23089
24031
|
case "youtrack_json": {
|
|
23090
|
-
const out =
|
|
24032
|
+
const out = path38.join(dir, "youtrack.json");
|
|
23091
24033
|
fs24.writeFileSync(out, JSON.stringify(youtrackJsonContent(dir), null, 2) + `
|
|
23092
24034
|
`, "utf8");
|
|
23093
24035
|
return { action, ok: true, path: out };
|
|
23094
24036
|
}
|
|
23095
24037
|
case "youtrack_token_placeholder": {
|
|
23096
|
-
const p =
|
|
24038
|
+
const p = path38.join(dir, "youtrack.token");
|
|
23097
24039
|
const preserved = writeFileExclusive(p, TOKEN_PLACEHOLDER2 + `
|
|
23098
24040
|
`, 384) === "preserved";
|
|
23099
|
-
const abs =
|
|
24041
|
+
const abs = path38.resolve(p);
|
|
23100
24042
|
return {
|
|
23101
24043
|
action,
|
|
23102
24044
|
ok: true,
|
|
@@ -23108,14 +24050,14 @@ function initApplyData(action, env = process.env) {
|
|
|
23108
24050
|
};
|
|
23109
24051
|
}
|
|
23110
24052
|
case "youtrack_scaffold": {
|
|
23111
|
-
const jsonOut =
|
|
23112
|
-
const tokenOut =
|
|
24053
|
+
const jsonOut = path38.join(dir, "youtrack.json");
|
|
24054
|
+
const tokenOut = path38.join(dir, "youtrack.token");
|
|
23113
24055
|
fs24.writeFileSync(jsonOut, JSON.stringify(youtrackJsonContent(dir), null, 2) + `
|
|
23114
24056
|
`, "utf8");
|
|
23115
24057
|
const preserved = writeFileExclusive(tokenOut, TOKEN_PLACEHOLDER2 + `
|
|
23116
24058
|
`, 384) === "preserved";
|
|
23117
|
-
const configPath =
|
|
23118
|
-
const tokenPath =
|
|
24059
|
+
const configPath = path38.resolve(jsonOut);
|
|
24060
|
+
const tokenPath = path38.resolve(tokenOut);
|
|
23119
24061
|
const prev = process.env.WORKFLOW_YOUTRACK_CONFIG;
|
|
23120
24062
|
process.env.WORKFLOW_YOUTRACK_CONFIG = configPath;
|
|
23121
24063
|
let tokenCreate = {};
|
|
@@ -23167,10 +24109,10 @@ function initApplyData(action, env = process.env) {
|
|
|
23167
24109
|
}
|
|
23168
24110
|
}
|
|
23169
24111
|
case "vcs_scaffold": {
|
|
23170
|
-
const jsonOut =
|
|
24112
|
+
const jsonOut = path38.join(dir, "vcs.json");
|
|
23171
24113
|
fs24.writeFileSync(jsonOut, JSON.stringify(vcsJsonContent(), null, 2) + `
|
|
23172
24114
|
`, "utf8");
|
|
23173
|
-
const configPath =
|
|
24115
|
+
const configPath = path38.resolve(jsonOut);
|
|
23174
24116
|
const prev = process.env.WORKFLOW_VCS_CONFIG;
|
|
23175
24117
|
process.env.WORKFLOW_VCS_CONFIG = configPath;
|
|
23176
24118
|
try {
|
|
@@ -23289,7 +24231,7 @@ var executeInitApply = (args, directory, runtime) => {
|
|
|
23289
24231
|
protectedNames: args.branch_policy_protected
|
|
23290
24232
|
}, current);
|
|
23291
24233
|
writeConfig(next);
|
|
23292
|
-
return output(ok({ action: "config", path:
|
|
24234
|
+
return output(ok({ action: "config", path: path39.join(configDir(), "config.json"), ...next }));
|
|
23293
24235
|
}
|
|
23294
24236
|
const env = Object.fromEntries(Object.entries({
|
|
23295
24237
|
WORKFLOW_YT_BASE_URL: args.base_url,
|
|
@@ -23306,14 +24248,14 @@ var executeInitApply = (args, directory, runtime) => {
|
|
|
23306
24248
|
|
|
23307
24249
|
// packages/workit-opencode/src/shared/session.ts
|
|
23308
24250
|
import { realpathSync as realpathSync7 } from "node:fs";
|
|
23309
|
-
import
|
|
24251
|
+
import path40 from "node:path";
|
|
23310
24252
|
var sameWorkspace = (expected, observed) => {
|
|
23311
24253
|
if (typeof observed !== "string" || !observed)
|
|
23312
24254
|
return false;
|
|
23313
24255
|
try {
|
|
23314
24256
|
return realpathSync7(expected) === realpathSync7(observed);
|
|
23315
24257
|
} catch {
|
|
23316
|
-
return
|
|
24258
|
+
return path40.resolve(expected) === path40.resolve(observed);
|
|
23317
24259
|
}
|
|
23318
24260
|
};
|
|
23319
24261
|
|
|
@@ -23385,7 +24327,7 @@ var workitFamilyOf = (toolName) => {
|
|
|
23385
24327
|
|
|
23386
24328
|
// packages/workit-opencode/src/tools/context.ts
|
|
23387
24329
|
import { realpathSync as realpathSync8 } from "node:fs";
|
|
23388
|
-
import
|
|
24330
|
+
import path41 from "node:path";
|
|
23389
24331
|
var createContextTool = () => ({
|
|
23390
24332
|
description: "Read Git, pull request, YouTrack, issue, changelog, release, or affected-file context.",
|
|
23391
24333
|
execute: async (args, context) => {
|
|
@@ -23395,7 +24337,7 @@ var createContextTool = () => ({
|
|
|
23395
24337
|
let root;
|
|
23396
24338
|
try {
|
|
23397
24339
|
const cwd = parsed.data.cwd;
|
|
23398
|
-
root = realpathSync8(cwd ?
|
|
24340
|
+
root = realpathSync8(cwd ? path41.resolve(context.directory, cwd) : context.directory);
|
|
23399
24341
|
} catch {
|
|
23400
24342
|
return JSON.stringify(failure2("invalid_input", "context target directory cannot be resolved"), null, 2);
|
|
23401
24343
|
}
|
|
@@ -23427,118 +24369,13 @@ var workerCoordinatorFor = (task, worker) => {
|
|
|
23427
24369
|
// packages/workit-core/src/fanout.ts
|
|
23428
24370
|
import { createHash as createHash17 } from "node:crypto";
|
|
23429
24371
|
import fs26 from "node:fs";
|
|
23430
|
-
import
|
|
24372
|
+
import path43 from "node:path";
|
|
23431
24373
|
|
|
23432
24374
|
// packages/workit-core/src/stack.ts
|
|
23433
24375
|
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
23434
24376
|
import { createHash as createHash16, randomBytes as randomBytes4 } from "node:crypto";
|
|
23435
24377
|
import fs25 from "node:fs";
|
|
23436
|
-
import
|
|
23437
|
-
|
|
23438
|
-
// packages/workit-core/src/git/ops.ts
|
|
23439
|
-
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
23440
|
-
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "node:fs";
|
|
23441
|
-
import path40 from "node:path";
|
|
23442
|
-
|
|
23443
|
-
// packages/workit-core/src/forge/redact.ts
|
|
23444
|
-
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_.-]*`;
|
|
23445
|
-
var ASSIGNMENT2 = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*["']?)((?:bearer|basic|token|digest)\s+)?([^\s"',;&]+)`, "giu");
|
|
23446
|
-
var QUOTED_ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*)(["'])([^"'\n]*[^\s"'][^"'\n]*)\2`, "giu");
|
|
23447
|
-
var ANSI = new RegExp(String.raw`\u001b\[[0-9;?]*[ -/]*[@-~]|\u001b\][^\u0007]*\u0007`, "gu");
|
|
23448
|
-
|
|
23449
|
-
// packages/workit-core/src/forge/types.ts
|
|
23450
|
-
var success2 = (data) => ({ ok: true, data });
|
|
23451
|
-
var failure3 = (code, error, unblock) => ({ ok: false, code, error, ...unblock ? { unblock } : {} });
|
|
23452
|
-
|
|
23453
|
-
// packages/workit-core/src/git/ops.ts
|
|
23454
|
-
var COMMIT_TIMEOUT_MS = 10 * 60000;
|
|
23455
|
-
var git5 = (cwd, args, options = {}) => {
|
|
23456
|
-
const result = spawnSync20("git", args, {
|
|
23457
|
-
cwd,
|
|
23458
|
-
encoding: "utf8",
|
|
23459
|
-
env: { ...options.env ?? process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
23460
|
-
maxBuffer: 64 * 1024 * 1024,
|
|
23461
|
-
timeout: options.timeoutMs ?? GIT_TIMEOUTS.local,
|
|
23462
|
-
killSignal: "SIGKILL",
|
|
23463
|
-
windowsHide: true,
|
|
23464
|
-
...options.input === undefined ? { stdio: ["ignore", "pipe", "pipe"] } : { input: options.input, stdio: ["pipe", "pipe", "pipe"] }
|
|
23465
|
-
});
|
|
23466
|
-
return {
|
|
23467
|
-
ok: result.status === 0,
|
|
23468
|
-
status: result.status,
|
|
23469
|
-
stdout: result.stdout ?? "",
|
|
23470
|
-
stderr: result.stderr ?? ""
|
|
23471
|
-
};
|
|
23472
|
-
};
|
|
23473
|
-
function operationInProgress(cwd) {
|
|
23474
|
-
const markers = [
|
|
23475
|
-
["rebase-merge", "rebase"],
|
|
23476
|
-
["rebase-apply", "rebase"],
|
|
23477
|
-
["MERGE_HEAD", "merge"],
|
|
23478
|
-
["CHERRY_PICK_HEAD", "cherry-pick"],
|
|
23479
|
-
["REVERT_HEAD", "revert"]
|
|
23480
|
-
];
|
|
23481
|
-
const run = git5(cwd, ["rev-parse", ...markers.flatMap(([name]) => ["--git-path", name])]);
|
|
23482
|
-
if (!run.ok)
|
|
23483
|
-
return null;
|
|
23484
|
-
const found = run.stdout.split(`
|
|
23485
|
-
`).map((line) => path40.resolve(cwd, line.trim()));
|
|
23486
|
-
const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
|
|
23487
|
-
for (const [index, [, operation]] of markers.entries()) {
|
|
23488
|
-
const marker = found[index];
|
|
23489
|
-
if (!marker || !existsSync12(marker))
|
|
23490
|
-
continue;
|
|
23491
|
-
if (index === 1 && existsSync12(path40.join(marker, "applying")))
|
|
23492
|
-
return { operation: "am", commitAllowed: false, branch: null };
|
|
23493
|
-
if (index === 0 && existsSync12(path40.join(marker, "amend")) && !conflicted()) {
|
|
23494
|
-
let headName = "";
|
|
23495
|
-
try {
|
|
23496
|
-
headName = readFileSync9(path40.join(marker, "head-name"), "utf8").trim();
|
|
23497
|
-
} catch {}
|
|
23498
|
-
const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
|
|
23499
|
-
return { operation, commitAllowed: branch !== null, branch };
|
|
23500
|
-
}
|
|
23501
|
-
if ((operation === "revert" || operation === "merge") && !conflicted())
|
|
23502
|
-
return { operation, commitAllowed: true, branch: null };
|
|
23503
|
-
return { operation, commitAllowed: false, branch: null };
|
|
23504
|
-
}
|
|
23505
|
-
return null;
|
|
23506
|
-
}
|
|
23507
|
-
function inProgressFailure(operation, verb) {
|
|
23508
|
-
const command = operation === "am" ? "git am" : `git ${operation}`;
|
|
23509
|
-
return failure3("blocked", `${operation.replace("-", "_")}_in_progress: a ${operation === "am" ? "git am" : operation} is in progress; finish or abort it before workit can ${verb}`, `resolve the conflicts, git add <files>, then ${command} --continue # or ${command} --abort to return to where you started`);
|
|
23510
|
-
}
|
|
23511
|
-
function pushPreflight(cwd, options = {}) {
|
|
23512
|
-
const progress = operationInProgress(cwd);
|
|
23513
|
-
if (progress)
|
|
23514
|
-
return inProgressFailure(progress.operation, "push");
|
|
23515
|
-
const branch = options.branch ?? currentBranch(cwd);
|
|
23516
|
-
if (!branch)
|
|
23517
|
-
return failure3("invalid_input", "HEAD is detached; push a branch");
|
|
23518
|
-
if (isProtectedTarget(cwd, branch))
|
|
23519
|
-
return failure3("blocked", `protected_branch: ${branch} is protected by the workspace branch policy; workit git push never pushes to it`, releaseBranch(cwd, branch) ? `workit git push --release ${branch} # finishing a release or hotfix; needs the release grant` : "workit git branch <feature/name> # push a feature branch and open a PR");
|
|
23520
|
-
const sha = resolveRef(cwd, `refs/heads/${branch}`);
|
|
23521
|
-
if (!sha)
|
|
23522
|
-
return failure3("not_found", `branch ${branch} has no commit to push`);
|
|
23523
|
-
const remote = pushRemoteName(cwd, branch);
|
|
23524
|
-
if (!remote)
|
|
23525
|
-
return failure3("not_found", "no push remote is configured for this branch", "git remote add origin <url>");
|
|
23526
|
-
const raw = pushUrl(cwd, remote);
|
|
23527
|
-
if (!raw)
|
|
23528
|
-
return failure3("blocked", `remote "${remote}" has no single push URL`, `git remote get-url --push --all ${remote} # keep exactly one push URL`);
|
|
23529
|
-
const parsed = parseRemoteUrl(raw);
|
|
23530
|
-
const local = parsed?.protocol === "file";
|
|
23531
|
-
if (!local && !pushTargetIsStable(cwd, raw))
|
|
23532
|
-
return failure3("blocked", `push_target_rewritten: the push URL of "${remote}" is rewritten by a url.*.insteadOf rule, so the destination is not the one checked`, "git config --get-regexp '^url\\.' # remove the rewrite for this remote");
|
|
23533
|
-
return success2({
|
|
23534
|
-
branch,
|
|
23535
|
-
sha,
|
|
23536
|
-
remote,
|
|
23537
|
-
url: redactRemote(raw),
|
|
23538
|
-
rawUrl: raw,
|
|
23539
|
-
local
|
|
23540
|
-
});
|
|
23541
|
-
}
|
|
24378
|
+
import path42 from "node:path";
|
|
23542
24379
|
|
|
23543
24380
|
// packages/workit-core/src/forge/report.ts
|
|
23544
24381
|
var GITLAB_MERGEABLE = new Set(["mergeable"]);
|
|
@@ -23620,7 +24457,7 @@ function rebaseInProgress(dir) {
|
|
|
23620
24457
|
}
|
|
23621
24458
|
var scratchDir = (cwd) => {
|
|
23622
24459
|
const dir = stacksDir(cwd);
|
|
23623
|
-
return dir.ok ?
|
|
24460
|
+
return dir.ok ? path42.join(dir.data, "worktrees") : null;
|
|
23624
24461
|
};
|
|
23625
24462
|
function gitRestack(cwd, input) {
|
|
23626
24463
|
const owner = worktreeOf(cwd, input.branch);
|
|
@@ -23630,7 +24467,7 @@ function gitRestack(cwd, input) {
|
|
|
23630
24467
|
if (!scratch)
|
|
23631
24468
|
return { ok: false, conflict: false, worktree: cwd, error: "no store root" };
|
|
23632
24469
|
fs25.mkdirSync(scratch, { recursive: true });
|
|
23633
|
-
dir =
|
|
24470
|
+
dir = path42.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
|
|
23634
24471
|
const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
|
|
23635
24472
|
if (!added.ok)
|
|
23636
24473
|
return { ok: false, conflict: false, worktree: cwd, error: firstLine(added) };
|
|
@@ -23674,7 +24511,7 @@ function stacksDir(cwd) {
|
|
|
23674
24511
|
const root = storeRoot(cwd);
|
|
23675
24512
|
if (!root.ok)
|
|
23676
24513
|
return stackFail(root.code, root.error, root.unblock);
|
|
23677
|
-
return { ok: true, data:
|
|
24514
|
+
return { ok: true, data: path42.join(root.value.root, "stacks") };
|
|
23678
24515
|
}
|
|
23679
24516
|
var HEARTBEAT_STALE_MS = 2 * 60000;
|
|
23680
24517
|
|
|
@@ -23785,7 +24622,7 @@ function fanoutsDir(cwd) {
|
|
|
23785
24622
|
const root = storeRoot(cwd);
|
|
23786
24623
|
if (!root.ok)
|
|
23787
24624
|
return fanoutFail(root.code, root.error, root.unblock);
|
|
23788
|
-
return { ok: true, data:
|
|
24625
|
+
return { ok: true, data: path43.join(root.value.root, "fanouts") };
|
|
23789
24626
|
}
|
|
23790
24627
|
function parseStored(raw) {
|
|
23791
24628
|
if (!isRecord7(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
|
|
@@ -23853,7 +24690,7 @@ function readFanout(cwd, name) {
|
|
|
23853
24690
|
const dir = fanoutsDir(cwd);
|
|
23854
24691
|
if (!dir.ok)
|
|
23855
24692
|
return dir;
|
|
23856
|
-
const file =
|
|
24693
|
+
const file = path43.join(dir.data, stackFileName(name));
|
|
23857
24694
|
let parsed = null;
|
|
23858
24695
|
try {
|
|
23859
24696
|
parsed = parseStored(JSON.parse(fs26.readFileSync(file, "utf8")));
|
|
@@ -23878,7 +24715,7 @@ function listFanouts(cwd) {
|
|
|
23878
24715
|
for (const entry of names) {
|
|
23879
24716
|
let parsed = null;
|
|
23880
24717
|
try {
|
|
23881
|
-
parsed = parseStored(JSON.parse(fs26.readFileSync(
|
|
24718
|
+
parsed = parseStored(JSON.parse(fs26.readFileSync(path43.join(dir.data, entry), "utf8")));
|
|
23882
24719
|
} catch {
|
|
23883
24720
|
parsed = null;
|
|
23884
24721
|
}
|
|
@@ -24570,7 +25407,7 @@ var childTaskMissing = (store, input) => {
|
|
|
24570
25407
|
var childDenial = (identity) => `OpenCode child session has no validated Workit worker: as ${identity} it may only inspect the task summary (workit_task action "inspect") or record evidence or findings (workit_evidence/workit_finding action "record") on an existing task; for anything else the lead assigns it a worker with workit_worker before launching it`;
|
|
24571
25408
|
|
|
24572
25409
|
// packages/workit-opencode/src/v2/shell.ts
|
|
24573
|
-
import
|
|
25410
|
+
import path44 from "node:path";
|
|
24574
25411
|
var commandOf = (input) => {
|
|
24575
25412
|
if (input === null || typeof input !== "object")
|
|
24576
25413
|
return null;
|
|
@@ -24579,7 +25416,7 @@ var commandOf = (input) => {
|
|
|
24579
25416
|
};
|
|
24580
25417
|
var hookInput = (root, sessionID, id, shell) => ({
|
|
24581
25418
|
host: "opencode",
|
|
24582
|
-
cwd: shell.workdir ?
|
|
25419
|
+
cwd: shell.workdir ? path44.resolve(root, shell.workdir) : root,
|
|
24583
25420
|
session: { id: sessionID, agentId: null, agentType: null, parentId: null },
|
|
24584
25421
|
permissionMode: null,
|
|
24585
25422
|
transcriptPath: null,
|
|
@@ -24785,38 +25622,38 @@ var createStopControl = (root, port) => {
|
|
|
24785
25622
|
};
|
|
24786
25623
|
|
|
24787
25624
|
// packages/workit-opencode/src/v2/registry.ts
|
|
24788
|
-
import { existsSync as
|
|
24789
|
-
import
|
|
25625
|
+
import { existsSync as existsSync15, readFileSync as readFileSync11 } from "node:fs";
|
|
25626
|
+
import path46 from "node:path";
|
|
24790
25627
|
|
|
24791
25628
|
// packages/workit-opencode/src/shared/assets.ts
|
|
24792
|
-
import { existsSync as
|
|
24793
|
-
import
|
|
25629
|
+
import { existsSync as existsSync14, realpathSync as realpathSync9 } from "node:fs";
|
|
25630
|
+
import path45 from "node:path";
|
|
24794
25631
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
24795
25632
|
var moduleDir = () => {
|
|
24796
25633
|
try {
|
|
24797
|
-
return realpathSync9(
|
|
25634
|
+
return realpathSync9(path45.dirname(fileURLToPath2(import.meta.url)));
|
|
24798
25635
|
} catch {
|
|
24799
|
-
return
|
|
25636
|
+
return path45.dirname(fileURLToPath2(import.meta.url));
|
|
24800
25637
|
}
|
|
24801
25638
|
};
|
|
24802
25639
|
var packageRoot2 = () => {
|
|
24803
25640
|
const dir = moduleDir();
|
|
24804
25641
|
for (const candidate of [
|
|
24805
|
-
|
|
24806
|
-
|
|
24807
|
-
|
|
25642
|
+
path45.resolve(dir, ".."),
|
|
25643
|
+
path45.resolve(dir, "..", ".."),
|
|
25644
|
+
path45.resolve(dir, "..", "..", "..")
|
|
24808
25645
|
]) {
|
|
24809
|
-
if (
|
|
25646
|
+
if (existsSync14(path45.join(candidate, "package.json")))
|
|
24810
25647
|
return candidate;
|
|
24811
25648
|
}
|
|
24812
|
-
return
|
|
25649
|
+
return path45.resolve(dir, "..");
|
|
24813
25650
|
};
|
|
24814
25651
|
var skillsRoot = () => {
|
|
24815
25652
|
const root = packageRoot2();
|
|
24816
|
-
const canonical =
|
|
24817
|
-
if (
|
|
25653
|
+
const canonical = path45.resolve(root, "..", "workit-core", "skills");
|
|
25654
|
+
if (existsSync14(path45.join(root, "src")) && existsSync14(canonical))
|
|
24818
25655
|
return canonical;
|
|
24819
|
-
return
|
|
25656
|
+
return path45.join(root, "assets", "skills");
|
|
24820
25657
|
};
|
|
24821
25658
|
|
|
24822
25659
|
// packages/workit-opencode/src/v2/registry.ts
|
|
@@ -24840,15 +25677,15 @@ var parseFrontmatter = (markdown) => {
|
|
|
24840
25677
|
};
|
|
24841
25678
|
var registerSkills = async (ctx) => {
|
|
24842
25679
|
const skillsDir = skillsRoot();
|
|
24843
|
-
if (!
|
|
25680
|
+
if (!existsSync15(skillsDir))
|
|
24844
25681
|
return new Set;
|
|
24845
25682
|
const listed = await ctx.skill.list().catch(() => ({ data: [] }));
|
|
24846
|
-
const own = (skill) => typeof skill.path === "string" &&
|
|
25683
|
+
const own = (skill) => typeof skill.path === "string" && path46.resolve(skill.path).startsWith(skillsDir + path46.sep);
|
|
24847
25684
|
const userSkills = new Set((listed?.data ?? []).filter((skill) => !own(skill)).map((skill) => skill.id));
|
|
24848
25685
|
const packaged = new Map;
|
|
24849
25686
|
for (const id of WORKIT_METHOD_SKILLS) {
|
|
24850
|
-
const file =
|
|
24851
|
-
if (!userSkills.has(id) &&
|
|
25687
|
+
const file = path46.join(skillsDir, id, "SKILL.md");
|
|
25688
|
+
if (!userSkills.has(id) && existsSync15(file))
|
|
24852
25689
|
packaged.set(id, file);
|
|
24853
25690
|
}
|
|
24854
25691
|
await ctx.skill.transform((editor) => {
|
|
@@ -24856,7 +25693,7 @@ var registerSkills = async (ctx) => {
|
|
|
24856
25693
|
for (const [id, file] of packaged) {
|
|
24857
25694
|
if (existing.has(id))
|
|
24858
25695
|
continue;
|
|
24859
|
-
const parsed = parseFrontmatter(
|
|
25696
|
+
const parsed = parseFrontmatter(readFileSync11(file, "utf8"));
|
|
24860
25697
|
editor.add({
|
|
24861
25698
|
id,
|
|
24862
25699
|
name: parsed.name || id,
|
|
@@ -24894,25 +25731,25 @@ var registerCommands = async (ctx, registeredSkills) => {
|
|
|
24894
25731
|
};
|
|
24895
25732
|
|
|
24896
25733
|
// packages/workit-opencode/src/stale-sources.ts
|
|
24897
|
-
import { existsSync as
|
|
24898
|
-
import
|
|
25734
|
+
import { existsSync as existsSync16, readdirSync as readdirSync6 } from "node:fs";
|
|
25735
|
+
import path47 from "node:path";
|
|
24899
25736
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
24900
25737
|
var typescriptFiles = (directory) => {
|
|
24901
|
-
if (!
|
|
25738
|
+
if (!existsSync16(directory))
|
|
24902
25739
|
return [];
|
|
24903
25740
|
return readdirSync6(directory, { withFileTypes: true }).flatMap((entry) => {
|
|
24904
|
-
const file =
|
|
25741
|
+
const file = path47.join(directory, entry.name);
|
|
24905
25742
|
return entry.isDirectory() ? typescriptFiles(file) : entry.isFile() && file.endsWith(".ts") ? [file] : [];
|
|
24906
25743
|
});
|
|
24907
25744
|
};
|
|
24908
25745
|
var pluginSourceFiles = [
|
|
24909
25746
|
...new Set([
|
|
24910
25747
|
fileURLToPath3(import.meta.url),
|
|
24911
|
-
...typescriptFiles(
|
|
24912
|
-
|
|
24913
|
-
...typescriptFiles(
|
|
25748
|
+
...typescriptFiles(path47.join(packageRoot2(), "src")),
|
|
25749
|
+
path47.join(packageRoot2(), "..", "workit-core", "src", "core.ts"),
|
|
25750
|
+
...typescriptFiles(path47.join(packageRoot2(), "..", "workit-core", "src", "core"))
|
|
24914
25751
|
])
|
|
24915
|
-
].filter((file) =>
|
|
25752
|
+
].filter((file) => existsSync16(file)).toSorted();
|
|
24916
25753
|
|
|
24917
25754
|
// packages/workit-opencode/src/v2/plugin.ts
|
|
24918
25755
|
var sessionFacts = async (ctx, sessionID) => {
|