finitemonkey 0.1.0-next.29 → 0.1.0-next.30
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/README.es.md +1 -0
- package/README.md +1 -0
- package/README.pt-BR.md +1 -0
- package/dist/finitemonkey.mjs +1080 -340
- package/package.json +1 -1
package/dist/finitemonkey.mjs
CHANGED
|
@@ -95,16 +95,16 @@ var nodeExec = (request) => {
|
|
|
95
95
|
};
|
|
96
96
|
const resolved = process.platform === "win32" && request.shell !== true ? resolveWindowsCommand(request.command, options.env, existsSync) : void 0;
|
|
97
97
|
const result = request.shell === true ? spawnSync([request.command, ...request.args].join(" "), { ...options, shell: true }) : resolved?.shell === true ? spawnSync(windowsCommandLine(resolved, request.args), { ...options, shell: true }) : spawnSync(resolved?.command ?? request.command, [...request.args], options);
|
|
98
|
-
const
|
|
98
|
+
const code2 = errnoCode(result.error);
|
|
99
99
|
const exitCode = result.status;
|
|
100
100
|
const shellMissing = request.shell === true && exitCode !== null && (SHELL_NOT_FOUND.has(exitCode) || exitCode === 1 && CMD_NOT_FOUND.test(text(result.stderr)));
|
|
101
|
-
const notFound3 =
|
|
101
|
+
const notFound3 = code2 === "ENOENT" || shellMissing;
|
|
102
102
|
return {
|
|
103
103
|
found: !notFound3,
|
|
104
104
|
exitCode,
|
|
105
105
|
stdout: text(result.stdout),
|
|
106
106
|
stderr: text(result.stderr),
|
|
107
|
-
timedOut:
|
|
107
|
+
timedOut: code2 === "ETIMEDOUT",
|
|
108
108
|
durationMs: Date.now() - started
|
|
109
109
|
};
|
|
110
110
|
};
|
|
@@ -318,8 +318,8 @@ var nodeGitLines = (args2, cwd, onLine) => new Promise((resolve2) => {
|
|
|
318
318
|
});
|
|
319
319
|
const lines3 = createInterface({ input: child2.stdout, crlfDelay: Infinity });
|
|
320
320
|
lines3.on("line", onLine);
|
|
321
|
-
child2.on("close", (
|
|
322
|
-
resolve2({ found, ok: found &&
|
|
321
|
+
child2.on("close", (code2) => {
|
|
322
|
+
resolve2({ found, ok: found && code2 === 0, stdout: "" });
|
|
323
323
|
});
|
|
324
324
|
});
|
|
325
325
|
var textOf = (value) => typeof value === "string" ? value : "";
|
|
@@ -359,13 +359,13 @@ var nodeProbe = (command, args2, timeoutMs) => {
|
|
|
359
359
|
return { found: false, ok: false, stdout: "", timedOut: false };
|
|
360
360
|
}
|
|
361
361
|
const result = spawnProbe(command, args2, timeoutMs);
|
|
362
|
-
const
|
|
362
|
+
const code2 = errnoCode2(result.error);
|
|
363
363
|
const stdout = result.stdout;
|
|
364
364
|
return {
|
|
365
|
-
found:
|
|
365
|
+
found: code2 !== "ENOENT" && result.status !== WINDOWS_NOT_FOUND,
|
|
366
366
|
ok: result.error === void 0 && result.status === 0,
|
|
367
367
|
stdout: typeof stdout === "string" ? stdout.trim() : "",
|
|
368
|
-
timedOut:
|
|
368
|
+
timedOut: code2 === "ETIMEDOUT"
|
|
369
369
|
};
|
|
370
370
|
};
|
|
371
371
|
var nodeReadText = (path) => {
|
|
@@ -461,8 +461,8 @@ var startApp = (command, cwd, port) => {
|
|
|
461
461
|
output = `${output}${error.message}`;
|
|
462
462
|
exit = { code: null };
|
|
463
463
|
});
|
|
464
|
-
child2.once("exit", (
|
|
465
|
-
exit = { code };
|
|
464
|
+
child2.once("exit", (code2) => {
|
|
465
|
+
exit = { code: code2 };
|
|
466
466
|
});
|
|
467
467
|
return { child: child2, output: () => output, exited: () => exit };
|
|
468
468
|
};
|
|
@@ -586,8 +586,8 @@ var exitCodeDocs = {
|
|
|
586
586
|
};
|
|
587
587
|
|
|
588
588
|
// src/core/problem.ts
|
|
589
|
-
var usageProblem = (
|
|
590
|
-
code,
|
|
589
|
+
var usageProblem = (code2, messageKey, fix, params2 = {}) => ({
|
|
590
|
+
code: code2,
|
|
591
591
|
messageKey,
|
|
592
592
|
params: params2,
|
|
593
593
|
fix,
|
|
@@ -667,6 +667,11 @@ var stringOption = (values, name) => {
|
|
|
667
667
|
const value = values[name];
|
|
668
668
|
return typeof value === "string" ? value : void 0;
|
|
669
669
|
};
|
|
670
|
+
var listOption = (values, name) => {
|
|
671
|
+
const value = values[name];
|
|
672
|
+
const raw = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
|
|
673
|
+
return raw.filter((item2) => typeof item2 === "string" && item2.trim() !== "");
|
|
674
|
+
};
|
|
670
675
|
|
|
671
676
|
// src/core/result.ts
|
|
672
677
|
var SCHEMA_VERSION = 1;
|
|
@@ -905,12 +910,12 @@ var DEFAULT_PROTECTED = ["main", "master", "release/*", "prod", "production", "r
|
|
|
905
910
|
var openRepo = (runtime, dir) => {
|
|
906
911
|
const result = runtime.git(["rev-parse", "--show-toplevel", "--absolute-git-dir", "--show-prefix"], dir);
|
|
907
912
|
if (!result.ok) return void 0;
|
|
908
|
-
const [root, gitDir,
|
|
913
|
+
const [root, gitDir, prefix2] = result.stdout.split("\n");
|
|
909
914
|
if (root === void 0 || root === "" || gitDir === void 0 || gitDir === "") return void 0;
|
|
910
915
|
return {
|
|
911
916
|
root: toAbsolutePath(root),
|
|
912
917
|
gitDir: toAbsolutePath(gitDir),
|
|
913
|
-
prefix: (
|
|
918
|
+
prefix: (prefix2 ?? "").replace(/\/$/, "")
|
|
914
919
|
};
|
|
915
920
|
};
|
|
916
921
|
var globRegex = (pattern) => new RegExp(`^${pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`);
|
|
@@ -1147,9 +1152,9 @@ var readLedger = (runtime, root) => {
|
|
|
1147
1152
|
});
|
|
1148
1153
|
};
|
|
1149
1154
|
var GROUP_ORDER = ["must", "should", "nice", "already-there", "not-reproduced"];
|
|
1150
|
-
var resultText = (
|
|
1151
|
-
if (
|
|
1152
|
-
return
|
|
1155
|
+
var resultText = (row2) => {
|
|
1156
|
+
if (row2 === void 0) return "-";
|
|
1157
|
+
return row2.exitCode === null ? "did not run" : `exit ${String(row2.exitCode)}`;
|
|
1153
1158
|
};
|
|
1154
1159
|
var findingLines = (t, settled) => GROUP_ORDER.flatMap((group) => {
|
|
1155
1160
|
const items = settled.filter((item2) => item2.group === group);
|
|
@@ -1171,7 +1176,7 @@ var findingLines = (t, settled) => GROUP_ORDER.flatMap((group) => {
|
|
|
1171
1176
|
var tableLines = (t, checked, ledger) => {
|
|
1172
1177
|
const rows = checked.filter((item2) => item2.finding.group === "must");
|
|
1173
1178
|
if (rows.length === 0) return [];
|
|
1174
|
-
const last = (id, side) => ledger.filter((
|
|
1179
|
+
const last = (id, side) => ledger.filter((row2) => row2.finding === id && row2.side === side).at(-1);
|
|
1175
1180
|
return [
|
|
1176
1181
|
"",
|
|
1177
1182
|
`| # | ${t("critique.table.command")} | base | head | ${t("critique.table.outcome")} |`,
|
|
@@ -1204,7 +1209,7 @@ var notRepository = (dir) => ({
|
|
|
1204
1209
|
fix: "git init",
|
|
1205
1210
|
exitCode: ExitCode.NotConfigured
|
|
1206
1211
|
});
|
|
1207
|
-
var gitProblem = (
|
|
1212
|
+
var gitProblem = (code2, messageKey, detail, fix, exitCode = ExitCode.CheckFailed) => ({ code: code2, messageKey, params: { detail }, fix, exitCode });
|
|
1208
1213
|
var repoOf = (ctx) => openRepo(ctx.runtime, ctx.cwd);
|
|
1209
1214
|
|
|
1210
1215
|
// src/commands/critique.ts
|
|
@@ -1343,7 +1348,7 @@ var isOwnHandler = (handler) => {
|
|
|
1343
1348
|
|
|
1344
1349
|
// src/install/statusline.ts
|
|
1345
1350
|
var OWN = /finitemonkey(\.mjs|\.cmd|\.exe)?"?\s+statusline\s*$/;
|
|
1346
|
-
var projectFile = (
|
|
1351
|
+
var projectFile = (relative12) => relative12;
|
|
1347
1352
|
var commandFor = (runner) => {
|
|
1348
1353
|
if (runner.kind === "local") return `node ${projectFile(LOCAL_BIN)} statusline`;
|
|
1349
1354
|
if (runner.kind === "vendored") return `node ${projectFile(VENDOR_BIN)} statusline`;
|
|
@@ -2421,11 +2426,11 @@ var needsWrite = (plan) => hasChanges(plan) || plan.previous === void 0;
|
|
|
2421
2426
|
|
|
2422
2427
|
// src/install/apply.ts
|
|
2423
2428
|
var stamp = (iso) => iso.replace(/[:.]/g, "-");
|
|
2424
|
-
var ensureParent = (project,
|
|
2425
|
-
var writeText = (project,
|
|
2426
|
-
const parent = ensureParent(project,
|
|
2427
|
-
const written = parent.ok ? project.runtime.writeAtomic(project.abs(
|
|
2428
|
-
return written.ok ? accept(void 0) : reject({ path:
|
|
2429
|
+
var ensureParent = (project, relative12) => project.runtime.mkdir(project.abs(dirname3(relative12)));
|
|
2430
|
+
var writeText = (project, relative12, text9) => {
|
|
2431
|
+
const parent = ensureParent(project, relative12);
|
|
2432
|
+
const written = parent.ok ? project.runtime.writeAtomic(project.abs(relative12), text9) : parent;
|
|
2433
|
+
return written.ok ? accept(void 0) : reject({ path: relative12, detail: written.error });
|
|
2429
2434
|
};
|
|
2430
2435
|
var restore = (project, items) => {
|
|
2431
2436
|
for (const item2 of items) {
|
|
@@ -2567,17 +2572,17 @@ var detectLang = (flag2, env, settings = {}) => {
|
|
|
2567
2572
|
// src/install/project.ts
|
|
2568
2573
|
import { dirname as dirname4, join as join7 } from "node:path";
|
|
2569
2574
|
var projectAt = (root, runtime) => {
|
|
2570
|
-
const abs = (
|
|
2575
|
+
const abs = (relative12) => toAbsolutePath(join7(root, ...relative12.split("/")));
|
|
2571
2576
|
return {
|
|
2572
2577
|
root,
|
|
2573
2578
|
runtime,
|
|
2574
2579
|
abs,
|
|
2575
|
-
read: (
|
|
2576
|
-
const text9 = runtime.readText(abs(
|
|
2580
|
+
read: (relative12) => {
|
|
2581
|
+
const text9 = runtime.readText(abs(relative12));
|
|
2577
2582
|
return text9.ok ? text9.value : void 0;
|
|
2578
2583
|
},
|
|
2579
|
-
exists: (
|
|
2580
|
-
isDir: (
|
|
2584
|
+
exists: (relative12) => runtime.stat(abs(relative12)) !== void 0,
|
|
2585
|
+
isDir: (relative12) => runtime.stat(abs(relative12))?.kind === "dir"
|
|
2581
2586
|
};
|
|
2582
2587
|
};
|
|
2583
2588
|
var findGitRoot = (start, runtime) => {
|
|
@@ -2595,8 +2600,8 @@ var openProject = (ctx) => {
|
|
|
2595
2600
|
const root = findGitRoot(ctx.cwd, ctx.runtime);
|
|
2596
2601
|
return { project: projectAt(root ?? ctx.cwd, ctx.runtime), gitRoot: root !== void 0 };
|
|
2597
2602
|
};
|
|
2598
|
-
var problem = (
|
|
2599
|
-
code,
|
|
2603
|
+
var problem = (code2, messageKey, fix, exitCode, params2) => ({
|
|
2604
|
+
code: code2,
|
|
2600
2605
|
messageKey,
|
|
2601
2606
|
params: params2,
|
|
2602
2607
|
fix,
|
|
@@ -3651,7 +3656,7 @@ var checkAuthVariables = ({ env, platform }) => {
|
|
|
3651
3656
|
};
|
|
3652
3657
|
|
|
3653
3658
|
// src/doctor/hooks.ts
|
|
3654
|
-
import { join as
|
|
3659
|
+
import { join as join37 } from "node:path";
|
|
3655
3660
|
|
|
3656
3661
|
// src/hooks/events.ts
|
|
3657
3662
|
var HOOK_EVENTS = [
|
|
@@ -4737,20 +4742,20 @@ var POPULAR = { npm: NPM, pypi: PYPI };
|
|
|
4737
4742
|
var distance = (left, right) => {
|
|
4738
4743
|
const rows = Array.from(
|
|
4739
4744
|
{ length: left.length + 1 },
|
|
4740
|
-
(_,
|
|
4745
|
+
(_, row2) => Array.from({ length: right.length + 1 }, (_2, column) => row2 === 0 ? column : column === 0 ? row2 : 0)
|
|
4741
4746
|
);
|
|
4742
|
-
const
|
|
4743
|
-
for (let
|
|
4744
|
-
const current2 = rows[
|
|
4747
|
+
const cell2 = (row2, column) => rows[row2]?.[column] ?? Number.POSITIVE_INFINITY;
|
|
4748
|
+
for (let row2 = 1; row2 <= left.length; row2 += 1) {
|
|
4749
|
+
const current2 = rows[row2] ?? [];
|
|
4745
4750
|
for (let column = 1; column <= right.length; column += 1) {
|
|
4746
|
-
const cost = left[
|
|
4747
|
-
let best = Math.min(
|
|
4748
|
-
const swapped = left[
|
|
4749
|
-
if (
|
|
4751
|
+
const cost = left[row2 - 1] === right[column - 1] ? 0 : 1;
|
|
4752
|
+
let best = Math.min(cell2(row2 - 1, column) + 1, cell2(row2, column - 1) + 1, cell2(row2 - 1, column - 1) + cost);
|
|
4753
|
+
const swapped = left[row2 - 1] === right[column - 2] && left[row2 - 2] === right[column - 1];
|
|
4754
|
+
if (row2 > 1 && column > 1 && swapped) best = Math.min(best, cell2(row2 - 2, column - 2) + 1);
|
|
4750
4755
|
current2[column] = best;
|
|
4751
4756
|
}
|
|
4752
4757
|
}
|
|
4753
|
-
return
|
|
4758
|
+
return cell2(left.length, right.length);
|
|
4754
4759
|
};
|
|
4755
4760
|
var squash2 = (name) => name.replace(/^@[^/]+\//, "").replace(/[-_.]/g, "");
|
|
4756
4761
|
var closePopular = (ecosystem, name) => {
|
|
@@ -5002,8 +5007,8 @@ var npmDeclared = (runtime, root) => {
|
|
|
5002
5007
|
const parsed = text9.ok ? parseJsonObject(text9.value) : void 0;
|
|
5003
5008
|
if (parsed?.ok !== true) return /* @__PURE__ */ new Set();
|
|
5004
5009
|
return new Set(
|
|
5005
|
-
NPM_SECTIONS.flatMap((
|
|
5006
|
-
const value = parsed.value[
|
|
5010
|
+
NPM_SECTIONS.flatMap((section3) => {
|
|
5011
|
+
const value = parsed.value[section3];
|
|
5007
5012
|
return isRecord(value) ? Object.keys(value) : [];
|
|
5008
5013
|
})
|
|
5009
5014
|
);
|
|
@@ -5620,9 +5625,9 @@ var hostsInText = (text9) => {
|
|
|
5620
5625
|
return [...urls, ...keyed, ...commands].filter((host) => host !== "" && !host.includes("$"));
|
|
5621
5626
|
};
|
|
5622
5627
|
var workflowFiles = (runtime, root) => {
|
|
5623
|
-
const
|
|
5624
|
-
if (!
|
|
5625
|
-
return
|
|
5628
|
+
const listed5 = runtime.listDir(toAbsolutePath(join14(root, ".github", "workflows")));
|
|
5629
|
+
if (!listed5.ok) return [];
|
|
5630
|
+
return listed5.value.filter((name) => /deploy/i.test(name) && /\.ya?ml$/i.test(name)).map((name) => `.github/workflows/${name}`);
|
|
5626
5631
|
};
|
|
5627
5632
|
var detectedHosts = (runtime, root, files) => files.flatMap((file) => {
|
|
5628
5633
|
const text9 = runtime.readText(toAbsolutePath(join14(root, file)));
|
|
@@ -6080,10 +6085,10 @@ var RULES2 = {
|
|
|
6080
6085
|
}
|
|
6081
6086
|
};
|
|
6082
6087
|
var countTests = (language, source) => {
|
|
6083
|
-
const
|
|
6088
|
+
const code2 = language === "py" ? stripHash(source) : stripJs(source);
|
|
6084
6089
|
const rules = RULES2[language];
|
|
6085
|
-
const skips = count(
|
|
6086
|
-
return { tests: count(
|
|
6090
|
+
const skips = count(code2, rules.skips);
|
|
6091
|
+
return { tests: count(code2, rules.tests), skips, assertions: count(code2, rules.asserts) };
|
|
6087
6092
|
};
|
|
6088
6093
|
|
|
6089
6094
|
// src/guards/tests/analyze.ts
|
|
@@ -6715,7 +6720,8 @@ var CHECK_KINDS = [
|
|
|
6715
6720
|
"merge",
|
|
6716
6721
|
"prod",
|
|
6717
6722
|
"prose",
|
|
6718
|
-
"review"
|
|
6723
|
+
"review",
|
|
6724
|
+
"inventory"
|
|
6719
6725
|
];
|
|
6720
6726
|
var GIT_REQUIREMENTS = ["committed", "pushed", "pr_open"];
|
|
6721
6727
|
var SIZES = ["S", "M", "L"];
|
|
@@ -6982,8 +6988,8 @@ var parseNameStatus = (text9) => {
|
|
|
6982
6988
|
const fields = nulFields(text9);
|
|
6983
6989
|
const changes = [];
|
|
6984
6990
|
for (let index = 0; index < fields.length; index += 1) {
|
|
6985
|
-
const
|
|
6986
|
-
const letter =
|
|
6991
|
+
const code2 = fields[index] ?? "";
|
|
6992
|
+
const letter = code2.slice(0, 1);
|
|
6987
6993
|
if (letter === "R" || letter === "C") {
|
|
6988
6994
|
const oldPath = fields[index + 1] ?? "";
|
|
6989
6995
|
const path2 = fields[index + 2] ?? "";
|
|
@@ -7032,9 +7038,9 @@ var parseAddedLines = (diff) => {
|
|
|
7032
7038
|
};
|
|
7033
7039
|
var addedLines = (git2, base) => parseAddedLines(git2.out(["diff", "-U0", "--no-color", "--no-ext-diff", base, "--", ".", EXCLUDE_FM]) ?? "");
|
|
7034
7040
|
var numstat = (git2, base) => {
|
|
7035
|
-
const rows = (git2.out(["diff", "--numstat", "--no-color", base, "--", ".", EXCLUDE_FM]) ?? "").split("\n").filter((
|
|
7036
|
-
const lines3 = rows.reduce((sum,
|
|
7037
|
-
const [plus = "0", minus = "0"] =
|
|
7041
|
+
const rows = (git2.out(["diff", "--numstat", "--no-color", base, "--", ".", EXCLUDE_FM]) ?? "").split("\n").filter((row2) => row2.trim() !== "");
|
|
7042
|
+
const lines3 = rows.reduce((sum, row2) => {
|
|
7043
|
+
const [plus = "0", minus = "0"] = row2.split(" ");
|
|
7038
7044
|
return sum + (Number(plus) || 0) + (Number(minus) || 0);
|
|
7039
7045
|
}, 0);
|
|
7040
7046
|
return { files: rows.length, lines: lines3 };
|
|
@@ -7252,21 +7258,21 @@ var applySize = (contract, verdict) => {
|
|
|
7252
7258
|
|
|
7253
7259
|
// src/gate/prepare.ts
|
|
7254
7260
|
var diskFiles = (runtime, root) => ({
|
|
7255
|
-
read: (
|
|
7256
|
-
const text9 = runtime.readText(toAbsolutePath(join19(root,
|
|
7261
|
+
read: (relative12) => {
|
|
7262
|
+
const text9 = runtime.readText(toAbsolutePath(join19(root, relative12)));
|
|
7257
7263
|
return text9.ok ? text9.value : void 0;
|
|
7258
7264
|
},
|
|
7259
|
-
exists: (
|
|
7265
|
+
exists: (relative12) => runtime.stat(toAbsolutePath(join19(root, relative12))) !== void 0
|
|
7260
7266
|
});
|
|
7261
7267
|
var baseFiles = (git2, base, disk) => ({
|
|
7262
|
-
read: (
|
|
7268
|
+
read: (relative12) => base === EMPTY_TREE ? disk.read(relative12) : fileAt(git2, base, relative12),
|
|
7263
7269
|
exists: disk.exists
|
|
7264
7270
|
});
|
|
7265
7271
|
var loadContract = (options, paths, git2, base) => {
|
|
7266
7272
|
const disk = diskFiles(options.runtime, paths.root);
|
|
7267
7273
|
const id = activeTaskId(options.runtime, paths, options.taskId);
|
|
7268
7274
|
if (id === void 0) return accept(loadImplicit(options.runtime, paths, baseFiles(git2, base, disk)));
|
|
7269
|
-
return loadTask(options.runtime, paths, { disk: disk.read, base: (
|
|
7275
|
+
return loadTask(options.runtime, paths, { disk: disk.read, base: (relative12) => fileAt(git2, base, relative12) }, id);
|
|
7270
7276
|
};
|
|
7271
7277
|
var memo2 = (make) => {
|
|
7272
7278
|
let value;
|
|
@@ -8285,7 +8291,50 @@ var en_default = {
|
|
|
8285
8291
|
"deps.finding.young": "{name} has little history: first published {days, plural, one {# day} other {# days}} ago, {count, plural, one {# version} other {# versions}}.",
|
|
8286
8292
|
"deps.finding.fresh": "{name}@{version} was published {hours, plural, one {# hour} other {# hours}} ago; prefer a version at least {days, plural, one {# day} other {# days}} old.",
|
|
8287
8293
|
"deps.finding.script": "{name}@{version} adds an install script that the previous version did not have; read it before installing.",
|
|
8288
|
-
"deps.finding.unchecked": "{name} was not checked on {registry} (offline or no answer in time), so only the spelling was checked."
|
|
8294
|
+
"deps.finding.unchecked": "{name} was not checked on {registry} (offline or no answer in time), so only the spelling was checked.",
|
|
8295
|
+
"command.inventory.summary": "Write docs/plan/NNa-today-<topic>.md: what the code does today, tied to the commit read",
|
|
8296
|
+
"inventory.written": "Wrote {file} ({count, plural, one {# repository read} other {# repositories read}}).",
|
|
8297
|
+
"inventory.error.ref": "{ref} is not a commit in {repo}",
|
|
8298
|
+
"inventory.error.topic": "name the topic: finitemonkey inventory <topic>",
|
|
8299
|
+
"plan.error.write": "could not write the plan file: {detail}",
|
|
8300
|
+
"inventory.title": "Today: {topic}",
|
|
8301
|
+
"inventory.read_at": "Read `{path}` at {hash} on {date} (ref {ref}).",
|
|
8302
|
+
"inventory.risks": "Active risks",
|
|
8303
|
+
"inventory.col.risk": "Risk",
|
|
8304
|
+
"inventory.col.still": "Still there?",
|
|
8305
|
+
"inventory.col.evidence": "Evidence",
|
|
8306
|
+
"inventory.col.fix": "Minimal fix",
|
|
8307
|
+
"inventory.risk.credential": "Credential in a tracked file ({rule})",
|
|
8308
|
+
"inventory.risk.yes": "yes",
|
|
8309
|
+
"inventory.risk.fix_credential": "move it to the environment, rotate it, run finitemonkey secrets scan",
|
|
8310
|
+
"inventory.gap": "The plan says, the code does today",
|
|
8311
|
+
"inventory.col.plan": "The plan says",
|
|
8312
|
+
"inventory.col.today": "The code does today",
|
|
8313
|
+
"inventory.col.effect": "Effect",
|
|
8314
|
+
"inventory.modules": "Modules",
|
|
8315
|
+
"inventory.routes": "Routes",
|
|
8316
|
+
"inventory.tables": "Tables",
|
|
8317
|
+
"inventory.queues": "Queues",
|
|
8318
|
+
"inventory.jobs": "Jobs",
|
|
8319
|
+
"inventory.env": "Environment variables (names only)",
|
|
8320
|
+
"inventory.dependencies": "Dependencies",
|
|
8321
|
+
"inventory.tests": "Tests",
|
|
8322
|
+
"inventory.test_count": "{count, plural, one {# test file} other {# test files}}.",
|
|
8323
|
+
"inventory.credentials": "Credentials",
|
|
8324
|
+
"inventory.credentials_note": "Cited by file and line only. The value never goes into this report.",
|
|
8325
|
+
"inventory.deploy": "Deploy",
|
|
8326
|
+
"inventory.history": "Secrets in history",
|
|
8327
|
+
"inventory.worktrees": "Existing worktrees",
|
|
8328
|
+
"inventory.hotspots": "Hotspots",
|
|
8329
|
+
"inventory.delta": "Changed since {hash}",
|
|
8330
|
+
"inventory.none": "Nothing found.",
|
|
8331
|
+
"inventory.more": "and {count} more",
|
|
8332
|
+
"inventory.files": "{count, plural, one {# file} other {# files}}",
|
|
8333
|
+
"inventory.changes": "{count, plural, one {# change} other {# changes}} in the last 300 commits",
|
|
8334
|
+
"gate.inventory.missing": "no inventory in docs/plan; run finitemonkey inventory <topic>",
|
|
8335
|
+
"gate.inventory.expired": "{report} expired: {count, plural, one {# covered path changed} other {# covered paths changed}} since {hash} ({paths}); run finitemonkey inventory {topic} for the delta",
|
|
8336
|
+
"gate.inventory.unknown": "{report} cites {hash} in {repo}, a commit this clone cannot read",
|
|
8337
|
+
"gate.inventory.fresh": "{count, plural, one {# inventory matches} other {# inventories match}} the covered paths"
|
|
8289
8338
|
};
|
|
8290
8339
|
|
|
8291
8340
|
// src/i18n/es.json
|
|
@@ -8990,7 +9039,50 @@ var es_default = {
|
|
|
8990
9039
|
"deps.finding.young": "{name} tiene poco historial: se publicó por primera vez hace {days, plural, one {# día} other {# días}}, {count, plural, one {# versión} other {# versiones}}.",
|
|
8991
9040
|
"deps.finding.fresh": "{name}@{version} salió hace {hours, plural, one {# hora} other {# horas}}; mejor una versión con al menos {days, plural, one {# día} other {# días}}.",
|
|
8992
9041
|
"deps.finding.script": "{name}@{version} trae un script de instalación que la versión anterior no tenía; léelo antes de instalar.",
|
|
8993
|
-
"deps.finding.unchecked": "{name} no se comprobó en {registry} (sin red o sin respuesta a tiempo), así que solo se revisó la ortografía."
|
|
9042
|
+
"deps.finding.unchecked": "{name} no se comprobó en {registry} (sin red o sin respuesta a tiempo), así que solo se revisó la ortografía.",
|
|
9043
|
+
"command.inventory.summary": "Escribe docs/plan/NNa-today-<tema>.md: lo que hace el código hoy, ligado al commit leído",
|
|
9044
|
+
"inventory.written": "Escrito {file} ({count, plural, one {# repositorio leído} other {# repositorios leídos}}).",
|
|
9045
|
+
"inventory.error.ref": "{ref} no es un commit en {repo}",
|
|
9046
|
+
"inventory.error.topic": "indica el tema: finitemonkey inventory <tema>",
|
|
9047
|
+
"plan.error.write": "no se pudo escribir el archivo del plan: {detail}",
|
|
9048
|
+
"inventory.title": "Hoy: {topic}",
|
|
9049
|
+
"inventory.read_at": "Leído `{path}` en {hash} el {date} (ref {ref}).",
|
|
9050
|
+
"inventory.risks": "Riesgos activos",
|
|
9051
|
+
"inventory.col.risk": "Riesgo",
|
|
9052
|
+
"inventory.col.still": "¿Sigue ahí?",
|
|
9053
|
+
"inventory.col.evidence": "Evidencia",
|
|
9054
|
+
"inventory.col.fix": "Corrección mínima",
|
|
9055
|
+
"inventory.risk.credential": "Credencial en un archivo versionado ({rule})",
|
|
9056
|
+
"inventory.risk.yes": "sí",
|
|
9057
|
+
"inventory.risk.fix_credential": "moverla al entorno, rotarla, ejecutar finitemonkey secrets scan",
|
|
9058
|
+
"inventory.gap": "El plan dice, el código hace hoy",
|
|
9059
|
+
"inventory.col.plan": "El plan dice",
|
|
9060
|
+
"inventory.col.today": "El código hace hoy",
|
|
9061
|
+
"inventory.col.effect": "Efecto",
|
|
9062
|
+
"inventory.modules": "Módulos",
|
|
9063
|
+
"inventory.routes": "Rutas",
|
|
9064
|
+
"inventory.tables": "Tablas",
|
|
9065
|
+
"inventory.queues": "Colas",
|
|
9066
|
+
"inventory.jobs": "Jobs",
|
|
9067
|
+
"inventory.env": "Variables de entorno (solo los nombres)",
|
|
9068
|
+
"inventory.dependencies": "Dependencias",
|
|
9069
|
+
"inventory.tests": "Tests",
|
|
9070
|
+
"inventory.test_count": "{count, plural, one {# archivo de test} other {# archivos de test}}.",
|
|
9071
|
+
"inventory.credentials": "Credenciales",
|
|
9072
|
+
"inventory.credentials_note": "Citadas solo por archivo y línea. El valor nunca entra en este informe.",
|
|
9073
|
+
"inventory.deploy": "Despliegue",
|
|
9074
|
+
"inventory.history": "Secretos en el historial",
|
|
9075
|
+
"inventory.worktrees": "Worktrees existentes",
|
|
9076
|
+
"inventory.hotspots": "Puntos calientes",
|
|
9077
|
+
"inventory.delta": "Cambió desde {hash}",
|
|
9078
|
+
"inventory.none": "Nada encontrado.",
|
|
9079
|
+
"inventory.more": "y {count} más",
|
|
9080
|
+
"inventory.files": "{count, plural, one {# archivo} other {# archivos}}",
|
|
9081
|
+
"inventory.changes": "{count, plural, one {# cambio} other {# cambios}} en los últimos 300 commits",
|
|
9082
|
+
"gate.inventory.missing": "ningún inventario en docs/plan; ejecuta finitemonkey inventory <tema>",
|
|
9083
|
+
"gate.inventory.expired": "{report} venció: {count, plural, one {# ruta cubierta cambió} other {# rutas cubiertas cambiaron}} desde {hash} ({paths}); ejecuta finitemonkey inventory {topic} para el delta",
|
|
9084
|
+
"gate.inventory.unknown": "{report} cita {hash} en {repo}, un commit que este clon no puede leer",
|
|
9085
|
+
"gate.inventory.fresh": "{count, plural, one {# inventario coincide} other {# inventarios coinciden}} con las rutas cubiertas"
|
|
8994
9086
|
};
|
|
8995
9087
|
|
|
8996
9088
|
// src/i18n/pt-BR.json
|
|
@@ -9695,7 +9787,50 @@ var pt_BR_default = {
|
|
|
9695
9787
|
"deps.finding.young": "{name} tem pouco histórico: publicado pela primeira vez há {days, plural, one {# dia} other {# dias}}, {count, plural, one {# versão} other {# versões}}.",
|
|
9696
9788
|
"deps.finding.fresh": "{name}@{version} saiu há {hours, plural, one {# hora} other {# horas}}; prefira uma versão com pelo menos {days, plural, one {# dia} other {# dias}}.",
|
|
9697
9789
|
"deps.finding.script": "{name}@{version} traz um script de instalação que a versão anterior não tinha; leia antes de instalar.",
|
|
9698
|
-
"deps.finding.unchecked": "{name} não foi conferido no {registry} (sem rede ou sem resposta a tempo), então só a grafia foi checada."
|
|
9790
|
+
"deps.finding.unchecked": "{name} não foi conferido no {registry} (sem rede ou sem resposta a tempo), então só a grafia foi checada.",
|
|
9791
|
+
"command.inventory.summary": "Grava docs/plan/NNa-today-<tema>.md: o que o código faz hoje, ligado ao commit lido",
|
|
9792
|
+
"inventory.written": "Gravado {file} ({count, plural, one {# repositório lido} other {# repositórios lidos}}).",
|
|
9793
|
+
"inventory.error.ref": "{ref} não é um commit em {repo}",
|
|
9794
|
+
"inventory.error.topic": "diga o tema: finitemonkey inventory <tema>",
|
|
9795
|
+
"plan.error.write": "não deu para gravar o arquivo do plano: {detail}",
|
|
9796
|
+
"inventory.title": "Hoje: {topic}",
|
|
9797
|
+
"inventory.read_at": "Lido `{path}` em {hash} no dia {date} (ref {ref}).",
|
|
9798
|
+
"inventory.risks": "Riscos ativos",
|
|
9799
|
+
"inventory.col.risk": "Risco",
|
|
9800
|
+
"inventory.col.still": "Ainda está lá?",
|
|
9801
|
+
"inventory.col.evidence": "Evidência",
|
|
9802
|
+
"inventory.col.fix": "Correção mínima",
|
|
9803
|
+
"inventory.risk.credential": "Credencial em arquivo versionado ({rule})",
|
|
9804
|
+
"inventory.risk.yes": "sim",
|
|
9805
|
+
"inventory.risk.fix_credential": "mover para o ambiente, rotacionar, rodar finitemonkey secrets scan",
|
|
9806
|
+
"inventory.gap": "O plano diz, o código faz hoje",
|
|
9807
|
+
"inventory.col.plan": "O plano diz",
|
|
9808
|
+
"inventory.col.today": "O código faz hoje",
|
|
9809
|
+
"inventory.col.effect": "Efeito",
|
|
9810
|
+
"inventory.modules": "Módulos",
|
|
9811
|
+
"inventory.routes": "Rotas",
|
|
9812
|
+
"inventory.tables": "Tabelas",
|
|
9813
|
+
"inventory.queues": "Filas",
|
|
9814
|
+
"inventory.jobs": "Jobs",
|
|
9815
|
+
"inventory.env": "Variáveis de ambiente (só os nomes)",
|
|
9816
|
+
"inventory.dependencies": "Dependências",
|
|
9817
|
+
"inventory.tests": "Testes",
|
|
9818
|
+
"inventory.test_count": "{count, plural, one {# arquivo de teste} other {# arquivos de teste}}.",
|
|
9819
|
+
"inventory.credentials": "Credenciais",
|
|
9820
|
+
"inventory.credentials_note": "Citadas só por arquivo e linha. O valor nunca entra neste relatório.",
|
|
9821
|
+
"inventory.deploy": "Deploy",
|
|
9822
|
+
"inventory.history": "Segredos no histórico",
|
|
9823
|
+
"inventory.worktrees": "Worktrees existentes",
|
|
9824
|
+
"inventory.hotspots": "Pontos quentes",
|
|
9825
|
+
"inventory.delta": "Mudou desde {hash}",
|
|
9826
|
+
"inventory.none": "Nada encontrado.",
|
|
9827
|
+
"inventory.more": "e mais {count}",
|
|
9828
|
+
"inventory.files": "{count, plural, one {# arquivo} other {# arquivos}}",
|
|
9829
|
+
"inventory.changes": "{count, plural, one {# mudança} other {# mudanças}} nos últimos 300 commits",
|
|
9830
|
+
"gate.inventory.missing": "nenhum inventário em docs/plan; rode finitemonkey inventory <tema>",
|
|
9831
|
+
"gate.inventory.expired": "{report} venceu: {count, plural, one {# caminho coberto mudou} other {# caminhos cobertos mudaram}} desde {hash} ({paths}); rode finitemonkey inventory {topic} para o delta",
|
|
9832
|
+
"gate.inventory.unknown": "{report} cita {hash} em {repo}, um commit que este clone não lê",
|
|
9833
|
+
"gate.inventory.fresh": "{count, plural, one {# inventário confere} other {# inventários conferem}} com os caminhos cobertos"
|
|
9699
9834
|
};
|
|
9700
9835
|
|
|
9701
9836
|
// src/i18n/review.json
|
|
@@ -10401,7 +10536,50 @@ var review_default = {
|
|
|
10401
10536
|
"deps.finding.young": "machine",
|
|
10402
10537
|
"deps.finding.fresh": "machine",
|
|
10403
10538
|
"deps.finding.script": "machine",
|
|
10404
|
-
"deps.finding.unchecked": "machine"
|
|
10539
|
+
"deps.finding.unchecked": "machine",
|
|
10540
|
+
"command.inventory.summary": "machine",
|
|
10541
|
+
"inventory.written": "machine",
|
|
10542
|
+
"inventory.error.ref": "machine",
|
|
10543
|
+
"inventory.error.topic": "machine",
|
|
10544
|
+
"plan.error.write": "machine",
|
|
10545
|
+
"inventory.title": "machine",
|
|
10546
|
+
"inventory.read_at": "machine",
|
|
10547
|
+
"inventory.risks": "machine",
|
|
10548
|
+
"inventory.col.risk": "machine",
|
|
10549
|
+
"inventory.col.still": "machine",
|
|
10550
|
+
"inventory.col.evidence": "machine",
|
|
10551
|
+
"inventory.col.fix": "machine",
|
|
10552
|
+
"inventory.risk.credential": "machine",
|
|
10553
|
+
"inventory.risk.yes": "machine",
|
|
10554
|
+
"inventory.risk.fix_credential": "machine",
|
|
10555
|
+
"inventory.gap": "machine",
|
|
10556
|
+
"inventory.col.plan": "machine",
|
|
10557
|
+
"inventory.col.today": "machine",
|
|
10558
|
+
"inventory.col.effect": "machine",
|
|
10559
|
+
"inventory.modules": "machine",
|
|
10560
|
+
"inventory.routes": "machine",
|
|
10561
|
+
"inventory.tables": "machine",
|
|
10562
|
+
"inventory.queues": "machine",
|
|
10563
|
+
"inventory.jobs": "machine",
|
|
10564
|
+
"inventory.env": "machine",
|
|
10565
|
+
"inventory.dependencies": "machine",
|
|
10566
|
+
"inventory.tests": "machine",
|
|
10567
|
+
"inventory.test_count": "machine",
|
|
10568
|
+
"inventory.credentials": "machine",
|
|
10569
|
+
"inventory.credentials_note": "machine",
|
|
10570
|
+
"inventory.deploy": "machine",
|
|
10571
|
+
"inventory.history": "machine",
|
|
10572
|
+
"inventory.worktrees": "machine",
|
|
10573
|
+
"inventory.hotspots": "machine",
|
|
10574
|
+
"inventory.delta": "machine",
|
|
10575
|
+
"inventory.none": "machine",
|
|
10576
|
+
"inventory.more": "machine",
|
|
10577
|
+
"inventory.files": "machine",
|
|
10578
|
+
"inventory.changes": "machine",
|
|
10579
|
+
"gate.inventory.missing": "machine",
|
|
10580
|
+
"gate.inventory.expired": "machine",
|
|
10581
|
+
"gate.inventory.unknown": "machine",
|
|
10582
|
+
"gate.inventory.fresh": "machine"
|
|
10405
10583
|
},
|
|
10406
10584
|
es: {
|
|
10407
10585
|
"command.init.summary": "machine",
|
|
@@ -11104,7 +11282,50 @@ var review_default = {
|
|
|
11104
11282
|
"deps.finding.young": "machine",
|
|
11105
11283
|
"deps.finding.fresh": "machine",
|
|
11106
11284
|
"deps.finding.script": "machine",
|
|
11107
|
-
"deps.finding.unchecked": "machine"
|
|
11285
|
+
"deps.finding.unchecked": "machine",
|
|
11286
|
+
"command.inventory.summary": "machine",
|
|
11287
|
+
"inventory.written": "machine",
|
|
11288
|
+
"inventory.error.ref": "machine",
|
|
11289
|
+
"inventory.error.topic": "machine",
|
|
11290
|
+
"plan.error.write": "machine",
|
|
11291
|
+
"inventory.title": "machine",
|
|
11292
|
+
"inventory.read_at": "machine",
|
|
11293
|
+
"inventory.risks": "machine",
|
|
11294
|
+
"inventory.col.risk": "machine",
|
|
11295
|
+
"inventory.col.still": "machine",
|
|
11296
|
+
"inventory.col.evidence": "machine",
|
|
11297
|
+
"inventory.col.fix": "machine",
|
|
11298
|
+
"inventory.risk.credential": "machine",
|
|
11299
|
+
"inventory.risk.yes": "machine",
|
|
11300
|
+
"inventory.risk.fix_credential": "machine",
|
|
11301
|
+
"inventory.gap": "machine",
|
|
11302
|
+
"inventory.col.plan": "machine",
|
|
11303
|
+
"inventory.col.today": "machine",
|
|
11304
|
+
"inventory.col.effect": "machine",
|
|
11305
|
+
"inventory.modules": "machine",
|
|
11306
|
+
"inventory.routes": "machine",
|
|
11307
|
+
"inventory.tables": "machine",
|
|
11308
|
+
"inventory.queues": "machine",
|
|
11309
|
+
"inventory.jobs": "machine",
|
|
11310
|
+
"inventory.env": "machine",
|
|
11311
|
+
"inventory.dependencies": "machine",
|
|
11312
|
+
"inventory.tests": "machine",
|
|
11313
|
+
"inventory.test_count": "machine",
|
|
11314
|
+
"inventory.credentials": "machine",
|
|
11315
|
+
"inventory.credentials_note": "machine",
|
|
11316
|
+
"inventory.deploy": "machine",
|
|
11317
|
+
"inventory.history": "machine",
|
|
11318
|
+
"inventory.worktrees": "machine",
|
|
11319
|
+
"inventory.hotspots": "machine",
|
|
11320
|
+
"inventory.delta": "machine",
|
|
11321
|
+
"inventory.none": "machine",
|
|
11322
|
+
"inventory.more": "machine",
|
|
11323
|
+
"inventory.files": "machine",
|
|
11324
|
+
"inventory.changes": "machine",
|
|
11325
|
+
"gate.inventory.missing": "machine",
|
|
11326
|
+
"gate.inventory.expired": "machine",
|
|
11327
|
+
"gate.inventory.unknown": "machine",
|
|
11328
|
+
"gate.inventory.fresh": "machine"
|
|
11108
11329
|
}
|
|
11109
11330
|
};
|
|
11110
11331
|
|
|
@@ -11569,8 +11790,8 @@ var removedSymbols = (runtime, git2, base, changes) => {
|
|
|
11569
11790
|
}
|
|
11570
11791
|
return [...found.values()].slice(0, MAX_SYMBOLS);
|
|
11571
11792
|
};
|
|
11572
|
-
var parseGrep = (output) => output.split("\n").filter((
|
|
11573
|
-
const [file = "", line2 = "", ...rest] =
|
|
11793
|
+
var parseGrep = (output) => output.split("\n").filter((row2) => row2 !== "").flatMap((row2) => {
|
|
11794
|
+
const [file = "", line2 = "", ...rest] = row2.split("\0");
|
|
11574
11795
|
const number2 = Number(line2);
|
|
11575
11796
|
return file === "" || !Number.isInteger(number2) ? [] : [{ file: toPosixPath(file), line: number2, text: rest.join("\0") }];
|
|
11576
11797
|
});
|
|
@@ -11811,11 +12032,224 @@ var gitCheck = (check2, ctx) => {
|
|
|
11811
12032
|
return missing2.length > 0 ? failed(missing2) : passed([note("gate.git.ok", { require: wants.join(", ") })]);
|
|
11812
12033
|
};
|
|
11813
12034
|
|
|
12035
|
+
// src/plan/folder.ts
|
|
12036
|
+
import { join as join21 } from "node:path";
|
|
12037
|
+
var PLAN_DIR = "docs/plan";
|
|
12038
|
+
var NUMBERED = /^(\d{2,})([a-z]?)-/;
|
|
12039
|
+
var planDir = (root) => toAbsolutePath(join21(root, ...PLAN_DIR.split("/")));
|
|
12040
|
+
var planPath = (root, name) => toAbsolutePath(join21(planDir(root), name));
|
|
12041
|
+
var planFiles = (runtime, root) => {
|
|
12042
|
+
const listed5 = runtime.listDir(planDir(root));
|
|
12043
|
+
return listed5.ok ? [...listed5.value].sort() : [];
|
|
12044
|
+
};
|
|
12045
|
+
var numberOf = (name) => {
|
|
12046
|
+
const match = NUMBERED.exec(name);
|
|
12047
|
+
return match?.[1] === void 0 ? void 0 : Number.parseInt(match[1], 10);
|
|
12048
|
+
};
|
|
12049
|
+
var nextNumber = (names) => {
|
|
12050
|
+
const highest = Math.max(0, ...names.map((name) => numberOf(name) ?? 0));
|
|
12051
|
+
return String(highest + 1).padStart(2, "0");
|
|
12052
|
+
};
|
|
12053
|
+
var slugOf = (topic) => {
|
|
12054
|
+
const slug2 = topic.toLowerCase().normalize("NFKD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48).replace(/-+$/, "");
|
|
12055
|
+
return slug2 === "" ? "topic" : slug2;
|
|
12056
|
+
};
|
|
12057
|
+
var findByKind = (names, kind, topic) => names.find((name) => NUMBERED.test(name) && name.endsWith(`-${kind}-${slugOf(topic)}.md`));
|
|
12058
|
+
|
|
12059
|
+
// src/core/yaml/write.ts
|
|
12060
|
+
var PLAIN_SAFE = /^[A-Za-z_./][A-Za-z0-9_./ ()-]*$/;
|
|
12061
|
+
var RESERVED = /^(true|false|null|~|-?\d.*)$/;
|
|
12062
|
+
var scalarText = (value) => {
|
|
12063
|
+
if (value === null) return "null";
|
|
12064
|
+
if (typeof value !== "string") return String(value);
|
|
12065
|
+
return PLAIN_SAFE.test(value) && !RESERVED.test(value) && !value.endsWith(" ") ? value : JSON.stringify(value);
|
|
12066
|
+
};
|
|
12067
|
+
var isScalar = (value) => value === null || typeof value !== "object";
|
|
12068
|
+
var inline2 = (value) => {
|
|
12069
|
+
if (isScalar(value)) return scalarText(value);
|
|
12070
|
+
if (Array.isArray(value)) {
|
|
12071
|
+
if (value.length === 0) return "[]";
|
|
12072
|
+
return value.every(isScalar) ? `[${value.map(scalarText).join(", ")}]` : void 0;
|
|
12073
|
+
}
|
|
12074
|
+
return Object.keys(value).length === 0 ? "{}" : void 0;
|
|
12075
|
+
};
|
|
12076
|
+
var lines = (value, indent) => {
|
|
12077
|
+
if (Array.isArray(value)) {
|
|
12078
|
+
return value.flatMap((item2) => {
|
|
12079
|
+
const flat = inline2(item2);
|
|
12080
|
+
if (flat !== void 0) return [`${indent}- ${flat}`];
|
|
12081
|
+
const [head = "", ...rest] = lines(item2, `${indent} `);
|
|
12082
|
+
return [`${indent}- ${head.trimStart()}`, ...rest];
|
|
12083
|
+
});
|
|
12084
|
+
}
|
|
12085
|
+
if (isScalar(value)) return [`${indent}${scalarText(value)}`];
|
|
12086
|
+
return Object.entries(value).flatMap(([key, item2]) => {
|
|
12087
|
+
const flat = inline2(item2);
|
|
12088
|
+
const name = scalarText(key);
|
|
12089
|
+
return flat === void 0 ? [`${indent}${name}:`, ...lines(item2, `${indent} `)] : [`${indent}${name}: ${flat}`];
|
|
12090
|
+
});
|
|
12091
|
+
};
|
|
12092
|
+
var stringifyYaml = (value) => `${lines(value, "").join("\n")}
|
|
12093
|
+
`;
|
|
12094
|
+
|
|
12095
|
+
// src/plan/front.ts
|
|
12096
|
+
var FENCE2 = "---";
|
|
12097
|
+
var readFront = (text9) => {
|
|
12098
|
+
const normalized = text9.replace(/\r\n/g, "\n");
|
|
12099
|
+
if (!normalized.startsWith(`${FENCE2}
|
|
12100
|
+
`)) return { data: void 0, body: normalized };
|
|
12101
|
+
const end = normalized.indexOf(`
|
|
12102
|
+
${FENCE2}
|
|
12103
|
+
`, FENCE2.length);
|
|
12104
|
+
if (end === -1) return { data: void 0, body: normalized };
|
|
12105
|
+
const parsed = parseYaml(normalized.slice(FENCE2.length + 1, end + 1));
|
|
12106
|
+
const data = parsed.ok && isRecord(parsed.value) ? parsed.value : void 0;
|
|
12107
|
+
return { data, body: normalized.slice(end + FENCE2.length + 2).replace(/^\n/, "") };
|
|
12108
|
+
};
|
|
12109
|
+
var writeFront = (data, body2) => `${FENCE2}
|
|
12110
|
+
${stringifyYaml(data)}${FENCE2}
|
|
12111
|
+
|
|
12112
|
+
${body2}`;
|
|
12113
|
+
var textList = (record4, key) => {
|
|
12114
|
+
const value = record4[key];
|
|
12115
|
+
return Array.isArray(value) ? value.filter((item2) => typeof item2 === "string") : [];
|
|
12116
|
+
};
|
|
12117
|
+
|
|
12118
|
+
// src/inventory/patterns.ts
|
|
12119
|
+
var ROUTES = {
|
|
12120
|
+
pattern: `(^|[^A-Za-z0-9_])(app|router|server|api|route|r)\\.(get|post|put|patch|delete|all|route)\\(|@(Get|Post|Put|Patch|Delete|Request)(Mapping)?\\(|@(app|router|bp|blueprint)\\.(route|get|post|put|patch|delete)\\(|(^|[^A-Za-z0-9_])path\\(["']|HandleFunc\\(`
|
|
12121
|
+
};
|
|
12122
|
+
var TABLES = {
|
|
12123
|
+
pattern: `create table|(pg|sqlite|mysql)Table\\(|^model [A-Z][A-Za-z0-9_]* *\\{|__tablename__|@Entity\\(|createTable\\(|(^|[^A-Za-z0-9_])define\\(["'][A-Za-z_]+["'], *\\{`,
|
|
12124
|
+
ignoreCase: true
|
|
12125
|
+
};
|
|
12126
|
+
var QUEUES = {
|
|
12127
|
+
pattern: "new (Queue|Worker|QueueScheduler)\\(|createQueue\\(|@Processor\\(|\\.consume\\(|(^|[^A-Za-z0-9_])sqs([^A-Za-z0-9_]|$)|SendMessageCommand|(^|[^A-Za-z0-9_])kafka([^A-Za-z0-9_]|$)|(^|[^A-Za-z0-9_])amqp([^A-Za-z0-9_]|$)|(^|[^A-Za-z0-9_])pubsub([^A-Za-z0-9_]|$)|@shared_task|@celery",
|
|
12128
|
+
ignoreCase: true
|
|
12129
|
+
};
|
|
12130
|
+
var JOBS = {
|
|
12131
|
+
pattern: "cron\\.schedule\\(|new CronJob\\(|@Cron\\(|@Scheduled\\(|^[[:space:]]*-? *cron: |schedule\\.every\\(|setInterval\\("
|
|
12132
|
+
};
|
|
12133
|
+
var ENV = {
|
|
12134
|
+
pattern: `process\\.env(\\.[A-Z_][A-Z0-9_]*|\\[["'][A-Z_][A-Z0-9_]*)|import\\.meta\\.env\\.[A-Z_]|os\\.environ|os\\.getenv\\(|Getenv\\(|ENV\\[["'][A-Z_]|env\\("[A-Z_]`
|
|
12135
|
+
};
|
|
12136
|
+
var CREDENTIAL_HINTS = {
|
|
12137
|
+
pattern: "(key|secret|token|passw|pwd|bearer|auth|credential|private)|sk_live|ghp_|github_pat_|AKIA|xox[bp]-|-----BEGIN|://[^/ ]+:[^@ ]+@",
|
|
12138
|
+
ignoreCase: true
|
|
12139
|
+
};
|
|
12140
|
+
var ENV_NAME = /(?:process\.env\.|process\.env\[["']|import\.meta\.env\.|os\.environ\.get\(["']|os\.environ\[["']|os\.getenv\(["']|Getenv\(["']|ENV\[["']|env\(["'])([A-Z_][A-Z0-9_]*)/g;
|
|
12141
|
+
var envNamesIn = (text9) => [...text9.matchAll(ENV_NAME)].map((match) => match[1] ?? "").filter((name) => name !== "");
|
|
12142
|
+
var SKIPPED = [
|
|
12143
|
+
":(exclude,glob)**/node_modules/**",
|
|
12144
|
+
":(exclude,glob)**/dist/**",
|
|
12145
|
+
":(exclude,glob)**/build/**",
|
|
12146
|
+
":(exclude,glob)**/vendor/**",
|
|
12147
|
+
":(exclude,glob)**/*.min.js",
|
|
12148
|
+
":(exclude,glob)**/package-lock.json",
|
|
12149
|
+
":(exclude,glob)**/yarn.lock",
|
|
12150
|
+
":(exclude,glob)**/pnpm-lock.yaml",
|
|
12151
|
+
":(exclude,glob)docs/plan/**",
|
|
12152
|
+
":(exclude,glob).finitemonkey/**"
|
|
12153
|
+
];
|
|
12154
|
+
var TEST_FILE = /(^|\/)(tests?|__tests__|spec)\/|\.(test|spec)\.[a-z]+$|_test\.(go|py)$|(^|\/)test_[^/]+\.py$/;
|
|
12155
|
+
var DEPLOY_FILE = /(^|\/)(Dockerfile[^/]*|docker-compose[^/]*\.ya?ml|compose\.ya?ml|fly\.toml|vercel\.json|netlify\.toml|Procfile|render\.yaml|app\.yaml|serverless\.ya?ml|wrangler\.toml|railway\.json)$|^\.github\/workflows\/|\.tf$|(^|\/)(k8s|kubernetes|helm|deploy)\//;
|
|
12156
|
+
|
|
12157
|
+
// src/inventory/grep.ts
|
|
12158
|
+
var GREP_LINE = /^[^:]+:(.+?):(\d+):(.*)$/;
|
|
12159
|
+
var pathspecOf = (covered) => [
|
|
12160
|
+
...covered.length === 0 ? ["."] : covered,
|
|
12161
|
+
...SKIPPED
|
|
12162
|
+
];
|
|
12163
|
+
var linesOf = (text9) => (text9 ?? "").split("\n").map(withoutCarriageReturn).filter((line2) => line2 !== "");
|
|
12164
|
+
var grepAt = (git2, hash, grep2, covered) => {
|
|
12165
|
+
const flags = grep2.ignoreCase === true ? ["-i"] : [];
|
|
12166
|
+
const out = git2.out(["grep", "-n", "-I", "-E", ...flags, "-e", grep2.pattern, hash, "--", ...pathspecOf(covered)]);
|
|
12167
|
+
return linesOf(out).flatMap((line2) => {
|
|
12168
|
+
const match = GREP_LINE.exec(line2);
|
|
12169
|
+
if (match?.[1] === void 0 || match[2] === void 0) return [];
|
|
12170
|
+
return [{ file: match[1], line: Number.parseInt(match[2], 10), text: (match[3] ?? "").trim() }];
|
|
12171
|
+
});
|
|
12172
|
+
};
|
|
12173
|
+
var SKIPPED_FILE = /(^|\/)(node_modules|dist|build|vendor)\/|\.min\.js$|(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml)$|^docs\/plan\/|^\.finitemonkey\//;
|
|
12174
|
+
var insideAny = (file, covered) => covered.length === 0 || covered.some((dir) => {
|
|
12175
|
+
const prefix2 = dir.replace(/\/+$/, "");
|
|
12176
|
+
return prefix2 === "." || prefix2 === "" || file === prefix2 || file.startsWith(`${prefix2}/`);
|
|
12177
|
+
});
|
|
12178
|
+
var filesAt = (git2, hash, covered) => linesOf(git2.out(["ls-tree", "-r", "--name-only", hash])).filter(
|
|
12179
|
+
(file) => insideAny(file, covered) && !SKIPPED_FILE.test(file)
|
|
12180
|
+
);
|
|
12181
|
+
var showAt = (git2, hash, file) => git2.out(["show", `${hash}:${file}`]);
|
|
12182
|
+
var resolveCommit = (git2, ref) => {
|
|
12183
|
+
const hash = git2.out(["rev-parse", "--verify", "-q", `${ref}^{commit}`])?.trim();
|
|
12184
|
+
return hash === void 0 || hash === "" ? void 0 : hash;
|
|
12185
|
+
};
|
|
12186
|
+
|
|
12187
|
+
// src/inventory/report.ts
|
|
12188
|
+
var reposOf = (data) => {
|
|
12189
|
+
const value = data?.["repos"];
|
|
12190
|
+
if (!Array.isArray(value)) return [];
|
|
12191
|
+
return value.flatMap((item2) => {
|
|
12192
|
+
if (!isRecord(item2)) return [];
|
|
12193
|
+
const { path, hash } = item2;
|
|
12194
|
+
return typeof path === "string" && typeof hash === "string" ? [{ path, hash }] : [];
|
|
12195
|
+
});
|
|
12196
|
+
};
|
|
12197
|
+
|
|
12198
|
+
// src/inventory/types.ts
|
|
12199
|
+
var INVENTORY_SCHEMA = "finitemonkey/inventory@1";
|
|
12200
|
+
|
|
12201
|
+
// src/inventory/expiry.ts
|
|
12202
|
+
var TODAY = /^\d{2,}[a-z]?-today-.+\.md$/;
|
|
12203
|
+
var changedSince = (runtime, dir, hash, covered) => {
|
|
12204
|
+
const git2 = gitAt(runtime, dir);
|
|
12205
|
+
if (git2.out(["cat-file", "-e", `${hash}^{commit}`]) === void 0) return void 0;
|
|
12206
|
+
const spec2 = pathspecOf(covered);
|
|
12207
|
+
const tracked = linesOf(git2.out(["diff", "--name-only", hash, "--", ...spec2]));
|
|
12208
|
+
const untracked3 = linesOf(git2.out(["ls-files", "--others", "--exclude-standard", "--", ...spec2]));
|
|
12209
|
+
return [.../* @__PURE__ */ new Set([...tracked, ...untracked3])].sort();
|
|
12210
|
+
};
|
|
12211
|
+
var stateOf = (runtime, root, name) => {
|
|
12212
|
+
const text9 = runtime.readText(planPath(root, name));
|
|
12213
|
+
const front = text9.ok ? readFront(text9.value).data : void 0;
|
|
12214
|
+
if (front?.["schema"] !== INVENTORY_SCHEMA) return void 0;
|
|
12215
|
+
const report2 = `${PLAN_DIR}/${name}`;
|
|
12216
|
+
const topic = typeof front["topic"] === "string" ? front["topic"] : name;
|
|
12217
|
+
const covered = textList(front, "covered");
|
|
12218
|
+
for (const repo of reposOf(front)) {
|
|
12219
|
+
const changed = changedSince(runtime, toAbsolutePath(repo.path, root), repo.hash, covered);
|
|
12220
|
+
if (changed === void 0) return { kind: "unknown", report: report2, repo: repo.path, hash: repo.hash };
|
|
12221
|
+
if (changed.length > 0) return { kind: "expired", report: report2, topic, hash: repo.hash, changed };
|
|
12222
|
+
}
|
|
12223
|
+
return { kind: "fresh", report: report2 };
|
|
12224
|
+
};
|
|
12225
|
+
var inventoryStates = (runtime, root) => planFiles(runtime, root).filter((name) => TODAY.test(name)).flatMap((name) => stateOf(runtime, root, name) ?? []);
|
|
12226
|
+
|
|
12227
|
+
// src/gate/checks/inventory.ts
|
|
12228
|
+
var MAX_PATHS = 5;
|
|
12229
|
+
var noteOf = (state) => {
|
|
12230
|
+
if (state.kind === "fresh") return void 0;
|
|
12231
|
+
if (state.kind === "unknown")
|
|
12232
|
+
return note("gate.inventory.unknown", { report: state.report, repo: state.repo, hash: state.hash });
|
|
12233
|
+
return note("gate.inventory.expired", {
|
|
12234
|
+
report: state.report,
|
|
12235
|
+
count: state.changed.length,
|
|
12236
|
+
hash: state.hash.slice(0, 12),
|
|
12237
|
+
paths: state.changed.slice(0, MAX_PATHS).join(", "),
|
|
12238
|
+
topic: state.topic
|
|
12239
|
+
});
|
|
12240
|
+
};
|
|
12241
|
+
var inventoryOutcome = (states) => {
|
|
12242
|
+
if (states.length === 0) return failed([note("gate.inventory.missing")]);
|
|
12243
|
+
const notes2 = states.flatMap((state) => noteOf(state) ?? []);
|
|
12244
|
+
return notes2.length === 0 ? passed([note("gate.inventory.fresh", { count: states.length })]) : failed(notes2);
|
|
12245
|
+
};
|
|
12246
|
+
var inventoryCheck = (_check, ctx) => inventoryOutcome(inventoryStates(ctx.runtime, ctx.paths.root));
|
|
12247
|
+
|
|
11814
12248
|
// src/gate/checks/look.ts
|
|
11815
|
-
import { join as
|
|
12249
|
+
import { join as join24 } from "node:path";
|
|
11816
12250
|
|
|
11817
12251
|
// src/look/config.ts
|
|
11818
|
-
import { join as
|
|
12252
|
+
import { join as join22 } from "node:path";
|
|
11819
12253
|
|
|
11820
12254
|
// src/look/types.ts
|
|
11821
12255
|
var LOOK_RULES = [
|
|
@@ -11877,18 +12311,18 @@ var parseLookConfig = (source) => {
|
|
|
11877
12311
|
};
|
|
11878
12312
|
};
|
|
11879
12313
|
var loadLookConfig = (runtime, root) => {
|
|
11880
|
-
const source = runtime.readText(toAbsolutePath(
|
|
12314
|
+
const source = runtime.readText(toAbsolutePath(join22(root, LOOK_CONFIG)));
|
|
11881
12315
|
return source.ok ? parseLookConfig(source.value) : void 0;
|
|
11882
12316
|
};
|
|
11883
12317
|
var withMock = (route, mock) => `${route}${route.includes("?") ? "&" : "?"}mock=${encodeURIComponent(mock)}`;
|
|
11884
12318
|
var lookRoutes = (config) => config.routes.flatMap((route) => [route, ...config.mocks.map((mock) => withMock(route, mock))]);
|
|
11885
12319
|
|
|
11886
12320
|
// src/look/paths.ts
|
|
11887
|
-
import { join as
|
|
12321
|
+
import { join as join23, relative as relative5 } from "node:path";
|
|
11888
12322
|
var LOOK_DIR = "look";
|
|
11889
12323
|
var SUMMARY_FILE = "summary.json";
|
|
11890
|
-
var lookDir = (paths, treeHash2) => toAbsolutePath(
|
|
11891
|
-
var summaryPath = (paths, treeHash2) => toAbsolutePath(
|
|
12324
|
+
var lookDir = (paths, treeHash2) => toAbsolutePath(join23(paths.dir, LOOK_DIR, treeHash2));
|
|
12325
|
+
var summaryPath = (paths, treeHash2) => toAbsolutePath(join23(lookDir(paths, treeHash2), SUMMARY_FILE));
|
|
11892
12326
|
var projectRelative = (paths, absolute) => toPosixPath(relative5(paths.root, absolute));
|
|
11893
12327
|
|
|
11894
12328
|
// src/gate/checks/look.ts
|
|
@@ -11923,7 +12357,7 @@ var readSummary = (ctx) => {
|
|
|
11923
12357
|
var lastScreenEdit = (ctx) => {
|
|
11924
12358
|
const screens = loadLookConfig(ctx.runtime, ctx.paths.root)?.screens ?? DEFAULT_SCREENS;
|
|
11925
12359
|
return ctx.changes.filter((change) => change.status !== "D" && matchesAny(change.path, screens)).reduce((latest, change) => {
|
|
11926
|
-
const stat = ctx.runtime.stat(toAbsolutePath(
|
|
12360
|
+
const stat = ctx.runtime.stat(toAbsolutePath(join24(ctx.paths.root, change.path)));
|
|
11927
12361
|
return Math.max(latest, stat?.mtimeMs ?? 0);
|
|
11928
12362
|
}, 0);
|
|
11929
12363
|
};
|
|
@@ -11970,13 +12404,13 @@ var manualCheck = (check2, ctx) => {
|
|
|
11970
12404
|
};
|
|
11971
12405
|
|
|
11972
12406
|
// src/gate/checks/placeholders.ts
|
|
11973
|
-
import { join as
|
|
12407
|
+
import { join as join25 } from "node:path";
|
|
11974
12408
|
var MAX_LISTED3 = 10;
|
|
11975
12409
|
var SKIP_FILES = /\.(md|mdx|txt|rst|lock|snap|svg|png|jpg|gif|json)$|(^|\/)(CHANGELOG|LICENSE)/i;
|
|
11976
12410
|
var PLACEHOLDER = /\b(TODO|FIXME|XXX)\b|not implemented|NotImplementedError|unimplemented!|todo!\(|lorem ipsum/i;
|
|
11977
12411
|
var findPlaceholders = (lines3) => lines3.filter((line2) => !isTestFile(line2.path) && !SKIP_FILES.test(line2.path) && PLACEHOLDER.test(line2.text));
|
|
11978
12412
|
var untrackedAdded = (ctx) => ctx.changes.filter((change) => change.status === "A" && !SKIP_FILES.test(change.path)).flatMap((change) => {
|
|
11979
|
-
const text9 = ctx.runtime.readText(toAbsolutePath(
|
|
12413
|
+
const text9 = ctx.runtime.readText(toAbsolutePath(join25(ctx.paths.root, change.path)));
|
|
11980
12414
|
return text9.ok ? text9.value.split("\n").map((line2, index) => ({ path: change.path, line: index + 1, text: line2 })) : [];
|
|
11981
12415
|
});
|
|
11982
12416
|
var placeholdersCheck = (_check, ctx) => {
|
|
@@ -12211,13 +12645,13 @@ var LINE_MARKER = /<!--\s*finitemonkey:prose-allow\s*-->/;
|
|
|
12211
12645
|
var FILE_MARKER = /<!--\s*finitemonkey:prose-allow-file\s*-->/;
|
|
12212
12646
|
var ANY_MARKER = /<!--\s*finitemonkey:prose-allow(?:-file)?\s*-->/g;
|
|
12213
12647
|
var INLINE_CODE = /`[^`]*`/g;
|
|
12214
|
-
var
|
|
12648
|
+
var FENCE3 = /^\s*(```|~~~)/;
|
|
12215
12649
|
var outsideCode = (line2) => line2.replace(INLINE_CODE, "");
|
|
12216
12650
|
var unfencedLines = (text9) => {
|
|
12217
12651
|
let fenced = false;
|
|
12218
12652
|
return text9.split("\n").filter((line2) => {
|
|
12219
|
-
if (
|
|
12220
|
-
return !fenced && !
|
|
12653
|
+
if (FENCE3.test(line2)) fenced = !fenced;
|
|
12654
|
+
return !fenced && !FENCE3.test(line2);
|
|
12221
12655
|
});
|
|
12222
12656
|
};
|
|
12223
12657
|
var allowsWholeFile = (text9) => unfencedLines(text9).some((line2) => FILE_MARKER.test(outsideCode(line2)));
|
|
@@ -12226,7 +12660,7 @@ var markerCount = (text9) => text9.match(ANY_MARKER)?.length ?? 0;
|
|
|
12226
12660
|
var isMarkerOnlyLine = (line2) => allowsLine(line2) && outsideCode(line2).replace(LINE_MARKER, "").trim() === "";
|
|
12227
12661
|
|
|
12228
12662
|
// src/prose/extract.ts
|
|
12229
|
-
var
|
|
12663
|
+
var FENCE4 = /^\s*(```|~~~)/;
|
|
12230
12664
|
var HEADING = /^#{1,6}\s+/;
|
|
12231
12665
|
var ITEM = /^\s*(?:[-*+]|\d+[.)])\s+/;
|
|
12232
12666
|
var SKIPPED_LINE = /^\s*[|>]|^\s*<(?!!--)/;
|
|
@@ -12304,7 +12738,7 @@ var readBlocks = (lines3) => {
|
|
|
12304
12738
|
let commented = false;
|
|
12305
12739
|
for (let index = skipFrontmatter(lines3); index < lines3.length; index += 1) {
|
|
12306
12740
|
const raw = lines3[index] ?? "";
|
|
12307
|
-
if (
|
|
12741
|
+
if (FENCE4.test(raw)) {
|
|
12308
12742
|
fenced = !fenced;
|
|
12309
12743
|
reader.flush();
|
|
12310
12744
|
} else if (commented) {
|
|
@@ -12338,9 +12772,9 @@ var splitBlock = (block4) => {
|
|
|
12338
12772
|
});
|
|
12339
12773
|
};
|
|
12340
12774
|
var unitsOf = (blocks) => {
|
|
12341
|
-
let
|
|
12775
|
+
let section3 = 0;
|
|
12342
12776
|
return blocks.flatMap((block4, paragraph) => {
|
|
12343
|
-
if (block4.kind === "heading")
|
|
12777
|
+
if (block4.kind === "heading") section3 += 1;
|
|
12344
12778
|
const pieces = splitBlock(block4);
|
|
12345
12779
|
const next2 = blocks[paragraph + 1];
|
|
12346
12780
|
const closesSection = block4.kind === "sentence" && (next2 === void 0 || next2.kind === "heading");
|
|
@@ -12348,7 +12782,7 @@ var unitsOf = (blocks) => {
|
|
|
12348
12782
|
text: piece.text,
|
|
12349
12783
|
line: piece.line,
|
|
12350
12784
|
paragraph,
|
|
12351
|
-
section:
|
|
12785
|
+
section: section3,
|
|
12352
12786
|
kind: block4.kind,
|
|
12353
12787
|
lastInParagraph: index === pieces.length - 1,
|
|
12354
12788
|
closesSection
|
|
@@ -12576,9 +13010,9 @@ var phraseHits = (units, catalog) => units.flatMap(
|
|
|
12576
13010
|
})
|
|
12577
13011
|
);
|
|
12578
13012
|
var windowEnd = (units, from, size) => {
|
|
12579
|
-
const
|
|
13013
|
+
const section3 = units[from]?.section;
|
|
12580
13014
|
let to = from;
|
|
12581
|
-
while (to + 1 < Math.min(units.length, from + size) && units[to + 1]?.section ===
|
|
13015
|
+
while (to + 1 < Math.min(units.length, from + size) && units[to + 1]?.section === section3) to += 1;
|
|
12582
13016
|
return to;
|
|
12583
13017
|
};
|
|
12584
13018
|
var windowScore = (hits, window) => hits.filter((item2) => item2.unit >= window.from && item2.unit <= window.to).reduce((sum, item2) => sum + item2.weight, 0);
|
|
@@ -12745,8 +13179,8 @@ var PROBE_MARGIN_MS = 15e3;
|
|
|
12745
13179
|
var MIN_REMAINING_MS2 = 5e3;
|
|
12746
13180
|
var TAIL2 = 160;
|
|
12747
13181
|
var lastLine = (text9) => {
|
|
12748
|
-
const rows = text9.split(/\r?\n/).filter((
|
|
12749
|
-
const line2 = (rows.findLast((
|
|
13182
|
+
const rows = text9.split(/\r?\n/).filter((row2) => row2.trim() !== "" && !/^\s*at\s|^Node\.js v\d/.test(row2));
|
|
13183
|
+
const line2 = (rows.findLast((row2) => /error/i.test(row2)) ?? rows.at(-1))?.trim() ?? "";
|
|
12750
13184
|
return line2.length > TAIL2 ? `${line2.slice(0, TAIL2)}…` : line2;
|
|
12751
13185
|
};
|
|
12752
13186
|
var args = (check2, timeoutS) => [
|
|
@@ -12823,23 +13257,23 @@ ${run4.stderr}`)) })]);
|
|
|
12823
13257
|
};
|
|
12824
13258
|
|
|
12825
13259
|
// src/secrets/baseline.ts
|
|
12826
|
-
import { join as
|
|
13260
|
+
import { join as join26 } from "node:path";
|
|
12827
13261
|
var BASELINE_FILE2 = ".finitemonkey/findings/baseline.json";
|
|
12828
13262
|
var BASELINE_SCHEMA = "finitemonkey/secrets-baseline@1";
|
|
12829
13263
|
var BASELINE_STATES = ["aceito", "falso-positivo"];
|
|
12830
13264
|
var EXCEPTION_MAX_DAYS = 90;
|
|
12831
13265
|
var EMPTY_BASELINE = { schema: BASELINE_SCHEMA, entries: [] };
|
|
12832
|
-
var baselinePath = (root) => toAbsolutePath(
|
|
13266
|
+
var baselinePath = (root) => toAbsolutePath(join26(root, BASELINE_FILE2));
|
|
12833
13267
|
var text7 = (record4, key) => {
|
|
12834
13268
|
const value = record4[key];
|
|
12835
13269
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
12836
13270
|
};
|
|
12837
|
-
var
|
|
13271
|
+
var stateOf2 = (value) => BASELINE_STATES.find((state) => state === value);
|
|
12838
13272
|
var parseEntry2 = (value) => {
|
|
12839
13273
|
if (!isRecord(value)) return void 0;
|
|
12840
13274
|
const fields = ["id", "rule", "file", "fingerprint", "owner", "reason", "acceptedAt", "expiresAt"];
|
|
12841
13275
|
const [id, rule, file, fingerprint, owner, reason, acceptedAt, expiresAt] = fields.map((key) => text7(value, key));
|
|
12842
|
-
const state =
|
|
13276
|
+
const state = stateOf2(value["state"]);
|
|
12843
13277
|
const line2 = value["line"];
|
|
12844
13278
|
if (id === void 0 || rule === void 0 || file === void 0 || fingerprint === void 0) return void 0;
|
|
12845
13279
|
if (owner === void 0 || reason === void 0 || acceptedAt === void 0 || expiresAt === void 0)
|
|
@@ -12889,14 +13323,14 @@ var withoutFixed = (baseline, fixed) => {
|
|
|
12889
13323
|
var acceptedFingerprints = (baseline, now) => new Set(baseline.entries.filter((entry2) => entry2.expiresAt >= now).map((entry2) => entry2.fingerprint));
|
|
12890
13324
|
|
|
12891
13325
|
// src/secrets/incidents.ts
|
|
12892
|
-
import { join as
|
|
13326
|
+
import { join as join27 } from "node:path";
|
|
12893
13327
|
var INCIDENTS_DIR = ".finitemonkey/incidents";
|
|
12894
13328
|
var INCIDENT_STATES = ["aberto", "exposicao-local", "rotacionado", "fechado"];
|
|
12895
13329
|
var INCIDENT_SOURCES = ["tool-output", "prompt", "history", "scan"];
|
|
12896
13330
|
var ID = /^inc-[0-9a-f]{12}$/;
|
|
12897
13331
|
var incidentId = (rule, fingerprint) => `inc-${sha256Hex(`${rule}\0${fingerprint}`).slice(0, 12)}`;
|
|
12898
|
-
var incidentsDir = (root) => toAbsolutePath(
|
|
12899
|
-
var incidentFile = (root, id) => toAbsolutePath(
|
|
13332
|
+
var incidentsDir = (root) => toAbsolutePath(join27(root, INCIDENTS_DIR));
|
|
13333
|
+
var incidentFile = (root, id) => toAbsolutePath(join27(incidentsDir(root), `${id}.json`));
|
|
12900
13334
|
var pick3 = (options, value) => options.find((option) => option === value);
|
|
12901
13335
|
var str2 = (record4, key) => {
|
|
12902
13336
|
const value = record4[key];
|
|
@@ -12918,19 +13352,19 @@ var parseIncident = (raw) => {
|
|
|
12918
13352
|
const parsed = parseJsonObject(raw);
|
|
12919
13353
|
if (!parsed.ok) return parsed;
|
|
12920
13354
|
const record4 = parsed.value;
|
|
12921
|
-
const [id, rule,
|
|
13355
|
+
const [id, rule, where2, fingerprint, createdAt, updatedAt] = ["id", "rule", "where", "fingerprint", "createdAt", "updatedAt"].map((key) => str2(record4, key));
|
|
12922
13356
|
const state = pick3(INCIDENT_STATES, record4["state"]);
|
|
12923
13357
|
const source = pick3(INCIDENT_SOURCES, record4["source"]);
|
|
12924
13358
|
const history = parseHistory(record4["history"]);
|
|
12925
13359
|
const firstCommit = str2(record4, "firstCommit");
|
|
12926
|
-
if (id === void 0 || !ID.test(id) || rule === void 0 ||
|
|
13360
|
+
if (id === void 0 || !ID.test(id) || rule === void 0 || where2 === void 0) return reject("incomplete");
|
|
12927
13361
|
if (fingerprint === void 0 || createdAt === void 0 || updatedAt === void 0) return reject("incomplete");
|
|
12928
13362
|
if (state === void 0 || source === void 0 || history === void 0) return reject("incomplete");
|
|
12929
13363
|
const base = {
|
|
12930
13364
|
schemaVersion: 1,
|
|
12931
13365
|
id,
|
|
12932
13366
|
rule,
|
|
12933
|
-
where,
|
|
13367
|
+
where: where2,
|
|
12934
13368
|
fingerprint,
|
|
12935
13369
|
source,
|
|
12936
13370
|
state,
|
|
@@ -12951,7 +13385,7 @@ var listIncidents = (runtime, root) => {
|
|
|
12951
13385
|
return names.value.filter((name) => name.endsWith(".json")).map((name) => readIncident(runtime, root, name.slice(0, -".json".length))).flatMap((parsed) => parsed.ok ? [parsed.value] : []).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
12952
13386
|
};
|
|
12953
13387
|
var saveIncident = (runtime, root, incident) => {
|
|
12954
|
-
const ignore = runtime.writeText(toAbsolutePath(
|
|
13388
|
+
const ignore = runtime.writeText(toAbsolutePath(join27(incidentsDir(root), ".gitignore")), "*\n");
|
|
12955
13389
|
if (!ignore.ok) return ignore;
|
|
12956
13390
|
return runtime.writeText(incidentFile(root, incident.id), `${JSON.stringify(incident, null, 2)}
|
|
12957
13391
|
`);
|
|
@@ -12998,7 +13432,7 @@ var moveIncident = (incident, to, now, by) => ({
|
|
|
12998
13432
|
var isRotated = (incident) => incident.state === "rotacionado" || incident.state === "fechado";
|
|
12999
13433
|
|
|
13000
13434
|
// src/secrets/scan.ts
|
|
13001
|
-
import { join as
|
|
13435
|
+
import { join as join28, relative as relative6 } from "node:path";
|
|
13002
13436
|
|
|
13003
13437
|
// src/secrets/located.ts
|
|
13004
13438
|
var findingId = (ruleId, file, fingerprint) => `fm-${sha256Hex(`${ruleId}\0${file}\0${fingerprint}`).slice(0, 16)}`;
|
|
@@ -13059,7 +13493,7 @@ var diffScanner = () => {
|
|
|
13059
13493
|
collect2(chunk, commit2, found);
|
|
13060
13494
|
chunk = fresh2();
|
|
13061
13495
|
};
|
|
13062
|
-
const
|
|
13496
|
+
const header2 = (line2) => {
|
|
13063
13497
|
const match = COMMIT.exec(line2);
|
|
13064
13498
|
if (match !== null) {
|
|
13065
13499
|
flush2();
|
|
@@ -13075,7 +13509,7 @@ var diffScanner = () => {
|
|
|
13075
13509
|
return {
|
|
13076
13510
|
push: (raw) => {
|
|
13077
13511
|
const line2 = withoutCarriageReturn(raw);
|
|
13078
|
-
if (!
|
|
13512
|
+
if (!header2(line2)) addLine(chunk, line2);
|
|
13079
13513
|
},
|
|
13080
13514
|
end: () => {
|
|
13081
13515
|
flush2();
|
|
@@ -13086,7 +13520,7 @@ var diffScanner = () => {
|
|
|
13086
13520
|
|
|
13087
13521
|
// src/secrets/scan.ts
|
|
13088
13522
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
13089
|
-
var
|
|
13523
|
+
var SKIPPED2 = /(?:^|\/)(?:\.git|node_modules|\.finitemonkey)\//;
|
|
13090
13524
|
var DIFF_FLAGS = ["-U0", "--no-color", "--no-ext-diff", "--no-renames"];
|
|
13091
13525
|
var binary = (text9) => text9.slice(0, 8e3).includes("\0");
|
|
13092
13526
|
var listed2 = (runtime, root, target2) => {
|
|
@@ -13098,7 +13532,7 @@ var listed2 = (runtime, root, target2) => {
|
|
|
13098
13532
|
const base = toAbsolutePath(target2, root);
|
|
13099
13533
|
const walked = runtime.walkFiles(base);
|
|
13100
13534
|
if (!walked.ok) return walked;
|
|
13101
|
-
return accept(walked.value.map((name) => toPosixPath(relative6(root,
|
|
13535
|
+
return accept(walked.value.map((name) => toPosixPath(relative6(root, join28(base, toPosixPath(name))))));
|
|
13102
13536
|
};
|
|
13103
13537
|
var scanFile = (runtime, root, file) => {
|
|
13104
13538
|
const text9 = runtime.readText(toAbsolutePath(file, root));
|
|
@@ -13108,12 +13542,12 @@ var scanFile = (runtime, root, file) => {
|
|
|
13108
13542
|
var scanPath = (runtime, root, target2) => {
|
|
13109
13543
|
const files = listed2(runtime, root, target2);
|
|
13110
13544
|
if (!files.ok) return files;
|
|
13111
|
-
return accept(files.value.filter((file) => !
|
|
13545
|
+
return accept(files.value.filter((file) => !SKIPPED2.test(file)).flatMap((file) => scanFile(runtime, root, file)));
|
|
13112
13546
|
};
|
|
13113
13547
|
var diffFindings = (diff) => {
|
|
13114
13548
|
const scanner = diffScanner();
|
|
13115
13549
|
for (const line2 of diff.split("\n")) scanner.push(line2);
|
|
13116
|
-
return scanner.end().filter((finding4) => !
|
|
13550
|
+
return scanner.end().filter((finding4) => !SKIPPED2.test(finding4.file));
|
|
13117
13551
|
};
|
|
13118
13552
|
var scanStaged = (runtime, root, includeUnstaged = false) => {
|
|
13119
13553
|
const args2 = includeUnstaged ? ["diff", "HEAD", ...DIFF_FLAGS] : ["diff", "--cached", ...DIFF_FLAGS];
|
|
@@ -13126,14 +13560,14 @@ var scanHistory = async (runtime, root) => {
|
|
|
13126
13560
|
const args2 = ["log", "-p", "--all", "--format=commit %H", ...DIFF_FLAGS];
|
|
13127
13561
|
const git2 = await runtime.gitLines(args2, root, scanner.push);
|
|
13128
13562
|
if (!git2.ok) return reject(git2.found ? "git log failed" : "git not found");
|
|
13129
|
-
return accept(scanner.end().filter((finding4) => !
|
|
13563
|
+
return accept(scanner.end().filter((finding4) => !SKIPPED2.test(finding4.file)));
|
|
13130
13564
|
};
|
|
13131
13565
|
|
|
13132
13566
|
// src/secrets/gate.ts
|
|
13133
13567
|
var untracked2 = (runtime, root) => {
|
|
13134
|
-
const
|
|
13135
|
-
if (!
|
|
13136
|
-
return
|
|
13568
|
+
const listed5 = runtime.git(["ls-files", "-z", "--others", "--exclude-standard"], root);
|
|
13569
|
+
if (!listed5.ok) return [];
|
|
13570
|
+
return listed5.stdout.split("\0").map(toPosixPath).filter((file) => file !== "" && !file.startsWith(".finitemonkey/")).flatMap((file) => scanFile(runtime, root, file));
|
|
13137
13571
|
};
|
|
13138
13572
|
var secretsGateStatus = (runtime, root, since) => {
|
|
13139
13573
|
const changed = scanStaged(runtime, root, true);
|
|
@@ -13168,7 +13602,7 @@ var secretsCheck = (_check, ctx) => {
|
|
|
13168
13602
|
};
|
|
13169
13603
|
|
|
13170
13604
|
// src/gate/checks/tests.ts
|
|
13171
|
-
import { join as
|
|
13605
|
+
import { join as join29 } from "node:path";
|
|
13172
13606
|
|
|
13173
13607
|
// src/guards/tests/tree.ts
|
|
13174
13608
|
var outOfScope = (input, change) => input.testsProtected && input.scopePaths.length > 0 && change.status !== "A" && isTestFile(change.path) && !matchesAny(change.path, input.scopePaths) ? [{ kind: "out_of_scope", path: change.path }] : [];
|
|
@@ -13200,7 +13634,7 @@ var treeViolations = (ctx) => {
|
|
|
13200
13634
|
changes: relevant,
|
|
13201
13635
|
before: (path) => fileAt(ctx.git, ctx.base, path),
|
|
13202
13636
|
after: (path) => {
|
|
13203
|
-
const text9 = ctx.runtime.readText(toAbsolutePath(
|
|
13637
|
+
const text9 = ctx.runtime.readText(toAbsolutePath(join29(ctx.paths.root, path)));
|
|
13204
13638
|
return text9.ok ? text9.value : void 0;
|
|
13205
13639
|
},
|
|
13206
13640
|
acceptedConfigs: ctx.trust.configs,
|
|
@@ -13221,7 +13655,7 @@ var testsCheck = (check2, ctx) => {
|
|
|
13221
13655
|
};
|
|
13222
13656
|
|
|
13223
13657
|
// src/git/tree.ts
|
|
13224
|
-
import { join as
|
|
13658
|
+
import { join as join30 } from "node:path";
|
|
13225
13659
|
|
|
13226
13660
|
// src/secrets/guards/paths.ts
|
|
13227
13661
|
var SAFE_ENV = /^\.env\.(?:example|sample|template|dist|defaults|schema)$/i;
|
|
@@ -13252,15 +13686,15 @@ var run = (runtime, repo, args2, env, options, input) => {
|
|
|
13252
13686
|
return result.ok ? accept(result.stdout.trim()) : reject(failure(args2[0] ?? "git", result));
|
|
13253
13687
|
};
|
|
13254
13688
|
var dropSensitive = (runtime, repo, env, options) => {
|
|
13255
|
-
const
|
|
13256
|
-
if (!
|
|
13257
|
-
const sensitive =
|
|
13689
|
+
const listed5 = run(runtime, repo, ["ls-files", "-z"], env, options);
|
|
13690
|
+
if (!listed5.ok) return listed5;
|
|
13691
|
+
const sensitive = listed5.value.split("\0").filter((path) => path !== "" && isSensitivePath(path));
|
|
13258
13692
|
if (sensitive.length === 0) return accept(void 0);
|
|
13259
13693
|
const removed = run(runtime, repo, ["rm", "--cached", "-q", "--ignore-unmatch", "--", ...sensitive], env, options);
|
|
13260
13694
|
return removed.ok ? accept(void 0) : removed;
|
|
13261
13695
|
};
|
|
13262
13696
|
var withTempIndex = (runtime, repo, options, work) => {
|
|
13263
|
-
const path = toAbsolutePath(
|
|
13697
|
+
const path = toAbsolutePath(join30(repo.gitDir, `finitemonkey-${options.stamp}.index`));
|
|
13264
13698
|
const env = { GIT_INDEX_FILE: path, GIT_OPTIONAL_LOCKS: "0" };
|
|
13265
13699
|
try {
|
|
13266
13700
|
return work(env);
|
|
@@ -13304,8 +13738,8 @@ var commitTree = (runtime, repo, tree, parents, message, options) => run(
|
|
|
13304
13738
|
// src/git/merge/diff-parse.ts
|
|
13305
13739
|
var HUNK3 = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
13306
13740
|
var BINARY = /^Binary files (?:a\/(.+)|\/dev\/null) and (?:b\/(.+)|\/dev\/null) differ$/;
|
|
13307
|
-
var pathAfter = (line2,
|
|
13308
|
-
const value = line2.slice(
|
|
13741
|
+
var pathAfter = (line2, prefix2) => {
|
|
13742
|
+
const value = line2.slice(prefix2.length).replace(/\t$/, "");
|
|
13309
13743
|
return value === "/dev/null" ? void 0 : value.replace(/^[ab]\//, "");
|
|
13310
13744
|
};
|
|
13311
13745
|
var flushHunk = (draft) => {
|
|
@@ -13468,7 +13902,7 @@ var mergeCommitsSince = (runtime, repo, since) => {
|
|
|
13468
13902
|
var mergeInProgress = (runtime, repo) => revParse(runtime, repo, "MERGE_HEAD") !== void 0;
|
|
13469
13903
|
|
|
13470
13904
|
// src/git/merge/dropped.ts
|
|
13471
|
-
import { join as
|
|
13905
|
+
import { join as join31 } from "node:path";
|
|
13472
13906
|
|
|
13473
13907
|
// src/git/merge/lines.ts
|
|
13474
13908
|
var normalizeLine = (line2) => line2.replace(/\r$/, "").trim().replace(/\s*,$/, "");
|
|
@@ -13548,7 +13982,7 @@ var parseDropped = (text9) => {
|
|
|
13548
13982
|
return accept({ items, invalid });
|
|
13549
13983
|
};
|
|
13550
13984
|
var loadDropped = (runtime, root, file) => {
|
|
13551
|
-
const path = toAbsolutePath(file ??
|
|
13985
|
+
const path = toAbsolutePath(file ?? join31(root, DROPPED_FILE), root);
|
|
13552
13986
|
const text9 = runtime.readText(path);
|
|
13553
13987
|
if (!text9.ok) return file === void 0 ? accept({ items: [], invalid: [] }) : reject(`${file}: ${text9.error}`);
|
|
13554
13988
|
return parseDropped(text9.value);
|
|
@@ -13558,7 +13992,7 @@ var isDropped = (finding4, items) => items.some(
|
|
|
13558
13992
|
);
|
|
13559
13993
|
|
|
13560
13994
|
// src/git/merge/generated.ts
|
|
13561
|
-
import { join as
|
|
13995
|
+
import { join as join32 } from "node:path";
|
|
13562
13996
|
var LOCKFILES3 = /* @__PURE__ */ new Set([
|
|
13563
13997
|
"package-lock.json",
|
|
13564
13998
|
"npm-shrinkwrap.json",
|
|
@@ -13621,7 +14055,7 @@ var verifyGenerated = (runtime, repo, inputs, paths, generators) => {
|
|
|
13621
14055
|
if (declared.length === 0) return accept([]);
|
|
13622
14056
|
const commit2 = resultCommit(runtime, repo, inputs);
|
|
13623
14057
|
if (!commit2.ok) return commit2;
|
|
13624
|
-
const dir =
|
|
14058
|
+
const dir = join32(repo.gitDir, `finitemonkey-generate-${runtime.now().replace(/[:.]/g, "-")}`);
|
|
13625
14059
|
if (!runtime.git(["worktree", "add", "--detach", dir, commit2.value], repo.root).ok)
|
|
13626
14060
|
return reject("could not check out the merge result");
|
|
13627
14061
|
try {
|
|
@@ -13631,7 +14065,7 @@ var verifyGenerated = (runtime, repo, inputs, paths, generators) => {
|
|
|
13631
14065
|
}
|
|
13632
14066
|
return accept(
|
|
13633
14067
|
declared.flatMap(({ path }) => {
|
|
13634
|
-
const fresh3 = runtime.readText(toAbsolutePath(
|
|
14068
|
+
const fresh3 = runtime.readText(toAbsolutePath(join32(dir, path)));
|
|
13635
14069
|
const merged2 = blobText(runtime, repo, commit2.value, path);
|
|
13636
14070
|
if (fresh3.ok && fresh3.value === merged2) return [];
|
|
13637
14071
|
return [{ kind: "generated-differs", file: path, side: void 0, line: void 0, text: path, weak: false }];
|
|
@@ -13742,14 +14176,14 @@ var DECLARATION = /\b(?:function\*?|class|interface|type|enum|def|fn|func|struct
|
|
|
13742
14176
|
var BINDING = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*[:=]/g;
|
|
13743
14177
|
var KEY = /^["']?([A-Za-z_$][\w$.-]*)["']?\s*:(?!:)/;
|
|
13744
14178
|
var TEST = /\b(?:it|test|describe|context)(?:\.\w+)?\s*\(\s*(["'`])(.+?)\1/;
|
|
13745
|
-
var
|
|
14179
|
+
var RESERVED2 = /* @__PURE__ */ new Set(["default", "case", "http", "https"]);
|
|
13746
14180
|
var symbolsOf = (line2) => {
|
|
13747
14181
|
if (isWeak(line2)) return [];
|
|
13748
14182
|
const names = [...line2.matchAll(DECLARATION), ...line2.matchAll(BINDING)].map((match) => match[1] ?? "");
|
|
13749
14183
|
const key = KEY.exec(line2)?.[1];
|
|
13750
14184
|
const title = TEST.exec(line2)?.[2];
|
|
13751
14185
|
return [
|
|
13752
|
-
...[...names, ...key === void 0 ? [] : [key]].filter((name) => name.length > 1 && !
|
|
14186
|
+
...[...names, ...key === void 0 ? [] : [key]].filter((name) => name.length > 1 && !RESERVED2.has(name)).map((name) => ({ name, test: false })),
|
|
13753
14187
|
...title === void 0 ? [] : [{ name: title, test: true }]
|
|
13754
14188
|
];
|
|
13755
14189
|
};
|
|
@@ -13917,19 +14351,19 @@ var verifyMerge = (runtime, repo, options = {}) => {
|
|
|
13917
14351
|
};
|
|
13918
14352
|
|
|
13919
14353
|
// src/git/ownership.ts
|
|
13920
|
-
import { join as
|
|
14354
|
+
import { join as join33 } from "node:path";
|
|
13921
14355
|
var OWNERSHIP_DIR = ".finitemonkey/git";
|
|
13922
14356
|
var ownerKey = (raw) => {
|
|
13923
14357
|
const cleaned = (raw ?? "").replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 80);
|
|
13924
14358
|
return cleaned === "" ? "unknown" : cleaned;
|
|
13925
14359
|
};
|
|
13926
|
-
var fileOf = (repo, kind, owner) => toAbsolutePath(
|
|
14360
|
+
var fileOf = (repo, kind, owner) => toAbsolutePath(join33(repo.root, OWNERSHIP_DIR, kind, `${ownerKey(owner)}.json`));
|
|
13927
14361
|
var readDirty = (runtime, root) => {
|
|
13928
14362
|
const status = runtime.git(["status", "--porcelain=v2", "-z", "--untracked-files=all"], root);
|
|
13929
14363
|
return status.ok ? parsePorcelainV2(status.stdout) : void 0;
|
|
13930
14364
|
};
|
|
13931
14365
|
var hashDirty = (runtime, repo, entries) => {
|
|
13932
|
-
const present2 = entries.filter((entry2) => runtime.stat(toAbsolutePath(
|
|
14366
|
+
const present2 = entries.filter((entry2) => runtime.stat(toAbsolutePath(join33(repo.root, entry2.path)))?.kind === "file");
|
|
13933
14367
|
const hashed = present2.length === 0 ? void 0 : runtime.gitWith(["hash-object", "--stdin-paths"], repo.root, {
|
|
13934
14368
|
input: `${present2.map((entry2) => entry2.path).join("\n")}
|
|
13935
14369
|
`
|
|
@@ -14013,11 +14447,11 @@ var foreignFiles = (runtime, repo, owner, targets2) => {
|
|
|
14013
14447
|
};
|
|
14014
14448
|
|
|
14015
14449
|
// src/git/gate-status.ts
|
|
14016
|
-
var
|
|
14450
|
+
var lines2 = (text9) => text9.split("\n").filter((line2) => line2.trim() !== "");
|
|
14017
14451
|
var unpushedSince = (runtime, repo, since) => {
|
|
14018
|
-
if (
|
|
14452
|
+
if (lines2(runtime.git(["remote"], repo.root).stdout).length === 0) return [];
|
|
14019
14453
|
const result = runtime.git(["rev-list", `${since}..HEAD`, "--not", "--remotes"], repo.root);
|
|
14020
|
-
return result.ok ?
|
|
14454
|
+
return result.ok ? lines2(result.stdout) : [];
|
|
14021
14455
|
};
|
|
14022
14456
|
var worktreeGateStatus = (runtime, repo, owner) => {
|
|
14023
14457
|
const edits = readEdits(runtime, repo, owner);
|
|
@@ -14037,8 +14471,8 @@ var mergeGateStatus = (runtime, repo, owner) => {
|
|
|
14037
14471
|
return [...pending, ...commits.map((commit2) => ({ commit: commit2, report: verifyMerge(runtime, repo, { rev: commit2 }) }))];
|
|
14038
14472
|
};
|
|
14039
14473
|
var findingLabel = (finding4) => {
|
|
14040
|
-
const
|
|
14041
|
-
return `${
|
|
14474
|
+
const where2 = finding4.line === void 0 ? finding4.file : `${finding4.file}:${String(finding4.line)}`;
|
|
14475
|
+
return `${where2} ${finding4.text === "" ? finding4.kind : `"${finding4.text}"`}`;
|
|
14042
14476
|
};
|
|
14043
14477
|
|
|
14044
14478
|
// src/gate/checks/worktree.ts
|
|
@@ -14105,7 +14539,8 @@ var DEFAULT_CHECKS = {
|
|
|
14105
14539
|
review: reviewCheck,
|
|
14106
14540
|
callers: callersCheck,
|
|
14107
14541
|
runtime: runtimeCheck,
|
|
14108
|
-
look: lookCheck
|
|
14542
|
+
look: lookCheck,
|
|
14543
|
+
inventory: inventoryCheck
|
|
14109
14544
|
};
|
|
14110
14545
|
|
|
14111
14546
|
// src/gate/run.ts
|
|
@@ -14299,7 +14734,7 @@ var subagentStopGate = (input) => {
|
|
|
14299
14734
|
};
|
|
14300
14735
|
|
|
14301
14736
|
// src/gate/hooks/subagent.ts
|
|
14302
|
-
import { join as
|
|
14737
|
+
import { join as join34 } from "node:path";
|
|
14303
14738
|
var NO_CONTRACT_AGENTS = /(^|:)(reviewer|verifier|explore|plan|claude-code-guide|statusline-setup)$/i;
|
|
14304
14739
|
var KNOWN_KINDS = /* @__PURE__ */ new Set([
|
|
14305
14740
|
"command",
|
|
@@ -14336,13 +14771,13 @@ var subagentStart = (input) => {
|
|
|
14336
14771
|
const { runtime, t } = input;
|
|
14337
14772
|
const active = readState(runtime, paths).active;
|
|
14338
14773
|
if (active === void 0) return { kind: "allow" };
|
|
14339
|
-
const disk = (
|
|
14340
|
-
const text9 = runtime.readText(toAbsolutePath(
|
|
14774
|
+
const disk = (relative12) => {
|
|
14775
|
+
const text9 = runtime.readText(toAbsolutePath(join34(paths.root, relative12)));
|
|
14341
14776
|
return text9.ok ? text9.value : void 0;
|
|
14342
14777
|
};
|
|
14343
14778
|
const loaded = loadTask(runtime, paths, { disk, base: () => void 0 }, active);
|
|
14344
14779
|
if (!loaded.ok) return { kind: "allow" };
|
|
14345
|
-
const briefing = runtime.stat(toAbsolutePath(
|
|
14780
|
+
const briefing = runtime.stat(toAbsolutePath(join34(paths.dir, "briefing.md"))) !== void 0;
|
|
14346
14781
|
return { kind: "allow", output: contextOutput("SubagentStart", contractFacts(t, loaded.value.contract, briefing)) };
|
|
14347
14782
|
};
|
|
14348
14783
|
|
|
@@ -14449,14 +14884,14 @@ var resolveFrom = (base, ...parts) => parts.reduce((current2, part2) => {
|
|
|
14449
14884
|
import { posix as posix4 } from "node:path";
|
|
14450
14885
|
var MAGIC = /^:(?:\(([^)]*)\)|([!^/]*))(.*)$/s;
|
|
14451
14886
|
var GLOB = /[*?[]/;
|
|
14452
|
-
var specOf = (raw,
|
|
14887
|
+
var specOf = (raw, prefix2) => {
|
|
14453
14888
|
const posixRaw = toPosixPath(raw);
|
|
14454
14889
|
const magic = MAGIC.exec(posixRaw);
|
|
14455
14890
|
const words = magic === null ? "" : magic[1] ?? magic[2] ?? "";
|
|
14456
14891
|
const rest = magic === null ? posixRaw : magic[3] ?? "";
|
|
14457
14892
|
const exclude = /(?:^|,)exclude(?:,|$)|[!^]/.test(words);
|
|
14458
14893
|
const top = /(?:^|,)top(?:,|$)|\//.test(words);
|
|
14459
|
-
const joined = posix4.normalize(top ? rest : posix4.join(
|
|
14894
|
+
const joined = posix4.normalize(top ? rest : posix4.join(prefix2 === "" ? "." : prefix2, rest));
|
|
14460
14895
|
return { pattern: joined === "./" ? "." : joined.replace(/\/$/, ""), exclude };
|
|
14461
14896
|
};
|
|
14462
14897
|
var globRegex3 = (pattern) => {
|
|
@@ -14468,8 +14903,8 @@ var matchesOne = (file, pattern) => {
|
|
|
14468
14903
|
if (GLOB.test(pattern)) return globRegex3(pattern).test(file);
|
|
14469
14904
|
return file === pattern || file.startsWith(`${pattern}/`);
|
|
14470
14905
|
};
|
|
14471
|
-
var matchPathspecs = (file, specs,
|
|
14472
|
-
const parsed = specs.map((raw) => specOf(raw,
|
|
14906
|
+
var matchPathspecs = (file, specs, prefix2) => {
|
|
14907
|
+
const parsed = specs.map((raw) => specOf(raw, prefix2));
|
|
14473
14908
|
const include = parsed.filter((spec2) => !spec2.exclude);
|
|
14474
14909
|
const included = include.length === 0 || include.some((spec2) => matchesOne(file, spec2.pattern));
|
|
14475
14910
|
return included && !parsed.some((spec2) => spec2.exclude && matchesOne(file, spec2.pattern));
|
|
@@ -15006,11 +15441,11 @@ var expandAlias = (runtime, repo, invocation, depth = 0) => {
|
|
|
15006
15441
|
const words = normalizeCommand(`git ${configured}`).commands[0]?.args ?? [];
|
|
15007
15442
|
return expandAlias(runtime, repo, withAlias(invocation, words), depth + 1);
|
|
15008
15443
|
};
|
|
15009
|
-
var targetsOf = (entries, spec2,
|
|
15444
|
+
var targetsOf = (entries, spec2, prefix2) => entries.filter((entry2) => {
|
|
15010
15445
|
if (spec2.scope === "tracked") return entry2.kind !== "untracked";
|
|
15011
15446
|
if (spec2.scope === "worktree") return entry2.kind !== "untracked" && entry2.unstaged;
|
|
15012
15447
|
return true;
|
|
15013
|
-
}).filter((entry2) => spec2.pathspecs.length === 0 || matchPathspecs(entry2.path, spec2.pathspecs,
|
|
15448
|
+
}).filter((entry2) => spec2.pathspecs.length === 0 || matchPathspecs(entry2.path, spec2.pathspecs, prefix2)).map((entry2) => entry2.path);
|
|
15014
15449
|
var shellAliasCommands = (invocation, runtime, repo) => {
|
|
15015
15450
|
const configured = invocation.config[`alias.${invocation.subcommand.toLowerCase()}`] ?? runtime.git(["config", "--get", `alias.${invocation.subcommand}`], repo.root).stdout.trim();
|
|
15016
15451
|
return configured.startsWith("!") ? normalizeCommand(configured.slice(1)).commands : [];
|
|
@@ -15117,16 +15552,16 @@ var rmVerdict = (runtime, context, command) => {
|
|
|
15117
15552
|
return PASS;
|
|
15118
15553
|
};
|
|
15119
15554
|
var listWorktrees = (runtime, cwd) => {
|
|
15120
|
-
const
|
|
15121
|
-
if (!
|
|
15122
|
-
return
|
|
15555
|
+
const listed5 = runtime.git(["worktree", "list", "--porcelain"], toAbsolutePath(cwd));
|
|
15556
|
+
if (!listed5.ok) return [];
|
|
15557
|
+
return listed5.stdout.split("\n").filter((line2) => line2.startsWith("worktree ")).map((line2) => pathKey(line2.slice("worktree ".length)));
|
|
15123
15558
|
};
|
|
15124
15559
|
|
|
15125
15560
|
// src/git/journal.ts
|
|
15126
|
-
import { join as
|
|
15561
|
+
import { join as join35 } from "node:path";
|
|
15127
15562
|
var JOURNAL_FILE = ".finitemonkey/git-journal.jsonl";
|
|
15128
15563
|
var JOURNAL_SCHEMA = "finitemonkey/git-journal@1";
|
|
15129
|
-
var journalPath = (root) => toAbsolutePath(
|
|
15564
|
+
var journalPath = (root) => toAbsolutePath(join35(root, JOURNAL_FILE));
|
|
15130
15565
|
var headsOf = (value) => isRecord(value) ? Object.fromEntries(
|
|
15131
15566
|
Object.entries(value).filter((entry2) => typeof entry2[1] === "string")
|
|
15132
15567
|
) : {};
|
|
@@ -15162,7 +15597,7 @@ var readJournal = (runtime, root) => {
|
|
|
15162
15597
|
};
|
|
15163
15598
|
var appendJournal = (runtime, root, entry2) => {
|
|
15164
15599
|
const path = journalPath(root);
|
|
15165
|
-
const made = runtime.mkdir(toAbsolutePath(
|
|
15600
|
+
const made = runtime.mkdir(toAbsolutePath(join35(root, ".finitemonkey")));
|
|
15166
15601
|
if (!made.ok) return made;
|
|
15167
15602
|
const previous = runtime.readText(path);
|
|
15168
15603
|
const before = previous.ok ? previous.value : "";
|
|
@@ -15183,13 +15618,13 @@ var optionalLine = (runtime, repo, args2) => {
|
|
|
15183
15618
|
return result.ok && value !== "" ? value : void 0;
|
|
15184
15619
|
};
|
|
15185
15620
|
var branchHeads = (runtime, repo) => {
|
|
15186
|
-
const
|
|
15621
|
+
const listed5 = runtime.git(
|
|
15187
15622
|
["for-each-ref", "--format=%(refname) %(objectname)", "refs/heads", "refs/stash"],
|
|
15188
15623
|
repo.root
|
|
15189
15624
|
);
|
|
15190
|
-
if (!
|
|
15625
|
+
if (!listed5.ok) return {};
|
|
15191
15626
|
return Object.fromEntries(
|
|
15192
|
-
|
|
15627
|
+
listed5.stdout.split("\n").flatMap((line2) => {
|
|
15193
15628
|
const [ref, sha] = line2.split(" ");
|
|
15194
15629
|
return ref === void 0 || sha === void 0 || ref === "" ? [] : [[ref, sha]];
|
|
15195
15630
|
})
|
|
@@ -15244,8 +15679,8 @@ var takeSnapshot = (runtime, repo, request) => {
|
|
|
15244
15679
|
return logged.ok ? accept(entry2) : reject(`journal: ${logged.error}`);
|
|
15245
15680
|
};
|
|
15246
15681
|
var listSnapshots = (runtime, repo) => {
|
|
15247
|
-
const
|
|
15248
|
-
return
|
|
15682
|
+
const listed5 = runtime.git(["for-each-ref", "--sort=-refname", "--format=%(refname)", BACKUP_PREFIX], repo.root);
|
|
15683
|
+
return listed5.ok ? listed5.stdout.split("\n").filter((line2) => line2 !== "") : [];
|
|
15249
15684
|
};
|
|
15250
15685
|
|
|
15251
15686
|
// src/git/hooks/context.ts
|
|
@@ -15409,7 +15844,7 @@ var GIT_HANDLERS = {
|
|
|
15409
15844
|
|
|
15410
15845
|
// src/policy/guards.ts
|
|
15411
15846
|
var SHADOW_FILE = "shadow.json";
|
|
15412
|
-
var
|
|
15847
|
+
var numberOf2 = (value) => typeof value === "number" && Number.isInteger(value) ? value : 0;
|
|
15413
15848
|
var readShadow = (runtime, paths) => {
|
|
15414
15849
|
const text9 = runtime.readText(paths.cache(SHADOW_FILE));
|
|
15415
15850
|
const parsed = text9.ok ? parseJsonObject(text9.value) : void 0;
|
|
@@ -15420,8 +15855,8 @@ var readShadow = (runtime, paths) => {
|
|
|
15420
15855
|
[
|
|
15421
15856
|
id,
|
|
15422
15857
|
{
|
|
15423
|
-
firings:
|
|
15424
|
-
falsePositives:
|
|
15858
|
+
firings: numberOf2(value["firings"]),
|
|
15859
|
+
falsePositives: numberOf2(value["falsePositives"]),
|
|
15425
15860
|
promoted: value["promoted"] === true
|
|
15426
15861
|
}
|
|
15427
15862
|
]
|
|
@@ -15795,9 +16230,9 @@ var PROSE_HANDLERS = {
|
|
|
15795
16230
|
// src/secrets/guards/describe.ts
|
|
15796
16231
|
var MAX_LISTED8 = 5;
|
|
15797
16232
|
var describeFindings = (t, items) => {
|
|
15798
|
-
const
|
|
15799
|
-
const rest = items.length -
|
|
15800
|
-
return rest > 0 ? `${
|
|
16233
|
+
const listed5 = items.slice(0, MAX_LISTED8).map(({ ruleId, where: where2 }) => t("secrets.found_item", { rule: ruleId, where: where2 }));
|
|
16234
|
+
const rest = items.length - listed5.length;
|
|
16235
|
+
return rest > 0 ? `${listed5.join("; ")}; ${t("secrets.found_more", { count: rest })}` : listed5.join("; ");
|
|
15801
16236
|
};
|
|
15802
16237
|
var lineWhere = (t, finding4) => t("secrets.where.line", { line: finding4.line, column: finding4.column });
|
|
15803
16238
|
|
|
@@ -15808,12 +16243,12 @@ var liveFindings = (input, texts2) => {
|
|
|
15808
16243
|
const accepted2 = acceptedFingerprints(baseline.ok ? baseline.value : EMPTY_BASELINE, input.runtime.now());
|
|
15809
16244
|
return texts2.flatMap((text9) => scanText(text9, { rules: CREDENTIAL_RULES })).filter((finding4) => !accepted2.has(finding4.fingerprint));
|
|
15810
16245
|
};
|
|
15811
|
-
var record3 = (input, findings, draft,
|
|
16246
|
+
var record3 = (input, findings, draft, where2) => {
|
|
15812
16247
|
const ids2 = findings.map((finding4) => {
|
|
15813
16248
|
const saved = recordIncident(
|
|
15814
16249
|
input.runtime,
|
|
15815
16250
|
input.cwd,
|
|
15816
|
-
{ ...draft, rule: finding4.ruleId, fingerprint: finding4.fingerprint, where: `${
|
|
16251
|
+
{ ...draft, rule: finding4.ruleId, fingerprint: finding4.fingerprint, where: `${where2}:${String(finding4.line)}` },
|
|
15817
16252
|
HOOK_ACTOR
|
|
15818
16253
|
);
|
|
15819
16254
|
return saved.ok ? saved.value.id : input.t("secrets.incident.unsaved", { detail: saved.error });
|
|
@@ -16057,9 +16492,9 @@ var parseRemotes = (output) => {
|
|
|
16057
16492
|
return remotes;
|
|
16058
16493
|
};
|
|
16059
16494
|
var remotesWithCredentials = (runtime, root) => {
|
|
16060
|
-
const
|
|
16061
|
-
if (!
|
|
16062
|
-
return [...parseRemotes(
|
|
16495
|
+
const listed5 = runtime.git(["remote", "-v"], root);
|
|
16496
|
+
if (!listed5.ok) return [];
|
|
16497
|
+
return [...parseRemotes(listed5.stdout)].filter(([, urls]) => urls.some(hasCredential)).map(([name]) => name).sort();
|
|
16063
16498
|
};
|
|
16064
16499
|
|
|
16065
16500
|
// src/secrets/guards/session.ts
|
|
@@ -16534,7 +16969,7 @@ var hookSchemaProblems = (hooks, claude) => {
|
|
|
16534
16969
|
};
|
|
16535
16970
|
|
|
16536
16971
|
// src/doctor/hook-sources.ts
|
|
16537
|
-
import { join as
|
|
16972
|
+
import { join as join36 } from "node:path";
|
|
16538
16973
|
var entriesOf = (source, hooks, own) => Object.entries(asRecord(hooks)).flatMap(
|
|
16539
16974
|
([event, groups]) => asList(groups).flatMap((group) => {
|
|
16540
16975
|
const record4 = asRecord(group);
|
|
@@ -16547,7 +16982,7 @@ var projectHookFiles = (env) => readSettings(env).flatMap(({ scope: scope2, path
|
|
|
16547
16982
|
const source = PROJECT_SCOPES[scope2];
|
|
16548
16983
|
return source === void 0 || !("hooks" in settings) ? [] : [{ source, path, hooks: settings["hooks"] }];
|
|
16549
16984
|
});
|
|
16550
|
-
var pluginsDir = ({ env, runtime }) =>
|
|
16985
|
+
var pluginsDir = ({ env, runtime }) => join36(env["CLAUDE_CONFIG_DIR"] ?? join36(runtime.homeDir(), ".claude"), "plugins");
|
|
16551
16986
|
var installRecord = (value, root) => {
|
|
16552
16987
|
const records = Array.isArray(value) ? value.filter(isRecord) : isRecord(value) ? [value] : [];
|
|
16553
16988
|
return records.find((record4) => record4["projectPath"] === root) ?? records[0];
|
|
@@ -16558,13 +16993,13 @@ var readJson = (env, path) => {
|
|
|
16558
16993
|
return parsed?.ok === true ? parsed.value : void 0;
|
|
16559
16994
|
};
|
|
16560
16995
|
var installedPlugin = (env) => {
|
|
16561
|
-
const index = readJson(env, toAbsolutePath(
|
|
16996
|
+
const index = readJson(env, toAbsolutePath(join36(pluginsDir(env), "installed_plugins.json")));
|
|
16562
16997
|
const record4 = installRecord(asRecord(index?.["plugins"])[PLUGIN_ID], env.root);
|
|
16563
16998
|
const installPath = record4 === void 0 ? void 0 : optionalString(record4, "installPath");
|
|
16564
16999
|
if (record4 === void 0 || installPath === void 0) return void 0;
|
|
16565
17000
|
const root = toAbsolutePath(installPath);
|
|
16566
|
-
const manifest = readJson(env, toAbsolutePath(
|
|
16567
|
-
const hooksPath = toAbsolutePath(
|
|
17001
|
+
const manifest = readJson(env, toAbsolutePath(join36(root, ".claude-plugin", "plugin.json")));
|
|
17002
|
+
const hooksPath = toAbsolutePath(join36(root, "hooks", "hooks.json"));
|
|
16568
17003
|
const text9 = env.runtime.readText(hooksPath);
|
|
16569
17004
|
const parsed = text9.ok ? parseJsonObject(text9.value) : void 0;
|
|
16570
17005
|
return {
|
|
@@ -16609,7 +17044,7 @@ var schemaFindings = (env, plugin, claude) => {
|
|
|
16609
17044
|
const files = [...projectHookFiles(env), ...plugin?.hooksFile === void 0 ? [] : [plugin.hooksFile]];
|
|
16610
17045
|
const invalidJson = [
|
|
16611
17046
|
...unreadableProjectFiles(env),
|
|
16612
|
-
...plugin?.hooksText !== void 0 && plugin.hooksFile === void 0 ? [toAbsolutePath(
|
|
17047
|
+
...plugin?.hooksText !== void 0 && plugin.hooksFile === void 0 ? [toAbsolutePath(join37(plugin.root, "hooks", "hooks.json"))] : []
|
|
16613
17048
|
];
|
|
16614
17049
|
return [
|
|
16615
17050
|
...invalidJson.flatMap((file) => schemaFinding(file, ["not valid JSON"], label2)),
|
|
@@ -16630,7 +17065,7 @@ var pluginFindings = (env, projectOwn) => {
|
|
|
16630
17065
|
];
|
|
16631
17066
|
};
|
|
16632
17067
|
var coverageFindings = (env, entries) => {
|
|
16633
|
-
const installed = env.runtime.stat(toAbsolutePath(
|
|
17068
|
+
const installed = env.runtime.stat(toAbsolutePath(join37(env.root, ...LOCK_FILE.split("/")))) !== void 0;
|
|
16634
17069
|
if (entries.length === 0 && !installed) {
|
|
16635
17070
|
return [finding("hooks.registered", "warn", "doctor.hooks.none", {}, "doctor.hooks.fix_none")];
|
|
16636
17071
|
}
|
|
@@ -16682,18 +17117,18 @@ var checkHooks = (env) => {
|
|
|
16682
17117
|
};
|
|
16683
17118
|
|
|
16684
17119
|
// src/doctor/instructions.ts
|
|
16685
|
-
import { join as
|
|
17120
|
+
import { join as join38 } from "node:path";
|
|
16686
17121
|
var INSTRUCTION_LINE_CEILING = 200;
|
|
16687
17122
|
var TOP_INSTRUCTIONS = ["AGENTS.md", "CLAUDE.md", ".claude/CLAUDE.md", "CLAUDE.local.md"];
|
|
16688
17123
|
var RULES_DIR = ".claude/rules";
|
|
16689
17124
|
var SHOWN = 3;
|
|
16690
|
-
var readProjectFile = (env,
|
|
16691
|
-
const text9 = env.runtime.readText(toAbsolutePath(
|
|
17125
|
+
var readProjectFile = (env, relative12) => {
|
|
17126
|
+
const text9 = env.runtime.readText(toAbsolutePath(join38(env.root, ...relative12.split("/"))));
|
|
16692
17127
|
return text9.ok ? text9.value : void 0;
|
|
16693
17128
|
};
|
|
16694
17129
|
var instructionFiles = (env) => {
|
|
16695
|
-
const
|
|
16696
|
-
const rules =
|
|
17130
|
+
const listed5 = env.runtime.listDir(toAbsolutePath(join38(env.root, ...RULES_DIR.split("/"))));
|
|
17131
|
+
const rules = listed5.ok ? listed5.value.filter((name) => name.endsWith(".md")).map((name) => `${RULES_DIR}/${name}`) : [];
|
|
16697
17132
|
return [...TOP_INSTRUCTIONS, ...rules].flatMap((path) => {
|
|
16698
17133
|
const text9 = readProjectFile(env, path);
|
|
16699
17134
|
return text9 === void 0 ? [] : [{ path, text: text9 }];
|
|
@@ -16797,12 +17232,12 @@ var checkInstructions = (env) => {
|
|
|
16797
17232
|
};
|
|
16798
17233
|
|
|
16799
17234
|
// src/doctor/line-endings.ts
|
|
16800
|
-
import { join as
|
|
17235
|
+
import { join as join39 } from "node:path";
|
|
16801
17236
|
var LF_RULE = /^\*\s.*\beol=lf\b/m;
|
|
16802
17237
|
var checkLineEndings = ({ root, runtime }) => {
|
|
16803
17238
|
const autocrlf = runtime.git(["config", "--get", "core.autocrlf"], root);
|
|
16804
17239
|
if (!autocrlf.ok || autocrlf.stdout.trim().toLowerCase() !== "true") return [];
|
|
16805
|
-
const attributes = runtime.readText(toAbsolutePath(
|
|
17240
|
+
const attributes = runtime.readText(toAbsolutePath(join39(root, ".gitattributes")));
|
|
16806
17241
|
if (attributes.ok && LF_RULE.test(attributes.value)) return [];
|
|
16807
17242
|
return [
|
|
16808
17243
|
finding("git.autocrlf", "warn", "doctor.git.autocrlf", { file: ".gitattributes" }, "doctor.git.fix_autocrlf")
|
|
@@ -16810,7 +17245,7 @@ var checkLineEndings = ({ root, runtime }) => {
|
|
|
16810
17245
|
};
|
|
16811
17246
|
|
|
16812
17247
|
// src/doctor/memory.ts
|
|
16813
|
-
import { join as
|
|
17248
|
+
import { join as join40 } from "node:path";
|
|
16814
17249
|
var ceilingOf = (config) => {
|
|
16815
17250
|
const value = configAt(parseConfigYaml(config ?? ""), "memory", "maxLines");
|
|
16816
17251
|
const parsed = typeof value === "string" ? Number.parseInt(value, 10) : Number.NaN;
|
|
@@ -16818,9 +17253,9 @@ var ceilingOf = (config) => {
|
|
|
16818
17253
|
};
|
|
16819
17254
|
var lineCount2 = (text9) => text9.replace(/\r?\n$/, "").split(/\r?\n/).length;
|
|
16820
17255
|
var checkAgentsFile = ({ root, runtime }) => {
|
|
16821
|
-
const text9 = runtime.readText(toAbsolutePath(
|
|
17256
|
+
const text9 = runtime.readText(toAbsolutePath(join40(root, AGENTS_FILE)));
|
|
16822
17257
|
if (!text9.ok) return [];
|
|
16823
|
-
const config = runtime.readText(toAbsolutePath(
|
|
17258
|
+
const config = runtime.readText(toAbsolutePath(join40(root, CONFIG_FILE2)));
|
|
16824
17259
|
const max = ceilingOf(config.ok ? config.value : void 0);
|
|
16825
17260
|
const lines3 = lineCount2(text9.value);
|
|
16826
17261
|
const params2 = { file: AGENTS_FILE, lines: lines3, max };
|
|
@@ -16828,7 +17263,7 @@ var checkAgentsFile = ({ root, runtime }) => {
|
|
|
16828
17263
|
};
|
|
16829
17264
|
|
|
16830
17265
|
// src/doctor/project-files.ts
|
|
16831
|
-
import { join as
|
|
17266
|
+
import { join as join41 } from "node:path";
|
|
16832
17267
|
var variants = (base, extensions) => extensions.map((extension) => `${base}${extension}`);
|
|
16833
17268
|
var SCRIPT = [".js", ".cjs", ".mjs", ".ts", ".cts", ".mts"];
|
|
16834
17269
|
var DATA = ["", ".json", ".yml", ".yaml"];
|
|
@@ -16859,7 +17294,7 @@ var CONFIG_GROUPS = [
|
|
|
16859
17294
|
files: [...variants("commitlint.config", SCRIPT), ...variants(".commitlintrc", [...DATA, ".js"])]
|
|
16860
17295
|
}
|
|
16861
17296
|
];
|
|
16862
|
-
var present = (env, files) => files.filter((file) => env.runtime.stat(toAbsolutePath(
|
|
17297
|
+
var present = (env, files) => files.filter((file) => env.runtime.stat(toAbsolutePath(join41(env.root, file)))?.kind === "file");
|
|
16863
17298
|
var crowded = (env, groups, build) => groups.flatMap(({ name, files }) => {
|
|
16864
17299
|
const found = present(env, files);
|
|
16865
17300
|
return found.length > 1 ? [build(name, found.join(", "))] : [];
|
|
@@ -17059,7 +17494,7 @@ var doctorCommand = {
|
|
|
17059
17494
|
};
|
|
17060
17495
|
|
|
17061
17496
|
// src/gain/gain.ts
|
|
17062
|
-
import { join as
|
|
17497
|
+
import { join as join42 } from "node:path";
|
|
17063
17498
|
var GAIN_SCHEMA = "finitemonkey/gain@1";
|
|
17064
17499
|
var DAY_MS3 = 864e5;
|
|
17065
17500
|
var SAVE_WINDOW_MS = DAY_MS3;
|
|
@@ -17075,8 +17510,8 @@ var readLog = (runtime, paths) => {
|
|
|
17075
17510
|
});
|
|
17076
17511
|
};
|
|
17077
17512
|
var readGates = (runtime, paths) => {
|
|
17078
|
-
const
|
|
17079
|
-
const files =
|
|
17513
|
+
const listed5 = runtime.listDir(toAbsolutePath(join42(paths.dir, "evidence")));
|
|
17514
|
+
const files = listed5.ok ? listed5.value.filter((name) => name.endsWith(".jsonl")) : [];
|
|
17080
17515
|
return files.flatMap((name) => readLedger2(runtime, paths.evidence(name.replace(/\.jsonl$/, "")))).filter((entry2) => entry2.check === GATE_CHECK);
|
|
17081
17516
|
};
|
|
17082
17517
|
var countsIn = (log, gates, from, to) => {
|
|
@@ -17122,7 +17557,7 @@ var ROWS = [
|
|
|
17122
17557
|
{ key: "gain.row.gate_failed", pick: (counts) => counts.gateFailed },
|
|
17123
17558
|
{ key: "gain.row.gate_unverified", pick: (counts) => counts.gateUnverified }
|
|
17124
17559
|
];
|
|
17125
|
-
var
|
|
17560
|
+
var linesOf2 = (ctx, report2) => [
|
|
17126
17561
|
ctx.t("gain.title", { days: report2.days }),
|
|
17127
17562
|
...ROWS.map(
|
|
17128
17563
|
({ key, pick: pick4 }) => ` ${ctx.t(key, { count: pick4(report2.current) })}${trend(ctx, pick4(report2.current), pick4(report2.previous))}`
|
|
@@ -17141,7 +17576,7 @@ var runGain = (ctx, rawDays) => {
|
|
|
17141
17576
|
);
|
|
17142
17577
|
}
|
|
17143
17578
|
const report2 = gainReport(ctx.runtime, fmPaths(findRepoRoot(ctx.runtime, ctx.cwd) ?? ctx.cwd), days);
|
|
17144
|
-
return success(report2,
|
|
17579
|
+
return success(report2, linesOf2(ctx, report2));
|
|
17145
17580
|
};
|
|
17146
17581
|
var gainCommand = {
|
|
17147
17582
|
path: ["gain"],
|
|
@@ -17188,13 +17623,13 @@ var gateResult = (ctx, report2, strict) => {
|
|
|
17188
17623
|
const human2 = reportLines(ctx.t, report2);
|
|
17189
17624
|
const failedVerdict = report2.verdict === "failed" || strict && report2.verdict === "incomplete";
|
|
17190
17625
|
if (!failedVerdict) return success(report2, human2);
|
|
17191
|
-
const
|
|
17626
|
+
const code2 = report2.verdict === "failed" ? "gate_failed" : "gate_incomplete";
|
|
17192
17627
|
return {
|
|
17193
17628
|
ok: false,
|
|
17194
17629
|
exitCode: ExitCode.CheckFailed,
|
|
17195
17630
|
data: report2,
|
|
17196
17631
|
human: human2,
|
|
17197
|
-
error: { code, message: ctx.t(`error.${
|
|
17632
|
+
error: { code: code2, message: ctx.t(`error.${code2}`, report2.counts), fix: `finitemonkey gate --task ${report2.task}` }
|
|
17198
17633
|
};
|
|
17199
17634
|
};
|
|
17200
17635
|
var runResult = (ctx, run4, strict) => {
|
|
@@ -17282,10 +17717,10 @@ var hasAttribution = (body2) => {
|
|
|
17282
17717
|
};
|
|
17283
17718
|
var commitMessageProblems = (message) => {
|
|
17284
17719
|
const lines3 = meaningful2(message);
|
|
17285
|
-
const
|
|
17720
|
+
const header2 = lines3.find((line2) => line2.trim() !== "") ?? "";
|
|
17286
17721
|
const problems = [];
|
|
17287
|
-
if (!EXEMPT.test(
|
|
17288
|
-
if (
|
|
17722
|
+
if (!EXEMPT.test(header2) && !HEADER.test(header2)) problems.push("header");
|
|
17723
|
+
if (header2.length > MAX_HEADER) problems.push("header_length");
|
|
17289
17724
|
if (hasAttribution(lines3.join("\n"))) problems.push("attribution");
|
|
17290
17725
|
return problems;
|
|
17291
17726
|
};
|
|
@@ -17313,8 +17748,8 @@ var commitMessagesInRange = (runtime, root, range) => {
|
|
|
17313
17748
|
return { id: "commit-messages", failures, fix: "git rebase -i <base> and reword the listed commits" };
|
|
17314
17749
|
};
|
|
17315
17750
|
var mergesInRange = (runtime, repo, range) => {
|
|
17316
|
-
const
|
|
17317
|
-
const merges =
|
|
17751
|
+
const listed5 = runtime.git(["rev-list", "--merges", ...range, "--"], repo.root);
|
|
17752
|
+
const merges = listed5.ok ? listed5.stdout.split("\n").filter((line2) => line2 !== "") : [];
|
|
17318
17753
|
const failures = merges.flatMap((sha) => {
|
|
17319
17754
|
const report2 = verifyMerge(runtime, repo, { rev: sha });
|
|
17320
17755
|
if (report2.exit === 0) return [];
|
|
@@ -17392,12 +17827,12 @@ var prePushChecks = (runtime, repo, remote, updates) => {
|
|
|
17392
17827
|
// src/githooks/render.ts
|
|
17393
17828
|
var MAX_LISTED9 = 5;
|
|
17394
17829
|
var detailOf = (check2) => {
|
|
17395
|
-
const
|
|
17830
|
+
const listed5 = check2.failures.slice(0, MAX_LISTED9).join("; ");
|
|
17396
17831
|
const rest = check2.failures.length - MAX_LISTED9;
|
|
17397
|
-
return rest > 0 ? `${
|
|
17832
|
+
return rest > 0 ? `${listed5}; +${String(rest)}` : listed5;
|
|
17398
17833
|
};
|
|
17399
17834
|
var checkLine = (t, check2) => check2.failures.length === 0 ? t("githooks.pass", { check: check2.id }) : t("githooks.fail", { check: check2.id, detail: detailOf(check2), fix: check2.fix });
|
|
17400
|
-
var checksResult = (t, schema,
|
|
17835
|
+
var checksResult = (t, schema, code2, checks) => {
|
|
17401
17836
|
const data = { schema, checks };
|
|
17402
17837
|
const bad = failing(checks);
|
|
17403
17838
|
const human2 = bad.length === 0 ? checks.map((check2) => checkLine(t, check2)) : bad.map((check2) => checkLine(t, check2));
|
|
@@ -17409,7 +17844,7 @@ var checksResult = (t, schema, code, checks) => {
|
|
|
17409
17844
|
data,
|
|
17410
17845
|
human: human2,
|
|
17411
17846
|
error: {
|
|
17412
|
-
code,
|
|
17847
|
+
code: code2,
|
|
17413
17848
|
message: t("githooks.error.failed", { count: bad.length }),
|
|
17414
17849
|
fix: first?.fix ?? ""
|
|
17415
17850
|
}
|
|
@@ -17582,11 +18017,11 @@ var mergeVerifyCommand = {
|
|
|
17582
18017
|
var REFLOG_LIMIT = 300;
|
|
17583
18018
|
var LIST_LIMIT = 50;
|
|
17584
18019
|
var SHA = /^[0-9a-f]{40,64}$/;
|
|
17585
|
-
var
|
|
18020
|
+
var linesOf3 = (text9) => text9.split("\n").filter((line2) => line2.trim() !== "");
|
|
17586
18021
|
var reflogLines = (runtime, repo) => {
|
|
17587
18022
|
const result = runtime.git(["reflog", "show", "--all", `-n${String(REFLOG_LIMIT)}`, "--format=%H %gD"], repo.root);
|
|
17588
18023
|
if (!result.ok) return [];
|
|
17589
|
-
return
|
|
18024
|
+
return linesOf3(result.stdout).flatMap((line2) => {
|
|
17590
18025
|
const [sha, ref] = line2.split(" ");
|
|
17591
18026
|
return sha === void 0 || ref === void 0 || !SHA.test(sha) || ref.startsWith("refs/finitemonkey/") ? [] : [{ sha, ref }];
|
|
17592
18027
|
});
|
|
@@ -17594,11 +18029,11 @@ var reflogLines = (runtime, repo) => {
|
|
|
17594
18029
|
var unreachable = (runtime, repo, shas) => {
|
|
17595
18030
|
if (shas.length === 0) return /* @__PURE__ */ new Set();
|
|
17596
18031
|
const result = runtime.git(["rev-list", ...shas, "--not", "--branches", "--tags", "--remotes"], repo.root);
|
|
17597
|
-
return new Set(result.ok ?
|
|
18032
|
+
return new Set(result.ok ? linesOf3(result.stdout) : []);
|
|
17598
18033
|
};
|
|
17599
18034
|
var fsckDangling = (runtime, repo) => {
|
|
17600
18035
|
const result = runtime.git(["fsck", "--no-reflogs", "--no-progress", "--dangling"], repo.root);
|
|
17601
|
-
const lines3 =
|
|
18036
|
+
const lines3 = linesOf3(result.stdout);
|
|
17602
18037
|
const pick4 = (kind) => lines3.flatMap((line2) => {
|
|
17603
18038
|
const [label2, type, sha] = line2.split(" ");
|
|
17604
18039
|
return label2 === "dangling" && type === kind && sha !== void 0 ? [sha] : [];
|
|
@@ -17609,7 +18044,7 @@ var describe2 = (runtime, repo, shas) => {
|
|
|
17609
18044
|
if (shas.length === 0) return /* @__PURE__ */ new Map();
|
|
17610
18045
|
const result = runtime.git(["log", "--no-walk=unsorted", "--format=%H%x09%cr%x09%s", ...shas], repo.root);
|
|
17611
18046
|
return new Map(
|
|
17612
|
-
|
|
18047
|
+
linesOf3(result.stdout).flatMap((line2) => {
|
|
17613
18048
|
const [sha, when, ...subject2] = line2.split(" ");
|
|
17614
18049
|
return sha === void 0 ? [] : [[sha, [when ?? "", subject2.join(" ")]]];
|
|
17615
18050
|
})
|
|
@@ -17703,7 +18138,7 @@ var rescueCommand = {
|
|
|
17703
18138
|
};
|
|
17704
18139
|
|
|
17705
18140
|
// src/git/undo.ts
|
|
17706
|
-
import { basename as basename3, dirname as dirname8, join as
|
|
18141
|
+
import { basename as basename3, dirname as dirname8, join as join43 } from "node:path";
|
|
17707
18142
|
var INDEX_SUBJECT = "finitemonkey index:";
|
|
17708
18143
|
var gitLine = (runtime, repo, args2) => {
|
|
17709
18144
|
const result = runtime.git(args2, repo.root);
|
|
@@ -17712,8 +18147,8 @@ var gitLine = (runtime, repo, args2) => {
|
|
|
17712
18147
|
};
|
|
17713
18148
|
var failure2 = (step3, result) => `${step3}: ${result.stderr.trim() || "git failed"}`;
|
|
17714
18149
|
var parentsOf2 = (runtime, repo, commit2) => {
|
|
17715
|
-
const
|
|
17716
|
-
return
|
|
18150
|
+
const listed5 = gitLine(runtime, repo, ["rev-list", "--parents", "-n", "1", commit2])?.split(" ").slice(1) ?? [];
|
|
18151
|
+
return listed5.reduce((found, parent) => {
|
|
17717
18152
|
const subject2 = gitLine(runtime, repo, ["log", "-1", "--format=%s", parent]) ?? "";
|
|
17718
18153
|
return subject2.startsWith(INDEX_SUBJECT) ? { ...found, index: parent } : { ...found, head: parent };
|
|
17719
18154
|
}, {});
|
|
@@ -17746,7 +18181,7 @@ var findSnapshot = (views, wanted) => {
|
|
|
17746
18181
|
};
|
|
17747
18182
|
var stampOf2 = (iso) => iso.replace(/[:.]/g, "-");
|
|
17748
18183
|
var worktreePath = (runtime, repo) => {
|
|
17749
|
-
const base =
|
|
18184
|
+
const base = join43(dirname8(repo.root), `${basename3(repo.root)}-undo-${stampOf2(runtime.now())}`);
|
|
17750
18185
|
return toAbsolutePath(runtime.stat(toAbsolutePath(base)) === void 0 ? base : `${base}-2`);
|
|
17751
18186
|
};
|
|
17752
18187
|
var intoWorktree = (runtime, repo, view2) => {
|
|
@@ -17981,7 +18416,7 @@ var hookCommand = {
|
|
|
17981
18416
|
};
|
|
17982
18417
|
|
|
17983
18418
|
// src/commands/i18n-check.ts
|
|
17984
|
-
import { join as
|
|
18419
|
+
import { join as join44 } from "node:path";
|
|
17985
18420
|
|
|
17986
18421
|
// src/i18n/message.ts
|
|
17987
18422
|
var ARG = /^\s*([a-zA-Z][a-zA-Z0-9_]*)\s*(?:,\s*(plural|select)\s*,)?/;
|
|
@@ -18207,7 +18642,7 @@ var unreadable = (dir, file, detail) => ({
|
|
|
18207
18642
|
exitCode: ExitCode.NotConfigured
|
|
18208
18643
|
});
|
|
18209
18644
|
var readCatalog = (ctx, dir, lang) => {
|
|
18210
|
-
const file = toAbsolutePath(
|
|
18645
|
+
const file = toAbsolutePath(join44(dir, `${lang}.json`));
|
|
18211
18646
|
const text9 = ctx.runtime.readText(file);
|
|
18212
18647
|
if (!text9.ok) return reject(unreadable(dir, file, text9.error));
|
|
18213
18648
|
const parsed = parseJsonObject(text9.value);
|
|
@@ -18230,7 +18665,7 @@ var describeProblem = (ctx, problem4) => {
|
|
|
18230
18665
|
return ` ${problem4.lang} ${problem4.key} ${kind}`;
|
|
18231
18666
|
};
|
|
18232
18667
|
var loadReview = (ctx, dir) => {
|
|
18233
|
-
const text9 = ctx.runtime.readText(toAbsolutePath(
|
|
18668
|
+
const text9 = ctx.runtime.readText(toAbsolutePath(join44(dir, "review.json")));
|
|
18234
18669
|
const parsed = text9.ok ? parseJsonObject(text9.value) : void 0;
|
|
18235
18670
|
if (parsed?.ok !== true) return void 0;
|
|
18236
18671
|
const statuses = (lang) => {
|
|
@@ -18271,7 +18706,7 @@ var i18nCheckCommand = {
|
|
|
18271
18706
|
};
|
|
18272
18707
|
|
|
18273
18708
|
// src/history/look-back.ts
|
|
18274
|
-
import { join as
|
|
18709
|
+
import { join as join45 } from "node:path";
|
|
18275
18710
|
|
|
18276
18711
|
// src/history/patterns.ts
|
|
18277
18712
|
import { posix as posix5 } from "node:path";
|
|
@@ -18284,7 +18719,7 @@ var READ_COMMAND = /(^|[\s;&|(])(cat|less|more|head|tail|bat|type|Get-Content|so
|
|
|
18284
18719
|
var PUSH = /(^|[\s;&|(])git\s+push\b([^;&|\n]*)/;
|
|
18285
18720
|
var FORCE = /\s(--force(-with-lease)?(=\S*)?|-f|-[A-Za-z]*f[A-Za-z]*)(?=\s|$)|\s\+\S/;
|
|
18286
18721
|
var NO_VERIFY = /(^|[\s;&|(])git\s+(commit|push|merge|rebase|am|cherry-pick)\b[^;&|\n]*\s--no-verify\b/;
|
|
18287
|
-
var
|
|
18722
|
+
var TEST_FILE2 = /(\.(test|spec)\.[cm]?[jt]sx?$|(^|\/)__tests__\/|_test\.(go|py)$|(^|\/)test_[^/]+\.py$)/;
|
|
18288
18723
|
var SKIP = /\b(it|test|describe)\.skip\s*\(|\bx(it|describe|test)\s*\(|@pytest\.mark\.skip|\bt\.Skip\(|\.only\s*\(/;
|
|
18289
18724
|
var commandOf2 = (tool) => {
|
|
18290
18725
|
if (tool.name !== "Bash" && tool.name !== "PowerShell") return void 0;
|
|
@@ -18312,7 +18747,7 @@ var forcePush = (command) => {
|
|
|
18312
18747
|
};
|
|
18313
18748
|
var addedSkip = (tool) => {
|
|
18314
18749
|
const path = stringField(tool, "file_path");
|
|
18315
|
-
if (!
|
|
18750
|
+
if (!TEST_FILE2.test(path.replace(/\\/g, "/"))) return false;
|
|
18316
18751
|
if (tool.name === "Write") return SKIP.test(stringField(tool, "content"));
|
|
18317
18752
|
if (tool.name === "Edit")
|
|
18318
18753
|
return SKIP.test(stringField(tool, "new_string")) && !SKIP.test(stringField(tool, "old_string"));
|
|
@@ -18407,11 +18842,11 @@ var parseTranscript = (jsonl) => {
|
|
|
18407
18842
|
// src/history/look-back.ts
|
|
18408
18843
|
var SAMPLES = 3;
|
|
18409
18844
|
var projectLogKey = (root) => root.replace(/[^A-Za-z0-9-]/g, "-");
|
|
18410
|
-
var projectLogDir = (runtime, root, env) =>
|
|
18845
|
+
var projectLogDir = (runtime, root, env) => join45(env["CLAUDE_CONFIG_DIR"] ?? join45(runtime.homeDir(), ".claude"), "projects", projectLogKey(root));
|
|
18411
18846
|
var lookBack = (runtime, root, env) => {
|
|
18412
18847
|
const dir = projectLogDir(runtime, root, env);
|
|
18413
|
-
const
|
|
18414
|
-
const files =
|
|
18848
|
+
const listed5 = runtime.listDir(toAbsolutePath(dir));
|
|
18849
|
+
const files = listed5.ok ? listed5.value.filter((name) => name.endsWith(".jsonl")).sort() : [];
|
|
18415
18850
|
const counts = {
|
|
18416
18851
|
done_after_failing_tests: 0,
|
|
18417
18852
|
env_read: 0,
|
|
@@ -18428,7 +18863,7 @@ var lookBack = (runtime, root, env) => {
|
|
|
18428
18863
|
};
|
|
18429
18864
|
let turns = 0;
|
|
18430
18865
|
for (const name of files) {
|
|
18431
|
-
const text9 = runtime.readText(toAbsolutePath(
|
|
18866
|
+
const text9 = runtime.readText(toAbsolutePath(join45(dir, name)));
|
|
18432
18867
|
if (!text9.ok) continue;
|
|
18433
18868
|
for (const turn of parseTranscript(text9.value)) {
|
|
18434
18869
|
turns += 1;
|
|
@@ -18448,10 +18883,10 @@ var MAX_LCS_CELLS = 4e6;
|
|
|
18448
18883
|
var table = (a, b) => {
|
|
18449
18884
|
const rows = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
|
|
18450
18885
|
for (let i = a.length - 1; i >= 0; i -= 1) {
|
|
18451
|
-
const
|
|
18886
|
+
const row2 = rows[i] ?? [];
|
|
18452
18887
|
const below = rows[i + 1] ?? [];
|
|
18453
18888
|
for (let j = b.length - 1; j >= 0; j -= 1) {
|
|
18454
|
-
|
|
18889
|
+
row2[j] = a[i] === b[j] ? (below[j + 1] ?? 0) + 1 : Math.max(below[j] ?? 0, row2[j + 1] ?? 0);
|
|
18455
18890
|
}
|
|
18456
18891
|
}
|
|
18457
18892
|
return rows;
|
|
@@ -18484,17 +18919,17 @@ var sharedPrefix = (a, b) => {
|
|
|
18484
18919
|
while (count4 < a.length && count4 < b.length && a[count4] === b[count4]) count4 += 1;
|
|
18485
18920
|
return count4;
|
|
18486
18921
|
};
|
|
18487
|
-
var sharedSuffix = (a, b,
|
|
18922
|
+
var sharedSuffix = (a, b, prefix2) => {
|
|
18488
18923
|
let count4 = 0;
|
|
18489
|
-
while (count4 < a.length -
|
|
18924
|
+
while (count4 < a.length - prefix2 && count4 < b.length - prefix2 && a[a.length - 1 - count4] === b[b.length - 1 - count4])
|
|
18490
18925
|
count4 += 1;
|
|
18491
18926
|
return count4;
|
|
18492
18927
|
};
|
|
18493
18928
|
var changedOps = (a, b) => {
|
|
18494
|
-
const
|
|
18495
|
-
const suffix = sharedSuffix(a, b,
|
|
18496
|
-
const left = a.slice(
|
|
18497
|
-
const right = b.slice(
|
|
18929
|
+
const prefix2 = sharedPrefix(a, b);
|
|
18930
|
+
const suffix = sharedSuffix(a, b, prefix2);
|
|
18931
|
+
const left = a.slice(prefix2, a.length - suffix);
|
|
18932
|
+
const right = b.slice(prefix2, b.length - suffix);
|
|
18498
18933
|
if (left.length * right.length <= MAX_LCS_CELLS) return walk2(left, right).filter(([op]) => op !== "=");
|
|
18499
18934
|
return [...left.map((line2) => ["-", line2]), ...right.map((line2) => ["+", line2])];
|
|
18500
18935
|
};
|
|
@@ -18502,9 +18937,9 @@ var lineDiff = (path, before, after) => {
|
|
|
18502
18937
|
const changes = changedOps(splitLines(before), splitLines(after));
|
|
18503
18938
|
if (changes.length === 0) return [];
|
|
18504
18939
|
const lines3 = changes.map(([op, line2]) => `${op} ${line2}`);
|
|
18505
|
-
const
|
|
18506
|
-
const hidden = lines3.length -
|
|
18507
|
-
return [`--- ${path}`, `+++ ${path}`, ...
|
|
18940
|
+
const shown4 = lines3.slice(0, MAX_DIFF_LINES);
|
|
18941
|
+
const hidden = lines3.length - shown4.length;
|
|
18942
|
+
return [`--- ${path}`, `+++ ${path}`, ...shown4, ...hidden > 0 ? [`… ${String(hidden)} more`] : []];
|
|
18508
18943
|
};
|
|
18509
18944
|
|
|
18510
18945
|
// src/install/report.ts
|
|
@@ -18654,6 +19089,346 @@ var initCommand = {
|
|
|
18654
19089
|
}
|
|
18655
19090
|
};
|
|
18656
19091
|
|
|
19092
|
+
// src/inventory/run.ts
|
|
19093
|
+
import { relative as relative10 } from "node:path";
|
|
19094
|
+
|
|
19095
|
+
// src/inventory/dependencies.ts
|
|
19096
|
+
var MANIFESTS = /(^|\/)(package\.json|requirements\.txt|go\.mod)$/;
|
|
19097
|
+
var MAX_MANIFESTS = 8;
|
|
19098
|
+
var PACKAGE_SECTIONS = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
|
19099
|
+
var REQUIREMENT = /^([A-Za-z0-9_.-]+)\s*(?:[=<>~!]=?\s*([^\s;#]+))?/;
|
|
19100
|
+
var GO_REQUIRE = /^\s*(?:require\s+)?([\w.-]+\.[\w./-]+)\s+(v[\w.+-]+)/;
|
|
19101
|
+
var lineOf = (lines3, needle) => lines3.findIndex((line2) => line2.includes(needle)) + 1;
|
|
19102
|
+
var fromPackage = (file, text9) => {
|
|
19103
|
+
const parsed = parseJsonObject(text9);
|
|
19104
|
+
if (!parsed.ok) return [];
|
|
19105
|
+
const lines3 = text9.split("\n");
|
|
19106
|
+
return PACKAGE_SECTIONS.flatMap((section3) => {
|
|
19107
|
+
const block4 = parsed.value[section3];
|
|
19108
|
+
if (!isRecord(block4)) return [];
|
|
19109
|
+
return Object.entries(block4).map(([name, version]) => ({
|
|
19110
|
+
name,
|
|
19111
|
+
version: typeof version === "string" ? version : "",
|
|
19112
|
+
at: `${file}:${String(lineOf(lines3, `"${name}"`))}`
|
|
19113
|
+
}));
|
|
19114
|
+
});
|
|
19115
|
+
};
|
|
19116
|
+
var fromLines = (file, text9, pattern) => text9.split("\n").flatMap((line2, index) => {
|
|
19117
|
+
const match = pattern.exec(line2.trim() === "" || line2.trimStart().startsWith("#") ? "" : line2);
|
|
19118
|
+
if (match?.[1] === void 0) return [];
|
|
19119
|
+
return [{ name: match[1], version: match[2] ?? "", at: `${file}:${String(index + 1)}` }];
|
|
19120
|
+
});
|
|
19121
|
+
var parseManifest = (file, text9) => {
|
|
19122
|
+
if (file.endsWith("package.json")) return fromPackage(file, text9);
|
|
19123
|
+
return fromLines(file, text9, file.endsWith("go.mod") ? GO_REQUIRE : REQUIREMENT);
|
|
19124
|
+
};
|
|
19125
|
+
var dependenciesAt = (git2, hash, files) => files.filter((file) => MANIFESTS.test(file)).slice(0, MAX_MANIFESTS).flatMap((file) => {
|
|
19126
|
+
const text9 = showAt(git2, hash, file);
|
|
19127
|
+
return text9 === void 0 ? [] : parseManifest(file, text9);
|
|
19128
|
+
});
|
|
19129
|
+
|
|
19130
|
+
// src/inventory/read.ts
|
|
19131
|
+
var MAX_TEXT = 120;
|
|
19132
|
+
var HOTSPOT_COMMITS = 300;
|
|
19133
|
+
var MAX_HOTSPOTS = 10;
|
|
19134
|
+
var where = (hit3) => `${hit3.file}:${String(hit3.line)}`;
|
|
19135
|
+
var shown3 = (hits) => hits.map((hit3) => ({ ...hit3, text: maskText(hit3.text).slice(0, MAX_TEXT) }));
|
|
19136
|
+
var moduleOf = (file) => {
|
|
19137
|
+
const parts = file.split("/");
|
|
19138
|
+
return parts.length <= 1 ? "." : parts.slice(0, Math.min(2, parts.length - 1)).join("/");
|
|
19139
|
+
};
|
|
19140
|
+
var modulesOf = (files) => {
|
|
19141
|
+
const counts = /* @__PURE__ */ new Map();
|
|
19142
|
+
for (const file of files.filter((item2) => !TEST_FILE.test(item2))) {
|
|
19143
|
+
counts.set(moduleOf(file), (counts.get(moduleOf(file)) ?? 0) + 1);
|
|
19144
|
+
}
|
|
19145
|
+
return [...counts].map(([path, count4]) => ({ path, files: count4 })).sort((a, b) => a.path.localeCompare(b.path));
|
|
19146
|
+
};
|
|
19147
|
+
var envOf = (hits) => {
|
|
19148
|
+
const names = /* @__PURE__ */ new Map();
|
|
19149
|
+
for (const hit3 of hits) {
|
|
19150
|
+
for (const name of envNamesIn(hit3.text)) names.set(name, [...names.get(name) ?? [], where(hit3)]);
|
|
19151
|
+
}
|
|
19152
|
+
return [...names].map(([name, at]) => ({ name, at: [...new Set(at)] })).sort((a, b) => a.name.localeCompare(b.name));
|
|
19153
|
+
};
|
|
19154
|
+
var credentialsOf = (hits) => hits.flatMap(
|
|
19155
|
+
(hit3) => scanText(hit3.text, { path: hit3.file }).map((finding4) => ({ at: where(hit3), rule: finding4.ruleId }))
|
|
19156
|
+
);
|
|
19157
|
+
var hotspotsOf = (git2, hash, covered) => {
|
|
19158
|
+
const out = git2.out([
|
|
19159
|
+
"log",
|
|
19160
|
+
"--format=",
|
|
19161
|
+
"--name-only",
|
|
19162
|
+
"-n",
|
|
19163
|
+
String(HOTSPOT_COMMITS),
|
|
19164
|
+
hash,
|
|
19165
|
+
"--",
|
|
19166
|
+
...pathspecOf(covered)
|
|
19167
|
+
]);
|
|
19168
|
+
const counts = /* @__PURE__ */ new Map();
|
|
19169
|
+
for (const file of linesOf(out)) counts.set(file, (counts.get(file) ?? 0) + 1);
|
|
19170
|
+
return [...counts].map(([path, changes]) => ({ path, changes })).filter((item2) => item2.changes > 1).sort((a, b) => b.changes - a.changes || a.path.localeCompare(b.path)).slice(0, MAX_HOTSPOTS);
|
|
19171
|
+
};
|
|
19172
|
+
var worktreesOf = (git2) => {
|
|
19173
|
+
const paths = linesOf(git2.out(["worktree", "list", "--porcelain"])).filter((line2) => line2.startsWith("worktree ")).map((line2) => line2.slice("worktree ".length));
|
|
19174
|
+
return paths.length > 1 ? paths : [];
|
|
19175
|
+
};
|
|
19176
|
+
var readRepo = (git2, path, ref, hash, covered) => {
|
|
19177
|
+
const files = filesAt(git2, hash, covered);
|
|
19178
|
+
return {
|
|
19179
|
+
path,
|
|
19180
|
+
hash,
|
|
19181
|
+
ref,
|
|
19182
|
+
modules: modulesOf(files),
|
|
19183
|
+
routes: shown3(grepAt(git2, hash, ROUTES, covered)),
|
|
19184
|
+
tables: shown3(grepAt(git2, hash, TABLES, covered)),
|
|
19185
|
+
queues: shown3(grepAt(git2, hash, QUEUES, covered)),
|
|
19186
|
+
jobs: shown3(grepAt(git2, hash, JOBS, covered)),
|
|
19187
|
+
env: envOf(grepAt(git2, hash, ENV, covered)),
|
|
19188
|
+
dependencies: dependenciesAt(git2, hash, files),
|
|
19189
|
+
tests: files.filter((file) => TEST_FILE.test(file)),
|
|
19190
|
+
credentials: credentialsOf(grepAt(git2, hash, CREDENTIAL_HINTS, covered)),
|
|
19191
|
+
deploy: files.filter((file) => DEPLOY_FILE.test(file)),
|
|
19192
|
+
hotspots: hotspotsOf(git2, hash, covered),
|
|
19193
|
+
worktrees: worktreesOf(git2)
|
|
19194
|
+
};
|
|
19195
|
+
};
|
|
19196
|
+
|
|
19197
|
+
// src/plan/markdown.ts
|
|
19198
|
+
var cell = (text9) => text9.replace(/\r?\n/g, " ").replace(/\|/g, "\\|");
|
|
19199
|
+
var code = (text9) => `\`${text9.replace(/`/g, "'")}\``;
|
|
19200
|
+
var row = (cells) => `| ${cells.map(cell).join(" | ")} |`;
|
|
19201
|
+
var table2 = (header2, rows) => [
|
|
19202
|
+
row(header2),
|
|
19203
|
+
`|${header2.map(() => "---").join("|")}|`,
|
|
19204
|
+
...rows.length === 0 ? [row(header2.map(() => ""))] : rows.map(row)
|
|
19205
|
+
];
|
|
19206
|
+
var section = (heading, lines3) => [
|
|
19207
|
+
`## ${heading}`,
|
|
19208
|
+
"",
|
|
19209
|
+
...lines3,
|
|
19210
|
+
""
|
|
19211
|
+
];
|
|
19212
|
+
|
|
19213
|
+
// src/inventory/render.ts
|
|
19214
|
+
var MAX_LISTED10 = 40;
|
|
19215
|
+
var capped = (t, lines3) => lines3.length > MAX_LISTED10 ? [...lines3.slice(0, MAX_LISTED10), `- ${t("inventory.more", { count: lines3.length - MAX_LISTED10 })}`] : lines3;
|
|
19216
|
+
var listed4 = (t, lines3) => lines3.length === 0 ? [t("inventory.none")] : capped(t, lines3);
|
|
19217
|
+
var hitLines = (t, hits) => listed4(
|
|
19218
|
+
t,
|
|
19219
|
+
hits.map((hit3) => `- ${code(`${hit3.file}:${String(hit3.line)}`)} ${code(hit3.text)}`)
|
|
19220
|
+
);
|
|
19221
|
+
var prefix = (repo, many2) => many2 ? `${repo.path}: ` : "";
|
|
19222
|
+
var riskRows = (t, repos) => repos.flatMap(
|
|
19223
|
+
(repo) => repo.credentials.map((hit3) => [
|
|
19224
|
+
t("inventory.risk.credential", { rule: hit3.rule }),
|
|
19225
|
+
t("inventory.risk.yes"),
|
|
19226
|
+
code(`${prefix(repo, repos.length > 1)}${hit3.at}`),
|
|
19227
|
+
t("inventory.risk.fix_credential")
|
|
19228
|
+
])
|
|
19229
|
+
);
|
|
19230
|
+
var codeSections = (t, repo) => [
|
|
19231
|
+
...section(
|
|
19232
|
+
t("inventory.modules"),
|
|
19233
|
+
listed4(
|
|
19234
|
+
t,
|
|
19235
|
+
repo.modules.map((item2) => `- ${code(item2.path)}: ${t("inventory.files", { count: item2.files })}`)
|
|
19236
|
+
)
|
|
19237
|
+
),
|
|
19238
|
+
...section(t("inventory.routes"), hitLines(t, repo.routes)),
|
|
19239
|
+
...section(t("inventory.tables"), hitLines(t, repo.tables)),
|
|
19240
|
+
...section(t("inventory.queues"), hitLines(t, repo.queues)),
|
|
19241
|
+
...section(t("inventory.jobs"), hitLines(t, repo.jobs)),
|
|
19242
|
+
...section(
|
|
19243
|
+
t("inventory.env"),
|
|
19244
|
+
listed4(
|
|
19245
|
+
t,
|
|
19246
|
+
repo.env.map((item2) => `- ${code(item2.name)}: ${item2.at.map(code).join(", ")}`)
|
|
19247
|
+
)
|
|
19248
|
+
),
|
|
19249
|
+
...section(
|
|
19250
|
+
t("inventory.dependencies"),
|
|
19251
|
+
listed4(
|
|
19252
|
+
t,
|
|
19253
|
+
repo.dependencies.map((item2) => `- ${code(item2.name)} ${item2.version}: ${code(item2.at)}`)
|
|
19254
|
+
)
|
|
19255
|
+
),
|
|
19256
|
+
...section(t("inventory.tests"), [
|
|
19257
|
+
t("inventory.test_count", { count: repo.tests.length }),
|
|
19258
|
+
...capped(
|
|
19259
|
+
t,
|
|
19260
|
+
repo.tests.map((file) => `- ${code(file)}`)
|
|
19261
|
+
)
|
|
19262
|
+
])
|
|
19263
|
+
];
|
|
19264
|
+
var optional2 = (heading, lines3) => lines3.length === 0 ? [] : section(heading, lines3);
|
|
19265
|
+
var whenPresent = (t, repo, incidents) => [
|
|
19266
|
+
...optional2(
|
|
19267
|
+
t("inventory.credentials"),
|
|
19268
|
+
repo.credentials.length === 0 ? [] : [t("inventory.credentials_note"), "", ...repo.credentials.map((hit3) => `- ${code(hit3.at)} (${hit3.rule})`)]
|
|
19269
|
+
),
|
|
19270
|
+
...optional2(
|
|
19271
|
+
t("inventory.deploy"),
|
|
19272
|
+
repo.deploy.map((file) => `- ${code(file)}`)
|
|
19273
|
+
),
|
|
19274
|
+
...optional2(
|
|
19275
|
+
t("inventory.history"),
|
|
19276
|
+
incidents.map((name) => `- ${code(`.finitemonkey/incidents/${name}`)}`)
|
|
19277
|
+
),
|
|
19278
|
+
...optional2(
|
|
19279
|
+
t("inventory.worktrees"),
|
|
19280
|
+
repo.worktrees.map((path) => `- ${code(path)}`)
|
|
19281
|
+
),
|
|
19282
|
+
...optional2(
|
|
19283
|
+
t("inventory.hotspots"),
|
|
19284
|
+
repo.hotspots.map((item2) => `- ${code(item2.path)}: ${t("inventory.changes", { count: item2.changes })}`)
|
|
19285
|
+
)
|
|
19286
|
+
];
|
|
19287
|
+
var repoBlock = (t, inventory, repo) => [
|
|
19288
|
+
...inventory.repos.length > 1 ? [`# ${code(repo.path)}`, ""] : [],
|
|
19289
|
+
...codeSections(t, repo),
|
|
19290
|
+
...whenPresent(t, repo, repo.path === "." ? inventory.incidents : [])
|
|
19291
|
+
];
|
|
19292
|
+
var header = (t, inventory) => [
|
|
19293
|
+
`# ${t("inventory.title", { topic: inventory.topic })}`,
|
|
19294
|
+
"",
|
|
19295
|
+
...inventory.repos.map(
|
|
19296
|
+
(repo) => t("inventory.read_at", { path: repo.path, hash: repo.hash, date: inventory.date, ref: repo.ref })
|
|
19297
|
+
),
|
|
19298
|
+
""
|
|
19299
|
+
];
|
|
19300
|
+
var deltaBlock = (t, inventory) => inventory.previousHash === void 0 ? [] : section(
|
|
19301
|
+
t("inventory.delta", { hash: inventory.previousHash }),
|
|
19302
|
+
listed4(
|
|
19303
|
+
t,
|
|
19304
|
+
inventory.delta.map((line2) => `- ${code(line2)}`)
|
|
19305
|
+
)
|
|
19306
|
+
);
|
|
19307
|
+
var renderInventory = (t, inventory) => [
|
|
19308
|
+
...header(t, inventory),
|
|
19309
|
+
...section(
|
|
19310
|
+
t("inventory.risks"),
|
|
19311
|
+
table2(
|
|
19312
|
+
[t("inventory.col.risk"), t("inventory.col.still"), t("inventory.col.evidence"), t("inventory.col.fix")],
|
|
19313
|
+
riskRows(t, inventory.repos)
|
|
19314
|
+
)
|
|
19315
|
+
),
|
|
19316
|
+
...section(
|
|
19317
|
+
t("inventory.gap"),
|
|
19318
|
+
table2([t("inventory.col.plan"), t("inventory.col.today"), t("inventory.col.effect")], [])
|
|
19319
|
+
),
|
|
19320
|
+
...deltaBlock(t, inventory),
|
|
19321
|
+
...inventory.repos.flatMap((repo) => repoBlock(t, inventory, repo))
|
|
19322
|
+
].join("\n");
|
|
19323
|
+
|
|
19324
|
+
// src/inventory/run.ts
|
|
19325
|
+
var readOne = (runtime, root, dir, request) => {
|
|
19326
|
+
const top = gitRoot(gitAt(runtime, toAbsolutePath(dir, root)));
|
|
19327
|
+
if (top === void 0) return reject({ kind: "repo", repo: dir });
|
|
19328
|
+
const git2 = gitAt(runtime, top);
|
|
19329
|
+
const hash = resolveCommit(git2, request.ref);
|
|
19330
|
+
if (hash === void 0) return reject({ kind: "ref", repo: dir, ref: request.ref });
|
|
19331
|
+
const path = toPosixPath(relative10(runtime.realpath(root), runtime.realpath(top))) || ".";
|
|
19332
|
+
return accept(readRepo(git2, path, request.ref, hash, request.covered));
|
|
19333
|
+
};
|
|
19334
|
+
var deltaOf = (runtime, root, previous, repo, covered) => {
|
|
19335
|
+
if (previous === void 0 || previous === repo.hash) return [];
|
|
19336
|
+
const git2 = gitAt(runtime, toAbsolutePath(repo.path, root));
|
|
19337
|
+
return linesOf(git2.out(["diff", "--name-status", previous, repo.hash, "--", ...pathspecOf(covered)]));
|
|
19338
|
+
};
|
|
19339
|
+
var frontOf = (inventory) => ({
|
|
19340
|
+
schema: INVENTORY_SCHEMA,
|
|
19341
|
+
topic: inventory.topic,
|
|
19342
|
+
date: inventory.date,
|
|
19343
|
+
repos: inventory.repos.map((repo) => ({ path: repo.path, ref: repo.ref, hash: repo.hash })),
|
|
19344
|
+
covered: [...inventory.covered]
|
|
19345
|
+
});
|
|
19346
|
+
var assemble2 = (runtime, root, request, repos, previousText) => {
|
|
19347
|
+
const previous = previousText === void 0 ? [] : reposOf(readFront(previousText).data);
|
|
19348
|
+
const main2 = repos[0];
|
|
19349
|
+
const previousHash = previous.find((item2) => item2.path === main2?.path)?.hash;
|
|
19350
|
+
const incidents = runtime.listDir(incidentsDir(root));
|
|
19351
|
+
return {
|
|
19352
|
+
schema: INVENTORY_SCHEMA,
|
|
19353
|
+
topic: request.topic,
|
|
19354
|
+
date: runtime.now().slice(0, 10),
|
|
19355
|
+
covered: request.covered.length === 0 ? ["."] : request.covered,
|
|
19356
|
+
repos,
|
|
19357
|
+
delta: main2 === void 0 ? [] : deltaOf(runtime, root, previousHash, main2, request.covered),
|
|
19358
|
+
...previousHash === void 0 || previousHash === main2?.hash ? {} : { previousHash },
|
|
19359
|
+
incidents: incidents.ok ? incidents.value.filter((name) => name.endsWith(".json")) : []
|
|
19360
|
+
};
|
|
19361
|
+
};
|
|
19362
|
+
var runInventory = (runtime, t, root, request) => {
|
|
19363
|
+
const reads = (request.repos.length === 0 ? ["."] : request.repos).map((dir) => readOne(runtime, root, dir, request));
|
|
19364
|
+
const repos = [];
|
|
19365
|
+
for (const read4 of reads) {
|
|
19366
|
+
if (!read4.ok) return read4;
|
|
19367
|
+
repos.push(read4.value);
|
|
19368
|
+
}
|
|
19369
|
+
const names = planFiles(runtime, root);
|
|
19370
|
+
const name = findByKind(names, "today", request.topic) ?? `${nextNumber(names)}a-today-${slugOf(request.topic)}.md`;
|
|
19371
|
+
const target2 = planPath(root, name);
|
|
19372
|
+
const before = runtime.readText(target2);
|
|
19373
|
+
const inventory = assemble2(runtime, root, request, repos, before.ok ? before.value : void 0);
|
|
19374
|
+
const made = runtime.mkdir(planDir(root));
|
|
19375
|
+
const written = made.ok ? runtime.writeText(target2, writeFront(frontOf(inventory), renderInventory(t, inventory))) : made;
|
|
19376
|
+
if (!written.ok) return reject({ kind: "write", detail: written.error });
|
|
19377
|
+
return accept({ file: `${PLAN_DIR}/${name}`, inventory });
|
|
19378
|
+
};
|
|
19379
|
+
|
|
19380
|
+
// src/commands/inventory.ts
|
|
19381
|
+
var USAGE2 = "finitemonkey inventory <topic> [--ref <ref>] [--path <dir>]... [--repo <dir>]...";
|
|
19382
|
+
var problemResult = (ctx, problem4) => {
|
|
19383
|
+
if (problem4.kind === "repo") return failureFrom(ctx.t, notRepository(problem4.repo));
|
|
19384
|
+
if (problem4.kind === "ref")
|
|
19385
|
+
return failureFrom(
|
|
19386
|
+
ctx.t,
|
|
19387
|
+
usageProblem("invalid_arguments", "inventory.error.ref", USAGE2, { ref: problem4.ref, repo: problem4.repo })
|
|
19388
|
+
);
|
|
19389
|
+
return failureFrom(ctx.t, {
|
|
19390
|
+
code: "plan_write_failed",
|
|
19391
|
+
messageKey: "plan.error.write",
|
|
19392
|
+
params: { detail: problem4.detail },
|
|
19393
|
+
fix: "check that docs/plan can be written",
|
|
19394
|
+
exitCode: ExitCode.CheckFailed
|
|
19395
|
+
});
|
|
19396
|
+
};
|
|
19397
|
+
var inventoryCommand = {
|
|
19398
|
+
path: ["inventory"],
|
|
19399
|
+
summaryKey: "command.inventory.summary",
|
|
19400
|
+
usage: USAGE2,
|
|
19401
|
+
status: "ready",
|
|
19402
|
+
maxPositionals: 1,
|
|
19403
|
+
options: {
|
|
19404
|
+
ref: { type: "string" },
|
|
19405
|
+
path: { type: "string", multiple: true },
|
|
19406
|
+
repo: { type: "string", multiple: true }
|
|
19407
|
+
},
|
|
19408
|
+
run: (ctx, args2) => {
|
|
19409
|
+
const repo = repoOf(ctx);
|
|
19410
|
+
if (repo === void 0) return Promise.resolve(failureFrom(ctx.t, notRepository(ctx.cwd)));
|
|
19411
|
+
const topic = args2.positionals[0]?.trim() ?? "";
|
|
19412
|
+
if (topic === "")
|
|
19413
|
+
return Promise.resolve(failureFrom(ctx.t, usageProblem("invalid_arguments", "inventory.error.topic", USAGE2)));
|
|
19414
|
+
const written = runInventory(ctx.runtime, ctx.t, repo.root, {
|
|
19415
|
+
topic,
|
|
19416
|
+
ref: stringOption(args2.values, "ref") ?? "HEAD",
|
|
19417
|
+
covered: listOption(args2.values, "path"),
|
|
19418
|
+
repos: listOption(args2.values, "repo")
|
|
19419
|
+
});
|
|
19420
|
+
if (!written.ok) return Promise.resolve(problemResult(ctx, written.error));
|
|
19421
|
+
const { file, inventory } = written.value;
|
|
19422
|
+
const repos = inventory.repos.map((item2) => ({ path: item2.path, ref: item2.ref, hash: item2.hash }));
|
|
19423
|
+
return Promise.resolve(
|
|
19424
|
+
success({ schema: INVENTORY_SCHEMA, file, topic, covered: inventory.covered, repos, delta: inventory.delta }, [
|
|
19425
|
+
ctx.t("inventory.written", { file, count: repos.length }),
|
|
19426
|
+
...repos.map((item2) => ` ${item2.path} ${item2.hash}`)
|
|
19427
|
+
])
|
|
19428
|
+
);
|
|
19429
|
+
}
|
|
19430
|
+
};
|
|
19431
|
+
|
|
18657
19432
|
// src/look/findings.ts
|
|
18658
19433
|
var MAX_PER_RULE = 5;
|
|
18659
19434
|
var finding3 = (result, rule, detail) => ({
|
|
@@ -18690,7 +19465,7 @@ var applyAllows = (findings, allows, decided) => {
|
|
|
18690
19465
|
|
|
18691
19466
|
// src/look/node-capture.ts
|
|
18692
19467
|
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
18693
|
-
import { join as
|
|
19468
|
+
import { join as join46 } from "node:path";
|
|
18694
19469
|
|
|
18695
19470
|
// src/look/measure.ts
|
|
18696
19471
|
var measurePage = (doc) => {
|
|
@@ -18728,7 +19503,7 @@ var parseMeasure = (value) => {
|
|
|
18728
19503
|
var HEIGHT = 900;
|
|
18729
19504
|
var MAX_EVENTS = 20;
|
|
18730
19505
|
var RESOURCE_ERROR = /^Failed to load resource\b/;
|
|
18731
|
-
var
|
|
19506
|
+
var slugOf2 = (route) => {
|
|
18732
19507
|
const slug2 = route.replace(/^\//, "").replace(/[^A-Za-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
18733
19508
|
return slug2 === "" ? "root" : slug2.slice(0, 80);
|
|
18734
19509
|
};
|
|
@@ -18766,7 +19541,7 @@ var captureOne = async (browser, request, route, viewport) => {
|
|
|
18766
19541
|
const context = await browser.newContext({ viewport: { width: viewport, height: HEIGHT }, reducedMotion: "reduce" });
|
|
18767
19542
|
const page = await context.newPage();
|
|
18768
19543
|
const events = watch(page);
|
|
18769
|
-
const path =
|
|
19544
|
+
const path = join46(request.dir, `${slugOf2(route)}-${String(viewport)}.png`);
|
|
18770
19545
|
const loadError = await loadAndShoot(page, `${request.baseUrl}${route}`, path, request.timeoutMs);
|
|
18771
19546
|
const measure = loadError === void 0 ? parseMeasure(await page.evaluate(MEASURE_SCRIPT)) : void 0;
|
|
18772
19547
|
await context.close();
|
|
@@ -18783,7 +19558,7 @@ var captureAll = async (browser, request) => {
|
|
|
18783
19558
|
|
|
18784
19559
|
// src/look/node-playwright.ts
|
|
18785
19560
|
import { createRequire } from "node:module";
|
|
18786
|
-
import { join as
|
|
19561
|
+
import { join as join47 } from "node:path";
|
|
18787
19562
|
import { fileURLToPath as fileURLToPath3, pathToFileURL } from "node:url";
|
|
18788
19563
|
var NAMES = ["playwright", "playwright-core"];
|
|
18789
19564
|
var isPlaywright = (value) => isRecord(value) && isRecord(value["chromium"]) && typeof value["chromium"]["launch"] === "function";
|
|
@@ -18798,7 +19573,7 @@ var tryLoad = async (base, name) => {
|
|
|
18798
19573
|
}
|
|
18799
19574
|
};
|
|
18800
19575
|
var loadPlaywright = async (root) => {
|
|
18801
|
-
for (const base of [
|
|
19576
|
+
for (const base of [join47(root, "package.json"), fileURLToPath3(import.meta.url)]) {
|
|
18802
19577
|
for (const name of NAMES) {
|
|
18803
19578
|
const found = await tryLoad(base, name);
|
|
18804
19579
|
if (found !== void 0) return found;
|
|
@@ -18819,7 +19594,7 @@ var launchBrowser = async (playwright) => {
|
|
|
18819
19594
|
|
|
18820
19595
|
// src/look/node-sheet.ts
|
|
18821
19596
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
18822
|
-
import { join as
|
|
19597
|
+
import { join as join48 } from "node:path";
|
|
18823
19598
|
var escapeHtml = (text9) => text9.replace(/[&<>"]/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[char] ?? char);
|
|
18824
19599
|
var card = (result) => {
|
|
18825
19600
|
const image = (() => {
|
|
@@ -18838,11 +19613,11 @@ var STYLE = [
|
|
|
18838
19613
|
"img{display:block;width:100%;max-height:720px;object-fit:cover;object-position:top}"
|
|
18839
19614
|
].join("");
|
|
18840
19615
|
var contactSheet = async (browser, results, dir) => {
|
|
18841
|
-
const
|
|
18842
|
-
if (
|
|
19616
|
+
const shown4 = results.filter((result) => result.loadError === void 0);
|
|
19617
|
+
if (shown4.length === 0) return void 0;
|
|
18843
19618
|
const page = await browser.newPage({ viewport: { width: 1600, height: 900 } });
|
|
18844
|
-
await page.setContent(`<!doctype html><style>${STYLE}</style>${
|
|
18845
|
-
const path =
|
|
19619
|
+
await page.setContent(`<!doctype html><style>${STYLE}</style>${shown4.map(card).join("")}`);
|
|
19620
|
+
const path = join48(dir, "contact-sheet.png");
|
|
18846
19621
|
await page.screenshot({ path, fullPage: true });
|
|
18847
19622
|
await page.close();
|
|
18848
19623
|
return path;
|
|
@@ -19050,7 +19825,7 @@ var policyFalsePositiveCommand = {
|
|
|
19050
19825
|
};
|
|
19051
19826
|
|
|
19052
19827
|
// src/commands/prose-check.ts
|
|
19053
|
-
import { relative as
|
|
19828
|
+
import { relative as relative11 } from "node:path";
|
|
19054
19829
|
|
|
19055
19830
|
// src/commands/prose-view.ts
|
|
19056
19831
|
var PROSE_CHECK_SCHEMA = "finitemonkey/prose-check@1";
|
|
@@ -19103,14 +19878,14 @@ var proseCheckHuman = (t, reports, data) => [
|
|
|
19103
19878
|
// src/commands/prose-check.ts
|
|
19104
19879
|
var TEXT_FILE = /\.(?:md|markdown|mdx|txt)$/i;
|
|
19105
19880
|
var STDIN_LABEL = "<stdin>";
|
|
19106
|
-
var problem2 = (
|
|
19107
|
-
code,
|
|
19881
|
+
var problem2 = (code2, messageKey, params2) => ({
|
|
19882
|
+
code: code2,
|
|
19108
19883
|
messageKey,
|
|
19109
19884
|
params: params2,
|
|
19110
19885
|
fix: "finitemonkey help prose check",
|
|
19111
19886
|
exitCode: ExitCode.Usage
|
|
19112
19887
|
});
|
|
19113
|
-
var underRoot = (root, path) => toPosixPath(
|
|
19888
|
+
var underRoot = (root, path) => toPosixPath(relative11(root, path));
|
|
19114
19889
|
var expand2 = (ctx, root, target2) => {
|
|
19115
19890
|
const path = toAbsolutePath(target2, ctx.cwd);
|
|
19116
19891
|
const stat = ctx.runtime.stat(path);
|
|
@@ -19182,12 +19957,12 @@ var proseCheckCommand = {
|
|
|
19182
19957
|
};
|
|
19183
19958
|
|
|
19184
19959
|
// src/review/packet.ts
|
|
19185
|
-
import { join as
|
|
19960
|
+
import { join as join49 } from "node:path";
|
|
19186
19961
|
var REVIEW_STATE_FILE = ".finitemonkey/review/state.json";
|
|
19187
19962
|
var FULL_ROUNDS = 3;
|
|
19188
19963
|
var REVIEW_FILE_MAX_LINES = 200;
|
|
19189
19964
|
var LEDGER_MAX_LINES = 100;
|
|
19190
|
-
var statePath = (root) => toAbsolutePath(
|
|
19965
|
+
var statePath = (root) => toAbsolutePath(join49(root, REVIEW_STATE_FILE));
|
|
19191
19966
|
var readReviewState = (runtime, root) => {
|
|
19192
19967
|
const raw = runtime.readText(statePath(root));
|
|
19193
19968
|
const parsed = raw.ok ? parseJsonObject(raw.value) : void 0;
|
|
@@ -19200,7 +19975,7 @@ var git = (runtime, root, args2) => {
|
|
|
19200
19975
|
return result.ok ? result.stdout : void 0;
|
|
19201
19976
|
};
|
|
19202
19977
|
var lastLines = (text9, max) => text9.split("\n").slice(-max).join("\n");
|
|
19203
|
-
var
|
|
19978
|
+
var section2 = (title, body2, empty) => `## ${title}
|
|
19204
19979
|
|
|
19205
19980
|
${body2 === void 0 || body2.trim() === "" ? empty : body2.trimEnd()}
|
|
19206
19981
|
`;
|
|
@@ -19208,12 +19983,12 @@ var taskSections = (runtime, root) => {
|
|
|
19208
19983
|
const paths = fmPaths(root);
|
|
19209
19984
|
const active = readState(runtime, paths).active;
|
|
19210
19985
|
if (active === void 0)
|
|
19211
|
-
return [
|
|
19212
|
-
const contract = runtime.readText(toAbsolutePath(
|
|
19986
|
+
return [section2("Contract", void 0, "(no active task)"), section2("Evidence ledger", void 0, "(none)")];
|
|
19987
|
+
const contract = runtime.readText(toAbsolutePath(join49(root, taskRelative(active))));
|
|
19213
19988
|
const ledger = runtime.readText(paths.evidence(active));
|
|
19214
19989
|
return [
|
|
19215
|
-
|
|
19216
|
-
|
|
19990
|
+
section2("Contract", contract.ok ? contract.value : void 0, "(contract file missing)"),
|
|
19991
|
+
section2("Evidence ledger", ledger.ok ? lastLines(ledger.value, LEDGER_MAX_LINES) : void 0, "(none)")
|
|
19217
19992
|
];
|
|
19218
19993
|
};
|
|
19219
19994
|
var reviewFile = (runtime, root, base) => {
|
|
@@ -19235,11 +20010,11 @@ var buildPacket = (runtime, root, base, head) => {
|
|
|
19235
20010
|
`# Review packet (round ${String(state.rounds)}, ${range})`,
|
|
19236
20011
|
"",
|
|
19237
20012
|
...state.rounds > FULL_ROUNDS ? ["Only the diff since the last review round is included.", ""] : [],
|
|
19238
|
-
|
|
20013
|
+
section2("Diff", diff, "(empty diff)"),
|
|
19239
20014
|
...taskSections(runtime, root),
|
|
19240
|
-
...owners === void 0 ? [] : [
|
|
20015
|
+
...owners === void 0 ? [] : [section2("REVIEW.md (base branch)", owners, "")]
|
|
19241
20016
|
].join("\n");
|
|
19242
|
-
runtime.mkdir(toAbsolutePath(
|
|
20017
|
+
runtime.mkdir(toAbsolutePath(join49(root, ".finitemonkey", "review")));
|
|
19243
20018
|
runtime.writeAtomic(statePath(root), `${JSON.stringify(state, null, 2)}
|
|
19244
20019
|
`);
|
|
19245
20020
|
return { round: state.rounds, base, head, range, text: text9 };
|
|
@@ -19394,7 +20169,7 @@ var secretsAcceptCommand = {
|
|
|
19394
20169
|
};
|
|
19395
20170
|
|
|
19396
20171
|
// src/secrets/runbooks.ts
|
|
19397
|
-
import { dirname as dirname9, join as
|
|
20172
|
+
import { dirname as dirname9, join as join50 } from "node:path";
|
|
19398
20173
|
var PROVIDER_OF_RULE = {
|
|
19399
20174
|
"aws-access-token": "aws",
|
|
19400
20175
|
"aws-secret-access-key": "aws",
|
|
@@ -19416,13 +20191,13 @@ var RUNBOOKS_URL = "https://github.com/gabrielvieiraf/finitemonkey/blob/main/run
|
|
|
19416
20191
|
var runbookProvider = (rule) => PROVIDER_OF_RULE[rule] ?? "generic";
|
|
19417
20192
|
var runbookLink = (runtime, rule) => {
|
|
19418
20193
|
const file = `${runbookProvider(rule)}.md`;
|
|
19419
|
-
const local = toAbsolutePath(
|
|
20194
|
+
const local = toAbsolutePath(join50(dirname9(dirname9(runtime.selfPath)), "runbooks", file));
|
|
19420
20195
|
return runtime.stat(local)?.kind === "file" ? local : `${RUNBOOKS_URL}/${file}`;
|
|
19421
20196
|
};
|
|
19422
20197
|
|
|
19423
20198
|
// src/commands/secrets-incident.ts
|
|
19424
20199
|
var INCIDENT_ACTIONS = ["list", "rotated", "close", "purge"];
|
|
19425
|
-
var
|
|
20200
|
+
var USAGE3 = "finitemonkey secrets incident [list | rotated <id> | close <id> | purge <id>]";
|
|
19426
20201
|
var TARGET = { rotated: "rotacionado", close: "fechado" };
|
|
19427
20202
|
var PURGE_STEPS = [
|
|
19428
20203
|
"secrets.purge.step1",
|
|
@@ -19480,7 +20255,7 @@ var move = (ctx, root, incident, action) => {
|
|
|
19480
20255
|
if (!canMove(incident.state, to))
|
|
19481
20256
|
return action === "close" ? notRotated(ctx, incident) : fail2(
|
|
19482
20257
|
ctx,
|
|
19483
|
-
usageProblem("invalid_arguments", "secrets.error.bad_transition",
|
|
20258
|
+
usageProblem("invalid_arguments", "secrets.error.bad_transition", USAGE3, {
|
|
19484
20259
|
id: incident.id,
|
|
19485
20260
|
from: incident.state,
|
|
19486
20261
|
to
|
|
@@ -19503,7 +20278,7 @@ var actionOf = (raw) => INCIDENT_ACTIONS.find((action) => action === (raw ?? "li
|
|
|
19503
20278
|
var secretsIncidentCommand = {
|
|
19504
20279
|
path: ["secrets", "incident"],
|
|
19505
20280
|
summaryKey: "secrets.command.incident",
|
|
19506
|
-
usage:
|
|
20281
|
+
usage: USAGE3,
|
|
19507
20282
|
status: "ready",
|
|
19508
20283
|
maxPositionals: 2,
|
|
19509
20284
|
run: (ctx, args2) => {
|
|
@@ -19513,7 +20288,7 @@ var secretsIncidentCommand = {
|
|
|
19513
20288
|
return Promise.resolve(
|
|
19514
20289
|
fail2(
|
|
19515
20290
|
ctx,
|
|
19516
|
-
usageProblem("invalid_arguments", "error.invalid_arguments",
|
|
20291
|
+
usageProblem("invalid_arguments", "error.invalid_arguments", USAGE3, { detail: args2.positionals[0] ?? "" })
|
|
19517
20292
|
)
|
|
19518
20293
|
);
|
|
19519
20294
|
if (action === "list") return Promise.resolve(list2(ctx, root));
|
|
@@ -19585,8 +20360,8 @@ var liveOutcome = (result) => {
|
|
|
19585
20360
|
|
|
19586
20361
|
// src/commands/secrets-live.ts
|
|
19587
20362
|
var SECRETS_LIVE_SCHEMA = "finitemonkey/secrets-live@1";
|
|
19588
|
-
var
|
|
19589
|
-
var
|
|
20363
|
+
var USAGE4 = `finitemonkey secrets live <${LIVE_PROVIDERS.join("|")}> --env <VARIABLE> [--send]`;
|
|
20364
|
+
var ENV_NAME2 = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
19590
20365
|
var target = (provider) => {
|
|
19591
20366
|
const probe = LIVE_PROBES[provider];
|
|
19592
20367
|
return { host: probe.host, url: `https://${probe.host}${probe.path}` };
|
|
@@ -19616,18 +20391,18 @@ var send = (ctx, provider, variable, key) => {
|
|
|
19616
20391
|
var secretsLiveCommand = {
|
|
19617
20392
|
path: ["secrets", "live"],
|
|
19618
20393
|
summaryKey: "secrets.command.live",
|
|
19619
|
-
usage:
|
|
20394
|
+
usage: USAGE4,
|
|
19620
20395
|
status: "ready",
|
|
19621
20396
|
maxPositionals: 1,
|
|
19622
20397
|
options: { env: { type: "string" }, send: { type: "boolean" } },
|
|
19623
20398
|
run: (ctx, args2) => {
|
|
19624
20399
|
const provider = liveProvider(args2.positionals[0]);
|
|
19625
20400
|
const variable = stringOption(args2.values, "env") ?? "";
|
|
19626
|
-
if (provider === void 0 || !
|
|
20401
|
+
if (provider === void 0 || !ENV_NAME2.test(variable))
|
|
19627
20402
|
return Promise.resolve(
|
|
19628
20403
|
failureFrom(
|
|
19629
20404
|
ctx.t,
|
|
19630
|
-
usageProblem("invalid_arguments", "error.invalid_arguments",
|
|
20405
|
+
usageProblem("invalid_arguments", "error.invalid_arguments", USAGE4, {
|
|
19631
20406
|
detail: provider === void 0 ? args2.positionals[0] ?? "<provider>" : "--env <VARIABLE>"
|
|
19632
20407
|
})
|
|
19633
20408
|
)
|
|
@@ -19637,7 +20412,7 @@ var secretsLiveCommand = {
|
|
|
19637
20412
|
return Promise.resolve(
|
|
19638
20413
|
failureFrom(
|
|
19639
20414
|
ctx.t,
|
|
19640
|
-
needsPersonProblem("secrets.error.person_only", `${
|
|
20415
|
+
needsPersonProblem("secrets.error.person_only", `${USAGE4.replace(" [--send]", "")} --send`, {
|
|
19641
20416
|
action: ctx.t("secrets.action.live")
|
|
19642
20417
|
})
|
|
19643
20418
|
)
|
|
@@ -19645,7 +20420,7 @@ var secretsLiveCommand = {
|
|
|
19645
20420
|
const key = ctx.env[variable] ?? "";
|
|
19646
20421
|
if (key === "")
|
|
19647
20422
|
return Promise.resolve(
|
|
19648
|
-
failureFrom(ctx.t, usageProblem("invalid_arguments", "secrets.live.no_value",
|
|
20423
|
+
failureFrom(ctx.t, usageProblem("invalid_arguments", "secrets.live.no_value", USAGE4, { variable }))
|
|
19649
20424
|
);
|
|
19650
20425
|
return Promise.resolve(send(ctx, provider, variable, key));
|
|
19651
20426
|
}
|
|
@@ -19673,8 +20448,8 @@ var modeOf3 = (values) => {
|
|
|
19673
20448
|
};
|
|
19674
20449
|
var normalizedTarget = (target2) => target2.replace(/\\/g, "/").replace(/^\.\/?/, "").replace(/\/$/, "");
|
|
19675
20450
|
var scopeOf = (target2) => {
|
|
19676
|
-
const
|
|
19677
|
-
return (file) =>
|
|
20451
|
+
const prefix2 = normalizedTarget(target2);
|
|
20452
|
+
return (file) => prefix2 === "" || file === prefix2 || file.startsWith(`${prefix2}/`);
|
|
19678
20453
|
};
|
|
19679
20454
|
var runScan = async (ctx, root, mode, target2) => {
|
|
19680
20455
|
if (mode === "staged") return scanStaged(ctx.runtime, root);
|
|
@@ -19976,43 +20751,7 @@ var statuslineCommand = {
|
|
|
19976
20751
|
};
|
|
19977
20752
|
|
|
19978
20753
|
// src/task/create.ts
|
|
19979
|
-
import { join as
|
|
19980
|
-
|
|
19981
|
-
// src/core/yaml/write.ts
|
|
19982
|
-
var PLAIN_SAFE = /^[A-Za-z_./][A-Za-z0-9_./ ()-]*$/;
|
|
19983
|
-
var RESERVED2 = /^(true|false|null|~|-?\d.*)$/;
|
|
19984
|
-
var scalarText = (value) => {
|
|
19985
|
-
if (value === null) return "null";
|
|
19986
|
-
if (typeof value !== "string") return String(value);
|
|
19987
|
-
return PLAIN_SAFE.test(value) && !RESERVED2.test(value) && !value.endsWith(" ") ? value : JSON.stringify(value);
|
|
19988
|
-
};
|
|
19989
|
-
var isScalar = (value) => value === null || typeof value !== "object";
|
|
19990
|
-
var inline2 = (value) => {
|
|
19991
|
-
if (isScalar(value)) return scalarText(value);
|
|
19992
|
-
if (Array.isArray(value)) {
|
|
19993
|
-
if (value.length === 0) return "[]";
|
|
19994
|
-
return value.every(isScalar) ? `[${value.map(scalarText).join(", ")}]` : void 0;
|
|
19995
|
-
}
|
|
19996
|
-
return Object.keys(value).length === 0 ? "{}" : void 0;
|
|
19997
|
-
};
|
|
19998
|
-
var lines2 = (value, indent) => {
|
|
19999
|
-
if (Array.isArray(value)) {
|
|
20000
|
-
return value.flatMap((item2) => {
|
|
20001
|
-
const flat = inline2(item2);
|
|
20002
|
-
if (flat !== void 0) return [`${indent}- ${flat}`];
|
|
20003
|
-
const [head = "", ...rest] = lines2(item2, `${indent} `);
|
|
20004
|
-
return [`${indent}- ${head.trimStart()}`, ...rest];
|
|
20005
|
-
});
|
|
20006
|
-
}
|
|
20007
|
-
if (isScalar(value)) return [`${indent}${scalarText(value)}`];
|
|
20008
|
-
return Object.entries(value).flatMap(([key, item2]) => {
|
|
20009
|
-
const flat = inline2(item2);
|
|
20010
|
-
const name = scalarText(key);
|
|
20011
|
-
return flat === void 0 ? [`${indent}${name}:`, ...lines2(item2, `${indent} `)] : [`${indent}${name}: ${flat}`];
|
|
20012
|
-
});
|
|
20013
|
-
};
|
|
20014
|
-
var stringifyYaml = (value) => `${lines2(value, "").join("\n")}
|
|
20015
|
-
`;
|
|
20754
|
+
import { join as join51 } from "node:path";
|
|
20016
20755
|
|
|
20017
20756
|
// src/task/serialize.ts
|
|
20018
20757
|
var checkYaml = (check2) => ({
|
|
@@ -20064,11 +20803,11 @@ var explicitChecks = (draft) => [
|
|
|
20064
20803
|
];
|
|
20065
20804
|
var draftChecks = (runtime, paths, draft) => {
|
|
20066
20805
|
const disk = {
|
|
20067
|
-
read: (
|
|
20068
|
-
const text9 = runtime.readText(toAbsolutePath(
|
|
20806
|
+
read: (relative12) => {
|
|
20807
|
+
const text9 = runtime.readText(toAbsolutePath(join51(paths.root, relative12)));
|
|
20069
20808
|
return text9.ok ? text9.value : void 0;
|
|
20070
20809
|
},
|
|
20071
|
-
exists: (
|
|
20810
|
+
exists: (relative12) => runtime.stat(toAbsolutePath(join51(paths.root, relative12))) !== void 0
|
|
20072
20811
|
};
|
|
20073
20812
|
const detected = detectChecks(disk);
|
|
20074
20813
|
const base = draft.runs.length > 0 || draft.tests !== void 0 ? explicitChecks(draft) : detected;
|
|
@@ -20083,7 +20822,7 @@ var draftChecks = (runtime, paths, draft) => {
|
|
|
20083
20822
|
{ id: "merge", kind: "merge" },
|
|
20084
20823
|
{ id: "callers", kind: "callers" },
|
|
20085
20824
|
...draft.paths.length > 0 || draft.budget !== void 0 ? [{ id: "diff", kind: "diff" }] : [],
|
|
20086
|
-
...runtime.stat(toAbsolutePath(
|
|
20825
|
+
...runtime.stat(toAbsolutePath(join51(paths.root, LOOK_CONFIG))) === void 0 ? [] : [{ id: "look", kind: "look" }],
|
|
20087
20826
|
...draft.git.length > 0 ? [{ id: "git", kind: "git", require: draft.git }] : [],
|
|
20088
20827
|
{ id: "pr", kind: "pr", requireOpen: draft.git.includes("pr_open") },
|
|
20089
20828
|
...draft.manual.map((description, index) => ({
|
|
@@ -20125,8 +20864,8 @@ var createTask = (runtime, paths, draft) => {
|
|
|
20125
20864
|
};
|
|
20126
20865
|
|
|
20127
20866
|
// src/commands/task.ts
|
|
20128
|
-
var problem3 = (
|
|
20129
|
-
code,
|
|
20867
|
+
var problem3 = (code2, messageKey, fix, params2 = {}, exitCode = ExitCode.Usage) => ({
|
|
20868
|
+
code: code2,
|
|
20130
20869
|
messageKey,
|
|
20131
20870
|
params: params2,
|
|
20132
20871
|
fix,
|
|
@@ -20325,9 +21064,9 @@ var applyItem = (project, item2) => {
|
|
|
20325
21064
|
if (item2.after === void 0 || item2.action === "gone" || item2.action.startsWith("keep")) return accept(void 0);
|
|
20326
21065
|
return writeText(project, item2.path, item2.after);
|
|
20327
21066
|
};
|
|
20328
|
-
var isEmptyDir = (project,
|
|
20329
|
-
const
|
|
20330
|
-
return
|
|
21067
|
+
var isEmptyDir = (project, relative12) => {
|
|
21068
|
+
const listed5 = project.runtime.listDir(project.abs(relative12));
|
|
21069
|
+
return listed5.ok && listed5.value.length === 0;
|
|
20331
21070
|
};
|
|
20332
21071
|
var finish3 = (project, plan) => {
|
|
20333
21072
|
const target2 = plan.purge ? STATE_DIR : LOCK_FILE;
|
|
@@ -20367,7 +21106,7 @@ var dataOf3 = (root, plan, applied) => ({
|
|
|
20367
21106
|
kept: plan.items.filter((item2) => item2.action.startsWith("keep")).map(({ path }) => path),
|
|
20368
21107
|
outside: OUTSIDE.map(({ command }) => command)
|
|
20369
21108
|
});
|
|
20370
|
-
var
|
|
21109
|
+
var linesOf4 = (ctx, data) => [
|
|
20371
21110
|
ctx.t("install.uninstall.title", { root: data.root }),
|
|
20372
21111
|
...data.actions.map(({ path, action }) => ` ${action.padEnd(15)}${path}`),
|
|
20373
21112
|
...data.purge ? [ctx.t("install.uninstall.purge")] : [ctx.t("install.uninstall.keeps_state")],
|
|
@@ -20388,16 +21127,16 @@ var runUninstall = (ctx, args2) => {
|
|
|
20388
21127
|
const options = { purge: args2.values["purge"] === true, keepGenerated: args2.values["keep-generated"] === true };
|
|
20389
21128
|
const plan = planRemoval(project, lock.value, options);
|
|
20390
21129
|
const preview = dataOf3(project.root, plan, false);
|
|
20391
|
-
if (ctx.dryRun) return success(preview, [...
|
|
21130
|
+
if (ctx.dryRun) return success(preview, [...linesOf4(ctx, preview), ctx.t("install.dry_run")]);
|
|
20392
21131
|
if (!ctx.yes) {
|
|
20393
21132
|
const next2 = fixFor(args2);
|
|
20394
21133
|
const problem4 = confirmProblem("uninstall", ctx.t("install.uninstall.question"), next2);
|
|
20395
|
-
return { ...failureFrom(ctx.t, { ...problem4, data: preview },
|
|
21134
|
+
return { ...failureFrom(ctx.t, { ...problem4, data: preview }, linesOf4(ctx, preview)), next: next2 };
|
|
20396
21135
|
}
|
|
20397
21136
|
const removed = applyRemoval(project, plan);
|
|
20398
21137
|
if (!removed.ok) return failureFrom(ctx.t, applyProblem(removed.error));
|
|
20399
21138
|
const data = dataOf3(project.root, plan, true);
|
|
20400
|
-
return success(data, [...
|
|
21139
|
+
return success(data, [...linesOf4(ctx, data), ctx.t("install.uninstall.done")]);
|
|
20401
21140
|
};
|
|
20402
21141
|
var uninstallCommand = {
|
|
20403
21142
|
path: ["uninstall"],
|
|
@@ -20493,12 +21232,13 @@ var REGISTRY = [
|
|
|
20493
21232
|
reviewPacketCommand,
|
|
20494
21233
|
statuslineCommand,
|
|
20495
21234
|
critiqueVerifyCommand,
|
|
21235
|
+
inventoryCommand,
|
|
20496
21236
|
versionCommand,
|
|
20497
21237
|
helpCommand
|
|
20498
21238
|
];
|
|
20499
21239
|
|
|
20500
21240
|
// src/i18n/lang-settings.ts
|
|
20501
|
-
import { join as
|
|
21241
|
+
import { join as join52 } from "node:path";
|
|
20502
21242
|
var read3 = (runtime, path) => {
|
|
20503
21243
|
const text9 = runtime.readText(toAbsolutePath(path));
|
|
20504
21244
|
return text9.ok ? text9.value : void 0;
|
|
@@ -20513,14 +21253,14 @@ var languageIn = (text9) => {
|
|
|
20513
21253
|
const value = parsed.ok && isRecord(parsed.value) ? parsed.value["language"] : void 0;
|
|
20514
21254
|
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
20515
21255
|
};
|
|
20516
|
-
var claudeDir = (runtime, env) => env["CLAUDE_CONFIG_DIR"] ??
|
|
21256
|
+
var claudeDir = (runtime, env) => env["CLAUDE_CONFIG_DIR"] ?? join52(runtime.homeDir(), ".claude");
|
|
20517
21257
|
var langSettings = (runtime, cwd, env, platform) => {
|
|
20518
21258
|
const root = findGitRoot(cwd, runtime) ?? cwd;
|
|
20519
|
-
const config = parseConfigYaml(read3(runtime,
|
|
21259
|
+
const config = parseConfigYaml(read3(runtime, join52(root, CONFIG_FILE2)) ?? "");
|
|
20520
21260
|
const claudeFiles = [
|
|
20521
|
-
|
|
20522
|
-
|
|
20523
|
-
|
|
21261
|
+
join52(root, ".claude", "settings.local.json"),
|
|
21262
|
+
join52(root, ".claude", "settings.json"),
|
|
21263
|
+
join52(claudeDir(runtime, env), "settings.json")
|
|
20524
21264
|
];
|
|
20525
21265
|
return {
|
|
20526
21266
|
config: configText(config, "lang"),
|
|
@@ -20532,18 +21272,18 @@ var langSettings = (runtime, cwd, env, platform) => {
|
|
|
20532
21272
|
|
|
20533
21273
|
// src/core/suggest.ts
|
|
20534
21274
|
var distance2 = (a, b) => {
|
|
20535
|
-
const
|
|
21275
|
+
const row2 = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
20536
21276
|
for (let i = 1; i <= a.length; i += 1) {
|
|
20537
|
-
let diagonal =
|
|
20538
|
-
|
|
21277
|
+
let diagonal = row2[0] ?? 0;
|
|
21278
|
+
row2[0] = i;
|
|
20539
21279
|
for (let j = 1; j <= b.length; j += 1) {
|
|
20540
|
-
const above =
|
|
21280
|
+
const above = row2[j] ?? 0;
|
|
20541
21281
|
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
20542
|
-
|
|
21282
|
+
row2[j] = Math.min(above + 1, (row2[j - 1] ?? 0) + 1, diagonal + cost);
|
|
20543
21283
|
diagonal = above;
|
|
20544
21284
|
}
|
|
20545
21285
|
}
|
|
20546
|
-
return
|
|
21286
|
+
return row2[b.length] ?? 0;
|
|
20547
21287
|
};
|
|
20548
21288
|
var closest = (input, candidates) => {
|
|
20549
21289
|
const group = candidates.find((name) => name.startsWith(`${input} `));
|
|
@@ -20676,8 +21416,8 @@ var run3 = async (options) => {
|
|
|
20676
21416
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
20677
21417
|
var UNKNOWN_VERSION = "0.0.0-unknown";
|
|
20678
21418
|
var VERSION_SOURCES = ["../package.json", "../.claude-plugin/plugin.json"];
|
|
20679
|
-
var versionAt = (readText, moduleUrl,
|
|
20680
|
-
const text9 = readText(toAbsolutePath(fileURLToPath4(new URL(
|
|
21419
|
+
var versionAt = (readText, moduleUrl, relative12) => {
|
|
21420
|
+
const text9 = readText(toAbsolutePath(fileURLToPath4(new URL(relative12, moduleUrl))));
|
|
20681
21421
|
if (!text9.ok) return void 0;
|
|
20682
21422
|
const parsed = parseJson(text9.value);
|
|
20683
21423
|
if (!parsed.ok || !isRecord(parsed.value)) return void 0;
|
|
@@ -20685,8 +21425,8 @@ var versionAt = (readText, moduleUrl, relative11) => {
|
|
|
20685
21425
|
return typeof version === "string" ? version : void 0;
|
|
20686
21426
|
};
|
|
20687
21427
|
var readPackageVersion = (readText, moduleUrl) => {
|
|
20688
|
-
for (const
|
|
20689
|
-
const version = versionAt(readText, moduleUrl,
|
|
21428
|
+
for (const relative12 of VERSION_SOURCES) {
|
|
21429
|
+
const version = versionAt(readText, moduleUrl, relative12);
|
|
20690
21430
|
if (version !== void 0) return version;
|
|
20691
21431
|
}
|
|
20692
21432
|
return UNKNOWN_VERSION;
|
|
@@ -20700,7 +21440,7 @@ var flush = (stream) => new Promise((resolve2) => {
|
|
|
20700
21440
|
});
|
|
20701
21441
|
var main = async () => {
|
|
20702
21442
|
const runtime = nodeRuntime();
|
|
20703
|
-
const
|
|
21443
|
+
const code2 = await run3({
|
|
20704
21444
|
argv: process.argv.slice(2),
|
|
20705
21445
|
env: process.env,
|
|
20706
21446
|
cwd: toAbsolutePath(process.cwd()),
|
|
@@ -20710,7 +21450,7 @@ var main = async () => {
|
|
|
20710
21450
|
runtime
|
|
20711
21451
|
});
|
|
20712
21452
|
await Promise.all([flush(process.stdout), flush(process.stderr)]);
|
|
20713
|
-
process.exit(
|
|
21453
|
+
process.exit(code2);
|
|
20714
21454
|
};
|
|
20715
21455
|
if (isEntryPoint(import.meta.url, process.argv[1], nodeRealpath, process.platform)) await main();
|
|
20716
21456
|
export {
|