@brainervirus/workit-claude-code 7.3.0 → 7.4.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/.claude-plugin/plugin.json +1 -1
- package/dist/workit-hook.js +29 -30
- package/dist/workit.js +512 -190
- package/package.json +3 -3
- package/skills/retro/SKILL.md +72 -0
- package/skills/retro/agents/openai.yaml +3 -0
- package/skills/retro/references/sources.md +35 -0
- package/skills/retro/references/steering.md +39 -0
- package/skills/review/SKILL.md +3 -2
- package/skills/shape/references/knowledge.md +3 -0
- package/skills/ship/SKILL.md +2 -1
package/dist/workit.js
CHANGED
|
@@ -65,7 +65,7 @@ var package_default;
|
|
|
65
65
|
var init_package = __esm(() => {
|
|
66
66
|
package_default = {
|
|
67
67
|
name: "@brainervirus/workit-cli",
|
|
68
|
-
version: "7.
|
|
68
|
+
version: "7.4.0",
|
|
69
69
|
private: false,
|
|
70
70
|
description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
71
71
|
keywords: [
|
|
@@ -103,9 +103,9 @@ var init_package = __esm(() => {
|
|
|
103
103
|
},
|
|
104
104
|
dependencies: {
|
|
105
105
|
"@babel/parser": "7.29.9",
|
|
106
|
-
"@brainervirus/workit-core": "^7.
|
|
107
|
-
"@brainervirus/workit-cursor": "^7.
|
|
108
|
-
"@brainervirus/workit-opencode": "^7.
|
|
106
|
+
"@brainervirus/workit-core": "^7.4.0",
|
|
107
|
+
"@brainervirus/workit-cursor": "^7.4.0",
|
|
108
|
+
"@brainervirus/workit-opencode": "^7.4.0",
|
|
109
109
|
"@inkjs/ui": "2.0.0",
|
|
110
110
|
ink: "7.1.1",
|
|
111
111
|
react: "19.2.8"
|
|
@@ -63144,7 +63144,8 @@ var init_skill_manifests = __esm(() => {
|
|
|
63144
63144
|
"workit-test-audit",
|
|
63145
63145
|
"workit-deslop",
|
|
63146
63146
|
"workit-fanout",
|
|
63147
|
-
"workit-verify-app"
|
|
63147
|
+
"workit-verify-app",
|
|
63148
|
+
"workit-retro"
|
|
63148
63149
|
];
|
|
63149
63150
|
if (false) {}
|
|
63150
63151
|
});
|
|
@@ -69916,6 +69917,270 @@ var init_launch = __esm(() => {
|
|
|
69916
69917
|
init_upgrade();
|
|
69917
69918
|
});
|
|
69918
69919
|
|
|
69920
|
+
// packages/workit-core/src/knowledge.ts
|
|
69921
|
+
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
69922
|
+
import fs17 from "node:fs";
|
|
69923
|
+
import path36 from "node:path";
|
|
69924
|
+
function lintKnowledge(root) {
|
|
69925
|
+
const seen = new Set;
|
|
69926
|
+
const unreadable = [];
|
|
69927
|
+
const load = (file) => {
|
|
69928
|
+
const doc = read(root, file);
|
|
69929
|
+
if (doc === "unreadable")
|
|
69930
|
+
unreadable.push(file);
|
|
69931
|
+
if (doc === null || doc === "unreadable" || seen.has(doc.real))
|
|
69932
|
+
return null;
|
|
69933
|
+
seen.add(doc.real);
|
|
69934
|
+
return doc;
|
|
69935
|
+
};
|
|
69936
|
+
const steering = STEERING_FILES.map(load).filter((doc) => doc !== null);
|
|
69937
|
+
const needBased = NEED_BASED_FILES.map(load).filter((doc) => doc !== null);
|
|
69938
|
+
const findings = [];
|
|
69939
|
+
for (const doc of steering) {
|
|
69940
|
+
const bytes = Buffer.byteLength(doc.text);
|
|
69941
|
+
if (bytes > AGENTS_BYTE_BUDGET)
|
|
69942
|
+
findings.push({
|
|
69943
|
+
rule: "agents-budget",
|
|
69944
|
+
file: doc.file,
|
|
69945
|
+
line: null,
|
|
69946
|
+
message: `${bytes} bytes, over the ${AGENTS_BYTE_BUDGET}-byte budget; move detail behind a pointer or into a check, and name what each addition removes`
|
|
69947
|
+
});
|
|
69948
|
+
}
|
|
69949
|
+
for (const doc of needBased)
|
|
69950
|
+
if (scaffoldOnly(doc))
|
|
69951
|
+
findings.push({
|
|
69952
|
+
rule: "scaffold-file",
|
|
69953
|
+
file: doc.file,
|
|
69954
|
+
line: null,
|
|
69955
|
+
message: "holds no entry (headings, comments or placeholders only); delete it, or create it in the same edit as its first real entry"
|
|
69956
|
+
});
|
|
69957
|
+
const tracked = trackedTopLevel(root);
|
|
69958
|
+
for (const doc of [...steering, ...needBased])
|
|
69959
|
+
findings.push(...brokenLinks(root, doc, tracked));
|
|
69960
|
+
const standards = needBased.find((doc) => doc.file === STANDARDS_FILE);
|
|
69961
|
+
if (standards)
|
|
69962
|
+
findings.push(...duplicateRules(steering, standards));
|
|
69963
|
+
return {
|
|
69964
|
+
root,
|
|
69965
|
+
budget: AGENTS_BYTE_BUDGET,
|
|
69966
|
+
files: [...steering, ...needBased].map((doc) => ({
|
|
69967
|
+
file: doc.file,
|
|
69968
|
+
bytes: Buffer.byteLength(doc.text)
|
|
69969
|
+
})),
|
|
69970
|
+
findings,
|
|
69971
|
+
unreadable
|
|
69972
|
+
};
|
|
69973
|
+
}
|
|
69974
|
+
var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODING_STANDARDS.md", MIN_RULE_WORDS = 6, FENCE, HEADING, TABLE_SEPARATOR, LIST_ITEM, PLACEHOLDER2, INDENTED_CODE, blank = (line) => (line ?? "").trim() === "", proseLines = (lines) => {
|
|
69975
|
+
const out = [];
|
|
69976
|
+
let fence = null;
|
|
69977
|
+
let comment = false;
|
|
69978
|
+
let indentedCode = false;
|
|
69979
|
+
let inList = false;
|
|
69980
|
+
lines.forEach((raw, index) => {
|
|
69981
|
+
if (fence) {
|
|
69982
|
+
const close = FENCE.exec(raw);
|
|
69983
|
+
if (close && close[1][0] === fence[0] && close[1].length >= fence.length && !close[2].trim())
|
|
69984
|
+
fence = null;
|
|
69985
|
+
return;
|
|
69986
|
+
}
|
|
69987
|
+
if (!comment) {
|
|
69988
|
+
const open = FENCE.exec(raw);
|
|
69989
|
+
if (open && !(open[1][0] === "`" && open[2].includes("`"))) {
|
|
69990
|
+
fence = open[1];
|
|
69991
|
+
indentedCode = false;
|
|
69992
|
+
return;
|
|
69993
|
+
}
|
|
69994
|
+
if (INDENTED_CODE.test(raw) && !blank(raw)) {
|
|
69995
|
+
if (indentedCode || !inList && blank(lines[index - 1])) {
|
|
69996
|
+
indentedCode = true;
|
|
69997
|
+
return;
|
|
69998
|
+
}
|
|
69999
|
+
} else if (!blank(raw)) {
|
|
70000
|
+
indentedCode = false;
|
|
70001
|
+
inList = LIST_ITEM.test(raw) || inList && /^\s/.test(raw);
|
|
70002
|
+
}
|
|
70003
|
+
}
|
|
70004
|
+
let text = raw;
|
|
70005
|
+
if (comment) {
|
|
70006
|
+
const end = text.indexOf("-->");
|
|
70007
|
+
if (end === -1)
|
|
70008
|
+
return;
|
|
70009
|
+
comment = false;
|
|
70010
|
+
text = text.slice(end + 3);
|
|
70011
|
+
}
|
|
70012
|
+
text = text.replace(/<!--[\s\S]*?-->/g, "");
|
|
70013
|
+
const open = text.indexOf("<!--");
|
|
70014
|
+
if (open !== -1) {
|
|
70015
|
+
comment = true;
|
|
70016
|
+
text = text.slice(0, open);
|
|
70017
|
+
}
|
|
70018
|
+
out.push({ index, text });
|
|
70019
|
+
});
|
|
70020
|
+
return out;
|
|
70021
|
+
}, withoutFrontMatter = (lines) => {
|
|
70022
|
+
if (lines[0]?.trim() !== "---")
|
|
70023
|
+
return lines;
|
|
70024
|
+
const end = lines.indexOf("---", 1);
|
|
70025
|
+
return end === -1 ? lines : [...lines.slice(0, end + 1).map(() => ""), ...lines.slice(end + 1)];
|
|
70026
|
+
}, read = (root, file) => {
|
|
70027
|
+
const full = path36.join(root, file);
|
|
70028
|
+
try {
|
|
70029
|
+
fs17.lstatSync(full);
|
|
70030
|
+
} catch {
|
|
70031
|
+
return null;
|
|
70032
|
+
}
|
|
70033
|
+
try {
|
|
70034
|
+
if (!fs17.statSync(full).isFile())
|
|
70035
|
+
return null;
|
|
70036
|
+
const text = fs17.readFileSync(full, "utf8");
|
|
70037
|
+
return { file, text, lines: text.split(/\r?\n/), real: fs17.realpathSync(full) };
|
|
70038
|
+
} catch {
|
|
70039
|
+
return "unreadable";
|
|
70040
|
+
}
|
|
70041
|
+
}, trackedTopLevel = (root) => {
|
|
70042
|
+
const run = spawnSync14("git", ["ls-files", "-z", "--cached"], {
|
|
70043
|
+
cwd: root,
|
|
70044
|
+
encoding: "utf8",
|
|
70045
|
+
maxBuffer: 256 * 1024 * 1024,
|
|
70046
|
+
timeout: 20000,
|
|
70047
|
+
windowsHide: true
|
|
70048
|
+
});
|
|
70049
|
+
if (run.status !== 0)
|
|
70050
|
+
return null;
|
|
70051
|
+
return new Set(run.stdout.split("\x00").filter(Boolean).map((file) => file.split("/")[0]));
|
|
70052
|
+
}, exists = (target) => {
|
|
70053
|
+
try {
|
|
70054
|
+
fs17.statSync(target);
|
|
70055
|
+
return true;
|
|
70056
|
+
} catch {
|
|
70057
|
+
return false;
|
|
70058
|
+
}
|
|
70059
|
+
}, LINK, REFERENCE_DEFINITION, CODE_SPAN, PATH_LIKE, isExternal = (target) => /^[a-z][a-z0-9+.-]*:/i.test(target) || target.startsWith("#") || target.startsWith("//"), localTarget = (target) => {
|
|
70060
|
+
const bare = target.replace(/[#?].*$/, "");
|
|
70061
|
+
try {
|
|
70062
|
+
return decodeURIComponent(bare);
|
|
70063
|
+
} catch {
|
|
70064
|
+
return bare;
|
|
70065
|
+
}
|
|
70066
|
+
}, brokenLinks = (root, doc, tracked) => {
|
|
70067
|
+
const findings = [];
|
|
70068
|
+
const base = path36.dirname(path36.join(root, doc.file));
|
|
70069
|
+
const missing = (target, line, how) => findings.push({
|
|
70070
|
+
rule: "broken-link",
|
|
70071
|
+
file: doc.file,
|
|
70072
|
+
line,
|
|
70073
|
+
message: `${how} \`${target}\` points at a missing file`
|
|
70074
|
+
});
|
|
70075
|
+
for (const { index, text } of proseLines(doc.lines)) {
|
|
70076
|
+
const prose = text.replace(CODE_SPAN, (span) => " ".repeat(span.length));
|
|
70077
|
+
const targets = [...prose.matchAll(LINK)].map((match) => match[1] ?? match[2]);
|
|
70078
|
+
const definition = REFERENCE_DEFINITION.exec(prose)?.[1];
|
|
70079
|
+
if (definition)
|
|
70080
|
+
targets.push(definition);
|
|
70081
|
+
for (const target of targets) {
|
|
70082
|
+
if (isExternal(target))
|
|
70083
|
+
continue;
|
|
70084
|
+
const local = localTarget(target);
|
|
70085
|
+
if (!local)
|
|
70086
|
+
continue;
|
|
70087
|
+
const resolved = local.startsWith("/") ? path36.join(root, local) : path36.resolve(base, local);
|
|
70088
|
+
if (!exists(resolved))
|
|
70089
|
+
missing(target, index + 1, "link");
|
|
70090
|
+
}
|
|
70091
|
+
for (const [, span] of text.matchAll(CODE_SPAN)) {
|
|
70092
|
+
const candidate = span.replace(/:\d+(?::\d+)?$/, "");
|
|
70093
|
+
if (!PATH_LIKE.test(candidate))
|
|
70094
|
+
continue;
|
|
70095
|
+
const relative = /^\.\.?\//.test(candidate);
|
|
70096
|
+
const first = candidate.split("/")[0];
|
|
70097
|
+
if (!relative && !(tracked ? tracked.has(first) : exists(path36.join(root, first))))
|
|
70098
|
+
continue;
|
|
70099
|
+
const resolved = relative ? path36.resolve(base, candidate) : path36.join(root, candidate);
|
|
70100
|
+
if (!exists(resolved))
|
|
70101
|
+
missing(span, index + 1, "pointer");
|
|
70102
|
+
}
|
|
70103
|
+
}
|
|
70104
|
+
return findings;
|
|
70105
|
+
}, isPlaceholder2 = (text) => PLACEHOLDER2.test(text.replace(LIST_ITEM, "").replace(/[*_`]/g, "").replace(/^\[\s?\]\s*/, "").trim()), scaffoldOnly = (doc) => {
|
|
70106
|
+
const lines = proseLines(withoutFrontMatter(doc.lines));
|
|
70107
|
+
return lines.every(({ text }, position) => {
|
|
70108
|
+
const trimmed = text.trim();
|
|
70109
|
+
if (trimmed === "" || HEADING.test(text) || /^([-*_])(\s*\1){2,}$/.test(trimmed))
|
|
70110
|
+
return true;
|
|
70111
|
+
if (TABLE_SEPARATOR.test(text))
|
|
70112
|
+
return true;
|
|
70113
|
+
const next = lines[position + 1]?.text ?? "";
|
|
70114
|
+
if (trimmed.startsWith("|") && TABLE_SEPARATOR.test(next))
|
|
70115
|
+
return true;
|
|
70116
|
+
if (trimmed.startsWith("|"))
|
|
70117
|
+
return trimmed.split("|").map((cell) => cell.trim()).every((cell) => cell === "" || isPlaceholder2(cell));
|
|
70118
|
+
return isPlaceholder2(trimmed);
|
|
70119
|
+
});
|
|
70120
|
+
}, ruleUnits = (doc) => {
|
|
70121
|
+
const units = [];
|
|
70122
|
+
let current = null;
|
|
70123
|
+
const flush = () => {
|
|
70124
|
+
if (current)
|
|
70125
|
+
units.push(current);
|
|
70126
|
+
current = null;
|
|
70127
|
+
};
|
|
70128
|
+
for (const { index, text } of proseLines(doc.lines)) {
|
|
70129
|
+
const trimmed = text.trim();
|
|
70130
|
+
if (trimmed === "" || HEADING.test(text) || trimmed.startsWith("|")) {
|
|
70131
|
+
flush();
|
|
70132
|
+
continue;
|
|
70133
|
+
}
|
|
70134
|
+
if (LIST_ITEM.test(text) || !current) {
|
|
70135
|
+
flush();
|
|
70136
|
+
current = { line: index + 1, text: trimmed.replace(LIST_ITEM, "") };
|
|
70137
|
+
} else
|
|
70138
|
+
current.text += ` ${trimmed}`;
|
|
70139
|
+
}
|
|
70140
|
+
flush();
|
|
70141
|
+
return units;
|
|
70142
|
+
}, normalize = (sentence) => sentence.replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/[*_`]/g, "").toLowerCase().replace(/\s+/g, " ").replace(/[\s.,;:!?]+$/, "").trim(), sentences = (doc) => {
|
|
70143
|
+
const out = new Map;
|
|
70144
|
+
for (const unit of ruleUnits(doc))
|
|
70145
|
+
for (const sentence of unit.text.split(/(?<=[.!?])\s+/)) {
|
|
70146
|
+
const key = normalize(sentence);
|
|
70147
|
+
if (key.split(" ").length >= MIN_RULE_WORDS && !out.has(key))
|
|
70148
|
+
out.set(key, unit.line);
|
|
70149
|
+
}
|
|
70150
|
+
return out;
|
|
70151
|
+
}, duplicateRules = (steering, standards) => {
|
|
70152
|
+
const findings = [];
|
|
70153
|
+
const rules = sentences(standards);
|
|
70154
|
+
for (const doc of steering)
|
|
70155
|
+
for (const [key, line] of sentences(doc)) {
|
|
70156
|
+
const standardsLine = rules.get(key);
|
|
70157
|
+
if (standardsLine === undefined)
|
|
70158
|
+
continue;
|
|
70159
|
+
findings.push({
|
|
70160
|
+
rule: "duplicate-rule",
|
|
70161
|
+
file: doc.file,
|
|
70162
|
+
line,
|
|
70163
|
+
message: `repeats ${standards.file}:${standardsLine} ("${key.slice(0, 60)}${key.length > 60 ? "…" : ""}"); keep the rule in one file`
|
|
70164
|
+
});
|
|
70165
|
+
}
|
|
70166
|
+
return findings;
|
|
70167
|
+
};
|
|
70168
|
+
var init_knowledge = __esm(() => {
|
|
70169
|
+
AGENTS_BYTE_BUDGET = 8 * 1024;
|
|
70170
|
+
STEERING_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
70171
|
+
NEED_BASED_FILES = ["CODING_STANDARDS.md", "GLOSSARY.md"];
|
|
70172
|
+
FENCE = /^ {0,3}(`{3,}|~{3,})(.*)$/;
|
|
70173
|
+
HEADING = /^\s{0,3}#{1,6}(\s|$)/;
|
|
70174
|
+
TABLE_SEPARATOR = /^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)*\|?\s*$/;
|
|
70175
|
+
LIST_ITEM = /^\s*(?:[-*+]|\d+[.)])\s+/;
|
|
70176
|
+
PLACEHOLDER2 = /^(?:(?:tbd|todo|tba|fixme)\b.*|n\/a|none|none yet|coming soon|placeholder|\.\.\.|…|-)?[.:]?$/i;
|
|
70177
|
+
INDENTED_CODE = /^(?: {4}|\t)/;
|
|
70178
|
+
LINK = /!?\[[^\]]*\]\(\s*(?:<([^>\n]+)>|((?:[^()\s<>]|\([^()\s]*\))+))(?:\s+["'(][^)]*)?\)/g;
|
|
70179
|
+
REFERENCE_DEFINITION = /^\s{0,3}\[[^\]]+\]:\s*<?(\S+?)>?(?:\s|$)/;
|
|
70180
|
+
CODE_SPAN = /`([^`\n]+)`/g;
|
|
70181
|
+
PATH_LIKE = /^(?:\.{1,2}\/)?[\w@.-]+(?:\/[\w@.-]+)+\/?$/;
|
|
70182
|
+
});
|
|
70183
|
+
|
|
69919
70184
|
// packages/workit-cli/src/prompt.ts
|
|
69920
70185
|
import { createInterface } from "node:readline/promises";
|
|
69921
70186
|
async function askLine(question, output = process.stdout) {
|
|
@@ -69999,8 +70264,23 @@ async function run5(argv, io) {
|
|
|
69999
70264
|
fixLock = clearStaleMetadataLock(root, { force });
|
|
70000
70265
|
}
|
|
70001
70266
|
const report = runDoctor({ host: "cli", cwd: io.cwd, workspaceRoot: root });
|
|
70267
|
+
let knowledge = null;
|
|
70268
|
+
try {
|
|
70269
|
+
knowledge = lintKnowledge(root);
|
|
70270
|
+
if (knowledge.unreadable.length > 0)
|
|
70271
|
+
knowledge = null;
|
|
70272
|
+
} catch {
|
|
70273
|
+
knowledge = null;
|
|
70274
|
+
}
|
|
70275
|
+
const agents = knowledge?.files.find((file) => file.file === "AGENTS.md");
|
|
70276
|
+
const knowledgeLine = knowledge ? `info knowledge — ${agents ? `AGENTS.md ${agents.bytes} of ${knowledge.budget} bytes` : "no AGENTS.md"}; ${knowledge.findings.length} finding(s) (workit knowledge lint)` : "info knowledge — unavailable";
|
|
70002
70277
|
if (argv.includes("--json")) {
|
|
70003
|
-
|
|
70278
|
+
const summary = knowledge ? {
|
|
70279
|
+
agentsBytes: agents?.bytes ?? null,
|
|
70280
|
+
budget: knowledge.budget,
|
|
70281
|
+
findings: knowledge.findings.length
|
|
70282
|
+
} : { unavailable: true };
|
|
70283
|
+
io.stdout(`${JSON.stringify({ ...report, ...fixLock ? { fixLock } : {}, knowledge: summary }, null, 2)}
|
|
70004
70284
|
`);
|
|
70005
70285
|
return report.exitCode;
|
|
70006
70286
|
}
|
|
@@ -70019,12 +70299,15 @@ async function run5(argv, io) {
|
|
|
70019
70299
|
io.stdout(` fix: ${check.fix}
|
|
70020
70300
|
`);
|
|
70021
70301
|
}
|
|
70302
|
+
io.stdout(`${knowledgeLine}
|
|
70303
|
+
`);
|
|
70022
70304
|
io.stdout(`passed ${report.summary.passed} / warned ${report.summary.warned} / failed ${report.summary.failed}
|
|
70023
70305
|
`);
|
|
70024
70306
|
return report.exitCode;
|
|
70025
70307
|
}
|
|
70026
70308
|
var init_doctor2 = __esm(() => {
|
|
70027
70309
|
init_doctor();
|
|
70310
|
+
init_knowledge();
|
|
70028
70311
|
init_store_lock();
|
|
70029
70312
|
init_output();
|
|
70030
70313
|
init_prompt();
|
|
@@ -70135,11 +70418,11 @@ var init_redact = __esm(() => {
|
|
|
70135
70418
|
});
|
|
70136
70419
|
|
|
70137
70420
|
// packages/workit-core/src/checks.ts
|
|
70138
|
-
import { spawn, spawnSync as
|
|
70421
|
+
import { spawn, spawnSync as spawnSync15 } from "node:child_process";
|
|
70139
70422
|
import { createHash as createHash14 } from "node:crypto";
|
|
70140
|
-
import
|
|
70423
|
+
import fs18 from "node:fs";
|
|
70141
70424
|
import os13 from "node:os";
|
|
70142
|
-
import
|
|
70425
|
+
import path37 from "node:path";
|
|
70143
70426
|
import { StringDecoder } from "node:string_decoder";
|
|
70144
70427
|
function tailLines(text, lines = TAIL_LINES) {
|
|
70145
70428
|
const all = text.replace(/\r\n?/gu, `
|
|
@@ -70259,10 +70542,10 @@ function planSpawn(argv, options) {
|
|
|
70259
70542
|
return { file: argv[0], args: [], verbatim: false, shell: true };
|
|
70260
70543
|
if (options.platform !== "win32")
|
|
70261
70544
|
return { file: argv[0], args: argv.slice(1), verbatim: false, shell: false };
|
|
70262
|
-
const win =
|
|
70545
|
+
const win = path37.win32;
|
|
70263
70546
|
const isFile = options.isFile ?? ((file) => {
|
|
70264
70547
|
try {
|
|
70265
|
-
return
|
|
70548
|
+
return fs18.statSync(file).isFile();
|
|
70266
70549
|
} catch {
|
|
70267
70550
|
return false;
|
|
70268
70551
|
}
|
|
@@ -70314,7 +70597,7 @@ function runCheckCommand(argv, options) {
|
|
|
70314
70597
|
if (!child?.pid)
|
|
70315
70598
|
return;
|
|
70316
70599
|
if (windows)
|
|
70317
|
-
|
|
70600
|
+
spawnSync15("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
70318
70601
|
stdio: "ignore",
|
|
70319
70602
|
windowsHide: true
|
|
70320
70603
|
});
|
|
@@ -70416,13 +70699,13 @@ function runCheckCommand(argv, options) {
|
|
|
70416
70699
|
function storeLog(storeRoot, log) {
|
|
70417
70700
|
const digest = logDigest(log);
|
|
70418
70701
|
const ref = `blobs/logs/${digest.slice("sha256:".length)}.log`;
|
|
70419
|
-
const file =
|
|
70702
|
+
const file = path37.join(storeRoot, ref);
|
|
70420
70703
|
try {
|
|
70421
|
-
if (!
|
|
70422
|
-
|
|
70704
|
+
if (!fs18.existsSync(file)) {
|
|
70705
|
+
fs18.mkdirSync(path37.dirname(file), { recursive: true });
|
|
70423
70706
|
const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
70424
|
-
|
|
70425
|
-
|
|
70707
|
+
fs18.writeFileSync(temp, log, { mode: 384 });
|
|
70708
|
+
fs18.renameSync(temp, file);
|
|
70426
70709
|
}
|
|
70427
70710
|
return { digest, ref };
|
|
70428
70711
|
} catch {
|
|
@@ -70432,17 +70715,17 @@ function storeLog(storeRoot, log) {
|
|
|
70432
70715
|
function pruneCheckLogs(storeRoot, options = {}) {
|
|
70433
70716
|
const limits = { ...LOG_RETENTION, ...options.retention };
|
|
70434
70717
|
const now = options.now ?? Date.now();
|
|
70435
|
-
const dir =
|
|
70718
|
+
const dir = path37.join(storeRoot, "blobs", "logs");
|
|
70436
70719
|
const report = { removed: 0, removedBytes: 0, kept: 0 };
|
|
70437
70720
|
let names;
|
|
70438
70721
|
try {
|
|
70439
|
-
names =
|
|
70722
|
+
names = fs18.readdirSync(dir);
|
|
70440
70723
|
} catch {
|
|
70441
70724
|
return report;
|
|
70442
70725
|
}
|
|
70443
70726
|
const files = names.flatMap((name) => {
|
|
70444
70727
|
try {
|
|
70445
|
-
const stat =
|
|
70728
|
+
const stat = fs18.statSync(path37.join(dir, name));
|
|
70446
70729
|
return stat.isFile() ? [{ name, size: stat.size, mtimeMs: stat.mtimeMs }] : [];
|
|
70447
70730
|
} catch {
|
|
70448
70731
|
return [];
|
|
@@ -70461,7 +70744,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
70461
70744
|
continue;
|
|
70462
70745
|
if (!options.dryRun)
|
|
70463
70746
|
try {
|
|
70464
|
-
|
|
70747
|
+
fs18.rmSync(path37.join(dir, file.name), { force: true });
|
|
70465
70748
|
} catch {
|
|
70466
70749
|
continue;
|
|
70467
70750
|
}
|
|
@@ -70712,7 +70995,7 @@ var exports_check = {};
|
|
|
70712
70995
|
__export(exports_check, {
|
|
70713
70996
|
run: () => run9
|
|
70714
70997
|
});
|
|
70715
|
-
import
|
|
70998
|
+
import path38 from "node:path";
|
|
70716
70999
|
function parse5(argv) {
|
|
70717
71000
|
const split = argv.indexOf("--");
|
|
70718
71001
|
const head = split >= 0 ? argv.slice(0, split) : [...argv];
|
|
@@ -70895,7 +71178,7 @@ async function run9(argv, io) {
|
|
|
70895
71178
|
if (options.shell && command.length !== 1)
|
|
70896
71179
|
return emit(io, fail("invalid_input", '--shell takes the command as one string: workit check --shell -- "<cmd>"'));
|
|
70897
71180
|
}
|
|
70898
|
-
const relCwd = posix(
|
|
71181
|
+
const relCwd = posix(path38.relative(top, runCwd));
|
|
70899
71182
|
const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
|
|
70900
71183
|
const actor = actorFromEnv(io.env);
|
|
70901
71184
|
const branchKey = codeKey(io.cwd, { base: options.base });
|
|
@@ -71019,7 +71302,7 @@ async function run9(argv, io) {
|
|
|
71019
71302
|
return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
|
|
71020
71303
|
return 0;
|
|
71021
71304
|
}
|
|
71022
|
-
var USAGE3 = "workit check <name> | workit check [--name <n>] [--shell] [--timeout <s>] [--task <id>] [--json] -- <cmd…>", RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(
|
|
71305
|
+
var USAGE3 = "workit check <name> | workit check [--name <n>] [--shell] [--timeout <s>] [--task <id>] [--json] -- <cmd…>", RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path38.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS;
|
|
71023
71306
|
var init_check = __esm(() => {
|
|
71024
71307
|
init_check_config();
|
|
71025
71308
|
init_checks3();
|
|
@@ -71040,7 +71323,7 @@ var init_check = __esm(() => {
|
|
|
71040
71323
|
var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock) => ({ ok: false, code, error, ...unblock ? { unblock } : {} });
|
|
71041
71324
|
|
|
71042
71325
|
// packages/workit-core/src/git/ops.ts
|
|
71043
|
-
import { spawnSync as
|
|
71326
|
+
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
71044
71327
|
function dirtEntries(cwd) {
|
|
71045
71328
|
const run = git5(cwd, ["status", "--porcelain=v1", "-z", "--untracked-files=all"]);
|
|
71046
71329
|
if (!run.ok)
|
|
@@ -71384,7 +71667,7 @@ ${run.stdout}`;
|
|
|
71384
71667
|
return /stale info|cannot lock ref|fetch first|non-fast-forward/iu.test(text) ? { ok: false, lease: true, error: "the remote branch tip changed before deletion" } : { ok: false, lease: false, error: gitError(run) };
|
|
71385
71668
|
}
|
|
71386
71669
|
var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}) => {
|
|
71387
|
-
const result =
|
|
71670
|
+
const result = spawnSync16("git", args, {
|
|
71388
71671
|
cwd,
|
|
71389
71672
|
encoding: "utf8",
|
|
71390
71673
|
env: { ...options.env ?? process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
@@ -71420,11 +71703,11 @@ var init_ops = __esm(() => {
|
|
|
71420
71703
|
});
|
|
71421
71704
|
|
|
71422
71705
|
// packages/workit-core/src/forge/reruns.ts
|
|
71423
|
-
import
|
|
71424
|
-
import
|
|
71706
|
+
import fs19 from "node:fs";
|
|
71707
|
+
import path39 from "node:path";
|
|
71425
71708
|
function rerunLogPath(cwd) {
|
|
71426
71709
|
const common = gitCommonDir(cwd);
|
|
71427
|
-
return common ?
|
|
71710
|
+
return common ? path39.join(common, "workit", "ci-reruns.jsonl") : null;
|
|
71428
71711
|
}
|
|
71429
71712
|
function rerunCounts(cwd, key) {
|
|
71430
71713
|
const counts = new Map;
|
|
@@ -71433,7 +71716,7 @@ function rerunCounts(cwd, key) {
|
|
|
71433
71716
|
return counts;
|
|
71434
71717
|
let text;
|
|
71435
71718
|
try {
|
|
71436
|
-
text =
|
|
71719
|
+
text = fs19.readFileSync(file, "utf8");
|
|
71437
71720
|
} catch {
|
|
71438
71721
|
return counts;
|
|
71439
71722
|
}
|
|
@@ -71459,8 +71742,8 @@ function recordReruns(cwd, rows) {
|
|
|
71459
71742
|
if (!file)
|
|
71460
71743
|
return false;
|
|
71461
71744
|
try {
|
|
71462
|
-
|
|
71463
|
-
|
|
71745
|
+
fs19.mkdirSync(path39.dirname(file), { recursive: true });
|
|
71746
|
+
fs19.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
|
|
71464
71747
|
`).join(""));
|
|
71465
71748
|
return true;
|
|
71466
71749
|
} catch {
|
|
@@ -71472,18 +71755,18 @@ function withRerunLock(cwd, fn) {
|
|
|
71472
71755
|
if (!file)
|
|
71473
71756
|
return fn();
|
|
71474
71757
|
const lock = `${file.slice(0, -".jsonl".length)}.lock`;
|
|
71475
|
-
|
|
71758
|
+
fs19.mkdirSync(path39.dirname(lock), { recursive: true });
|
|
71476
71759
|
const until = Date.now() + LOCK_WAIT_MS2;
|
|
71477
71760
|
for (;; ) {
|
|
71478
71761
|
try {
|
|
71479
|
-
|
|
71762
|
+
fs19.closeSync(fs19.openSync(lock, "wx"));
|
|
71480
71763
|
break;
|
|
71481
71764
|
} catch (error) {
|
|
71482
71765
|
if (error.code !== "EEXIST")
|
|
71483
71766
|
throw error;
|
|
71484
71767
|
try {
|
|
71485
|
-
if (Date.now() -
|
|
71486
|
-
|
|
71768
|
+
if (Date.now() - fs19.statSync(lock).mtimeMs > LOCK_STALE_MS2) {
|
|
71769
|
+
fs19.rmSync(lock, { force: true });
|
|
71487
71770
|
continue;
|
|
71488
71771
|
}
|
|
71489
71772
|
} catch {
|
|
@@ -71497,7 +71780,7 @@ function withRerunLock(cwd, fn) {
|
|
|
71497
71780
|
try {
|
|
71498
71781
|
return fn();
|
|
71499
71782
|
} finally {
|
|
71500
|
-
|
|
71783
|
+
fs19.rmSync(lock, { force: true });
|
|
71501
71784
|
}
|
|
71502
71785
|
}
|
|
71503
71786
|
var isRow = (value) => {
|
|
@@ -71865,7 +72148,7 @@ var init_report = __esm(() => {
|
|
|
71865
72148
|
});
|
|
71866
72149
|
|
|
71867
72150
|
// packages/workit-core/src/forge/pr-ops.ts
|
|
71868
|
-
import { spawnSync as
|
|
72151
|
+
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
71869
72152
|
function fillFromCommits(cwd, resolved, base) {
|
|
71870
72153
|
const tracking = `refs/remotes/${resolved.baseRemote}/${base}`;
|
|
71871
72154
|
if (!base.startsWith("-"))
|
|
@@ -71873,7 +72156,7 @@ function fillFromCommits(cwd, resolved, base) {
|
|
|
71873
72156
|
const from = resolveRef(cwd, tracking) ?? resolveRef(cwd, `refs/heads/${base}`);
|
|
71874
72157
|
if (!from)
|
|
71875
72158
|
return failure3("not_found", `base ${base} is not available locally`, `git fetch ${resolved.baseRemote} ${base}`);
|
|
71876
|
-
const log =
|
|
72159
|
+
const log = spawnSync17("git", ["log", "--reverse", "--no-merges", "--format=%s%x1f%b%x1e", `${from}..HEAD`], {
|
|
71877
72160
|
cwd,
|
|
71878
72161
|
encoding: "utf8",
|
|
71879
72162
|
timeout: GIT_TIMEOUTS.local,
|
|
@@ -72148,17 +72431,17 @@ var init_pr_ops = __esm(() => {
|
|
|
72148
72431
|
});
|
|
72149
72432
|
|
|
72150
72433
|
// packages/workit-core/src/forge/exec.ts
|
|
72151
|
-
import { spawnSync as
|
|
72152
|
-
import
|
|
72153
|
-
import
|
|
72434
|
+
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
72435
|
+
import fs20 from "node:fs";
|
|
72436
|
+
import path40 from "node:path";
|
|
72154
72437
|
function findExecutable(bin, env) {
|
|
72155
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
72438
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path40.delimiter).filter(Boolean);
|
|
72156
72439
|
const exts = process.platform === "win32" ? [".exe"] : [""];
|
|
72157
72440
|
for (const dir of dirs)
|
|
72158
72441
|
for (const ext of exts) {
|
|
72159
|
-
const candidate =
|
|
72442
|
+
const candidate = path40.join(dir, `${bin}${ext}`);
|
|
72160
72443
|
try {
|
|
72161
|
-
const stat =
|
|
72444
|
+
const stat = fs20.statSync(candidate);
|
|
72162
72445
|
if (stat.isFile())
|
|
72163
72446
|
return candidate;
|
|
72164
72447
|
} catch {}
|
|
@@ -72183,7 +72466,7 @@ function systemRunner(kind, apiHost, env = process.env) {
|
|
|
72183
72466
|
if (!exe)
|
|
72184
72467
|
return { status: null, stdout: "", stderr: "", timedOut: false, missing: true };
|
|
72185
72468
|
const token = options.token ? kind === "github" ? { GH_TOKEN: options.token, GH_ENTERPRISE_TOKEN: options.token } : { GITLAB_TOKEN: options.token } : {};
|
|
72186
|
-
const result =
|
|
72469
|
+
const result = spawnSync18(exe, [...args], {
|
|
72187
72470
|
encoding: "utf8",
|
|
72188
72471
|
env: { ...childEnv, ...token },
|
|
72189
72472
|
maxBuffer: MAX_BUFFER2,
|
|
@@ -72853,7 +73136,7 @@ var init_gitlab = __esm(() => {
|
|
|
72853
73136
|
});
|
|
72854
73137
|
|
|
72855
73138
|
// packages/workit-core/src/forge/resolve.ts
|
|
72856
|
-
import
|
|
73139
|
+
import fs21 from "node:fs";
|
|
72857
73140
|
function resolveForge(cwd, options = {}) {
|
|
72858
73141
|
let workspace;
|
|
72859
73142
|
try {
|
|
@@ -72882,7 +73165,7 @@ function resolveForge(cwd, options = {}) {
|
|
|
72882
73165
|
if (derived.via === "host_name" && !explicit)
|
|
72883
73166
|
return failure3("blocked", `token_host_unverified: push host ${derived.host} only looks like ${kind}; workspace ${workspace?.name ?? "?"} vcs.tokenFile is not sent to it`, `if ${apiHost} is your ${kind} server, set ${kind}.host in ~/.config/workit/vcs.json (or vcs.host for the workspace); otherwise fix the push remote`);
|
|
72884
73167
|
try {
|
|
72885
|
-
token =
|
|
73168
|
+
token = fs21.readFileSync(tokenFile.trim(), "utf8").trim();
|
|
72886
73169
|
} catch {
|
|
72887
73170
|
return failure3("blocked", `workspace ${workspace?.name ?? "?"} vcs.tokenFile cannot be read`, "fix vcs.tokenFile in ~/.config/workit/workspaces.json");
|
|
72888
73171
|
}
|
|
@@ -73114,7 +73397,7 @@ __export(exports_pr, {
|
|
|
73114
73397
|
run: () => run10
|
|
73115
73398
|
});
|
|
73116
73399
|
import { readFileSync as readFileSync18 } from "node:fs";
|
|
73117
|
-
import
|
|
73400
|
+
import path41 from "node:path";
|
|
73118
73401
|
async function status(argv, io) {
|
|
73119
73402
|
const flags = parseFlags(argv, { pr: "value", branch: "value", "log-lines": "value" });
|
|
73120
73403
|
if (typeof flags === "string")
|
|
@@ -73185,7 +73468,7 @@ async function create4(argv, io) {
|
|
|
73185
73468
|
let body = flags.values.body ?? null;
|
|
73186
73469
|
if (flags.values["body-file"] !== undefined) {
|
|
73187
73470
|
try {
|
|
73188
|
-
body = readFileSync18(
|
|
73471
|
+
body = readFileSync18(path41.resolve(io.cwd, flags.values["body-file"]), "utf8");
|
|
73189
73472
|
} catch {
|
|
73190
73473
|
return usage3(io, `cannot read --body-file ${flags.values["body-file"]}`, CREATE_USAGE);
|
|
73191
73474
|
}
|
|
@@ -73677,7 +73960,7 @@ var init_git2 = __esm(() => {
|
|
|
73677
73960
|
});
|
|
73678
73961
|
|
|
73679
73962
|
// packages/workit-core/src/forge/verify.ts
|
|
73680
|
-
import { spawnSync as
|
|
73963
|
+
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
73681
73964
|
function finish(cwd, report, actor) {
|
|
73682
73965
|
const delivered = report.observations.length > 0 && report.observations.every((entry) => entry.ok);
|
|
73683
73966
|
const out = { ...report, delivered };
|
|
@@ -73890,7 +74173,7 @@ var NPM_NAME, SEMVER, SAFE_ARG, systemNpm = (args) => {
|
|
|
73890
74173
|
};
|
|
73891
74174
|
const found = process.platform === "win32" ? findExecutable("npm.cmd", process.env) : null;
|
|
73892
74175
|
const npmCmd = found && !/["%!^]/u.test(found) ? `"${found}"` : "npm.cmd";
|
|
73893
|
-
const result = process.platform === "win32" ?
|
|
74176
|
+
const result = process.platform === "win32" ? spawnSync19(`${npmCmd} ${args.join(" ")}`, { ...options, shell: true }) : spawnSync19("npm", [...args], options);
|
|
73894
74177
|
return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
73895
74178
|
}, short3 = (sha) => sha ? sha.slice(0, 12) : "(absent)", npmView = (stdout) => {
|
|
73896
74179
|
try {
|
|
@@ -73997,10 +74280,10 @@ var init_verify_delivery = __esm(() => {
|
|
|
73997
74280
|
});
|
|
73998
74281
|
|
|
73999
74282
|
// packages/workit-core/src/stack.ts
|
|
74000
|
-
import { spawnSync as
|
|
74283
|
+
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
74001
74284
|
import { createHash as createHash15, randomBytes as randomBytes3 } from "node:crypto";
|
|
74002
|
-
import
|
|
74003
|
-
import
|
|
74285
|
+
import fs22 from "node:fs";
|
|
74286
|
+
import path42 from "node:path";
|
|
74004
74287
|
function worktreeOf(cwd, branch) {
|
|
74005
74288
|
const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
|
|
74006
74289
|
if (!list.ok)
|
|
@@ -74023,7 +74306,7 @@ function rebasingBranch2(dir) {
|
|
|
74023
74306
|
if (!found.ok)
|
|
74024
74307
|
continue;
|
|
74025
74308
|
try {
|
|
74026
|
-
return
|
|
74309
|
+
return fs22.readFileSync(found.stdout.trim(), "utf8").trim();
|
|
74027
74310
|
} catch {}
|
|
74028
74311
|
}
|
|
74029
74312
|
return null;
|
|
@@ -74031,7 +74314,7 @@ function rebasingBranch2(dir) {
|
|
|
74031
74314
|
function rebaseInProgress(dir) {
|
|
74032
74315
|
for (const name of ["rebase-merge", "rebase-apply"]) {
|
|
74033
74316
|
const found = gitRun3(dir, ["rev-parse", "--path-format=absolute", "--git-path", name]);
|
|
74034
|
-
if (found.ok &&
|
|
74317
|
+
if (found.ok && fs22.existsSync(found.stdout.trim()))
|
|
74035
74318
|
return true;
|
|
74036
74319
|
}
|
|
74037
74320
|
return false;
|
|
@@ -74043,8 +74326,8 @@ function gitRestack(cwd, input) {
|
|
|
74043
74326
|
const scratch = scratchDir(cwd);
|
|
74044
74327
|
if (!scratch)
|
|
74045
74328
|
return { ok: false, conflict: false, worktree: cwd, error: "no store root" };
|
|
74046
|
-
|
|
74047
|
-
dir =
|
|
74329
|
+
fs22.mkdirSync(scratch, { recursive: true });
|
|
74330
|
+
dir = path42.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes3(4).toString("hex")}`);
|
|
74048
74331
|
const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
|
|
74049
74332
|
if (!added.ok)
|
|
74050
74333
|
return { ok: false, conflict: false, worktree: cwd, error: firstLine(added) };
|
|
@@ -74082,10 +74365,10 @@ function gitRestack(cwd, input) {
|
|
|
74082
74365
|
}
|
|
74083
74366
|
function pruneScratch(cwd) {
|
|
74084
74367
|
const scratch = scratchDir(cwd);
|
|
74085
|
-
if (!scratch || !
|
|
74368
|
+
if (!scratch || !fs22.existsSync(scratch))
|
|
74086
74369
|
return;
|
|
74087
|
-
for (const name of
|
|
74088
|
-
const dir =
|
|
74370
|
+
for (const name of fs22.readdirSync(scratch)) {
|
|
74371
|
+
const dir = path42.join(scratch, name);
|
|
74089
74372
|
if (!rebaseInProgress(dir) && !trackedDirt(dir))
|
|
74090
74373
|
gitRun3(cwd, ["worktree", "remove", "--force", dir]);
|
|
74091
74374
|
}
|
|
@@ -74095,7 +74378,7 @@ function stacksDir(cwd) {
|
|
|
74095
74378
|
const root = storeRoot(cwd);
|
|
74096
74379
|
if (!root.ok)
|
|
74097
74380
|
return stackFail(root.code, root.error, root.unblock);
|
|
74098
|
-
return { ok: true, data:
|
|
74381
|
+
return { ok: true, data: path42.join(root.value.root, "stacks") };
|
|
74099
74382
|
}
|
|
74100
74383
|
function parseStack(raw) {
|
|
74101
74384
|
if (!isRecord7(raw) || !Array.isArray(raw.branches))
|
|
@@ -74147,10 +74430,10 @@ function readStack(cwd, name) {
|
|
|
74147
74430
|
const dir = stacksDir(cwd);
|
|
74148
74431
|
if (!dir.ok)
|
|
74149
74432
|
return dir;
|
|
74150
|
-
const file =
|
|
74433
|
+
const file = path42.join(dir.data, fileFor(name));
|
|
74151
74434
|
let text;
|
|
74152
74435
|
try {
|
|
74153
|
-
text =
|
|
74436
|
+
text = fs22.readFileSync(file, "utf8");
|
|
74154
74437
|
} catch (error) {
|
|
74155
74438
|
if (error.code === "ENOENT")
|
|
74156
74439
|
return { ok: true, data: null };
|
|
@@ -74168,17 +74451,17 @@ function writeStack(cwd, stack, now = new Date) {
|
|
|
74168
74451
|
const dir = stacksDir(cwd);
|
|
74169
74452
|
if (!dir.ok)
|
|
74170
74453
|
return dir;
|
|
74171
|
-
const file =
|
|
74454
|
+
const file = path42.join(dir.data, fileFor(stack.name));
|
|
74172
74455
|
const temp = `${file}.${process.pid}.tmp`;
|
|
74173
74456
|
try {
|
|
74174
|
-
|
|
74457
|
+
fs22.mkdirSync(dir.data, { recursive: true });
|
|
74175
74458
|
stack.updatedAt = now.toISOString();
|
|
74176
|
-
|
|
74459
|
+
fs22.writeFileSync(temp, `${JSON.stringify(stack, null, 2)}
|
|
74177
74460
|
`);
|
|
74178
|
-
|
|
74461
|
+
fs22.renameSync(temp, file);
|
|
74179
74462
|
return { ok: true, data: undefined };
|
|
74180
74463
|
} catch (error) {
|
|
74181
|
-
|
|
74464
|
+
fs22.rmSync(temp, { force: true });
|
|
74182
74465
|
return stackFail("unavailable", `cannot write ${file}: ${error.message}`);
|
|
74183
74466
|
}
|
|
74184
74467
|
}
|
|
@@ -74188,7 +74471,7 @@ function listStacks(cwd) {
|
|
|
74188
74471
|
return dir;
|
|
74189
74472
|
let names = [];
|
|
74190
74473
|
try {
|
|
74191
|
-
names =
|
|
74474
|
+
names = fs22.readdirSync(dir.data).filter((name) => name.endsWith(".json"));
|
|
74192
74475
|
} catch {
|
|
74193
74476
|
return { ok: true, data: [] };
|
|
74194
74477
|
}
|
|
@@ -74196,7 +74479,7 @@ function listStacks(cwd) {
|
|
|
74196
74479
|
for (const name of names) {
|
|
74197
74480
|
let parsed = null;
|
|
74198
74481
|
try {
|
|
74199
|
-
parsed = parseStack(JSON.parse(
|
|
74482
|
+
parsed = parseStack(JSON.parse(fs22.readFileSync(path42.join(dir.data, name), "utf8")));
|
|
74200
74483
|
} catch {
|
|
74201
74484
|
parsed = null;
|
|
74202
74485
|
}
|
|
@@ -74243,7 +74526,7 @@ function stackLockStale(raw, age) {
|
|
|
74243
74526
|
}
|
|
74244
74527
|
function takeLock(lock) {
|
|
74245
74528
|
try {
|
|
74246
|
-
|
|
74529
|
+
fs22.mkdirSync(lock);
|
|
74247
74530
|
} catch (error) {
|
|
74248
74531
|
if (error.code === "EEXIST")
|
|
74249
74532
|
return null;
|
|
@@ -74255,24 +74538,24 @@ function takeLock(lock) {
|
|
|
74255
74538
|
host: localLockHost(),
|
|
74256
74539
|
nonce: randomBytes3(8).toString("hex")
|
|
74257
74540
|
};
|
|
74258
|
-
|
|
74541
|
+
fs22.writeFileSync(path42.join(lock, OWNER), JSON.stringify(owner));
|
|
74259
74542
|
return owner;
|
|
74260
74543
|
}
|
|
74261
74544
|
function reapLock(lock, observed) {
|
|
74262
74545
|
const tomb = `${lock}.reap-${randomBytes3(6).toString("hex")}`;
|
|
74263
74546
|
try {
|
|
74264
|
-
|
|
74547
|
+
fs22.renameSync(lock, tomb);
|
|
74265
74548
|
} catch {
|
|
74266
74549
|
return false;
|
|
74267
74550
|
}
|
|
74268
74551
|
if (readOwner(tomb).raw === observed) {
|
|
74269
|
-
|
|
74552
|
+
fs22.rmSync(tomb, { recursive: true, force: true });
|
|
74270
74553
|
return true;
|
|
74271
74554
|
}
|
|
74272
74555
|
try {
|
|
74273
|
-
|
|
74556
|
+
fs22.renameSync(tomb, lock);
|
|
74274
74557
|
} catch {
|
|
74275
|
-
|
|
74558
|
+
fs22.rmSync(tomb, { recursive: true, force: true });
|
|
74276
74559
|
}
|
|
74277
74560
|
return false;
|
|
74278
74561
|
}
|
|
@@ -74282,8 +74565,8 @@ function releaseLock(lock, owner) {
|
|
|
74282
74565
|
return;
|
|
74283
74566
|
const tomb = `${lock}.release-${randomBytes3(6).toString("hex")}`;
|
|
74284
74567
|
try {
|
|
74285
|
-
|
|
74286
|
-
|
|
74568
|
+
fs22.renameSync(lock, tomb);
|
|
74569
|
+
fs22.rmSync(tomb, { recursive: true, force: true });
|
|
74287
74570
|
} catch {}
|
|
74288
74571
|
}
|
|
74289
74572
|
async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
@@ -74292,9 +74575,9 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
74292
74575
|
return dir;
|
|
74293
74576
|
if (!validName(name))
|
|
74294
74577
|
return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
|
|
74295
|
-
const lock =
|
|
74578
|
+
const lock = path42.join(dir.data, `${fileFor(name)}.lock`);
|
|
74296
74579
|
try {
|
|
74297
|
-
|
|
74580
|
+
fs22.mkdirSync(dir.data, { recursive: true });
|
|
74298
74581
|
} catch (error) {
|
|
74299
74582
|
return stackFail("unavailable", `cannot create ${dir.data}: ${error.message}`);
|
|
74300
74583
|
}
|
|
@@ -74322,7 +74605,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
74322
74605
|
const touch = () => {
|
|
74323
74606
|
try {
|
|
74324
74607
|
const now = new Date;
|
|
74325
|
-
|
|
74608
|
+
fs22.utimesSync(path42.join(lock, OWNER), now, now);
|
|
74326
74609
|
} catch {}
|
|
74327
74610
|
};
|
|
74328
74611
|
const beat = setInterval(touch, HEARTBEAT_MS);
|
|
@@ -74510,7 +74793,7 @@ function commitKeys(cwd, range) {
|
|
|
74510
74793
|
const patches = new Map;
|
|
74511
74794
|
const diff = gitRun3(cwd, ["log", "--no-merges", "-p", "--format=commit %H", range]);
|
|
74512
74795
|
if (diff.ok && diff.stdout.trim()) {
|
|
74513
|
-
const ids =
|
|
74796
|
+
const ids = spawnSync20("git", ["patch-id", "--stable"], {
|
|
74514
74797
|
cwd,
|
|
74515
74798
|
input: diff.stdout,
|
|
74516
74799
|
encoding: "utf8",
|
|
@@ -75118,7 +75401,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
75118
75401
|
...unblock ? { unblock } : {},
|
|
75119
75402
|
...data ? { data } : {}
|
|
75120
75403
|
}), fromForge = (result) => stackFail(result.code, result.error, result.unblock), stackDeps, gitRun3 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
|
|
75121
|
-
const run =
|
|
75404
|
+
const run = spawnSync20("git", args, {
|
|
75122
75405
|
cwd,
|
|
75123
75406
|
encoding: "utf8",
|
|
75124
75407
|
timeout: timeoutMs,
|
|
@@ -75146,7 +75429,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
75146
75429
|
return !status.ok || status.stdout.trim() !== "";
|
|
75147
75430
|
}, scratchDir = (cwd) => {
|
|
75148
75431
|
const dir = stacksDir(cwd);
|
|
75149
|
-
return dir.ok ?
|
|
75432
|
+
return dir.ok ? path42.join(dir.data, "worktrees") : null;
|
|
75150
75433
|
}, firstLine = (run) => (`${run.stderr}
|
|
75151
75434
|
${run.stdout}`.split(`
|
|
75152
75435
|
`).find((line) => line.trim()) ?? "git failed").trim().slice(0, 300), stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${createHash15("sha256").update(name).digest("hex").slice(0, 12)}.json`, fileFor, validName = (name) => {
|
|
@@ -75161,14 +75444,14 @@ ${run.stdout}`.split(`
|
|
|
75161
75444
|
}, isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), str3 = (value) => typeof value === "string" && value ? value : null, LOCK_WAIT_MS3 = 2000, HEARTBEAT_MS = 20000, HEARTBEAT_STALE_MS, OWNERLESS_STALE_MS = 30000, OWNER = "owner", readOwner = (lock) => {
|
|
75162
75445
|
let raw = null;
|
|
75163
75446
|
try {
|
|
75164
|
-
raw =
|
|
75447
|
+
raw = fs22.readFileSync(path42.join(lock, OWNER), "utf8");
|
|
75165
75448
|
} catch {
|
|
75166
75449
|
raw = null;
|
|
75167
75450
|
}
|
|
75168
75451
|
let age = null;
|
|
75169
|
-
for (const target of [
|
|
75452
|
+
for (const target of [path42.join(lock, OWNER), lock])
|
|
75170
75453
|
try {
|
|
75171
|
-
age = Date.now() -
|
|
75454
|
+
age = Date.now() - fs22.statSync(target).mtimeMs;
|
|
75172
75455
|
break;
|
|
75173
75456
|
} catch {}
|
|
75174
75457
|
return { raw, age };
|
|
@@ -75408,9 +75691,9 @@ var init_stack2 = __esm(() => {
|
|
|
75408
75691
|
});
|
|
75409
75692
|
|
|
75410
75693
|
// packages/workit-core/src/fanout.ts
|
|
75411
|
-
import { spawnSync as
|
|
75412
|
-
import
|
|
75413
|
-
import
|
|
75694
|
+
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
75695
|
+
import fs23 from "node:fs";
|
|
75696
|
+
import path43 from "node:path";
|
|
75414
75697
|
function scopeSamples(pattern) {
|
|
75415
75698
|
if (!hasWildcard(pattern))
|
|
75416
75699
|
return [unescape2(pattern)];
|
|
@@ -75607,7 +75890,7 @@ function parsePlan(raw, defaults, name) {
|
|
|
75607
75890
|
id,
|
|
75608
75891
|
branch,
|
|
75609
75892
|
base: optional("base") ?? "",
|
|
75610
|
-
worktree: optional("worktree") ??
|
|
75893
|
+
worktree: optional("worktree") ?? path43.join(defaults.worktreeRoot, id),
|
|
75611
75894
|
tier,
|
|
75612
75895
|
dependsOn: [...new Set(dependsOn ?? [])],
|
|
75613
75896
|
scope,
|
|
@@ -75807,14 +76090,14 @@ function defaultTrunk(cwd) {
|
|
|
75807
76090
|
}
|
|
75808
76091
|
function worktreeRoot(cwd) {
|
|
75809
76092
|
const common = gitCommonDir(cwd);
|
|
75810
|
-
const main = common &&
|
|
75811
|
-
return
|
|
76093
|
+
const main = common && path43.basename(common) === ".git" ? path43.dirname(common) : cwd;
|
|
76094
|
+
return path43.join(path43.dirname(main), `${path43.basename(main)}-wt`);
|
|
75812
76095
|
}
|
|
75813
76096
|
function fanoutsDir(cwd) {
|
|
75814
76097
|
const root = storeRoot(cwd);
|
|
75815
76098
|
if (!root.ok)
|
|
75816
76099
|
return fanoutFail(root.code, root.error, root.unblock);
|
|
75817
|
-
return { ok: true, data:
|
|
76100
|
+
return { ok: true, data: path43.join(root.value.root, "fanouts") };
|
|
75818
76101
|
}
|
|
75819
76102
|
function parseStored(raw) {
|
|
75820
76103
|
if (!isRecord8(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
|
|
@@ -75871,10 +76154,10 @@ function readFanout(cwd, name) {
|
|
|
75871
76154
|
const dir = fanoutsDir(cwd);
|
|
75872
76155
|
if (!dir.ok)
|
|
75873
76156
|
return dir;
|
|
75874
|
-
const file =
|
|
76157
|
+
const file = path43.join(dir.data, stackFileName(name));
|
|
75875
76158
|
let parsed = null;
|
|
75876
76159
|
try {
|
|
75877
|
-
parsed = parseStored(JSON.parse(
|
|
76160
|
+
parsed = parseStored(JSON.parse(fs23.readFileSync(file, "utf8")));
|
|
75878
76161
|
} catch (error) {
|
|
75879
76162
|
if (error.code === "ENOENT")
|
|
75880
76163
|
return { ok: true, data: null };
|
|
@@ -75888,7 +76171,7 @@ function listFanouts(cwd) {
|
|
|
75888
76171
|
return dir;
|
|
75889
76172
|
let names = [];
|
|
75890
76173
|
try {
|
|
75891
|
-
names =
|
|
76174
|
+
names = fs23.readdirSync(dir.data).filter((entry) => entry.endsWith(".json"));
|
|
75892
76175
|
} catch {
|
|
75893
76176
|
return { ok: true, data: [] };
|
|
75894
76177
|
}
|
|
@@ -75896,7 +76179,7 @@ function listFanouts(cwd) {
|
|
|
75896
76179
|
for (const entry of names) {
|
|
75897
76180
|
let parsed = null;
|
|
75898
76181
|
try {
|
|
75899
|
-
parsed = parseStored(JSON.parse(
|
|
76182
|
+
parsed = parseStored(JSON.parse(fs23.readFileSync(path43.join(dir.data, entry), "utf8")));
|
|
75900
76183
|
} catch {
|
|
75901
76184
|
parsed = null;
|
|
75902
76185
|
}
|
|
@@ -75926,16 +76209,16 @@ function writeFanout(cwd, plan) {
|
|
|
75926
76209
|
const dir = fanoutsDir(cwd);
|
|
75927
76210
|
if (!dir.ok)
|
|
75928
76211
|
return dir;
|
|
75929
|
-
const file =
|
|
76212
|
+
const file = path43.join(dir.data, stackFileName(plan.name));
|
|
75930
76213
|
const temp = `${file}.${process.pid}.tmp`;
|
|
75931
76214
|
try {
|
|
75932
|
-
|
|
75933
|
-
|
|
76215
|
+
fs23.mkdirSync(dir.data, { recursive: true });
|
|
76216
|
+
fs23.writeFileSync(temp, `${JSON.stringify(plan, null, 2)}
|
|
75934
76217
|
`);
|
|
75935
|
-
|
|
76218
|
+
fs23.renameSync(temp, file);
|
|
75936
76219
|
return { ok: true, data: file };
|
|
75937
76220
|
} catch (error) {
|
|
75938
|
-
|
|
76221
|
+
fs23.rmSync(temp, { force: true });
|
|
75939
76222
|
return fanoutFail("unavailable", `cannot write ${file}: ${error.message}`);
|
|
75940
76223
|
}
|
|
75941
76224
|
}
|
|
@@ -76014,7 +76297,7 @@ var FANOUT_VERSION = 1, TIERS, fanoutFail = (code, error, unblock, data) => ({
|
|
|
76014
76297
|
error,
|
|
76015
76298
|
...unblock ? { unblock } : {},
|
|
76016
76299
|
...data ? { data } : {}
|
|
76017
|
-
}), DEFAULT_SHARED, escapeRegExp4 = (text) => text.replace(/[.+^$()|[\]\\{}*?]/gu, "\\$&"), unescape2 = (pattern) => pattern.replace(/\\(.)/gu, "$1"), hasWildcard = (pattern) => /[*?{]/u.test(pattern.replace(/\\./gu, "")), compiled, matchesAny = (patterns, file) => patterns.some((pattern) => matchesScope(pattern, file)), isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value),
|
|
76300
|
+
}), DEFAULT_SHARED, escapeRegExp4 = (text) => text.replace(/[.+^$()|[\]\\{}*?]/gu, "\\$&"), unescape2 = (pattern) => pattern.replace(/\\(.)/gu, "$1"), hasWildcard = (pattern) => /[*?{]/u.test(pattern.replace(/\\./gu, "")), compiled, matchesAny = (patterns, file) => patterns.some((pattern) => matchesScope(pattern, file)), isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), PLACEHOLDER3, filled = (text) => text.trim() !== "" && !PLACEHOLDER3.test(text.trim()), textList = (value) => {
|
|
76018
76301
|
if (typeof value === "string")
|
|
76019
76302
|
return [value];
|
|
76020
76303
|
if (Array.isArray(value) && value.every((item) => typeof item === "string"))
|
|
@@ -76033,7 +76316,7 @@ var FANOUT_VERSION = 1, TIERS, fanoutFail = (code, error, unblock, data) => ({
|
|
|
76033
76316
|
text: edges.map((edge) => `add "${edge.dependsOn}" to "dependsOn" of slice ${edge.slice}`).join("; ")
|
|
76034
76317
|
};
|
|
76035
76318
|
}, gitRun4 = (cwd, args) => {
|
|
76036
|
-
const run =
|
|
76319
|
+
const run = spawnSync21("git", args, {
|
|
76037
76320
|
cwd,
|
|
76038
76321
|
encoding: "utf8",
|
|
76039
76322
|
timeout: GIT_TIMEOUTS.local,
|
|
@@ -76065,7 +76348,7 @@ var init_fanout = __esm(() => {
|
|
|
76065
76348
|
"CHANGELOG.md"
|
|
76066
76349
|
];
|
|
76067
76350
|
compiled = new Map;
|
|
76068
|
-
|
|
76351
|
+
PLACEHOLDER3 = /^(?:<[^>]*>|tbd|todo|fixme|\?+|\.\.\.|…)$/iu;
|
|
76069
76352
|
ID = /^[a-z0-9][a-z0-9._-]{0,63}$/u;
|
|
76070
76353
|
});
|
|
76071
76354
|
|
|
@@ -76255,8 +76538,8 @@ var exports_fanout = {};
|
|
|
76255
76538
|
__export(exports_fanout, {
|
|
76256
76539
|
run: () => run15
|
|
76257
76540
|
});
|
|
76258
|
-
import
|
|
76259
|
-
import
|
|
76541
|
+
import fs24 from "node:fs";
|
|
76542
|
+
import path44 from "node:path";
|
|
76260
76543
|
function renderBlockedPlan(io, result) {
|
|
76261
76544
|
if (io.json || result.code !== "blocked" && result.code !== "invalid_input")
|
|
76262
76545
|
return;
|
|
@@ -76301,10 +76584,10 @@ function plan2(argv, io) {
|
|
|
76301
76584
|
return usage3(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
|
|
76302
76585
|
if (flags.positionals.length !== 1)
|
|
76303
76586
|
return usage3(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
|
|
76304
|
-
const file =
|
|
76587
|
+
const file = path44.resolve(io.cwd, flags.positionals[0]);
|
|
76305
76588
|
let raw;
|
|
76306
76589
|
try {
|
|
76307
|
-
raw = JSON.parse(
|
|
76590
|
+
raw = JSON.parse(fs24.readFileSync(file, "utf8"));
|
|
76308
76591
|
} catch (error) {
|
|
76309
76592
|
return usage3(io, `cannot read ${file} as JSON: ${error.message}`, PLAN_USAGE2);
|
|
76310
76593
|
}
|
|
@@ -91532,7 +91815,7 @@ var init_ast = __esm(() => {
|
|
|
91532
91815
|
|
|
91533
91816
|
// packages/workit-cli/src/test-audit/rules.ts
|
|
91534
91817
|
import { builtinModules } from "node:module";
|
|
91535
|
-
import
|
|
91818
|
+
import path45 from "node:path";
|
|
91536
91819
|
function testCallee(call) {
|
|
91537
91820
|
let callee = call.callee;
|
|
91538
91821
|
if (callee.type === "CallExpression")
|
|
@@ -92025,12 +92308,12 @@ function checkConstantsOnly(ctx, emit) {
|
|
|
92025
92308
|
}
|
|
92026
92309
|
function checkOverMocking(ctx, emit) {
|
|
92027
92310
|
const { program } = ctx.parsed;
|
|
92028
|
-
const unit =
|
|
92311
|
+
const unit = path45.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
|
|
92029
92312
|
const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
|
|
92030
92313
|
const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
|
|
92031
92314
|
for (const call of mocked) {
|
|
92032
92315
|
const spec = call.arguments[0].value;
|
|
92033
|
-
const base =
|
|
92316
|
+
const base = path45.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
|
|
92034
92317
|
if (base === unit)
|
|
92035
92318
|
emit({
|
|
92036
92319
|
rule: "over-mocking",
|
|
@@ -92418,11 +92701,11 @@ var init_rules = __esm(() => {
|
|
|
92418
92701
|
});
|
|
92419
92702
|
|
|
92420
92703
|
// packages/workit-cli/src/test-audit/audit.ts
|
|
92421
|
-
import { spawnSync as
|
|
92704
|
+
import { spawnSync as spawnSync22 } from "node:child_process";
|
|
92422
92705
|
import { existsSync as existsSync18, readdirSync as readdirSync8, readFileSync as readFileSync19, statSync as statSync7 } from "node:fs";
|
|
92423
|
-
import
|
|
92706
|
+
import path46 from "node:path";
|
|
92424
92707
|
function git6(cwd, args) {
|
|
92425
|
-
const run =
|
|
92708
|
+
const run = spawnSync22("git", ["-c", "core.quotepath=off", ...args], {
|
|
92426
92709
|
cwd,
|
|
92427
92710
|
encoding: "utf8",
|
|
92428
92711
|
maxBuffer: 64 * 1024 * 1024
|
|
@@ -92433,7 +92716,7 @@ function walkTests(dir, out) {
|
|
|
92433
92716
|
for (const entry of readdirSync8(dir, { withFileTypes: true })) {
|
|
92434
92717
|
if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
|
|
92435
92718
|
continue;
|
|
92436
|
-
const full =
|
|
92719
|
+
const full = path46.join(dir, entry.name);
|
|
92437
92720
|
if (entry.isDirectory()) {
|
|
92438
92721
|
if (!SKIP_DIRS.has(entry.name))
|
|
92439
92722
|
walkTests(full, out);
|
|
@@ -92445,7 +92728,7 @@ function expandPaths(cwd, inputs) {
|
|
|
92445
92728
|
const files = [];
|
|
92446
92729
|
const missing = [];
|
|
92447
92730
|
for (const input of inputs.length > 0 ? inputs : ["."]) {
|
|
92448
|
-
const full =
|
|
92731
|
+
const full = path46.resolve(cwd, input);
|
|
92449
92732
|
if (!existsSync18(full))
|
|
92450
92733
|
missing.push(input);
|
|
92451
92734
|
else if (statSync7(full).isDirectory())
|
|
@@ -92482,11 +92765,11 @@ function changedLines(cwd, base) {
|
|
|
92482
92765
|
for (let offset = 0;offset < count; offset += 1)
|
|
92483
92766
|
lines.add(start + offset);
|
|
92484
92767
|
}
|
|
92485
|
-
changed.set(
|
|
92768
|
+
changed.set(path46.join(root, file), lines);
|
|
92486
92769
|
}
|
|
92487
92770
|
const untracked = git6(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
92488
92771
|
for (const file of untracked.stdout.split("\x00").filter(Boolean))
|
|
92489
|
-
changed.set(
|
|
92772
|
+
changed.set(path46.join(root, file), "all");
|
|
92490
92773
|
return changed;
|
|
92491
92774
|
}
|
|
92492
92775
|
function auditFiles(files, display) {
|
|
@@ -92548,7 +92831,7 @@ function auditFiles(files, display) {
|
|
|
92548
92831
|
durationMs: Math.round(performance.now() - started)
|
|
92549
92832
|
};
|
|
92550
92833
|
}
|
|
92551
|
-
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(
|
|
92834
|
+
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path46.sep).join("/"), SEVERITY_ORDER, ruleIds;
|
|
92552
92835
|
var init_audit = __esm(() => {
|
|
92553
92836
|
init_ast();
|
|
92554
92837
|
init_rules();
|
|
@@ -92578,7 +92861,7 @@ import {
|
|
|
92578
92861
|
copyFileSync as copyFileSync6
|
|
92579
92862
|
} from "node:fs";
|
|
92580
92863
|
import os14 from "node:os";
|
|
92581
|
-
import
|
|
92864
|
+
import path47 from "node:path";
|
|
92582
92865
|
function mutantsFor(source, file, lines) {
|
|
92583
92866
|
const parsed = parseSource(source, file);
|
|
92584
92867
|
const out = [];
|
|
@@ -92651,7 +92934,7 @@ function relatedTests(source, testFiles) {
|
|
|
92651
92934
|
for (const match of text.matchAll(SPECIFIER)) {
|
|
92652
92935
|
const spec = match[1];
|
|
92653
92936
|
if (spec.startsWith(".")) {
|
|
92654
|
-
if (stripExt(
|
|
92937
|
+
if (stripExt(path47.posix.join(path47.posix.dirname(file), spec)) === target)
|
|
92655
92938
|
return true;
|
|
92656
92939
|
} else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
|
|
92657
92940
|
return true;
|
|
@@ -92671,12 +92954,12 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
92671
92954
|
for (const name of names) {
|
|
92672
92955
|
if (!name.startsWith(TEMP_PREFIX))
|
|
92673
92956
|
continue;
|
|
92674
|
-
const dir =
|
|
92957
|
+
const dir = path47.join(tmp, name);
|
|
92675
92958
|
try {
|
|
92676
92959
|
const stat = lstatSync7(dir);
|
|
92677
92960
|
if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
|
|
92678
92961
|
continue;
|
|
92679
|
-
const pid = Number(readFileSync20(
|
|
92962
|
+
const pid = Number(readFileSync20(path47.join(dir, PID_FILE), "utf8"));
|
|
92680
92963
|
if (Number.isInteger(pid) && pid > 0 && alive(pid))
|
|
92681
92964
|
continue;
|
|
92682
92965
|
} catch (error) {
|
|
@@ -92693,8 +92976,8 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
92693
92976
|
function linkNodeModules(origin, target, repo, copy) {
|
|
92694
92977
|
mkdirSync9(target, { recursive: true });
|
|
92695
92978
|
for (const entry of readdirSync9(origin, { withFileTypes: true })) {
|
|
92696
|
-
const from =
|
|
92697
|
-
const to =
|
|
92979
|
+
const from = path47.join(origin, entry.name);
|
|
92980
|
+
const to = path47.join(target, entry.name);
|
|
92698
92981
|
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
|
92699
92982
|
linkNodeModules(from, to, repo, copy);
|
|
92700
92983
|
continue;
|
|
@@ -92710,9 +92993,9 @@ function linkNodeModules(origin, target, repo, copy) {
|
|
|
92710
92993
|
} catch {
|
|
92711
92994
|
continue;
|
|
92712
92995
|
}
|
|
92713
|
-
const relative =
|
|
92714
|
-
if (!relative.startsWith("..") && !
|
|
92715
|
-
symlinkSync(
|
|
92996
|
+
const relative = path47.relative(repo, real);
|
|
92997
|
+
if (!relative.startsWith("..") && !path47.isAbsolute(relative) && !relative.split(path47.sep).includes("node_modules")) {
|
|
92998
|
+
symlinkSync(path47.join(copy, relative), to, "junction");
|
|
92716
92999
|
continue;
|
|
92717
93000
|
}
|
|
92718
93001
|
}
|
|
@@ -92728,7 +93011,7 @@ function copySymlink(repo, tree, from, to) {
|
|
|
92728
93011
|
}
|
|
92729
93012
|
const realRepo = realpathSync9(repo);
|
|
92730
93013
|
if (real && inside2(realRepo, real)) {
|
|
92731
|
-
symlinkSync(
|
|
93014
|
+
symlinkSync(path47.relative(path47.dirname(to), path47.join(tree, path47.relative(realRepo, real))), to);
|
|
92732
93015
|
return;
|
|
92733
93016
|
}
|
|
92734
93017
|
if (real && statSync8(real).isFile())
|
|
@@ -92737,10 +93020,10 @@ function copySymlink(repo, tree, from, to) {
|
|
|
92737
93020
|
symlinkSync(readlinkSync3(from), to);
|
|
92738
93021
|
}
|
|
92739
93022
|
function writeInside(copy, file, content) {
|
|
92740
|
-
const target =
|
|
93023
|
+
const target = path47.join(copy, file);
|
|
92741
93024
|
try {
|
|
92742
93025
|
const stat = lstatSync7(target);
|
|
92743
|
-
if (!stat.isFile() || !inside2(realpathSync9(copy), realpathSync9(
|
|
93026
|
+
if (!stat.isFile() || !inside2(realpathSync9(copy), realpathSync9(path47.dirname(target))))
|
|
92744
93027
|
return false;
|
|
92745
93028
|
} catch {
|
|
92746
93029
|
return false;
|
|
@@ -92751,9 +93034,9 @@ function writeInside(copy, file, content) {
|
|
|
92751
93034
|
return true;
|
|
92752
93035
|
}
|
|
92753
93036
|
function copyWorkingTree(repo) {
|
|
92754
|
-
const dir = mkdtempSync4(
|
|
92755
|
-
writeFileSync9(
|
|
92756
|
-
const tree =
|
|
93037
|
+
const dir = mkdtempSync4(path47.join(os14.tmpdir(), TEMP_PREFIX));
|
|
93038
|
+
writeFileSync9(path47.join(dir, PID_FILE), String(process.pid));
|
|
93039
|
+
const tree = path47.join(dir, "tree");
|
|
92757
93040
|
const head = git6(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
|
|
92758
93041
|
if (head && git6(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
|
|
92759
93042
|
const branch = git6(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
|
|
@@ -92770,29 +93053,29 @@ function copyWorkingTree(repo) {
|
|
|
92770
93053
|
for (const relative of listed) {
|
|
92771
93054
|
if (!relative)
|
|
92772
93055
|
continue;
|
|
92773
|
-
const from =
|
|
93056
|
+
const from = path47.join(repo, relative);
|
|
92774
93057
|
let stat;
|
|
92775
93058
|
try {
|
|
92776
93059
|
stat = lstatSync7(from);
|
|
92777
93060
|
} catch {
|
|
92778
93061
|
continue;
|
|
92779
93062
|
}
|
|
92780
|
-
const to =
|
|
92781
|
-
mkdirSync9(
|
|
93063
|
+
const to = path47.join(tree, relative);
|
|
93064
|
+
mkdirSync9(path47.dirname(to), { recursive: true });
|
|
92782
93065
|
if (stat.isSymbolicLink())
|
|
92783
93066
|
copySymlink(repo, tree, from, to);
|
|
92784
93067
|
else if (stat.isFile())
|
|
92785
93068
|
copyFileSync6(from, to);
|
|
92786
|
-
let parent =
|
|
93069
|
+
let parent = path47.dirname(relative);
|
|
92787
93070
|
while (parent !== "." && !dirs.has(parent)) {
|
|
92788
93071
|
dirs.add(parent);
|
|
92789
|
-
parent =
|
|
93072
|
+
parent = path47.dirname(parent);
|
|
92790
93073
|
}
|
|
92791
93074
|
}
|
|
92792
93075
|
for (const parent of dirs) {
|
|
92793
|
-
const modules =
|
|
92794
|
-
if (existsSync19(modules) && !existsSync19(
|
|
92795
|
-
linkNodeModules(modules,
|
|
93076
|
+
const modules = path47.join(repo, parent, "node_modules");
|
|
93077
|
+
if (existsSync19(modules) && !existsSync19(path47.join(tree, parent, "node_modules")))
|
|
93078
|
+
linkNodeModules(modules, path47.join(tree, parent, "node_modules"), repo, tree);
|
|
92796
93079
|
}
|
|
92797
93080
|
return { dir, tree };
|
|
92798
93081
|
}
|
|
@@ -92831,14 +93114,14 @@ async function runMutation(options) {
|
|
|
92831
93114
|
const tracked = git6(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
|
|
92832
93115
|
const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
|
|
92833
93116
|
try {
|
|
92834
|
-
return { file, text: readFileSync20(
|
|
93117
|
+
return { file, text: readFileSync20(path47.join(repo, file), "utf8") };
|
|
92835
93118
|
} catch {
|
|
92836
93119
|
return { file, text: "" };
|
|
92837
93120
|
}
|
|
92838
93121
|
});
|
|
92839
93122
|
const candidates = [];
|
|
92840
93123
|
for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
|
|
92841
|
-
const relative = toPosix(
|
|
93124
|
+
const relative = toPosix(path47.relative(repo, absolute));
|
|
92842
93125
|
if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
|
|
92843
93126
|
continue;
|
|
92844
93127
|
if (NOT_SOURCE.test(relative) || !existsSync19(absolute))
|
|
@@ -92852,9 +93135,9 @@ async function runMutation(options) {
|
|
|
92852
93135
|
for (const mutant of mutants)
|
|
92853
93136
|
if (!related.has(mutant.file))
|
|
92854
93137
|
related.set(mutant.file, relatedTests(mutant.file, testFiles));
|
|
92855
|
-
const cwdRelative =
|
|
93138
|
+
const cwdRelative = path47.relative(repo, options.cwd);
|
|
92856
93139
|
const asArg = (file) => {
|
|
92857
|
-
const relative = toPosix(
|
|
93140
|
+
const relative = toPosix(path47.relative(cwdRelative, file));
|
|
92858
93141
|
return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
|
|
92859
93142
|
};
|
|
92860
93143
|
const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
|
|
@@ -92889,7 +93172,7 @@ async function runMutation(options) {
|
|
|
92889
93172
|
return finish2(options, 0, results, counts, started);
|
|
92890
93173
|
removeStaleCopies();
|
|
92891
93174
|
const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
|
|
92892
|
-
const copyCwd =
|
|
93175
|
+
const copyCwd = path47.join(copy, cwdRelative);
|
|
92893
93176
|
let current = null;
|
|
92894
93177
|
const restore = () => {
|
|
92895
93178
|
if (current)
|
|
@@ -92924,7 +93207,7 @@ async function runMutation(options) {
|
|
|
92924
93207
|
record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
|
|
92925
93208
|
continue;
|
|
92926
93209
|
}
|
|
92927
|
-
const original = readFileSync20(
|
|
93210
|
+
const original = readFileSync20(path47.join(copy, mutant.file), "utf8");
|
|
92928
93211
|
const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
|
|
92929
93212
|
current = { file: mutant.file, original };
|
|
92930
93213
|
if (!writeInside(copy, mutant.file, mutated)) {
|
|
@@ -92981,8 +93264,8 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
|
|
|
92981
93264
|
return error.code === "EPERM";
|
|
92982
93265
|
}
|
|
92983
93266
|
}, inside2 = (root, file) => {
|
|
92984
|
-
const relative =
|
|
92985
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
93267
|
+
const relative = path47.relative(root, file);
|
|
93268
|
+
return relative === "" || !relative.startsWith("..") && !path47.isAbsolute(relative);
|
|
92986
93269
|
}, active, killTree = (child) => {
|
|
92987
93270
|
try {
|
|
92988
93271
|
if (child.pid && process.platform !== "win32")
|
|
@@ -93031,7 +93314,7 @@ __export(exports_test_audit, {
|
|
|
93031
93314
|
run: () => run17
|
|
93032
93315
|
});
|
|
93033
93316
|
import { existsSync as existsSync20 } from "node:fs";
|
|
93034
|
-
import
|
|
93317
|
+
import path48 from "node:path";
|
|
93035
93318
|
function parse7(argv) {
|
|
93036
93319
|
const options = {
|
|
93037
93320
|
paths: [],
|
|
@@ -93131,8 +93414,8 @@ async function run17(argv, io) {
|
|
|
93131
93414
|
return emit(io, fail("invalid_input", `${options}
|
|
93132
93415
|
usage: ${USAGE10}`));
|
|
93133
93416
|
const top = git6(io.cwd, ["rev-parse", "--show-toplevel"]);
|
|
93134
|
-
const repo = top.ok ?
|
|
93135
|
-
const display = (file) => toPosix(
|
|
93417
|
+
const repo = top.ok ? path48.resolve(top.stdout.trim()) : null;
|
|
93418
|
+
const display = (file) => toPosix(path48.relative(io.cwd, file) || file);
|
|
93136
93419
|
let base = null;
|
|
93137
93420
|
let changed = null;
|
|
93138
93421
|
if (options.diff || options.mutate) {
|
|
@@ -93233,6 +93516,38 @@ var init_test_audit = __esm(() => {
|
|
|
93233
93516
|
]);
|
|
93234
93517
|
});
|
|
93235
93518
|
|
|
93519
|
+
// packages/workit-cli/src/verbs/knowledge.ts
|
|
93520
|
+
var exports_knowledge = {};
|
|
93521
|
+
__export(exports_knowledge, {
|
|
93522
|
+
run: () => run18
|
|
93523
|
+
});
|
|
93524
|
+
async function run18(argv, io) {
|
|
93525
|
+
const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
|
|
93526
|
+
if (sub !== "lint" || rest.length > 0)
|
|
93527
|
+
return emit(io, fail("invalid_input", `usage: ${USAGE11}`));
|
|
93528
|
+
const report = lintKnowledge(checkRoot(io.cwd));
|
|
93529
|
+
if (report.unreadable.length > 0)
|
|
93530
|
+
return emit(io, fail("unavailable", `knowledge lint: cannot read ${report.unreadable.join(", ")}`, {
|
|
93531
|
+
data: report,
|
|
93532
|
+
unblock: `make ${report.unreadable.join(", ")} readable, then re-run workit knowledge lint`
|
|
93533
|
+
}));
|
|
93534
|
+
const summary = `knowledge lint: ${report.findings.length} finding${report.findings.length === 1 ? "" : "s"} in ${report.files.length} file${report.files.length === 1 ? "" : "s"} (${report.files.map((file) => `${file.file} ${file.bytes} B`).join(", ") || "no knowledge files"}; AGENTS.md budget ${report.budget} B)`;
|
|
93535
|
+
if (io.json)
|
|
93536
|
+
return emit(io, report.findings.length === 0 ? ok(report) : fail("failed", summary, { data: report }));
|
|
93537
|
+
for (const finding of report.findings)
|
|
93538
|
+
io.stdout(`${finding.file}${finding.line === null ? "" : `:${finding.line}`} [${finding.rule}] ${finding.message}
|
|
93539
|
+
`);
|
|
93540
|
+
io.stdout(`${summary}
|
|
93541
|
+
`);
|
|
93542
|
+
return report.findings.length === 0 ? 0 : 1;
|
|
93543
|
+
}
|
|
93544
|
+
var USAGE11 = "workit knowledge lint [--json]";
|
|
93545
|
+
var init_knowledge2 = __esm(() => {
|
|
93546
|
+
init_check_config();
|
|
93547
|
+
init_knowledge();
|
|
93548
|
+
init_output();
|
|
93549
|
+
});
|
|
93550
|
+
|
|
93236
93551
|
// packages/workit-core/src/core/youtrack-tools.ts
|
|
93237
93552
|
async function logTimeUpdate(input, operation = defaultOperations) {
|
|
93238
93553
|
try {
|
|
@@ -93340,14 +93655,14 @@ var init_youtrack_writes = __esm(() => {
|
|
|
93340
93655
|
// packages/workit-cli/src/verbs/youtrack.ts
|
|
93341
93656
|
var exports_youtrack = {};
|
|
93342
93657
|
__export(exports_youtrack, {
|
|
93343
|
-
run: () =>
|
|
93658
|
+
run: () => run19
|
|
93344
93659
|
});
|
|
93345
93660
|
import { readFileSync as readFileSync21 } from "node:fs";
|
|
93346
|
-
import
|
|
93347
|
-
async function
|
|
93661
|
+
import path49 from "node:path";
|
|
93662
|
+
async function run19(argv, io) {
|
|
93348
93663
|
const [sub, ...rest] = argv;
|
|
93349
93664
|
if (sub !== "note" && sub !== "time" && sub !== "meeting")
|
|
93350
|
-
return usage3(io, `unknown subcommand "${sub ?? ""}"`,
|
|
93665
|
+
return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE12);
|
|
93351
93666
|
const flags = parseFlags(rest, {
|
|
93352
93667
|
markdown: "value",
|
|
93353
93668
|
file: "value",
|
|
@@ -93356,18 +93671,18 @@ async function run18(argv, io) {
|
|
|
93356
93671
|
date: "value"
|
|
93357
93672
|
});
|
|
93358
93673
|
if (typeof flags === "string")
|
|
93359
|
-
return usage3(io, flags,
|
|
93674
|
+
return usage3(io, flags, USAGE12);
|
|
93360
93675
|
const [issueId, extra] = flags.positionals;
|
|
93361
93676
|
if (!issueId || !ISSUE_RE2.test(issueId))
|
|
93362
|
-
return usage3(io, "an issue id like ABC-123 is required",
|
|
93677
|
+
return usage3(io, "an issue id like ABC-123 is required", USAGE12);
|
|
93363
93678
|
if (extra !== undefined)
|
|
93364
|
-
return usage3(io, `unexpected argument ${extra}`,
|
|
93679
|
+
return usage3(io, `unexpected argument ${extra}`, USAGE12);
|
|
93365
93680
|
const minutes = positiveInt(flags.values.minutes, "--minutes");
|
|
93366
93681
|
if (typeof minutes === "string")
|
|
93367
|
-
return usage3(io, minutes,
|
|
93682
|
+
return usage3(io, minutes, USAGE12);
|
|
93368
93683
|
const date = youTrackWorkDateMs(flags.values.date ?? "auto");
|
|
93369
93684
|
if ("error" in date)
|
|
93370
|
-
return usage3(io, date.error,
|
|
93685
|
+
return usage3(io, date.error, USAGE12);
|
|
93371
93686
|
const dateMs = date.data.dateMs;
|
|
93372
93687
|
const markedDay = flags.values.date !== undefined && flags.values.date !== "auto" ? { dateMs } : {};
|
|
93373
93688
|
const root = io.cwd;
|
|
@@ -93385,24 +93700,24 @@ async function run18(argv, io) {
|
|
|
93385
93700
|
};
|
|
93386
93701
|
if (sub === "note") {
|
|
93387
93702
|
if (Boolean(flags.values.markdown) === Boolean(flags.values.file))
|
|
93388
|
-
return usage3(io, "pass exactly one of --markdown or --file",
|
|
93703
|
+
return usage3(io, "pass exactly one of --markdown or --file", USAGE12);
|
|
93389
93704
|
let markdown = flags.values.markdown ?? "";
|
|
93390
93705
|
if (flags.values.file)
|
|
93391
93706
|
try {
|
|
93392
|
-
markdown = readFileSync21(
|
|
93707
|
+
markdown = readFileSync21(path49.resolve(io.cwd, flags.values.file), "utf8");
|
|
93393
93708
|
} catch (error) {
|
|
93394
|
-
return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`,
|
|
93709
|
+
return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE12);
|
|
93395
93710
|
}
|
|
93396
93711
|
if (!markdown.trim())
|
|
93397
|
-
return usage3(io, "the note is empty",
|
|
93712
|
+
return usage3(io, "the note is empty", USAGE12);
|
|
93398
93713
|
const missing = step("comment", "comments", { operation: "note", issueId, markdown }, markdown, async (text) => commentResult(await postComment(issueId, text, root))) ?? (minutes ? step("time", "workItems", { operation: "note.time", issueId, markdown, minutes, ...markedDay }, "workit update", (text) => logTimeUpdate({ issueId, minutes, text, dateMs, workspace_root: root })) : null);
|
|
93399
93714
|
if (missing)
|
|
93400
93715
|
return emit(io, fail("unavailable", missing));
|
|
93401
93716
|
} else {
|
|
93402
93717
|
if (!minutes)
|
|
93403
|
-
return usage3(io, `${sub} needs --minutes <n>`,
|
|
93718
|
+
return usage3(io, `${sub} needs --minutes <n>`, USAGE12);
|
|
93404
93719
|
if (sub === "meeting" && !flags.values.text)
|
|
93405
|
-
return usage3(io, "meeting needs --text <what the meeting was>",
|
|
93720
|
+
return usage3(io, "meeting needs --text <what the meeting was>", USAGE12);
|
|
93406
93721
|
const text = flags.values.text ?? "";
|
|
93407
93722
|
const missing = step(sub, "workItems", { operation: sub, issueId, minutes, text, ...markedDay }, text, (marked) => logTimeUpdate({ issueId, minutes, text: marked, dateMs, workspace_root: root }));
|
|
93408
93723
|
if (missing)
|
|
@@ -93431,7 +93746,7 @@ async function run18(argv, io) {
|
|
|
93431
93746
|
...data.steps.flatMap((entry) => entry.note ? [` note (${entry.step}): ${entry.note}`] : [])
|
|
93432
93747
|
]);
|
|
93433
93748
|
}
|
|
93434
|
-
var
|
|
93749
|
+
var USAGE12 = "workit youtrack note <ISSUE> (--markdown <t> | --file <p>) [--minutes <n>] [--date auto|YYYY-MM-DD] | youtrack time <ISSUE> --minutes <n> [--text <t>] [--date …] | youtrack meeting <ISSUE> --minutes <n> --text <t> [--date …]", commentResult = (value) => {
|
|
93435
93750
|
try {
|
|
93436
93751
|
return { ok: true, data: unwrap2(value) };
|
|
93437
93752
|
} catch (error) {
|
|
@@ -93455,14 +93770,14 @@ var init_youtrack2 = __esm(() => {
|
|
|
93455
93770
|
// packages/workit-cli/src/verbs/changelog.ts
|
|
93456
93771
|
var exports_changelog = {};
|
|
93457
93772
|
__export(exports_changelog, {
|
|
93458
|
-
run: () =>
|
|
93773
|
+
run: () => run20
|
|
93459
93774
|
});
|
|
93460
93775
|
import { readFileSync as readFileSync22 } from "node:fs";
|
|
93461
|
-
import
|
|
93462
|
-
async function
|
|
93776
|
+
import path50 from "node:path";
|
|
93777
|
+
async function run20(argv, io) {
|
|
93463
93778
|
const [sub, ...rest] = argv;
|
|
93464
93779
|
if (sub !== "apply")
|
|
93465
|
-
return usage3(io, `unknown subcommand "${sub ?? ""}"`,
|
|
93780
|
+
return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE13);
|
|
93466
93781
|
const flags = parseFlags(rest, {
|
|
93467
93782
|
entries: "value",
|
|
93468
93783
|
path: "value",
|
|
@@ -93470,18 +93785,18 @@ async function run19(argv, io) {
|
|
|
93470
93785
|
preview: "boolean"
|
|
93471
93786
|
});
|
|
93472
93787
|
if (typeof flags === "string")
|
|
93473
|
-
return usage3(io, flags,
|
|
93788
|
+
return usage3(io, flags, USAGE13);
|
|
93474
93789
|
if (flags.positionals.length)
|
|
93475
|
-
return usage3(io, `unexpected argument ${flags.positionals[0]}`,
|
|
93790
|
+
return usage3(io, `unexpected argument ${flags.positionals[0]}`, USAGE13);
|
|
93476
93791
|
const normalizeOnly = flags.booleans.has("normalize-only");
|
|
93477
93792
|
if (!normalizeOnly && !flags.values.entries)
|
|
93478
|
-
return usage3(io, "pass --entries <JSON> or --normalize-only",
|
|
93793
|
+
return usage3(io, "pass --entries <JSON> or --normalize-only", USAGE13);
|
|
93479
93794
|
let entries;
|
|
93480
93795
|
if (flags.values.entries)
|
|
93481
93796
|
try {
|
|
93482
93797
|
entries = readEntries(flags.values.entries, io.cwd);
|
|
93483
93798
|
} catch (error) {
|
|
93484
|
-
return usage3(io, `--entries is not valid JSON: ${String(error)}`,
|
|
93799
|
+
return usage3(io, `--entries is not valid JSON: ${String(error)}`, USAGE13);
|
|
93485
93800
|
}
|
|
93486
93801
|
const input = {
|
|
93487
93802
|
entries,
|
|
@@ -93503,8 +93818,8 @@ async function run19(argv, io) {
|
|
|
93503
93818
|
`changelog updated: ${String(applied.path ?? "CHANGELOG.md")}`
|
|
93504
93819
|
]);
|
|
93505
93820
|
}
|
|
93506
|
-
var
|
|
93507
|
-
const text = raw === "-" ? readFileSync22(0, "utf8") : raw.startsWith("@") ? readFileSync22(
|
|
93821
|
+
var USAGE13 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
|
|
93822
|
+
const text = raw === "-" ? readFileSync22(0, "utf8") : raw.startsWith("@") ? readFileSync22(path50.resolve(cwd, raw.slice(1)), "utf8") : raw;
|
|
93508
93823
|
return JSON.parse(text);
|
|
93509
93824
|
};
|
|
93510
93825
|
var init_changelog2 = __esm(() => {
|
|
@@ -93516,7 +93831,7 @@ var init_changelog2 = __esm(() => {
|
|
|
93516
93831
|
// packages/workit-cli/src/verbs/handoff.ts
|
|
93517
93832
|
var exports_handoff = {};
|
|
93518
93833
|
__export(exports_handoff, {
|
|
93519
|
-
run: () =>
|
|
93834
|
+
run: () => run21
|
|
93520
93835
|
});
|
|
93521
93836
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
93522
93837
|
function human2(brief) {
|
|
@@ -93564,11 +93879,11 @@ async function resumeBrief(argv, io) {
|
|
|
93564
93879
|
strict: true
|
|
93565
93880
|
}));
|
|
93566
93881
|
} catch (error) {
|
|
93567
|
-
return emit(io, fail("invalid_input", error.message, { unblock:
|
|
93882
|
+
return emit(io, fail("invalid_input", error.message, { unblock: USAGE14 }));
|
|
93568
93883
|
}
|
|
93569
93884
|
const last = values.last === undefined ? 10 : Number(values.last);
|
|
93570
93885
|
if (!Number.isInteger(last) || last < 1)
|
|
93571
|
-
return emit(io, fail("invalid_input", "--last must be a positive integer", { unblock:
|
|
93886
|
+
return emit(io, fail("invalid_input", "--last must be a positive integer", { unblock: USAGE14 }));
|
|
93572
93887
|
const built = buildHandoff(io.cwd, {
|
|
93573
93888
|
last,
|
|
93574
93889
|
note: values.note ?? null,
|
|
@@ -93586,13 +93901,13 @@ async function resumeBrief(argv, io) {
|
|
|
93586
93901
|
}
|
|
93587
93902
|
return emit(io, ok({ ...data, recorded }), human2);
|
|
93588
93903
|
}
|
|
93589
|
-
async function
|
|
93904
|
+
async function run21(argv, io) {
|
|
93590
93905
|
if (!argv.includes("--task"))
|
|
93591
93906
|
return resumeBrief(argv, io);
|
|
93592
93907
|
await Promise.resolve().then(() => init_task());
|
|
93593
93908
|
return runTaskCommand(["handoff", ...argv]);
|
|
93594
93909
|
}
|
|
93595
|
-
var
|
|
93910
|
+
var USAGE14 = "workit handoff [--note <text>] [--next <text>] [--record] [--last <n>] [--json]", short5 = (sha) => sha ? sha.slice(0, 12) : "no commit";
|
|
93596
93911
|
var init_handoff = __esm(() => {
|
|
93597
93912
|
init_ledger();
|
|
93598
93913
|
init_output();
|
|
@@ -93601,7 +93916,7 @@ var init_handoff = __esm(() => {
|
|
|
93601
93916
|
// packages/workit-cli/src/main.ts
|
|
93602
93917
|
init_package();
|
|
93603
93918
|
init_output();
|
|
93604
|
-
import
|
|
93919
|
+
import path51 from "node:path";
|
|
93605
93920
|
|
|
93606
93921
|
// packages/workit-cli/src/verbs/registry.ts
|
|
93607
93922
|
var TASK_FAMILY_NAMES = [
|
|
@@ -93734,6 +94049,13 @@ var VERBS = [
|
|
|
93734
94049
|
summary: "Flag tautological and low-value tests with a suggested independent oracle; --mutate checks changed lines with diff-scoped mutation",
|
|
93735
94050
|
load: () => Promise.resolve().then(() => (init_test_audit(), exports_test_audit))
|
|
93736
94051
|
},
|
|
94052
|
+
{
|
|
94053
|
+
name: "knowledge",
|
|
94054
|
+
group: "delivery",
|
|
94055
|
+
usage: "workit knowledge lint [--json]",
|
|
94056
|
+
summary: "Lint agent knowledge files: AGENTS.md byte budget, broken local links, scaffold-only files, duplicated rules (exit 1 on findings)",
|
|
94057
|
+
load: () => Promise.resolve().then(() => (init_knowledge2(), exports_knowledge))
|
|
94058
|
+
},
|
|
93737
94059
|
{
|
|
93738
94060
|
name: "youtrack",
|
|
93739
94061
|
group: "delivery",
|
|
@@ -93838,7 +94160,7 @@ var defaultIo = (json) => ({
|
|
|
93838
94160
|
});
|
|
93839
94161
|
async function main(argv, overrides = {}, options = {}) {
|
|
93840
94162
|
const parsed = parseGlobals(argv);
|
|
93841
|
-
const cwd =
|
|
94163
|
+
const cwd = path51.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
|
|
93842
94164
|
const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
|
|
93843
94165
|
if (parsed.error)
|
|
93844
94166
|
return emit(io, fail("invalid_input", parsed.error));
|