finitemonkey 0.1.0-next.23 → 0.1.0-next.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/finitemonkey.mjs +756 -461
- package/package.json +1 -1
package/dist/finitemonkey.mjs
CHANGED
|
@@ -28,15 +28,15 @@ import { dirname } from "node:path";
|
|
|
28
28
|
var accept = (value) => ({ ok: true, value });
|
|
29
29
|
var reject = (error) => ({ ok: false, error });
|
|
30
30
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31
|
-
var parseJson = (
|
|
31
|
+
var parseJson = (text8) => {
|
|
32
32
|
try {
|
|
33
|
-
return accept(JSON.parse(
|
|
33
|
+
return accept(JSON.parse(text8));
|
|
34
34
|
} catch (error) {
|
|
35
35
|
return reject(error instanceof Error ? error.message : String(error));
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
-
var parseJsonObject = (
|
|
39
|
-
const parsed = parseJson(
|
|
38
|
+
var parseJsonObject = (text8) => {
|
|
39
|
+
const parsed = parseJson(text8);
|
|
40
40
|
if (!parsed.ok) return parsed;
|
|
41
41
|
return isRecord(parsed.value) ? accept(parsed.value) : reject("expected a JSON object");
|
|
42
42
|
};
|
|
@@ -160,13 +160,13 @@ var attempt = (work) => {
|
|
|
160
160
|
return reject(messageOf(error));
|
|
161
161
|
}
|
|
162
162
|
};
|
|
163
|
-
var nodeWriteText = (path,
|
|
163
|
+
var nodeWriteText = (path, text8) => {
|
|
164
164
|
const temp = `${path}.${String(process.pid)}.tmp`;
|
|
165
165
|
try {
|
|
166
166
|
mkdirSync2(dirname2(path), { recursive: true, mode: 448 });
|
|
167
167
|
const fd = openSync(temp, "w", 384);
|
|
168
168
|
try {
|
|
169
|
-
writeSync(fd,
|
|
169
|
+
writeSync(fd, text8);
|
|
170
170
|
fsyncSync(fd);
|
|
171
171
|
} finally {
|
|
172
172
|
closeSync(fd);
|
|
@@ -778,7 +778,7 @@ import { dirname as dirname3 } from "node:path";
|
|
|
778
778
|
|
|
779
779
|
// src/install/hash.ts
|
|
780
780
|
import { createHash } from "node:crypto";
|
|
781
|
-
var hashText = (
|
|
781
|
+
var hashText = (text8) => `sha256:${createHash("sha256").update(text8, "utf8").digest("hex")}`;
|
|
782
782
|
|
|
783
783
|
// src/install/layout.ts
|
|
784
784
|
var STATE_DIR = ".finitemonkey";
|
|
@@ -809,6 +809,76 @@ var PRESETS = ["neutral", "gabriel"];
|
|
|
809
809
|
var parsePreset = (raw) => raw === void 0 ? "neutral" : PRESETS.find((preset) => preset === raw);
|
|
810
810
|
var COMMITTED_STATE = ["config.yml", "runtime/", "tasks/", "rules.yml", "policy.yml", "findings/"];
|
|
811
811
|
|
|
812
|
+
// src/install/hook-entries.ts
|
|
813
|
+
var INSTALLED_HOOKS = [
|
|
814
|
+
{ event: "SessionStart", timeout: 30, guard: false },
|
|
815
|
+
{ event: "UserPromptSubmit", timeout: 10, guard: true },
|
|
816
|
+
{ event: "PreToolUse", timeout: 10, guard: true },
|
|
817
|
+
{ event: "PostToolUse", timeout: 30, guard: false },
|
|
818
|
+
{ event: "Stop", timeout: 600, guard: false },
|
|
819
|
+
{ event: "SubagentStart", timeout: 30, guard: false },
|
|
820
|
+
{ event: "SubagentStop", timeout: 600, guard: false },
|
|
821
|
+
{ event: "PreCompact", timeout: 30, guard: false },
|
|
822
|
+
{ event: "ConfigChange", timeout: 10, guard: true }
|
|
823
|
+
];
|
|
824
|
+
var PROJECT_BIN = `\${CLAUDE_PROJECT_DIR}/${LOCAL_BIN}`;
|
|
825
|
+
var VENDORED_BIN = `\${CLAUDE_PROJECT_DIR}/${VENDOR_BIN}`;
|
|
826
|
+
var isScript = (path) => /\.(c|m)?js$/i.test(path);
|
|
827
|
+
var execForm = (runner, event) => {
|
|
828
|
+
if (runner.kind === "local") return { command: "node", args: [PROJECT_BIN, "hook", event] };
|
|
829
|
+
if (runner.kind === "vendored") return { command: "node", args: [VENDORED_BIN, "hook", event] };
|
|
830
|
+
if (isScript(runner.path)) return { command: "node", args: [runner.path, "hook", event] };
|
|
831
|
+
return { command: runner.path, args: ["hook", event] };
|
|
832
|
+
};
|
|
833
|
+
var hookHandler = (runner, spec2, failClosedSupported) => {
|
|
834
|
+
const failure4 = spec2.guard && failClosedSupported ? { onFailure: "block" } : {};
|
|
835
|
+
const { command, args: args2 } = execForm(runner, spec2.event);
|
|
836
|
+
return { type: "command", command, args: args2, timeout: spec2.timeout, ...failure4 };
|
|
837
|
+
};
|
|
838
|
+
var OWN_SHELL = /(^|[\s/"'])finitemonkey(@[^\s"]+|\.mjs|\.cmd|\.exe)?"?\s+hook\s/;
|
|
839
|
+
var OWN_SCRIPT = /finitemonkey(\.mjs|\.cmd|\.exe)?$/;
|
|
840
|
+
var stringsOf = (value) => Array.isArray(value) ? value.filter((item2) => typeof item2 === "string") : [];
|
|
841
|
+
var isOwnHandler = (handler) => {
|
|
842
|
+
if (!isRecord(handler)) return false;
|
|
843
|
+
const command = handler["command"];
|
|
844
|
+
if (typeof command !== "string") return false;
|
|
845
|
+
const args2 = stringsOf(handler["args"]);
|
|
846
|
+
if (args2.length === 0) return OWN_SHELL.test(`${command} `);
|
|
847
|
+
const hookAt = args2.indexOf("hook");
|
|
848
|
+
if (hookAt < 0) return false;
|
|
849
|
+
const target2 = hookAt === 0 ? command : args2[hookAt - 1] ?? "";
|
|
850
|
+
return OWN_SCRIPT.test(target2);
|
|
851
|
+
};
|
|
852
|
+
|
|
853
|
+
// src/install/statusline.ts
|
|
854
|
+
var OWN = /finitemonkey(\.mjs|\.cmd|\.exe)?"?\s+statusline\s*$/;
|
|
855
|
+
var projectFile = (relative11) => relative11;
|
|
856
|
+
var commandFor = (runner) => {
|
|
857
|
+
if (runner.kind === "local") return `node ${projectFile(LOCAL_BIN)} statusline`;
|
|
858
|
+
if (runner.kind === "vendored") return `node ${projectFile(VENDOR_BIN)} statusline`;
|
|
859
|
+
return isScript(runner.path) ? `node "${runner.path}" statusline` : `"${runner.path}" statusline`;
|
|
860
|
+
};
|
|
861
|
+
var ownStatusLine = (runner) => ({
|
|
862
|
+
type: "command",
|
|
863
|
+
command: commandFor(runner),
|
|
864
|
+
padding: 0
|
|
865
|
+
});
|
|
866
|
+
var isOwnStatusLine = (value) => isRecord(value) && typeof value["command"] === "string" && OWN.test(value["command"]);
|
|
867
|
+
var statusLineCommand = (value) => {
|
|
868
|
+
if (!isRecord(value) || isOwnStatusLine(value)) return void 0;
|
|
869
|
+
const command = value["command"];
|
|
870
|
+
return value["type"] === "command" && typeof command === "string" && command.trim() !== "" ? command : void 0;
|
|
871
|
+
};
|
|
872
|
+
var statusLineIn = (text8) => {
|
|
873
|
+
const parsed = text8 === void 0 ? void 0 : parseJsonObject(text8);
|
|
874
|
+
return parsed?.ok === true ? parsed.value["statusLine"] : void 0;
|
|
875
|
+
};
|
|
876
|
+
var parseStatusLineAdded = (value) => {
|
|
877
|
+
if (!isRecord(value) || !("previous" in value)) return void 0;
|
|
878
|
+
const wrap = value["wrap"];
|
|
879
|
+
return { previous: value["previous"], wrap: typeof wrap === "string" ? wrap : null };
|
|
880
|
+
};
|
|
881
|
+
|
|
812
882
|
// src/install/lock-file.ts
|
|
813
883
|
var ENTRY_KINDS = ["settings", "gitignore", "generated", "markdown", "githook"];
|
|
814
884
|
var strings = (value) => Array.isArray(value) && value.every((item2) => typeof item2 === "string") ? value : void 0;
|
|
@@ -822,7 +892,17 @@ var parseAdded = (value) => {
|
|
|
822
892
|
const marketplace = value["marketplace"] === true;
|
|
823
893
|
const plugin = value["plugin"] === true;
|
|
824
894
|
const language = value["language"];
|
|
825
|
-
const
|
|
895
|
+
const statusLine = parseStatusLineAdded(value["statusLine"]);
|
|
896
|
+
const added = {
|
|
897
|
+
schema,
|
|
898
|
+
attribution,
|
|
899
|
+
deny: deny2,
|
|
900
|
+
ask: ask2,
|
|
901
|
+
blockReads,
|
|
902
|
+
marketplace,
|
|
903
|
+
plugin,
|
|
904
|
+
...statusLine === void 0 ? {} : { statusLine }
|
|
905
|
+
};
|
|
826
906
|
return typeof language === "string" ? { ...added, language } : added;
|
|
827
907
|
};
|
|
828
908
|
var parseEntry = (value) => {
|
|
@@ -863,8 +943,8 @@ var fromRecord = (record3) => {
|
|
|
863
943
|
}
|
|
864
944
|
return accept({ schema, version, preset: known2, installedAt, updatedAt, createdDirs, entries });
|
|
865
945
|
};
|
|
866
|
-
var parseLock = (
|
|
867
|
-
const parsed = parseJsonObject(
|
|
946
|
+
var parseLock = (text8) => {
|
|
947
|
+
const parsed = parseJsonObject(text8);
|
|
868
948
|
return parsed.ok ? fromRecord(parsed.value) : reject(parsed.error);
|
|
869
949
|
};
|
|
870
950
|
var renderLock = (lock) => `${JSON.stringify(lock, null, 2)}
|
|
@@ -926,10 +1006,10 @@ var ensureTree = (tree, key) => {
|
|
|
926
1006
|
tree[key] = fresh3;
|
|
927
1007
|
return fresh3;
|
|
928
1008
|
};
|
|
929
|
-
var parseConfigYaml = (
|
|
1009
|
+
var parseConfigYaml = (text8) => {
|
|
930
1010
|
const root = {};
|
|
931
1011
|
const stack = [{ indent: -1, tree: root, key: void 0 }];
|
|
932
|
-
for (const raw of
|
|
1012
|
+
for (const raw of text8.split(/\r?\n/)) {
|
|
933
1013
|
const line2 = stripComment(raw).trimEnd();
|
|
934
1014
|
if (line2.trim() === "" || line2.trim() === "---") continue;
|
|
935
1015
|
const indent = line2.length - line2.trimStart().length;
|
|
@@ -952,33 +1032,33 @@ var configMap = (tree, ...path) => {
|
|
|
952
1032
|
);
|
|
953
1033
|
};
|
|
954
1034
|
var loadProjectConfig = (runtime, root) => {
|
|
955
|
-
const
|
|
956
|
-
return
|
|
1035
|
+
const text8 = runtime.readText(toAbsolutePath(join2(root, CONFIG_FILE2)));
|
|
1036
|
+
return text8.ok ? parseConfigYaml(text8.value) : {};
|
|
957
1037
|
};
|
|
958
1038
|
|
|
959
1039
|
// src/install/managed-block.ts
|
|
960
|
-
var lineBreak = (
|
|
1040
|
+
var lineBreak = (text8) => text8.includes("\r\n") ? "\r\n" : "\n";
|
|
961
1041
|
var blockRange = (lines3, markers) => {
|
|
962
1042
|
const start = lines3.findIndex((line2) => line2.trimEnd() === markers.begin);
|
|
963
1043
|
if (start < 0) return void 0;
|
|
964
1044
|
const end = lines3.findIndex((line2, index) => index > start && line2.trimEnd() === markers.end);
|
|
965
1045
|
return end < 0 ? void 0 : { start, end };
|
|
966
1046
|
};
|
|
967
|
-
var withManagedBlock = (
|
|
968
|
-
const eol =
|
|
1047
|
+
var withManagedBlock = (text8, markers, body2) => {
|
|
1048
|
+
const eol = text8 === void 0 ? "\n" : lineBreak(text8);
|
|
969
1049
|
const block4 = [markers.begin, ...body2, markers.end];
|
|
970
|
-
if (
|
|
971
|
-
const lines3 =
|
|
1050
|
+
if (text8 === void 0 || text8 === "") return `${block4.join(eol)}${eol}`;
|
|
1051
|
+
const lines3 = text8.split(eol);
|
|
972
1052
|
const range = blockRange(lines3, markers);
|
|
973
1053
|
if (range !== void 0) return [...lines3.slice(0, range.start), ...block4, ...lines3.slice(range.end + 1)].join(eol);
|
|
974
|
-
const separator =
|
|
975
|
-
return `${
|
|
1054
|
+
const separator = text8.endsWith(eol) ? "" : eol;
|
|
1055
|
+
return `${text8}${separator}${block4.join(eol)}${eol}`;
|
|
976
1056
|
};
|
|
977
|
-
var withoutManagedBlock = (
|
|
978
|
-
const eol = lineBreak(
|
|
979
|
-
const lines3 =
|
|
1057
|
+
var withoutManagedBlock = (text8, markers) => {
|
|
1058
|
+
const eol = lineBreak(text8);
|
|
1059
|
+
const lines3 = text8.split(eol);
|
|
980
1060
|
const range = blockRange(lines3, markers);
|
|
981
|
-
if (range === void 0) return
|
|
1061
|
+
if (range === void 0) return text8;
|
|
982
1062
|
return [...lines3.slice(0, range.start), ...lines3.slice(range.end + 1)].join(eol);
|
|
983
1063
|
};
|
|
984
1064
|
|
|
@@ -1075,48 +1155,7 @@ var configTemplate = (preset, lang) => [
|
|
|
1075
1155
|
`lang: ${lang}`,
|
|
1076
1156
|
""
|
|
1077
1157
|
].join("\n");
|
|
1078
|
-
var hasMarker = (
|
|
1079
|
-
|
|
1080
|
-
// src/install/hook-entries.ts
|
|
1081
|
-
var INSTALLED_HOOKS = [
|
|
1082
|
-
{ event: "SessionStart", timeout: 30, guard: false },
|
|
1083
|
-
{ event: "UserPromptSubmit", timeout: 10, guard: true },
|
|
1084
|
-
{ event: "PreToolUse", timeout: 10, guard: true },
|
|
1085
|
-
{ event: "PostToolUse", timeout: 30, guard: false },
|
|
1086
|
-
{ event: "Stop", timeout: 600, guard: false },
|
|
1087
|
-
{ event: "SubagentStart", timeout: 30, guard: false },
|
|
1088
|
-
{ event: "SubagentStop", timeout: 600, guard: false },
|
|
1089
|
-
{ event: "PreCompact", timeout: 30, guard: false },
|
|
1090
|
-
{ event: "ConfigChange", timeout: 10, guard: true }
|
|
1091
|
-
];
|
|
1092
|
-
var PROJECT_BIN = `\${CLAUDE_PROJECT_DIR}/${LOCAL_BIN}`;
|
|
1093
|
-
var VENDORED_BIN = `\${CLAUDE_PROJECT_DIR}/${VENDOR_BIN}`;
|
|
1094
|
-
var isScript = (path) => /\.(c|m)?js$/i.test(path);
|
|
1095
|
-
var execForm = (runner, event) => {
|
|
1096
|
-
if (runner.kind === "local") return { command: "node", args: [PROJECT_BIN, "hook", event] };
|
|
1097
|
-
if (runner.kind === "vendored") return { command: "node", args: [VENDORED_BIN, "hook", event] };
|
|
1098
|
-
if (isScript(runner.path)) return { command: "node", args: [runner.path, "hook", event] };
|
|
1099
|
-
return { command: runner.path, args: ["hook", event] };
|
|
1100
|
-
};
|
|
1101
|
-
var hookHandler = (runner, spec2, failClosedSupported) => {
|
|
1102
|
-
const failure4 = spec2.guard && failClosedSupported ? { onFailure: "block" } : {};
|
|
1103
|
-
const { command, args: args2 } = execForm(runner, spec2.event);
|
|
1104
|
-
return { type: "command", command, args: args2, timeout: spec2.timeout, ...failure4 };
|
|
1105
|
-
};
|
|
1106
|
-
var OWN_SHELL = /(^|[\s/"'])finitemonkey(@[^\s"]+|\.mjs|\.cmd|\.exe)?"?\s+hook\s/;
|
|
1107
|
-
var OWN_SCRIPT = /finitemonkey(\.mjs|\.cmd|\.exe)?$/;
|
|
1108
|
-
var stringsOf = (value) => Array.isArray(value) ? value.filter((item2) => typeof item2 === "string") : [];
|
|
1109
|
-
var isOwnHandler = (handler) => {
|
|
1110
|
-
if (!isRecord(handler)) return false;
|
|
1111
|
-
const command = handler["command"];
|
|
1112
|
-
if (typeof command !== "string") return false;
|
|
1113
|
-
const args2 = stringsOf(handler["args"]);
|
|
1114
|
-
if (args2.length === 0) return OWN_SHELL.test(`${command} `);
|
|
1115
|
-
const hookAt = args2.indexOf("hook");
|
|
1116
|
-
if (hookAt < 0) return false;
|
|
1117
|
-
const target2 = hookAt === 0 ? command : args2[hookAt - 1] ?? "";
|
|
1118
|
-
return OWN_SCRIPT.test(target2);
|
|
1119
|
-
};
|
|
1158
|
+
var hasMarker = (text8) => text8.includes(GENERATED_MARKER);
|
|
1120
1159
|
|
|
1121
1160
|
// src/install/skill-template.ts
|
|
1122
1161
|
var cliCommand = (runner, args2) => {
|
|
@@ -1181,7 +1220,7 @@ var lefthookBody = (runner) => [
|
|
|
1181
1220
|
` run: ${cliCommand(runner, "push check {1}")}`,
|
|
1182
1221
|
" use_stdin: true"
|
|
1183
1222
|
];
|
|
1184
|
-
var definesHook = (
|
|
1223
|
+
var definesHook = (text8) => GIT_HOOK_NAMES.some((hook) => new RegExp(`^${hook}:`, "m").test(withoutManagedBlock(text8, HOOK_MARKERS)));
|
|
1185
1224
|
var lefthookItem = (project, runner, path) => {
|
|
1186
1225
|
const before = project.read(path);
|
|
1187
1226
|
const after = withManagedBlock(before, HOOK_MARKERS, lefthookBody(runner));
|
|
@@ -1206,8 +1245,8 @@ var preCommitBody = (runner, indent) => {
|
|
|
1206
1245
|
];
|
|
1207
1246
|
};
|
|
1208
1247
|
var TOP_KEY = /^[A-Za-z_][\w-]*:/;
|
|
1209
|
-
var reposIsLast = (
|
|
1210
|
-
const keys = withoutManagedBlock(
|
|
1248
|
+
var reposIsLast = (text8) => {
|
|
1249
|
+
const keys = withoutManagedBlock(text8, HOOK_MARKERS).split(/\r?\n/).filter((line2) => TOP_KEY.test(line2));
|
|
1211
1250
|
return keys.at(-1)?.startsWith("repos:") === true;
|
|
1212
1251
|
};
|
|
1213
1252
|
var preCommitItem = (project, runner) => {
|
|
@@ -1245,8 +1284,8 @@ var DEFAULT_POLICY = {
|
|
|
1245
1284
|
guards: {}
|
|
1246
1285
|
};
|
|
1247
1286
|
var pick = (options, value, fallback) => options.find((option) => option === value) ?? fallback;
|
|
1248
|
-
var parsePolicy = (
|
|
1249
|
-
const tree = parseConfigYaml(
|
|
1287
|
+
var parsePolicy = (text8) => {
|
|
1288
|
+
const tree = parseConfigYaml(text8);
|
|
1250
1289
|
const raw = configAt(tree, "promoteAfter");
|
|
1251
1290
|
const promoteAfter = typeof raw === "string" ? Number.parseInt(raw, 10) : Number.NaN;
|
|
1252
1291
|
const guards = Object.fromEntries(
|
|
@@ -1265,8 +1304,8 @@ var parsePolicy = (text7) => {
|
|
|
1265
1304
|
};
|
|
1266
1305
|
var policyPath = (root) => toAbsolutePath(join3(root, POLICY_FILE));
|
|
1267
1306
|
var loadPolicy = (runtime, root) => {
|
|
1268
|
-
const
|
|
1269
|
-
return
|
|
1307
|
+
const text8 = runtime.readText(policyPath(root));
|
|
1308
|
+
return text8.ok ? parsePolicy(text8.value) : DEFAULT_POLICY;
|
|
1270
1309
|
};
|
|
1271
1310
|
|
|
1272
1311
|
// src/review/agents.ts
|
|
@@ -1331,16 +1370,16 @@ var agentMarkdown = (spec2, marker) => [
|
|
|
1331
1370
|
// src/install/agents-block.ts
|
|
1332
1371
|
var MARKDOWN_MARKERS = { begin: MD_BLOCK_BEGIN, end: MD_BLOCK_END };
|
|
1333
1372
|
var IMPORT_LINE = /^@AGENTS\.md[ \t]*$/m;
|
|
1334
|
-
var withAgentsBlock = (
|
|
1335
|
-
|
|
1373
|
+
var withAgentsBlock = (text8, runner, lang) => withManagedBlock(
|
|
1374
|
+
text8,
|
|
1336
1375
|
MARKDOWN_MARKERS,
|
|
1337
1376
|
TEMPLATES[lang].agentsBlock({
|
|
1338
1377
|
gate: cliCommand(runner, "gate --fast --json"),
|
|
1339
1378
|
doctor: cliCommand(runner, "doctor --json")
|
|
1340
1379
|
})
|
|
1341
1380
|
);
|
|
1342
|
-
var withAgentsImport = (
|
|
1343
|
-
var withoutMarkdownBlock = (
|
|
1381
|
+
var withAgentsImport = (text8) => text8 !== void 0 && IMPORT_LINE.test(withoutManagedBlock(text8, MARKDOWN_MARKERS)) ? text8 : withManagedBlock(text8, MARKDOWN_MARKERS, [AGENTS_IMPORT]);
|
|
1382
|
+
var withoutMarkdownBlock = (text8) => withoutManagedBlock(text8, MARKDOWN_MARKERS);
|
|
1344
1383
|
|
|
1345
1384
|
// src/install/ask-floor.ts
|
|
1346
1385
|
var DEFAULT_BRANCHES = ["main", "master"];
|
|
@@ -1416,7 +1455,7 @@ var ruleFor = (raw) => {
|
|
|
1416
1455
|
};
|
|
1417
1456
|
var claudeignoreRules = (texts2) => [
|
|
1418
1457
|
...new Set(
|
|
1419
|
-
texts2.flatMap((
|
|
1458
|
+
texts2.flatMap((text8) => (text8 ?? "").split("\n")).map(ruleFor).filter((rule) => rule !== void 0)
|
|
1420
1459
|
)
|
|
1421
1460
|
];
|
|
1422
1461
|
|
|
@@ -1449,12 +1488,12 @@ import { join as join4 } from "node:path";
|
|
|
1449
1488
|
|
|
1450
1489
|
// src/install/json-text.ts
|
|
1451
1490
|
var DEFAULT_STYLE = { indent: " ", finalNewline: true };
|
|
1452
|
-
var styleOf = (
|
|
1453
|
-
const indented = /\n([ \t]+)\S/.exec(
|
|
1454
|
-
return { indent: indented?.[1] ?? DEFAULT_STYLE.indent, finalNewline:
|
|
1491
|
+
var styleOf = (text8) => {
|
|
1492
|
+
const indented = /\n([ \t]+)\S/.exec(text8);
|
|
1493
|
+
return { indent: indented?.[1] ?? DEFAULT_STYLE.indent, finalNewline: text8.endsWith("\n") };
|
|
1455
1494
|
};
|
|
1456
1495
|
var renderJson = (value, style) => `${JSON.stringify(value, null, style.indent)}${style.finalNewline ? "\n" : ""}`;
|
|
1457
|
-
var parseSettings = (
|
|
1496
|
+
var parseSettings = (text8) => text8 === void 0 || text8.trim() === "" ? { ok: true, value: {} } : parseJsonObject(text8);
|
|
1458
1497
|
var asList = (value) => Array.isArray(value) ? value : [];
|
|
1459
1498
|
var asRecord = (value) => isRecord(value) ? value : {};
|
|
1460
1499
|
var setKey = (record3, key, value) => {
|
|
@@ -1491,8 +1530,8 @@ var WORKFLOW_DIRS = [
|
|
|
1491
1530
|
{ dir: "openspec", name: "openspec" }
|
|
1492
1531
|
];
|
|
1493
1532
|
var fromPackageJson = (project) => {
|
|
1494
|
-
const
|
|
1495
|
-
const parsed =
|
|
1533
|
+
const text8 = project.read("package.json");
|
|
1534
|
+
const parsed = text8 === void 0 ? void 0 : parseJsonObject(text8);
|
|
1496
1535
|
const field = parsed?.ok === true ? parsed.value["packageManager"] : void 0;
|
|
1497
1536
|
if (typeof field !== "string") return void 0;
|
|
1498
1537
|
return PACKAGE_MANAGERS.find(({ name }) => field.startsWith(`${name}@`))?.name;
|
|
@@ -1508,9 +1547,9 @@ var allHandlers = (settings) => {
|
|
|
1508
1547
|
const hooks = settings["hooks"];
|
|
1509
1548
|
return isRecord(hooks) ? Object.keys(hooks).flatMap((event) => handlersOf(settings, event)) : [];
|
|
1510
1549
|
};
|
|
1511
|
-
var settingsInfo = (
|
|
1512
|
-
if (
|
|
1513
|
-
const parsed =
|
|
1550
|
+
var settingsInfo = (text8) => {
|
|
1551
|
+
if (text8 === void 0) return { exists: false, valid: true, userHooks: 0, ownHooks: 0 };
|
|
1552
|
+
const parsed = text8.trim() === "" ? { ok: true, value: {} } : parseJsonObject(text8);
|
|
1514
1553
|
if (!parsed.ok) return { exists: true, valid: false, userHooks: 0, ownHooks: 0 };
|
|
1515
1554
|
const handlers = allHandlers(parsed.value);
|
|
1516
1555
|
const own = handlers.filter(isOwnHandler).length;
|
|
@@ -1524,8 +1563,8 @@ var pluginAuthorities = (settings, source) => {
|
|
|
1524
1563
|
return LOOP_PLUGINS.includes(name) ? [{ kind: "loop-plugin", source, name }] : [];
|
|
1525
1564
|
});
|
|
1526
1565
|
};
|
|
1527
|
-
var scopeAuthorities = (
|
|
1528
|
-
const parsed =
|
|
1566
|
+
var scopeAuthorities = (text8, source) => {
|
|
1567
|
+
const parsed = text8 === void 0 ? void 0 : parseJsonObject(text8);
|
|
1529
1568
|
if (parsed?.ok !== true) return [];
|
|
1530
1569
|
const stops = ["Stop", "SubagentStop"].flatMap(
|
|
1531
1570
|
(event) => handlersOf(parsed.value, event).filter((handler) => !isOwnHandler(handler)).map((handler) => {
|
|
@@ -1539,8 +1578,8 @@ var userSettingsText = (project, env) => {
|
|
|
1539
1578
|
const home = env["CLAUDE_CONFIG_DIR"] ?? env["HOME"] ?? env["USERPROFILE"];
|
|
1540
1579
|
if (home === void 0) return void 0;
|
|
1541
1580
|
const file = env["CLAUDE_CONFIG_DIR"] === void 0 ? join4(home, ".claude", "settings.json") : join4(home, "settings.json");
|
|
1542
|
-
const
|
|
1543
|
-
return
|
|
1581
|
+
const text8 = project.runtime.readText(toAbsolutePath(file));
|
|
1582
|
+
return text8.ok ? text8.value : void 0;
|
|
1544
1583
|
};
|
|
1545
1584
|
var detectAuthorities = (project, env) => [
|
|
1546
1585
|
...scopeAuthorities(project.read(SETTINGS_FILE), "project"),
|
|
@@ -1560,8 +1599,8 @@ var chooseRunner = (project, bin) => {
|
|
|
1560
1599
|
// src/install/gitignore-block.ts
|
|
1561
1600
|
var MARKERS = { begin: BLOCK_BEGIN, end: BLOCK_END };
|
|
1562
1601
|
var body = () => [`${STATE_DIR}/*`, ...COMMITTED_STATE.map((path) => `!${STATE_DIR}/${path}`)];
|
|
1563
|
-
var withBlock = (
|
|
1564
|
-
var withoutBlock = (
|
|
1602
|
+
var withBlock = (text8) => withManagedBlock(text8, MARKERS, body());
|
|
1603
|
+
var withoutBlock = (text8) => withoutManagedBlock(text8, MARKERS);
|
|
1565
1604
|
|
|
1566
1605
|
// src/core/semver.ts
|
|
1567
1606
|
var SEMVER = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
@@ -1604,7 +1643,7 @@ var pendingMigrations = (migrations, from, to) => {
|
|
|
1604
1643
|
};
|
|
1605
1644
|
var migrateItem = (item2, previous, steps) => {
|
|
1606
1645
|
if (steps.length === 0 || item2.before === void 0) return item2;
|
|
1607
|
-
const migrated = steps.reduce((
|
|
1646
|
+
const migrated = steps.reduce((text8, step3) => step3(text8), item2.after);
|
|
1608
1647
|
if (migrated === item2.after) return item2;
|
|
1609
1648
|
const recorded = previous.entries.find((entry2) => entry2.path === item2.path)?.hash;
|
|
1610
1649
|
if (recorded !== hashText(item2.before)) {
|
|
@@ -1696,6 +1735,15 @@ var withPermissions = (settings, lists) => {
|
|
|
1696
1735
|
var missing = (wanted, existing) => wanted.filter((rule) => !existing.includes(rule));
|
|
1697
1736
|
var withoutAdded = (existing, added) => existing.filter((rule) => typeof rule !== "string" || !added.includes(rule));
|
|
1698
1737
|
var ownHookMatcher = (recorded) => (handler) => isOwnHandler(handler) || recorded.some((own) => JSON.stringify(own) === JSON.stringify(handler));
|
|
1738
|
+
var statusLineFor = (base, wanted) => {
|
|
1739
|
+
if (wanted.statusLine === void 0 || isOwnStatusLine(base["statusLine"])) return void 0;
|
|
1740
|
+
return { previous: base["statusLine"] ?? null, wrap: wanted.statusLine.wrap ?? null };
|
|
1741
|
+
};
|
|
1742
|
+
var restoreStatusLine = (settings, added) => {
|
|
1743
|
+
if (added.statusLine === void 0 || !isOwnStatusLine(settings["statusLine"])) return settings;
|
|
1744
|
+
const previous = added.statusLine.previous;
|
|
1745
|
+
return setKey(settings, "statusLine", previous === null ? void 0 : previous);
|
|
1746
|
+
};
|
|
1699
1747
|
var mergeSettings = (current2, wanted, recorded) => {
|
|
1700
1748
|
const schema = Object.keys(current2).length === 0;
|
|
1701
1749
|
const base = schema ? { $schema: SETTINGS_SCHEMA_URL } : current2;
|
|
@@ -1719,7 +1767,18 @@ var mergeSettings = (current2, wanted, recorded) => {
|
|
|
1719
1767
|
if (marketplace) settings = withEntry(settings, "extraKnownMarketplaces", MARKETPLACE_KEY, MARKETPLACE_ENTRY);
|
|
1720
1768
|
if (plugin) settings = withEntry(settings, "enabledPlugins", PLUGIN_ID, true);
|
|
1721
1769
|
if (language !== void 0) settings = { ...settings, language };
|
|
1722
|
-
const
|
|
1770
|
+
const status = statusLineFor(base, wanted);
|
|
1771
|
+
if (status !== void 0) settings = { ...settings, statusLine: wanted.statusLine?.entry };
|
|
1772
|
+
const added = {
|
|
1773
|
+
schema,
|
|
1774
|
+
deny: deny2,
|
|
1775
|
+
ask: ask2,
|
|
1776
|
+
blockReads,
|
|
1777
|
+
attribution,
|
|
1778
|
+
marketplace,
|
|
1779
|
+
plugin,
|
|
1780
|
+
...status === void 0 ? {} : { statusLine: status }
|
|
1781
|
+
};
|
|
1723
1782
|
return { settings, added: language === void 0 ? added : { ...added, language } };
|
|
1724
1783
|
};
|
|
1725
1784
|
var sameAttribution = (value) => JSON.stringify(value) === JSON.stringify(ATTRIBUTION_OFF);
|
|
@@ -1739,15 +1798,20 @@ var unmergeSettings = (current2, added, recorded) => {
|
|
|
1739
1798
|
if (added.language !== void 0 && settings["language"] === added.language) {
|
|
1740
1799
|
settings = setKey(settings, "language", void 0);
|
|
1741
1800
|
}
|
|
1801
|
+
settings = restoreStatusLine(settings, added);
|
|
1742
1802
|
if (added.schema && Object.keys(settings).length === 1 && settings["$schema"] === SETTINGS_SCHEMA_URL) return {};
|
|
1743
1803
|
return settings;
|
|
1744
1804
|
};
|
|
1745
1805
|
var ownHandlersIn = (settings) => Object.values(asRecord(settings["hooks"])).flatMap((groups) => asList(groups)).flatMap((group) => asList(asRecord(group)["hooks"])).filter(isOwnHandler).length;
|
|
1746
1806
|
|
|
1807
|
+
// src/install/statusline-search.ts
|
|
1808
|
+
var LOCAL_SETTINGS_FILE = ".claude/settings.local.json";
|
|
1809
|
+
var existingStatusLine = (project, projectSettings, env) => statusLineCommand(projectSettings["statusLine"]) ?? statusLineCommand(statusLineIn(project.read(LOCAL_SETTINGS_FILE))) ?? statusLineCommand(statusLineIn(userSettingsText(project, env)));
|
|
1810
|
+
|
|
1747
1811
|
// src/install/vendor.ts
|
|
1748
|
-
var isBundle = (
|
|
1749
|
-
var isOwnPackage = (
|
|
1750
|
-
const parsed = parseJsonObject(
|
|
1812
|
+
var isBundle = (text8) => text8.startsWith("#!/usr/bin/env node") && text8.includes("finitemonkey");
|
|
1813
|
+
var isOwnPackage = (text8) => {
|
|
1814
|
+
const parsed = parseJsonObject(text8);
|
|
1751
1815
|
return parsed.ok && parsed.value["name"] === "finitemonkey";
|
|
1752
1816
|
};
|
|
1753
1817
|
var vendoredPackage = (version) => `${JSON.stringify({ name: "finitemonkey", version, private: true, type: "module" }, null, 2)}
|
|
@@ -1778,9 +1842,9 @@ var detect = (project, gitRoot2, input) => ({
|
|
|
1778
1842
|
location: locationOf(project.root, input.env)
|
|
1779
1843
|
});
|
|
1780
1844
|
var readPreviousLock = (project) => {
|
|
1781
|
-
const
|
|
1782
|
-
if (
|
|
1783
|
-
const parsed = parseLock(
|
|
1845
|
+
const text8 = project.read(LOCK_FILE);
|
|
1846
|
+
if (text8 === void 0) return accept(void 0);
|
|
1847
|
+
const parsed = parseLock(text8);
|
|
1784
1848
|
return parsed.ok ? accept(parsed.value) : reject({ kind: "lock", detail: parsed.error });
|
|
1785
1849
|
};
|
|
1786
1850
|
var actionFor = (before, after, existing) => {
|
|
@@ -1796,7 +1860,8 @@ var joinAdded = (previous, next2) => previous === void 0 ? next2 : {
|
|
|
1796
1860
|
blockReads: previous.blockReads || next2.blockReads,
|
|
1797
1861
|
marketplace: previous.marketplace || next2.marketplace,
|
|
1798
1862
|
plugin: previous.plugin || next2.plugin,
|
|
1799
|
-
...(previous.language ?? next2.language) === void 0 ? {} : { language: previous.language ?? next2.language }
|
|
1863
|
+
...(previous.language ?? next2.language) === void 0 ? {} : { language: previous.language ?? next2.language },
|
|
1864
|
+
...(previous.statusLine ?? next2.statusLine) === void 0 ? {} : { statusLine: previous.statusLine ?? next2.statusLine }
|
|
1800
1865
|
};
|
|
1801
1866
|
var wantedHooks = (detection) => Object.fromEntries(
|
|
1802
1867
|
INSTALLED_HOOKS.map((spec2) => [spec2.event, hookHandler(detection.runner, spec2, detection.claude.failClosed)])
|
|
@@ -1812,7 +1877,8 @@ var settingsItem = (project, detection, input, previous) => {
|
|
|
1812
1877
|
ask: ASK_RULES,
|
|
1813
1878
|
attributionOff: input.preset === "gabriel",
|
|
1814
1879
|
marketplace: input.marketplace,
|
|
1815
|
-
language: input.claudeLanguage
|
|
1880
|
+
language: input.claudeLanguage,
|
|
1881
|
+
statusLine: { entry: ownStatusLine(detection.runner), wrap: existingStatusLine(project, current2.value, input.env) }
|
|
1816
1882
|
};
|
|
1817
1883
|
const merged2 = mergeSettings(current2.value, wanted, previous?.handlers ?? []);
|
|
1818
1884
|
const after = renderJson(merged2.settings, before === void 0 ? DEFAULT_STYLE : styleOf(before));
|
|
@@ -1827,7 +1893,7 @@ var settingsItem = (project, detection, input, previous) => {
|
|
|
1827
1893
|
});
|
|
1828
1894
|
};
|
|
1829
1895
|
var markdownItems = (project, runner, lang) => [
|
|
1830
|
-
{ path: AGENTS_FILE, render: (
|
|
1896
|
+
{ path: AGENTS_FILE, render: (text8) => withAgentsBlock(text8, runner, lang) },
|
|
1831
1897
|
{ path: CLAUDE_FILE, render: withAgentsImport }
|
|
1832
1898
|
].map(({ path, render: render3 }) => {
|
|
1833
1899
|
const before = project.read(path);
|
|
@@ -1857,7 +1923,7 @@ var playwrightVerifier = (project) => {
|
|
|
1857
1923
|
const wanted = configAt(parseConfigYaml(project.read(CONFIG_FILE) ?? ""), "review", "playwright") === "true";
|
|
1858
1924
|
if (!wanted) return [];
|
|
1859
1925
|
const template = agentMarkdown(withPlaywright(VERIFIER), GENERATED_MARKER);
|
|
1860
|
-
return [{ path: PLAYWRIGHT_VERIFIER, template, isOurs: (
|
|
1926
|
+
return [{ path: PLAYWRIGHT_VERIFIER, template, isOurs: (text8) => text8.includes(GENERATED_MARKER) }];
|
|
1861
1927
|
};
|
|
1862
1928
|
var generatedFiles = (project, input, runner, vendor) => {
|
|
1863
1929
|
const own = [
|
|
@@ -1902,9 +1968,9 @@ var needsWrite = (plan) => hasChanges(plan) || plan.previous === void 0;
|
|
|
1902
1968
|
// src/install/apply.ts
|
|
1903
1969
|
var stamp = (iso) => iso.replace(/[:.]/g, "-");
|
|
1904
1970
|
var ensureParent = (project, relative11) => project.runtime.mkdir(project.abs(dirname3(relative11)));
|
|
1905
|
-
var writeText = (project, relative11,
|
|
1971
|
+
var writeText = (project, relative11, text8) => {
|
|
1906
1972
|
const parent = ensureParent(project, relative11);
|
|
1907
|
-
const written = parent.ok ? project.runtime.writeAtomic(project.abs(relative11),
|
|
1973
|
+
const written = parent.ok ? project.runtime.writeAtomic(project.abs(relative11), text8) : parent;
|
|
1908
1974
|
return written.ok ? accept(void 0) : reject({ path: relative11, detail: written.error });
|
|
1909
1975
|
};
|
|
1910
1976
|
var restore = (project, items) => {
|
|
@@ -2052,8 +2118,8 @@ var projectAt = (root, runtime) => {
|
|
|
2052
2118
|
runtime,
|
|
2053
2119
|
abs,
|
|
2054
2120
|
read: (relative11) => {
|
|
2055
|
-
const
|
|
2056
|
-
return
|
|
2121
|
+
const text8 = runtime.readText(abs(relative11));
|
|
2122
|
+
return text8.ok ? text8.value : void 0;
|
|
2057
2123
|
},
|
|
2058
2124
|
exists: (relative11) => runtime.stat(abs(relative11)) !== void 0,
|
|
2059
2125
|
isDir: (relative11) => runtime.stat(abs(relative11))?.kind === "dir"
|
|
@@ -2126,8 +2192,8 @@ var invalidPreset = (raw) => problem("invalid_arguments", "error.invalid_preset"
|
|
|
2126
2192
|
});
|
|
2127
2193
|
var selfBundle = (ctx) => {
|
|
2128
2194
|
if (!isBundlePath(ctx.runtime.selfPath)) return void 0;
|
|
2129
|
-
const
|
|
2130
|
-
return
|
|
2195
|
+
const text8 = ctx.runtime.readText(ctx.runtime.selfPath);
|
|
2196
|
+
return text8.ok ? text8.value : void 0;
|
|
2131
2197
|
};
|
|
2132
2198
|
var INHERITED = /* @__PURE__ */ new Set(["default", "config", "claude-settings"]);
|
|
2133
2199
|
var planInputFor = (ctx, preset, bin, marketplace) => ({
|
|
@@ -2231,13 +2297,13 @@ var isPlaceholder = (value) => {
|
|
|
2231
2297
|
var isTestOrLockPath = (path) => path !== void 0 && (LOCKFILES.test(toPosixPath(path)) || TEST_PATH.test(toPosixPath(path)));
|
|
2232
2298
|
|
|
2233
2299
|
// src/secrets/entropy.ts
|
|
2234
|
-
var shannonEntropy = (
|
|
2235
|
-
if (
|
|
2300
|
+
var shannonEntropy = (text8) => {
|
|
2301
|
+
if (text8.length === 0) return 0;
|
|
2236
2302
|
const counts = /* @__PURE__ */ new Map();
|
|
2237
|
-
for (const char of
|
|
2303
|
+
for (const char of text8) counts.set(char, (counts.get(char) ?? 0) + 1);
|
|
2238
2304
|
let entropy = 0;
|
|
2239
2305
|
for (const count4 of counts.values()) {
|
|
2240
|
-
const p = count4 /
|
|
2306
|
+
const p = count4 / text8.length;
|
|
2241
2307
|
entropy -= p * Math.log2(p);
|
|
2242
2308
|
}
|
|
2243
2309
|
return entropy;
|
|
@@ -2245,7 +2311,7 @@ var shannonEntropy = (text7) => {
|
|
|
2245
2311
|
|
|
2246
2312
|
// src/secrets/fingerprint.ts
|
|
2247
2313
|
import { createHash as createHash2 } from "node:crypto";
|
|
2248
|
-
var sha256Hex = (
|
|
2314
|
+
var sha256Hex = (text8) => createHash2("sha256").update(text8).digest("hex");
|
|
2249
2315
|
var fingerprintOf = (secret) => sha256Hex(`finitemonkey:secret:${secret}`).slice(0, 16);
|
|
2250
2316
|
var ALNUM = /[A-Za-z0-9]/g;
|
|
2251
2317
|
var MIN_TAIL_LENGTH = 12;
|
|
@@ -2255,9 +2321,9 @@ var tailOf = (secret) => {
|
|
|
2255
2321
|
};
|
|
2256
2322
|
|
|
2257
2323
|
// src/secrets/lines.ts
|
|
2258
|
-
var lineLocator = (
|
|
2324
|
+
var lineLocator = (text8) => {
|
|
2259
2325
|
const starts = [0];
|
|
2260
|
-
for (let index =
|
|
2326
|
+
for (let index = text8.indexOf("\n"); index !== -1; index = text8.indexOf("\n", index + 1)) starts.push(index + 1);
|
|
2261
2327
|
return (offset) => {
|
|
2262
2328
|
let low = 0;
|
|
2263
2329
|
let high = starts.length - 1;
|
|
@@ -2551,12 +2617,12 @@ var hasRandomRun = (secret, length) => (secret.match(new RegExp(`[A-Za-z0-9]{${S
|
|
|
2551
2617
|
);
|
|
2552
2618
|
var accepted = (rule, secret) => secret.length >= rule.minLength && (!rule.requireDigit || DIGIT.test(secret)) && (rule.minRandomRun === 0 || hasRandomRun(secret, rule.minRandomRun)) && (!rule.placeholders || !isPlaceholder(secret)) && (rule.minEntropy === 0 || shannonEntropy(secret) >= rule.minEntropy);
|
|
2553
2619
|
var NAME_CHAR = /[A-Za-z0-9_.-]/;
|
|
2554
|
-
var nameAround = (
|
|
2620
|
+
var nameAround = (text8, at) => {
|
|
2555
2621
|
let start = at;
|
|
2556
|
-
while (start > 0 && NAME_CHAR.test(
|
|
2622
|
+
while (start > 0 && NAME_CHAR.test(text8.charAt(start - 1))) start -= 1;
|
|
2557
2623
|
let end = at;
|
|
2558
|
-
while (end <
|
|
2559
|
-
return
|
|
2624
|
+
while (end < text8.length && NAME_CHAR.test(text8.charAt(end))) end += 1;
|
|
2625
|
+
return text8.slice(start, end).toLowerCase();
|
|
2560
2626
|
};
|
|
2561
2627
|
var ignoredName = (rule, match) => rule.ignoredNames.length > 0 && rule.ignoredNames.includes(nameAround(match.input, match.index));
|
|
2562
2628
|
var spanOf = (rule, match) => {
|
|
@@ -2566,9 +2632,9 @@ var spanOf = (rule, match) => {
|
|
|
2566
2632
|
const secret = match.input.slice(start, end);
|
|
2567
2633
|
return accepted(rule, secret) ? { rule, start, end, secret } : void 0;
|
|
2568
2634
|
};
|
|
2569
|
-
var ruleSpans = (rule,
|
|
2635
|
+
var ruleSpans = (rule, text8) => {
|
|
2570
2636
|
const spans = [];
|
|
2571
|
-
for (const match of
|
|
2637
|
+
for (const match of text8.matchAll(rule.pattern)) {
|
|
2572
2638
|
const span = spanOf(rule, match);
|
|
2573
2639
|
if (span !== void 0) spans.push(span);
|
|
2574
2640
|
}
|
|
@@ -2594,31 +2660,31 @@ var toFinding = (span, locate2) => {
|
|
|
2594
2660
|
tail: tailOf(span.secret)
|
|
2595
2661
|
};
|
|
2596
2662
|
};
|
|
2597
|
-
var scanText = (
|
|
2598
|
-
if (
|
|
2599
|
-
const rules = applicable(options.rules ?? RULES,
|
|
2663
|
+
var scanText = (text8, options = {}) => {
|
|
2664
|
+
if (text8.length === 0) return [];
|
|
2665
|
+
const rules = applicable(options.rules ?? RULES, text8.toLowerCase(), options.path);
|
|
2600
2666
|
if (rules.length === 0) return [];
|
|
2601
2667
|
const taken = [];
|
|
2602
2668
|
for (const rule of rules) {
|
|
2603
|
-
for (const span of ruleSpans(rule,
|
|
2669
|
+
for (const span of ruleSpans(rule, text8)) if (!overlaps(taken, span)) taken.push(span);
|
|
2604
2670
|
}
|
|
2605
2671
|
if (taken.length === 0) return [];
|
|
2606
|
-
const locate2 = lineLocator(
|
|
2672
|
+
const locate2 = lineLocator(text8);
|
|
2607
2673
|
return taken.sort((a, b) => a.start - b.start).map((span) => toFinding(span, locate2));
|
|
2608
2674
|
};
|
|
2609
2675
|
|
|
2610
2676
|
// src/mask/mask.ts
|
|
2611
2677
|
var maskToken = (finding4) => `«secret:${finding4.ruleId}:${finding4.tail}»`;
|
|
2612
|
-
var maskText = (
|
|
2613
|
-
const findings = scanText(
|
|
2614
|
-
if (findings.length === 0) return
|
|
2678
|
+
var maskText = (text8) => {
|
|
2679
|
+
const findings = scanText(text8, { rules: CREDENTIAL_RULES });
|
|
2680
|
+
if (findings.length === 0) return text8;
|
|
2615
2681
|
let out = "";
|
|
2616
2682
|
let cursor = 0;
|
|
2617
2683
|
for (const finding4 of findings) {
|
|
2618
|
-
out +=
|
|
2684
|
+
out += text8.slice(cursor, finding4.start) + maskToken(finding4);
|
|
2619
2685
|
cursor = finding4.end;
|
|
2620
2686
|
}
|
|
2621
|
-
return out +
|
|
2687
|
+
return out + text8.slice(cursor);
|
|
2622
2688
|
};
|
|
2623
2689
|
var maskDeep = (value) => {
|
|
2624
2690
|
if (typeof value === "string") return maskText(value);
|
|
@@ -2836,14 +2902,14 @@ var toolVersion = (env, command) => {
|
|
|
2836
2902
|
return result.ok ? result.stdout.trim().split("\n")[0] ?? "" : "not found";
|
|
2837
2903
|
};
|
|
2838
2904
|
var lastHookFailures = (env) => {
|
|
2839
|
-
const
|
|
2840
|
-
if (!
|
|
2841
|
-
return
|
|
2905
|
+
const text8 = env.runtime.readText(fmPaths(env.root).log);
|
|
2906
|
+
if (!text8.ok) return [];
|
|
2907
|
+
return text8.value.split("\n").filter((line2) => {
|
|
2842
2908
|
const parsed = line2.trim() === "" ? void 0 : parseJsonObject(line2);
|
|
2843
2909
|
return parsed?.ok === true && isRecord(parsed.value) && parsed.value["event"] === HOOK_FAILURE_EVENT;
|
|
2844
2910
|
}).slice(-MAX_FAILURES);
|
|
2845
2911
|
};
|
|
2846
|
-
var withoutHome = (
|
|
2912
|
+
var withoutHome = (text8, home) => home.length > 1 ? text8.split(home).join("~") : text8;
|
|
2847
2913
|
var reportMarkdown = (env, ctx, envelope) => {
|
|
2848
2914
|
const failures = lastHookFailures(env);
|
|
2849
2915
|
const lines3 = [
|
|
@@ -2879,9 +2945,9 @@ var YIELD_STDOUT = `${JSON.stringify({ continue: true })}
|
|
|
2879
2945
|
`;
|
|
2880
2946
|
var projectOwnsHooks = (ctx) => {
|
|
2881
2947
|
const root = ctx.env["CLAUDE_PROJECT_DIR"] ?? ctx.cwd;
|
|
2882
|
-
const
|
|
2883
|
-
if (!
|
|
2884
|
-
const parsed = parseJsonObject(
|
|
2948
|
+
const text8 = ctx.runtime.readText(toAbsolutePath(join8(root, ...SETTINGS_FILE.split("/"))));
|
|
2949
|
+
if (!text8.ok) return false;
|
|
2950
|
+
const parsed = parseJsonObject(text8.value);
|
|
2885
2951
|
return parsed.ok && ownHandlersIn(parsed.value) > 0;
|
|
2886
2952
|
};
|
|
2887
2953
|
|
|
@@ -2915,8 +2981,8 @@ var settingsPaths = (env) => {
|
|
|
2915
2981
|
];
|
|
2916
2982
|
};
|
|
2917
2983
|
var readSettings = (env) => settingsPaths(env).flatMap(({ scope: scope2, path }) => {
|
|
2918
|
-
const
|
|
2919
|
-
const parsed =
|
|
2984
|
+
const text8 = env.runtime.readText(path);
|
|
2985
|
+
const parsed = text8.ok ? parseJsonObject(text8.value) : void 0;
|
|
2920
2986
|
return parsed?.ok === true ? [{ scope: scope2, path, settings: parsed.value }] : [];
|
|
2921
2987
|
});
|
|
2922
2988
|
var scopesWith = (all, test) => all.filter(({ settings }) => test(settings)).map(({ scope: scope2 }) => scope2);
|
|
@@ -3202,7 +3268,7 @@ var editsOf = (input) => {
|
|
|
3202
3268
|
});
|
|
3203
3269
|
};
|
|
3204
3270
|
var applyEdits = (before, edits) => edits.reduce(
|
|
3205
|
-
(
|
|
3271
|
+
(text8, edit) => edit.all ? text8.split(edit.oldText).join(edit.newText) : text8.replace(edit.oldText, () => edit.newText),
|
|
3206
3272
|
before
|
|
3207
3273
|
);
|
|
3208
3274
|
|
|
@@ -3222,7 +3288,7 @@ var familyOf = (base) => {
|
|
|
3222
3288
|
if (found === void 0) throw new Error(`no reason family for ${base}`);
|
|
3223
3289
|
return found;
|
|
3224
3290
|
};
|
|
3225
|
-
var capReason = (
|
|
3291
|
+
var capReason = (text8) => text8.length <= REASON_LIMIT ? text8 : `${text8.slice(0, REASON_LIMIT - 1)}…`;
|
|
3226
3292
|
var modelReason = (t, base, params2 = {}) => {
|
|
3227
3293
|
const claim = `${base}.claim`;
|
|
3228
3294
|
const requires = `${base}.requires`;
|
|
@@ -3249,9 +3315,9 @@ var textRecord = (value) => isRecord(value) ? Object.fromEntries(
|
|
|
3249
3315
|
Object.entries(value).filter((entry2) => typeof entry2[1] === "string")
|
|
3250
3316
|
) : {};
|
|
3251
3317
|
var readJsonFile = (runtime, path) => {
|
|
3252
|
-
const
|
|
3253
|
-
if (!
|
|
3254
|
-
const parsed = parseJsonObject(
|
|
3318
|
+
const text8 = runtime.readText(path);
|
|
3319
|
+
if (!text8.ok) return void 0;
|
|
3320
|
+
const parsed = parseJsonObject(text8.value);
|
|
3255
3321
|
return parsed.ok ? parsed.value : void 0;
|
|
3256
3322
|
};
|
|
3257
3323
|
var writeJsonFile = (runtime, path, value) => runtime.writeText(path, `${JSON.stringify({ schemaVersion: 1, ...value }, null, 2)}
|
|
@@ -3364,7 +3430,7 @@ var SHELL_TOOLS = /* @__PURE__ */ new Set(["Bash", "PowerShell"]);
|
|
|
3364
3430
|
import { posix } from "node:path";
|
|
3365
3431
|
|
|
3366
3432
|
// src/shell/scan.ts
|
|
3367
|
-
var cursorOf = (
|
|
3433
|
+
var cursorOf = (text8) => ({ text: text8, pos: 0, incomplete: false, subs: [] });
|
|
3368
3434
|
var peek = (cursor, offset = 0) => cursor.text.charAt(cursor.pos + offset);
|
|
3369
3435
|
var atEnd = (cursor) => cursor.pos >= cursor.text.length;
|
|
3370
3436
|
var skipQuoted = (cursor, quote) => {
|
|
@@ -3579,8 +3645,8 @@ var nextToken = (cursor, tokens, pending) => {
|
|
|
3579
3645
|
tokens.push({ kind: "op", text: op });
|
|
3580
3646
|
if (op === "\n") flushHeredocs(cursor, tokens, pending);
|
|
3581
3647
|
};
|
|
3582
|
-
var lexBash = (
|
|
3583
|
-
const cursor = cursorOf(
|
|
3648
|
+
var lexBash = (text8) => {
|
|
3649
|
+
const cursor = cursorOf(text8.replace(/\r\n/g, "\n"));
|
|
3584
3650
|
const tokens = [];
|
|
3585
3651
|
const pending = [];
|
|
3586
3652
|
skipBlank(cursor);
|
|
@@ -3728,9 +3794,9 @@ var next = (cursor, tokens, cmd) => {
|
|
|
3728
3794
|
}
|
|
3729
3795
|
const op = OPERATORS2.find((candidate) => cursor.text.startsWith(candidate, cursor.pos));
|
|
3730
3796
|
if (op !== void 0 || cmd && peek(cursor) === "&") {
|
|
3731
|
-
const
|
|
3732
|
-
cursor.pos +=
|
|
3733
|
-
tokens.push({ kind: "op", text:
|
|
3797
|
+
const text8 = op ?? "&";
|
|
3798
|
+
cursor.pos += text8.length;
|
|
3799
|
+
tokens.push({ kind: "op", text: text8 });
|
|
3734
3800
|
return;
|
|
3735
3801
|
}
|
|
3736
3802
|
if ((peek(cursor) === "&" || peek(cursor) === ".") && peek(cursor, 1) === " " && commandStart(tokens)) {
|
|
@@ -3739,8 +3805,8 @@ var next = (cursor, tokens, cmd) => {
|
|
|
3739
3805
|
}
|
|
3740
3806
|
tokens.push(word(cursor, cmd));
|
|
3741
3807
|
};
|
|
3742
|
-
var lexPowerShell = (
|
|
3743
|
-
const cursor = cursorOf(
|
|
3808
|
+
var lexPowerShell = (text8, cmd = false) => {
|
|
3809
|
+
const cursor = cursorOf(text8.replace(/\r\n/g, "\n"));
|
|
3744
3810
|
const tokens = [];
|
|
3745
3811
|
const skip = () => {
|
|
3746
3812
|
while (peek(cursor) === " " || peek(cursor) === " ") cursor.pos += 1;
|
|
@@ -3943,7 +4009,7 @@ var MAX_DEPTH = 8;
|
|
|
3943
4009
|
var ASSIGNMENT2 = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/s;
|
|
3944
4010
|
var PS_ENV = /^\$env:([A-Za-z_][A-Za-z0-9_]*)=?(.*)$/is;
|
|
3945
4011
|
var CHANGES_DIR = /* @__PURE__ */ new Set(["cd", "pushd", "set-location", "push-location"]);
|
|
3946
|
-
var lex = (
|
|
4012
|
+
var lex = (text8, language) => language === "bash" ? lexBash(text8) : lexPowerShell(text8, language === "cmd");
|
|
3947
4013
|
var isWindowsAbsolute = (path) => /^[A-Za-z]:\//.test(path);
|
|
3948
4014
|
var joinDir = (current2, target2) => {
|
|
3949
4015
|
const next2 = toPosixPath(target2);
|
|
@@ -4014,21 +4080,21 @@ var visit = (raw, language, context, depth, collector) => {
|
|
|
4014
4080
|
emit(result.stage, raw, language, context, collector);
|
|
4015
4081
|
for (const extra of result.extra) emit(extra, raw, language, context, collector);
|
|
4016
4082
|
};
|
|
4017
|
-
var collect = (
|
|
4083
|
+
var collect = (text8, language, context, depth, collector) => {
|
|
4018
4084
|
if (depth > MAX_DEPTH) {
|
|
4019
4085
|
collector.incomplete = true;
|
|
4020
4086
|
return;
|
|
4021
4087
|
}
|
|
4022
|
-
const lexed = lex(
|
|
4088
|
+
const lexed = lex(text8, language);
|
|
4023
4089
|
if (lexed.incomplete) collector.incomplete = true;
|
|
4024
4090
|
for (const substitution of lexed.substitutions) {
|
|
4025
4091
|
collect(substitution, language, { ...context }, depth + 1, collector);
|
|
4026
4092
|
}
|
|
4027
4093
|
for (const raw of rawCommands(lexed.tokens)) visit(raw, language, context, depth, collector);
|
|
4028
4094
|
};
|
|
4029
|
-
var normalizeCommand = (
|
|
4095
|
+
var normalizeCommand = (text8, dialect = "bash") => {
|
|
4030
4096
|
const collector = { out: [], incomplete: false };
|
|
4031
|
-
collect(
|
|
4097
|
+
collect(text8, dialect, { env: {}, dir: void 0, via: [] }, 0, collector);
|
|
4032
4098
|
return { commands: collector.out, incomplete: collector.incomplete };
|
|
4033
4099
|
};
|
|
4034
4100
|
var dialectOf = (toolName3) => toolName3 === "PowerShell" ? "powershell" : "bash";
|
|
@@ -4040,7 +4106,7 @@ var segmentsOf = (command) => normalizeCommand(command).commands.map((item2) =>
|
|
|
4040
4106
|
|
|
4041
4107
|
// src/guards/shell.ts
|
|
4042
4108
|
var HEREDOC = /^<<[-<]?$/;
|
|
4043
|
-
var parseShell = (
|
|
4109
|
+
var parseShell = (text8) => normalizeCommand(text8).commands.map((command) => ({
|
|
4044
4110
|
env: command.env,
|
|
4045
4111
|
argv: command.program === "" ? [] : [command.program, ...command.args],
|
|
4046
4112
|
redirects: command.redirects.filter((redirect) => !HEREDOC.test(redirect.op)).map((redirect) => redirect.target)
|
|
@@ -4202,9 +4268,9 @@ var writtenPaths = (command) => {
|
|
|
4202
4268
|
if (name === "git" && GIT_WRITERS.has(operands2[0] ?? "")) return [...command.redirects, ...operands2.slice(1)];
|
|
4203
4269
|
return command.redirects;
|
|
4204
4270
|
};
|
|
4205
|
-
var mentioned = (
|
|
4206
|
-
if (/\.finitemonkey[\\/]allow/.test(
|
|
4207
|
-
if (/\.finitemonkey|\.gitleaksignore/.test(
|
|
4271
|
+
var mentioned = (text8) => {
|
|
4272
|
+
if (/\.finitemonkey[\\/]allow/.test(text8)) return "allow_store";
|
|
4273
|
+
if (/\.finitemonkey|\.gitleaksignore/.test(text8)) return "policy";
|
|
4208
4274
|
return void 0;
|
|
4209
4275
|
};
|
|
4210
4276
|
var bashSelfTargets = (root, commandLine) => parseShell(commandLine).flatMap(
|
|
@@ -4408,8 +4474,8 @@ var compareConfig = (path, before, after, accepted2) => {
|
|
|
4408
4474
|
// src/guards/tests/hook.ts
|
|
4409
4475
|
var localPath = (root, path) => toPosixPath(relative3(root, toAbsolutePath(path, root)));
|
|
4410
4476
|
var read = (input, path) => {
|
|
4411
|
-
const
|
|
4412
|
-
return
|
|
4477
|
+
const text8 = input.runtime.readText(path);
|
|
4478
|
+
return text8.ok ? text8.value : void 0;
|
|
4413
4479
|
};
|
|
4414
4480
|
var proposed = (tool, args2, before) => {
|
|
4415
4481
|
if (tool === "Write") return textField(args2, "content") ?? "";
|
|
@@ -4484,7 +4550,7 @@ var contextOutput = (event, additionalContext, systemMessage) => ({
|
|
|
4484
4550
|
hookSpecificOutput: { hookEventName: event, additionalContext },
|
|
4485
4551
|
...systemMessage === void 0 ? {} : { systemMessage }
|
|
4486
4552
|
});
|
|
4487
|
-
var human = (
|
|
4553
|
+
var human = (text8) => `finitemonkey: ${text8}`;
|
|
4488
4554
|
|
|
4489
4555
|
// src/look/reads.ts
|
|
4490
4556
|
var READS_FILE = "look-reads.json";
|
|
@@ -4546,8 +4612,8 @@ var parseMarkers = (prompt) => {
|
|
|
4546
4612
|
// src/policy/pause.ts
|
|
4547
4613
|
var PAUSE_FILE = "pause.json";
|
|
4548
4614
|
var readPause = (runtime, paths) => {
|
|
4549
|
-
const
|
|
4550
|
-
const parsed =
|
|
4615
|
+
const text8 = runtime.readText(paths.cache(PAUSE_FILE));
|
|
4616
|
+
const parsed = text8.ok ? parseJsonObject(text8.value) : void 0;
|
|
4551
4617
|
if (parsed?.ok !== true || !isRecord(parsed.value)) return void 0;
|
|
4552
4618
|
const { sessionId, since, by } = parsed.value;
|
|
4553
4619
|
if (typeof sessionId !== "string" || typeof since !== "string") return void 0;
|
|
@@ -4602,9 +4668,9 @@ var countIn = (value) => {
|
|
|
4602
4668
|
if (Array.isArray(value)) return value.reduce((sum, item2) => sum + countIn(item2), 0);
|
|
4603
4669
|
return isRecord(value) ? Object.values(value).reduce((sum, item2) => sum + countIn(item2), 0) : 0;
|
|
4604
4670
|
};
|
|
4605
|
-
var censusOf = (
|
|
4606
|
-
if (
|
|
4607
|
-
const parsed = parseJsonObject(
|
|
4671
|
+
var censusOf = (text8) => {
|
|
4672
|
+
if (text8 === void 0) return { hooks: 0, disabled: false };
|
|
4673
|
+
const parsed = parseJsonObject(text8);
|
|
4608
4674
|
if (!parsed.ok) return void 0;
|
|
4609
4675
|
return { hooks: countIn(parsed.value["hooks"]), disabled: parsed.value["disableAllHooks"] === true };
|
|
4610
4676
|
};
|
|
@@ -4614,8 +4680,8 @@ var settingsFiles = (paths, env) => [
|
|
|
4614
4680
|
...env["HOME"] === void 0 ? [] : [toAbsolutePath(join13(env["HOME"], ".claude", "settings.json"))]
|
|
4615
4681
|
];
|
|
4616
4682
|
var read2 = (runtime, path) => {
|
|
4617
|
-
const
|
|
4618
|
-
return
|
|
4683
|
+
const text8 = runtime.readText(path);
|
|
4684
|
+
return text8.ok ? text8.value : void 0;
|
|
4619
4685
|
};
|
|
4620
4686
|
var known = (runtime, paths) => {
|
|
4621
4687
|
const raw = readJsonFile(runtime, paths.cache(CONFIG_FILE3))?.["hooks"];
|
|
@@ -4670,9 +4736,9 @@ var LOCKFILES2 = [
|
|
|
4670
4736
|
];
|
|
4671
4737
|
var packageManager = (files) => LOCKFILES2.find(([file]) => files.exists(file))?.[1] ?? "npm";
|
|
4672
4738
|
var scriptChecks = (files) => {
|
|
4673
|
-
const
|
|
4674
|
-
if (
|
|
4675
|
-
const parsed = parseJsonObject(
|
|
4739
|
+
const text8 = files.read("package.json");
|
|
4740
|
+
if (text8 === void 0) return [];
|
|
4741
|
+
const parsed = parseJsonObject(text8);
|
|
4676
4742
|
const scripts = parsed.ok ? parsed.value["scripts"] : void 0;
|
|
4677
4743
|
if (!isRecord(scripts)) return [];
|
|
4678
4744
|
const pm = packageManager(files);
|
|
@@ -4762,16 +4828,16 @@ var unescapeDouble = (body2) => {
|
|
|
4762
4828
|
}
|
|
4763
4829
|
return accept(out);
|
|
4764
4830
|
};
|
|
4765
|
-
var quotedEnd = (
|
|
4766
|
-
const quote =
|
|
4767
|
-
for (let index = start + 1; index <
|
|
4768
|
-
const char =
|
|
4831
|
+
var quotedEnd = (text8, start) => {
|
|
4832
|
+
const quote = text8[start];
|
|
4833
|
+
for (let index = start + 1; index < text8.length; index += 1) {
|
|
4834
|
+
const char = text8[index];
|
|
4769
4835
|
if (quote === '"' && char === "\\") {
|
|
4770
4836
|
index += 1;
|
|
4771
4837
|
continue;
|
|
4772
4838
|
}
|
|
4773
4839
|
if (char !== quote) continue;
|
|
4774
|
-
if (quote === "'" &&
|
|
4840
|
+
if (quote === "'" && text8[index + 1] === "'") {
|
|
4775
4841
|
index += 1;
|
|
4776
4842
|
continue;
|
|
4777
4843
|
}
|
|
@@ -4779,20 +4845,20 @@ var quotedEnd = (text7, start) => {
|
|
|
4779
4845
|
}
|
|
4780
4846
|
return -1;
|
|
4781
4847
|
};
|
|
4782
|
-
var parseQuoted = (
|
|
4783
|
-
const end = quotedEnd(
|
|
4784
|
-
if (end !==
|
|
4785
|
-
const body2 =
|
|
4786
|
-
return
|
|
4848
|
+
var parseQuoted = (text8) => {
|
|
4849
|
+
const end = quotedEnd(text8, 0);
|
|
4850
|
+
if (end !== text8.length - 1) return reject(`unterminated or trailing text after quoted string`);
|
|
4851
|
+
const body2 = text8.slice(1, -1);
|
|
4852
|
+
return text8.startsWith('"') ? unescapeDouble(body2) : accept(body2.replace(/''/g, "'"));
|
|
4787
4853
|
};
|
|
4788
4854
|
var NUMBER = /^-?(0|[1-9]\d*)(\.\d+)?([eE][-+]?\d+)?$/;
|
|
4789
4855
|
var UNSUPPORTED = /^[&*!|>%@`]/;
|
|
4790
|
-
var parsePlain = (
|
|
4791
|
-
if (UNSUPPORTED.test(
|
|
4792
|
-
if (
|
|
4793
|
-
if (
|
|
4794
|
-
if (NUMBER.test(
|
|
4795
|
-
return accept(
|
|
4856
|
+
var parsePlain = (text8) => {
|
|
4857
|
+
if (UNSUPPORTED.test(text8)) return reject(`unsupported YAML syntax "${text8.slice(0, 1)}"`);
|
|
4858
|
+
if (text8 === "true" || text8 === "false") return accept(text8 === "true");
|
|
4859
|
+
if (text8 === "null" || text8 === "~") return accept(null);
|
|
4860
|
+
if (NUMBER.test(text8)) return accept(Number(text8));
|
|
4861
|
+
return accept(text8);
|
|
4796
4862
|
};
|
|
4797
4863
|
|
|
4798
4864
|
// src/core/yaml/flow.ts
|
|
@@ -4819,17 +4885,17 @@ var splitTop = (body2) => {
|
|
|
4819
4885
|
if (last.trim() !== "" || parts.length > 0) parts.push(last);
|
|
4820
4886
|
return accept(parts.map((part2) => part2.trim()));
|
|
4821
4887
|
};
|
|
4822
|
-
var splitKey = (
|
|
4888
|
+
var splitKey = (text8) => {
|
|
4823
4889
|
let index = 0;
|
|
4824
|
-
if (
|
|
4825
|
-
index = quotedEnd(
|
|
4890
|
+
if (text8.startsWith('"') || text8.startsWith("'")) {
|
|
4891
|
+
index = quotedEnd(text8, 0) + 1;
|
|
4826
4892
|
if (index <= 0) return void 0;
|
|
4827
4893
|
}
|
|
4828
|
-
for (; index <
|
|
4829
|
-
const char =
|
|
4830
|
-
if (char === "#" &&
|
|
4831
|
-
if (char === ":" && (index + 1 ===
|
|
4832
|
-
return { key:
|
|
4894
|
+
for (; index < text8.length; index += 1) {
|
|
4895
|
+
const char = text8[index];
|
|
4896
|
+
if (char === "#" && text8[index - 1] === " ") return void 0;
|
|
4897
|
+
if (char === ":" && (index + 1 === text8.length || text8[index + 1] === " ")) {
|
|
4898
|
+
return { key: text8.slice(0, index).trim(), rest: text8.slice(index + 1).trim() };
|
|
4833
4899
|
}
|
|
4834
4900
|
}
|
|
4835
4901
|
return void 0;
|
|
@@ -4858,39 +4924,39 @@ var flowSeq = (parts) => {
|
|
|
4858
4924
|
}
|
|
4859
4925
|
return accept(out);
|
|
4860
4926
|
};
|
|
4861
|
-
var parseValue = (
|
|
4862
|
-
if (
|
|
4863
|
-
const first =
|
|
4864
|
-
if (first === '"' || first === "'") return parseQuoted(
|
|
4927
|
+
var parseValue = (text8) => {
|
|
4928
|
+
if (text8 === "") return accept(null);
|
|
4929
|
+
const first = text8[0] ?? "";
|
|
4930
|
+
if (first === '"' || first === "'") return parseQuoted(text8);
|
|
4865
4931
|
const close2 = OPEN[first];
|
|
4866
|
-
if (close2 === void 0) return parsePlain(
|
|
4867
|
-
if (!
|
|
4868
|
-
const parts = splitTop(
|
|
4932
|
+
if (close2 === void 0) return parsePlain(text8);
|
|
4933
|
+
if (!text8.endsWith(close2)) return reject(`flow collection must end on the same line with "${close2}"`);
|
|
4934
|
+
const parts = splitTop(text8.slice(1, -1));
|
|
4869
4935
|
if (!parts.ok) return parts;
|
|
4870
4936
|
return first === "[" ? flowSeq(parts.value) : flowMap(parts.value);
|
|
4871
4937
|
};
|
|
4872
4938
|
|
|
4873
4939
|
// src/core/yaml/parse.ts
|
|
4874
4940
|
var BOM = new RegExp(`^${String.fromCharCode(65279)}`);
|
|
4875
|
-
var stripComment2 = (
|
|
4876
|
-
for (let index = 0; index <
|
|
4877
|
-
const char =
|
|
4941
|
+
var stripComment2 = (text8) => {
|
|
4942
|
+
for (let index = 0; index < text8.length; index += 1) {
|
|
4943
|
+
const char = text8[index];
|
|
4878
4944
|
if (char === '"' || char === "'") {
|
|
4879
|
-
const end = quotedEnd(
|
|
4880
|
-
if (end < 0) return
|
|
4945
|
+
const end = quotedEnd(text8, index);
|
|
4946
|
+
if (end < 0) return text8;
|
|
4881
4947
|
index = end;
|
|
4882
|
-
} else if (char === "#" && (index === 0 ||
|
|
4948
|
+
} else if (char === "#" && (index === 0 || text8[index - 1] === " ")) return text8.slice(0, index);
|
|
4883
4949
|
}
|
|
4884
|
-
return
|
|
4950
|
+
return text8;
|
|
4885
4951
|
};
|
|
4886
4952
|
var toLines = (source) => {
|
|
4887
4953
|
const lines3 = [];
|
|
4888
4954
|
const raw = source.replace(BOM, "").split(/\r?\n/);
|
|
4889
4955
|
for (const [index, full] of raw.entries()) {
|
|
4890
|
-
const
|
|
4891
|
-
const body2 =
|
|
4956
|
+
const text8 = stripComment2(full).trimEnd();
|
|
4957
|
+
const body2 = text8.trimStart();
|
|
4892
4958
|
if (body2 === "" || body2 === "---" && lines3.length === 0) continue;
|
|
4893
|
-
const indentText =
|
|
4959
|
+
const indentText = text8.slice(0, text8.length - body2.length);
|
|
4894
4960
|
if (indentText.includes(" ")) return reject({ line: index + 1, message: "tabs are not allowed for indentation" });
|
|
4895
4961
|
if (body2 === "---" || body2 === "...")
|
|
4896
4962
|
return reject({ line: index + 1, message: "only one YAML document is allowed" });
|
|
@@ -4899,11 +4965,11 @@ var toLines = (source) => {
|
|
|
4899
4965
|
return accept(lines3);
|
|
4900
4966
|
};
|
|
4901
4967
|
var fail = (line2, message) => reject({ line: line2?.number ?? 0, message });
|
|
4902
|
-
var scalar = (line2,
|
|
4903
|
-
const value = parseValue(
|
|
4968
|
+
var scalar = (line2, text8) => {
|
|
4969
|
+
const value = parseValue(text8);
|
|
4904
4970
|
return value.ok ? value : fail(line2, value.error);
|
|
4905
4971
|
};
|
|
4906
|
-
var isItem = (
|
|
4972
|
+
var isItem = (text8) => text8 === "-" || text8.startsWith("- ");
|
|
4907
4973
|
var child = (lines3, index, parent, sameIndentSeq) => {
|
|
4908
4974
|
const next2 = lines3[index];
|
|
4909
4975
|
if (next2 !== void 0 && next2.indent > parent.indent) return block(lines3, index, next2.indent);
|
|
@@ -5146,8 +5212,8 @@ var validateContract = (value, implicit = false) => {
|
|
|
5146
5212
|
// src/task/load.ts
|
|
5147
5213
|
var contractHash = (contract) => sha256Hex(JSON.stringify(contract.acceptance.map((check2) => [check2.id, check2.kind, check2.run ?? ""])));
|
|
5148
5214
|
var taskRelative = (id) => `.finitemonkey/tasks/${id}.yml`;
|
|
5149
|
-
var parseContract = (id,
|
|
5150
|
-
const yaml = parseYaml(
|
|
5215
|
+
var parseContract = (id, text8) => {
|
|
5216
|
+
const yaml = parseYaml(text8);
|
|
5151
5217
|
if (!yaml.ok)
|
|
5152
5218
|
return reject({ kind: "invalid", id, issues: [`line ${String(yaml.error.line)}: ${yaml.error.message}`] });
|
|
5153
5219
|
const valid = validateContract(yaml.value);
|
|
@@ -5257,10 +5323,10 @@ var resolveBase = (git2, declared) => {
|
|
|
5257
5323
|
const merged2 = remote === void 0 ? void 0 : git2.out(["merge-base", "HEAD", remote])?.trim();
|
|
5258
5324
|
return nonEmpty(merged2) ?? nonEmpty(headSha(git2)) ?? EMPTY_TREE;
|
|
5259
5325
|
};
|
|
5260
|
-
var nulFields = (
|
|
5326
|
+
var nulFields = (text8) => text8.split("\0").filter((part2) => part2 !== "");
|
|
5261
5327
|
var untracked = (git2) => nulFields(git2.out(["ls-files", "--others", "--exclude-standard", "-z", "--", ".", EXCLUDE_FM]) ?? "");
|
|
5262
|
-
var parseNameStatus = (
|
|
5263
|
-
const fields = nulFields(
|
|
5328
|
+
var parseNameStatus = (text8) => {
|
|
5329
|
+
const fields = nulFields(text8);
|
|
5264
5330
|
const changes = [];
|
|
5265
5331
|
for (let index = 0; index < fields.length; index += 1) {
|
|
5266
5332
|
const code = fields[index] ?? "";
|
|
@@ -5328,8 +5394,8 @@ var aheadOfUpstream = (git2) => {
|
|
|
5328
5394
|
|
|
5329
5395
|
// src/gate/diff-shape.ts
|
|
5330
5396
|
var untrackedLines = (runtime, root, changes) => changes.filter((change) => change.status === "A").reduce((sum, change) => {
|
|
5331
|
-
const
|
|
5332
|
-
return sum + (
|
|
5397
|
+
const text8 = runtime.readText(toAbsolutePath(join14(root, change.path)));
|
|
5398
|
+
return sum + (text8.ok ? text8.value.split("\n").length : 0);
|
|
5333
5399
|
}, 0);
|
|
5334
5400
|
var diffShape = (runtime, git2, base, changes) => ({
|
|
5335
5401
|
files: changes.map((change) => change.path),
|
|
@@ -5352,8 +5418,8 @@ var ciChecks = (value) => Array.isArray(value) ? value.flatMap((item2) => {
|
|
|
5352
5418
|
const name = optionalString(item2, "name") ?? optionalString(item2, "context") ?? "?";
|
|
5353
5419
|
return [{ name, state: ciState(item2) }];
|
|
5354
5420
|
}) : [];
|
|
5355
|
-
var parsePrView = (
|
|
5356
|
-
const parsed = parseJsonObject(
|
|
5421
|
+
var parsePrView = (text8) => {
|
|
5422
|
+
const parsed = parseJsonObject(text8);
|
|
5357
5423
|
if (!parsed.ok) return void 0;
|
|
5358
5424
|
const record3 = parsed.value;
|
|
5359
5425
|
const number2 = record3["number"];
|
|
@@ -5534,8 +5600,8 @@ var applySize = (contract, verdict) => {
|
|
|
5534
5600
|
// src/gate/prepare.ts
|
|
5535
5601
|
var diskFiles = (runtime, root) => ({
|
|
5536
5602
|
read: (relative11) => {
|
|
5537
|
-
const
|
|
5538
|
-
return
|
|
5603
|
+
const text8 = runtime.readText(toAbsolutePath(join15(root, relative11)));
|
|
5604
|
+
return text8.ok ? text8.value : void 0;
|
|
5539
5605
|
},
|
|
5540
5606
|
exists: (relative11) => runtime.stat(toAbsolutePath(join15(root, relative11))) !== void 0
|
|
5541
5607
|
});
|
|
@@ -5656,11 +5722,11 @@ var trust = (input, paths, task) => {
|
|
|
5656
5722
|
});
|
|
5657
5723
|
if (ready.kind !== "ready" || ready.prepared.ctx.contract.id !== task) return false;
|
|
5658
5724
|
const lock = readTrust(runtime, paths);
|
|
5659
|
-
const
|
|
5725
|
+
const text8 = runtime.readText(paths.task(task));
|
|
5660
5726
|
return writeTrust(runtime, paths, {
|
|
5661
5727
|
...lock,
|
|
5662
5728
|
contracts: { ...lock.contracts, [task]: ready.prepared.loaded.hash },
|
|
5663
|
-
approved: task === IMPLICIT_ID || !
|
|
5729
|
+
approved: task === IMPLICIT_ID || !text8.ok ? lock.approved : { ...lock.approved, [task]: text8.value }
|
|
5664
5730
|
}).ok;
|
|
5665
5731
|
};
|
|
5666
5732
|
var apply = (input, paths, markers) => {
|
|
@@ -5712,8 +5778,8 @@ var promptRelease = (input) => {
|
|
|
5712
5778
|
var PRS_CACHE_MS = 10 * 6e4;
|
|
5713
5779
|
var PRS_TIMEOUT_MS = 3e3;
|
|
5714
5780
|
var PRS_AUTH_TIMEOUT_MS = 2e3;
|
|
5715
|
-
var parsePrList = (
|
|
5716
|
-
const parsed = parseJson(
|
|
5781
|
+
var parsePrList = (text8) => {
|
|
5782
|
+
const parsed = parseJson(text8);
|
|
5717
5783
|
if (!parsed.ok || !Array.isArray(parsed.value)) return void 0;
|
|
5718
5784
|
return parsed.value.flatMap((item2) => {
|
|
5719
5785
|
if (!isRecord(item2) || typeof item2["number"] !== "number") return [];
|
|
@@ -6513,7 +6579,13 @@ var en_default = {
|
|
|
6513
6579
|
"reason.human.generic": "Blocked a tool call; the reason went to Claude.",
|
|
6514
6580
|
"review.command.packet": "Print the review packet for the reviewer and verifier agents: diff, task contract, evidence ledger and REVIEW.md, never the conversation",
|
|
6515
6581
|
"review.guard.read_only": "blocked: the {agent} agent is read-only and cannot use {tool}. Report the finding; the main session makes the change.",
|
|
6516
|
-
"review.error.no_base": "the base {detail} is not a commit here"
|
|
6582
|
+
"review.error.no_base": "the base {detail} is not a commit here",
|
|
6583
|
+
"command.statusline.summary": "Print the status line: active task, gate state and context use",
|
|
6584
|
+
"statusline.gate.green": "gate green",
|
|
6585
|
+
"statusline.gate.red": "gate red",
|
|
6586
|
+
"statusline.gate.incomplete": "gate incomplete",
|
|
6587
|
+
"statusline.gate.did_not_run": "gate did not run",
|
|
6588
|
+
"statusline.context": "ctx {percent}%"
|
|
6517
6589
|
};
|
|
6518
6590
|
|
|
6519
6591
|
// src/i18n/es.json
|
|
@@ -7165,7 +7237,13 @@ var es_default = {
|
|
|
7165
7237
|
"reason.human.generic": "Bloqueé una llamada de herramienta; el motivo fue a Claude.",
|
|
7166
7238
|
"review.command.packet": "Muestra el paquete de revisión para los agentes revisor y verificador: diff, contrato de la tarea, registro de evidencias y REVIEW.md, nunca la conversación",
|
|
7167
7239
|
"review.guard.read_only": "bloqueado: el agente {agent} es de solo lectura y no puede usar {tool}. Informa el hallazgo; la sesión principal hace el cambio.",
|
|
7168
|
-
"review.error.no_base": "la base {detail} no es un commit aquí"
|
|
7240
|
+
"review.error.no_base": "la base {detail} no es un commit aquí",
|
|
7241
|
+
"command.statusline.summary": "Imprime la línea de estado: tarea activa, estado de la compuerta y uso del contexto",
|
|
7242
|
+
"statusline.gate.green": "compuerta verde",
|
|
7243
|
+
"statusline.gate.red": "compuerta roja",
|
|
7244
|
+
"statusline.gate.incomplete": "compuerta incompleta",
|
|
7245
|
+
"statusline.gate.did_not_run": "la compuerta no se ejecutó",
|
|
7246
|
+
"statusline.context": "ctx {percent}%"
|
|
7169
7247
|
};
|
|
7170
7248
|
|
|
7171
7249
|
// src/i18n/pt-BR.json
|
|
@@ -7817,7 +7895,13 @@ var pt_BR_default = {
|
|
|
7817
7895
|
"reason.human.generic": "Bloqueei uma chamada de ferramenta; o motivo foi para o Claude.",
|
|
7818
7896
|
"review.command.packet": "Mostra o pacote de revisão para os agentes revisor e verificador: diff, contrato da tarefa, registro de evidências e REVIEW.md, nunca a conversa",
|
|
7819
7897
|
"review.guard.read_only": "bloqueado: o agente {agent} é só leitura e não pode usar {tool}. Relate o achado; a sessão principal faz a mudança.",
|
|
7820
|
-
"review.error.no_base": "a base {detail} não é um commit aqui"
|
|
7898
|
+
"review.error.no_base": "a base {detail} não é um commit aqui",
|
|
7899
|
+
"command.statusline.summary": "Imprime a linha de status: tarefa ativa, estado do portão e uso do contexto",
|
|
7900
|
+
"statusline.gate.green": "portão verde",
|
|
7901
|
+
"statusline.gate.red": "portão vermelho",
|
|
7902
|
+
"statusline.gate.incomplete": "portão incompleto",
|
|
7903
|
+
"statusline.gate.did_not_run": "portão não rodou",
|
|
7904
|
+
"statusline.context": "ctx {percent}%"
|
|
7821
7905
|
};
|
|
7822
7906
|
|
|
7823
7907
|
// src/i18n/review.json
|
|
@@ -8470,7 +8554,13 @@ var review_default = {
|
|
|
8470
8554
|
"reason.human.generic": "machine",
|
|
8471
8555
|
"review.command.packet": "machine",
|
|
8472
8556
|
"review.guard.read_only": "machine",
|
|
8473
|
-
"review.error.no_base": "machine"
|
|
8557
|
+
"review.error.no_base": "machine",
|
|
8558
|
+
"command.statusline.summary": "machine",
|
|
8559
|
+
"statusline.gate.green": "machine",
|
|
8560
|
+
"statusline.gate.red": "machine",
|
|
8561
|
+
"statusline.gate.incomplete": "machine",
|
|
8562
|
+
"statusline.gate.did_not_run": "machine",
|
|
8563
|
+
"statusline.context": "machine"
|
|
8474
8564
|
},
|
|
8475
8565
|
es: {
|
|
8476
8566
|
"command.init.summary": "machine",
|
|
@@ -9120,7 +9210,13 @@ var review_default = {
|
|
|
9120
9210
|
"reason.human.generic": "machine",
|
|
9121
9211
|
"review.command.packet": "machine",
|
|
9122
9212
|
"review.guard.read_only": "machine",
|
|
9123
|
-
"review.error.no_base": "machine"
|
|
9213
|
+
"review.error.no_base": "machine",
|
|
9214
|
+
"command.statusline.summary": "machine",
|
|
9215
|
+
"statusline.gate.green": "machine",
|
|
9216
|
+
"statusline.gate.red": "machine",
|
|
9217
|
+
"statusline.gate.incomplete": "machine",
|
|
9218
|
+
"statusline.gate.did_not_run": "machine",
|
|
9219
|
+
"statusline.context": "machine"
|
|
9124
9220
|
}
|
|
9125
9221
|
};
|
|
9126
9222
|
|
|
@@ -9410,10 +9506,10 @@ var pairs = (record3) => {
|
|
|
9410
9506
|
return names.filter((name) => typeof name === "string").map((name) => `${task}\0${name}`);
|
|
9411
9507
|
};
|
|
9412
9508
|
var callersRate = (runtime, paths) => {
|
|
9413
|
-
const
|
|
9509
|
+
const text8 = runtime.readText(paths.log);
|
|
9414
9510
|
const flagged = /* @__PURE__ */ new Set();
|
|
9415
9511
|
const released2 = /* @__PURE__ */ new Set();
|
|
9416
|
-
for (const line2 of
|
|
9512
|
+
for (const line2 of text8.ok ? text8.value.split("\n") : []) {
|
|
9417
9513
|
const parsed = line2.trim() === "" ? void 0 : parseJsonObject(line2);
|
|
9418
9514
|
if (parsed === void 0 || !parsed.ok || !isRecord(parsed.value)) continue;
|
|
9419
9515
|
const event = parsed.value["event"];
|
|
@@ -9438,7 +9534,7 @@ import { posix as posix2 } from "node:path";
|
|
|
9438
9534
|
var JS_SPECIFIER = /(?:\bfrom\s*|\bimport\s*\(?\s*|\brequire\s*\(\s*)["']([^"']+)["']/g;
|
|
9439
9535
|
var JS_EXTENSION = /\.(?:[cm]?[jt]sx?)$/;
|
|
9440
9536
|
var stripModule = (path) => path.replace(JS_EXTENSION, "").replace(/\/index$/, "");
|
|
9441
|
-
var jsSpecifiers = (
|
|
9537
|
+
var jsSpecifiers = (text8) => [...text8.matchAll(JS_SPECIFIER)].map((match) => match[1] ?? "");
|
|
9442
9538
|
var jsImports = (callerPath, callerText, origin) => {
|
|
9443
9539
|
const target2 = stripModule(origin);
|
|
9444
9540
|
return jsSpecifiers(callerText).some((specifier) => {
|
|
@@ -9540,9 +9636,9 @@ var languageOf = (path) => {
|
|
|
9540
9636
|
const extension = extname(path).toLowerCase();
|
|
9541
9637
|
return LANGUAGES2.find((language) => language.extensions.includes(extension));
|
|
9542
9638
|
};
|
|
9543
|
-
var definitionsIn = (language,
|
|
9639
|
+
var definitionsIn = (language, text8) => {
|
|
9544
9640
|
const names = /* @__PURE__ */ new Set();
|
|
9545
|
-
for (const line2 of
|
|
9641
|
+
for (const line2 of text8.split(/\r?\n/)) {
|
|
9546
9642
|
for (const pattern of language.definitions) {
|
|
9547
9643
|
const name = pattern.exec(line2)?.[1];
|
|
9548
9644
|
if (name !== void 0 && !KEYWORDS.has(name)) names.add(name);
|
|
@@ -9555,8 +9651,8 @@ var definesName = (language, line2, name) => language.definitions.some((pattern)
|
|
|
9555
9651
|
// src/gate/callers/scan.ts
|
|
9556
9652
|
var MAX_SYMBOLS = 200;
|
|
9557
9653
|
var current = (runtime, root, path) => {
|
|
9558
|
-
const
|
|
9559
|
-
return
|
|
9654
|
+
const text8 = runtime.readText(toAbsolutePath(join16(root, path)));
|
|
9655
|
+
return text8.ok ? text8.value : "";
|
|
9560
9656
|
};
|
|
9561
9657
|
var keyOf = (language, name) => `${language.id}\0${name}`;
|
|
9562
9658
|
var redefinedNames = (runtime, git2, changes) => {
|
|
@@ -9597,14 +9693,14 @@ var grep = (git2, names) => {
|
|
|
9597
9693
|
git2.out(["grep", "-n", "-z", "-w", "-I", "--untracked", "--no-color", ...patterns, "--", ".", EXCLUDE_FM]) ?? ""
|
|
9598
9694
|
);
|
|
9599
9695
|
};
|
|
9600
|
-
var mentions = (
|
|
9696
|
+
var mentions = (text8, name) => new RegExp(`(?<![\\w$])${name.replace(/[$?!]/g, "\\$&")}(?![\\w$])`).test(text8);
|
|
9601
9697
|
var callSites = (runtime, git2, symbols) => {
|
|
9602
9698
|
const hits = grep(git2, [...new Set(symbols.map((symbol) => symbol.name))]);
|
|
9603
9699
|
const texts2 = /* @__PURE__ */ new Map();
|
|
9604
9700
|
const textOf4 = (file) => {
|
|
9605
|
-
const
|
|
9606
|
-
texts2.set(file,
|
|
9607
|
-
return
|
|
9701
|
+
const cached3 = texts2.get(file) ?? current(runtime, git2.cwd, file);
|
|
9702
|
+
texts2.set(file, cached3);
|
|
9703
|
+
return cached3;
|
|
9608
9704
|
};
|
|
9609
9705
|
return symbols.flatMap(
|
|
9610
9706
|
(symbol) => hits.filter((hit3) => languageOf(hit3.file)?.id === symbol.language.id && mentions(hit3.text, symbol.name)).filter((hit3) => !symbol.language.comment.test(hit3.text) && !definesName(symbol.language, hit3.text, symbol.name)).filter((hit3) => importsOrigin(symbol.language, hit3.file, textOf4(hit3.file), symbol.origins)).map((hit3) => ({ name: symbol.name, file: hit3.file, line: hit3.line }))
|
|
@@ -9672,31 +9768,31 @@ var ZERO = [
|
|
|
9672
9768
|
/^ℹ tests 0$/m,
|
|
9673
9769
|
/No tests found/
|
|
9674
9770
|
];
|
|
9675
|
-
var pyTotal = (
|
|
9676
|
-
const line2 = /^=+ (.*) in [\d.]+s.*=+$/m.exec(
|
|
9771
|
+
var pyTotal = (text8) => {
|
|
9772
|
+
const line2 = /^=+ (.*) in [\d.]+s.*=+$/m.exec(text8)?.[1];
|
|
9677
9773
|
if (line2 === void 0) return void 0;
|
|
9678
9774
|
return [...line2.matchAll(/(\d+) (passed|failed|error|errors|skipped|xfailed|xpassed)/g)].reduce(
|
|
9679
9775
|
(sum, match) => sum + Number(match[1] ?? "0"),
|
|
9680
9776
|
0
|
|
9681
9777
|
);
|
|
9682
9778
|
};
|
|
9683
|
-
var counted = (
|
|
9779
|
+
var counted = (text8) => {
|
|
9684
9780
|
for (const counter of COUNTERS) {
|
|
9685
|
-
const total = counter.total.exec(
|
|
9781
|
+
const total = counter.total.exec(text8)?.[1];
|
|
9686
9782
|
if (total === void 0) continue;
|
|
9687
|
-
const failed4 = counter.failed?.exec(
|
|
9783
|
+
const failed4 = counter.failed?.exec(text8)?.[1];
|
|
9688
9784
|
return { total: Number(total), ...failed4 === void 0 ? {} : { failed: Number(failed4) } };
|
|
9689
9785
|
}
|
|
9690
|
-
const py = pyTotal(
|
|
9786
|
+
const py = pyTotal(text8);
|
|
9691
9787
|
return py === void 0 ? {} : { total: py };
|
|
9692
9788
|
};
|
|
9693
9789
|
var parseTestSummary = (output) => {
|
|
9694
|
-
const
|
|
9790
|
+
const text8 = output.replace(ANSI2, "");
|
|
9695
9791
|
const failures = [
|
|
9696
|
-
...new Set(FAILURE_LINES.flatMap((pattern) => [...
|
|
9792
|
+
...new Set(FAILURE_LINES.flatMap((pattern) => [...text8.matchAll(pattern)].map((match) => (match[1] ?? "").trim())))
|
|
9697
9793
|
].filter((name) => name !== "" && !/^failing tests:?$/i.test(name));
|
|
9698
|
-
if (ZERO.some((pattern) => pattern.test(
|
|
9699
|
-
return { ...counted(
|
|
9794
|
+
if (ZERO.some((pattern) => pattern.test(text8))) return { total: 0, failures };
|
|
9795
|
+
return { ...counted(text8), failures };
|
|
9700
9796
|
};
|
|
9701
9797
|
|
|
9702
9798
|
// src/gate/checks/command.ts
|
|
@@ -9707,8 +9803,8 @@ var REWRITERS = /^\s*(rtk)\b/;
|
|
|
9707
9803
|
var TRIVIAL = /* @__PURE__ */ new Set(["echo", "true", ":", "printf", "exit", "sleep", "cat", "yes", "pwd", "ls", "date", "env"]);
|
|
9708
9804
|
var TAIL = 160;
|
|
9709
9805
|
var MAX_FAILURES2 = 5;
|
|
9710
|
-
var tail = (
|
|
9711
|
-
const lines3 =
|
|
9806
|
+
var tail = (text8) => {
|
|
9807
|
+
const lines3 = text8.split(/\r?\n/).filter((line2) => line2.trim() !== "");
|
|
9712
9808
|
const last = lines3[lines3.length - 1]?.trim() ?? "";
|
|
9713
9809
|
return last.length > TAIL ? `${last.slice(0, TAIL)}…` : last;
|
|
9714
9810
|
};
|
|
@@ -9922,8 +10018,8 @@ var findingNote = (value) => {
|
|
|
9922
10018
|
];
|
|
9923
10019
|
};
|
|
9924
10020
|
var readSummary = (ctx) => {
|
|
9925
|
-
const
|
|
9926
|
-
const parsed =
|
|
10021
|
+
const text8 = ctx.runtime.readText(summaryPath(ctx.paths, ctx.treeHash));
|
|
10022
|
+
const parsed = text8.ok ? parseJsonObject(text8.value) : void 0;
|
|
9927
10023
|
if (!parsed?.ok) return void 0;
|
|
9928
10024
|
const { at, captures, findings, ignoredAllows } = parsed.value;
|
|
9929
10025
|
if (typeof at !== "string" || !Array.isArray(captures) || !Array.isArray(findings)) return void 0;
|
|
@@ -9992,8 +10088,8 @@ var SKIP_FILES = /\.(md|mdx|txt|rst|lock|snap|svg|png|jpg|gif|json)$|(^|\/)(CHAN
|
|
|
9992
10088
|
var PLACEHOLDER = /\b(TODO|FIXME|XXX)\b|not implemented|NotImplementedError|unimplemented!|todo!\(|lorem ipsum/i;
|
|
9993
10089
|
var findPlaceholders = (lines3) => lines3.filter((line2) => !isTestFile(line2.path) && !SKIP_FILES.test(line2.path) && PLACEHOLDER.test(line2.text));
|
|
9994
10090
|
var untrackedAdded = (ctx) => ctx.changes.filter((change) => change.status === "A" && !SKIP_FILES.test(change.path)).flatMap((change) => {
|
|
9995
|
-
const
|
|
9996
|
-
return
|
|
10091
|
+
const text8 = ctx.runtime.readText(toAbsolutePath(join20(ctx.paths.root, change.path)));
|
|
10092
|
+
return text8.ok ? text8.value.split("\n").map((line2, index) => ({ path: change.path, line: index + 1, text: line2 })) : [];
|
|
9997
10093
|
});
|
|
9998
10094
|
var placeholdersCheck = (_check, ctx) => {
|
|
9999
10095
|
const tracked = addedLines(ctx.git, ctx.base);
|
|
@@ -10052,7 +10148,7 @@ var prOutcome = (check2, ctx) => {
|
|
|
10052
10148
|
|
|
10053
10149
|
// src/prose/preset.ts
|
|
10054
10150
|
var PRESET_LINE = /^preset:\s*([A-Za-z0-9_-]+)\s*$/m;
|
|
10055
|
-
var presetFromConfig = (
|
|
10151
|
+
var presetFromConfig = (text8) => parsePreset(PRESET_LINE.exec(text8)?.[1]) ?? "neutral";
|
|
10056
10152
|
var projectPreset = (runtime, root) => {
|
|
10057
10153
|
const config = runtime.readText(toAbsolutePath(CONFIG_FILE, root));
|
|
10058
10154
|
return config.ok ? presetFromConfig(config.value) : "neutral";
|
|
@@ -10229,16 +10325,16 @@ var ANY_MARKER = /<!--\s*finitemonkey:prose-allow(?:-file)?\s*-->/g;
|
|
|
10229
10325
|
var INLINE_CODE = /`[^`]*`/g;
|
|
10230
10326
|
var FENCE2 = /^\s*(```|~~~)/;
|
|
10231
10327
|
var outsideCode = (line2) => line2.replace(INLINE_CODE, "");
|
|
10232
|
-
var unfencedLines = (
|
|
10328
|
+
var unfencedLines = (text8) => {
|
|
10233
10329
|
let fenced = false;
|
|
10234
|
-
return
|
|
10330
|
+
return text8.split("\n").filter((line2) => {
|
|
10235
10331
|
if (FENCE2.test(line2)) fenced = !fenced;
|
|
10236
10332
|
return !fenced && !FENCE2.test(line2);
|
|
10237
10333
|
});
|
|
10238
10334
|
};
|
|
10239
|
-
var allowsWholeFile = (
|
|
10335
|
+
var allowsWholeFile = (text8) => unfencedLines(text8).some((line2) => FILE_MARKER.test(outsideCode(line2)));
|
|
10240
10336
|
var allowsLine = (line2) => LINE_MARKER.test(outsideCode(line2));
|
|
10241
|
-
var markerCount = (
|
|
10337
|
+
var markerCount = (text8) => text8.match(ANY_MARKER)?.length ?? 0;
|
|
10242
10338
|
var isMarkerOnlyLine = (line2) => allowsLine(line2) && outsideCode(line2).replace(LINE_MARKER, "").trim() === "";
|
|
10243
10339
|
|
|
10244
10340
|
// src/prose/extract.ts
|
|
@@ -10258,7 +10354,7 @@ var MASKS = [
|
|
|
10258
10354
|
[/<[^>]+>/g, ""],
|
|
10259
10355
|
[/\*\*|__/g, ""]
|
|
10260
10356
|
];
|
|
10261
|
-
var maskInline = (line2) => MASKS.reduce((
|
|
10357
|
+
var maskInline = (line2) => MASKS.reduce((text8, [pattern, replacement]) => text8.replace(pattern, replacement), line2);
|
|
10262
10358
|
var BlockReader = class {
|
|
10263
10359
|
blocks = [];
|
|
10264
10360
|
current;
|
|
@@ -10349,8 +10445,8 @@ var splitBlock = (block4) => {
|
|
|
10349
10445
|
return joined.split(SENTENCE_END).flatMap((sentence) => {
|
|
10350
10446
|
const at = joined.indexOf(sentence, offset);
|
|
10351
10447
|
offset = at + sentence.length;
|
|
10352
|
-
const
|
|
10353
|
-
return
|
|
10448
|
+
const text8 = sentence.trim();
|
|
10449
|
+
return text8 === "" ? [] : [{ text: text8, line: lineAt(at) }];
|
|
10354
10450
|
});
|
|
10355
10451
|
};
|
|
10356
10452
|
var unitsOf = (blocks) => {
|
|
@@ -10371,9 +10467,9 @@ var unitsOf = (blocks) => {
|
|
|
10371
10467
|
}));
|
|
10372
10468
|
});
|
|
10373
10469
|
};
|
|
10374
|
-
var extractProse = (
|
|
10375
|
-
if (allowsWholeFile(
|
|
10376
|
-
const lines3 =
|
|
10470
|
+
var extractProse = (text8) => {
|
|
10471
|
+
if (allowsWholeFile(text8)) return { units: [], allowed: true };
|
|
10472
|
+
const lines3 = text8.split("\n").map(withoutCarriageReturn);
|
|
10377
10473
|
return { units: unitsOf(readBlocks(lines3)), allowed: false };
|
|
10378
10474
|
};
|
|
10379
10475
|
|
|
@@ -10498,7 +10594,7 @@ var CONNECTIVES = new Set(
|
|
|
10498
10594
|
" "
|
|
10499
10595
|
)
|
|
10500
10596
|
);
|
|
10501
|
-
var wordsOf = (
|
|
10597
|
+
var wordsOf = (text8) => text8.split(/\s+/).filter((word2) => WORD.test(word2));
|
|
10502
10598
|
var hit = (rule, units, index, weight) => {
|
|
10503
10599
|
const unit = units[index];
|
|
10504
10600
|
return { rule, unit: index, line: unit?.line ?? 0, weight, excerpt: unit?.text ?? "" };
|
|
@@ -10626,8 +10722,8 @@ var mergeSpans = (hits, windows) => {
|
|
|
10626
10722
|
return ranges.map(([from, to]) => spanOf2(hits, from, to)).filter((span) => span.hits.length > 0);
|
|
10627
10723
|
};
|
|
10628
10724
|
var byPosition = (left, right) => left.unit - right.unit || left.line - right.line;
|
|
10629
|
-
var scoreProse = (
|
|
10630
|
-
const { units, allowed: allowed2 } = extractProse(
|
|
10725
|
+
var scoreProse = (text8, options = {}) => {
|
|
10726
|
+
const { units, allowed: allowed2 } = extractProse(text8);
|
|
10631
10727
|
const size = options.window ?? DENSITY_WINDOW;
|
|
10632
10728
|
const threshold2 = options.threshold ?? DENSITY_THRESHOLD;
|
|
10633
10729
|
const catalog = options.context === "record" ? [...phraseRules(), ...recordRules()] : phraseRules();
|
|
@@ -10659,9 +10755,9 @@ var changedMarkdown = (runtime, root) => {
|
|
|
10659
10755
|
var scoreFiles = (runtime, root, files, forced) => {
|
|
10660
10756
|
const reports = [];
|
|
10661
10757
|
for (const file of files) {
|
|
10662
|
-
const
|
|
10663
|
-
if (!
|
|
10664
|
-
reports.push({ file: toPosixPath(file), report: scoreProse(
|
|
10758
|
+
const text8 = runtime.readText(toAbsolutePath(file, root));
|
|
10759
|
+
if (!text8.ok) return reject(`${file}: ${text8.error}`);
|
|
10760
|
+
reports.push({ file: toPosixPath(file), report: scoreProse(text8.value, { context: forced ?? contextOf(file) }) });
|
|
10665
10761
|
}
|
|
10666
10762
|
return accept(reports);
|
|
10667
10763
|
};
|
|
@@ -10760,8 +10856,8 @@ var parseAppCheck = (stdout) => {
|
|
|
10760
10856
|
var PROBE_MARGIN_MS = 15e3;
|
|
10761
10857
|
var MIN_REMAINING_MS2 = 5e3;
|
|
10762
10858
|
var TAIL2 = 160;
|
|
10763
|
-
var lastLine = (
|
|
10764
|
-
const rows =
|
|
10859
|
+
var lastLine = (text8) => {
|
|
10860
|
+
const rows = text8.split(/\r?\n/).filter((row) => row.trim() !== "" && !/^\s*at\s|^Node\.js v\d/.test(row));
|
|
10765
10861
|
const line2 = (rows.findLast((row) => /error/i.test(row)) ?? rows.at(-1))?.trim() ?? "";
|
|
10766
10862
|
return line2.length > TAIL2 ? `${line2.slice(0, TAIL2)}…` : line2;
|
|
10767
10863
|
};
|
|
@@ -11104,7 +11200,7 @@ var diffScanner = () => {
|
|
|
11104
11200
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
11105
11201
|
var SKIPPED = /(?:^|\/)(?:\.git|node_modules|\.finitemonkey)\//;
|
|
11106
11202
|
var DIFF_FLAGS = ["-U0", "--no-color", "--no-ext-diff", "--no-renames"];
|
|
11107
|
-
var binary = (
|
|
11203
|
+
var binary = (text8) => text8.slice(0, 8e3).includes("\0");
|
|
11108
11204
|
var listed2 = (runtime, root, target2) => {
|
|
11109
11205
|
const git2 = runtime.git(["ls-files", "-z", "--cached", "--others", "--exclude-standard", "--", target2], root);
|
|
11110
11206
|
if (git2.ok)
|
|
@@ -11117,9 +11213,9 @@ var listed2 = (runtime, root, target2) => {
|
|
|
11117
11213
|
return accept(walked.value.map((name) => toPosixPath(relative6(root, join23(base, toPosixPath(name))))));
|
|
11118
11214
|
};
|
|
11119
11215
|
var scanFile = (runtime, root, file) => {
|
|
11120
|
-
const
|
|
11121
|
-
if (!
|
|
11122
|
-
return scanText(
|
|
11216
|
+
const text8 = runtime.readText(toAbsolutePath(file, root));
|
|
11217
|
+
if (!text8.ok || text8.value.length > MAX_FILE_BYTES || binary(text8.value)) return [];
|
|
11218
|
+
return scanText(text8.value, { path: file }).map((finding4) => locate(finding4, file, finding4.line));
|
|
11123
11219
|
};
|
|
11124
11220
|
var scanPath = (runtime, root, target2) => {
|
|
11125
11221
|
const files = listed2(runtime, root, target2);
|
|
@@ -11216,8 +11312,8 @@ var treeViolations = (ctx) => {
|
|
|
11216
11312
|
changes: relevant,
|
|
11217
11313
|
before: (path) => fileAt(ctx.git, ctx.base, path),
|
|
11218
11314
|
after: (path) => {
|
|
11219
|
-
const
|
|
11220
|
-
return
|
|
11315
|
+
const text8 = ctx.runtime.readText(toAbsolutePath(join24(ctx.paths.root, path)));
|
|
11316
|
+
return text8.ok ? text8.value : void 0;
|
|
11221
11317
|
},
|
|
11222
11318
|
acceptedConfigs: ctx.trust.configs,
|
|
11223
11319
|
scopePaths: ctx.contract.scope.paths,
|
|
@@ -11381,10 +11477,10 @@ var bodyLine = (draft, line2) => {
|
|
|
11381
11477
|
else if (line2.startsWith("+")) draft.current.added.push(line2.slice(1));
|
|
11382
11478
|
};
|
|
11383
11479
|
var DIFF_GIT = /^diff --git a\/(.+) b\/(.+)$/;
|
|
11384
|
-
var parseUnifiedDiff = (
|
|
11480
|
+
var parseUnifiedDiff = (text8) => {
|
|
11385
11481
|
const out = [];
|
|
11386
11482
|
let draft;
|
|
11387
|
-
for (const raw of
|
|
11483
|
+
for (const raw of text8.split("\n")) {
|
|
11388
11484
|
const line2 = withoutCarriageReturn(raw);
|
|
11389
11485
|
const start = DIFF_GIT.exec(line2);
|
|
11390
11486
|
if (start !== null) {
|
|
@@ -11485,10 +11581,10 @@ var mergeInProgress = (runtime, repo) => revParse(runtime, repo, "MERGE_HEAD") !
|
|
|
11485
11581
|
|
|
11486
11582
|
// src/git/facts.ts
|
|
11487
11583
|
var memo2 = (compute) => {
|
|
11488
|
-
let
|
|
11584
|
+
let cached3;
|
|
11489
11585
|
return () => {
|
|
11490
|
-
|
|
11491
|
-
return
|
|
11586
|
+
cached3 ??= { value: compute() };
|
|
11587
|
+
return cached3.value;
|
|
11492
11588
|
};
|
|
11493
11589
|
};
|
|
11494
11590
|
var memoBy = (compute) => {
|
|
@@ -11535,7 +11631,7 @@ var normalizeLine = (line2) => line2.replace(/\r$/, "").trim().replace(/\s*,$/,
|
|
|
11535
11631
|
var WEAK = /^[\p{P}\p{S}\s]+$/u;
|
|
11536
11632
|
var isWeak = (line2) => WEAK.test(line2);
|
|
11537
11633
|
var meaningful = (lines3) => lines3.map(normalizeLine).filter((line2) => line2 !== "");
|
|
11538
|
-
var contentLines = (
|
|
11634
|
+
var contentLines = (text8) => text8 === void 0 ? [] : meaningful(text8.split("\n"));
|
|
11539
11635
|
var countLines = (lines3) => {
|
|
11540
11636
|
const counts = /* @__PURE__ */ new Map();
|
|
11541
11637
|
for (const line2 of lines3) counts.set(line2, (counts.get(line2) ?? 0) + 1);
|
|
@@ -11584,16 +11680,16 @@ var itemOf = (value) => {
|
|
|
11584
11680
|
approvedBy: optionalString(value, "approved_by")
|
|
11585
11681
|
};
|
|
11586
11682
|
};
|
|
11587
|
-
var invalidFinding = (file,
|
|
11683
|
+
var invalidFinding = (file, text8) => ({
|
|
11588
11684
|
kind: "invalid-dropped",
|
|
11589
11685
|
file,
|
|
11590
11686
|
side: void 0,
|
|
11591
11687
|
line: void 0,
|
|
11592
|
-
text:
|
|
11688
|
+
text: text8,
|
|
11593
11689
|
weak: false
|
|
11594
11690
|
});
|
|
11595
|
-
var parseDropped = (
|
|
11596
|
-
const parsed = parseJson(
|
|
11691
|
+
var parseDropped = (text8) => {
|
|
11692
|
+
const parsed = parseJson(text8);
|
|
11597
11693
|
if (!parsed.ok) return parsed;
|
|
11598
11694
|
const list4 = isRecord(parsed.value) ? parsed.value["dropped"] : parsed.value;
|
|
11599
11695
|
if (!Array.isArray(list4)) return reject("expected a list of dropped items");
|
|
@@ -11609,9 +11705,9 @@ var parseDropped = (text7) => {
|
|
|
11609
11705
|
};
|
|
11610
11706
|
var loadDropped = (runtime, root, file) => {
|
|
11611
11707
|
const path = toAbsolutePath(file ?? join26(root, DROPPED_FILE), root);
|
|
11612
|
-
const
|
|
11613
|
-
if (!
|
|
11614
|
-
return parseDropped(
|
|
11708
|
+
const text8 = runtime.readText(path);
|
|
11709
|
+
if (!text8.ok) return file === void 0 ? accept({ items: [], invalid: [] }) : reject(`${file}: ${text8.error}`);
|
|
11710
|
+
return parseDropped(text8.value);
|
|
11615
11711
|
};
|
|
11616
11712
|
var isDropped = (finding4, items) => items.some(
|
|
11617
11713
|
(item2) => item2.file === finding4.file && (item2.side === void 0 || finding4.side === void 0 || item2.side === finding4.side) && (item2.text === void 0 || normalizeLine(item2.text) === finding4.text)
|
|
@@ -11734,13 +11830,13 @@ var removalOf = (ours, theirs, paired) => {
|
|
|
11734
11830
|
var missingAdditions = (hunks, file, elsewhere) => {
|
|
11735
11831
|
const present2 = new Set(file.result);
|
|
11736
11832
|
return hunks.flatMap(({ side, hunk, added }) => {
|
|
11737
|
-
const
|
|
11738
|
-
if (
|
|
11833
|
+
const text8 = added.find((line2) => !isWeak(line2) && !present2.has(line2));
|
|
11834
|
+
if (text8 === void 0 || containsSequence(file.result, added) || elsewhere(added)) return [];
|
|
11739
11835
|
const offset = Math.max(
|
|
11740
11836
|
0,
|
|
11741
|
-
hunk.added.findIndex((line2) => normalizeLine(line2) ===
|
|
11837
|
+
hunk.added.findIndex((line2) => normalizeLine(line2) === text8)
|
|
11742
11838
|
);
|
|
11743
|
-
return [{ kind: "missing-addition", file: file.path, side, line: hunk.newStart + offset, text:
|
|
11839
|
+
return [{ kind: "missing-addition", file: file.path, side, line: hunk.newStart + offset, text: text8, weak: false }];
|
|
11744
11840
|
});
|
|
11745
11841
|
};
|
|
11746
11842
|
var expectations = (file, hunks, removal) => {
|
|
@@ -11813,8 +11909,8 @@ var symbolsOf = (line2) => {
|
|
|
11813
11909
|
...title === void 0 ? [] : [{ name: title, test: true }]
|
|
11814
11910
|
];
|
|
11815
11911
|
};
|
|
11816
|
-
var escapeRegex = (
|
|
11817
|
-
var containsSymbol = (
|
|
11912
|
+
var escapeRegex = (text8) => text8.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11913
|
+
var containsSymbol = (text8, symbol) => symbol.test ? text8.includes(symbol.name) : new RegExp(`(?<![\\w$])${escapeRegex(symbol.name)}(?![\\w$])`).test(text8);
|
|
11818
11914
|
var missingSymbols = (file, side, hunks, present2) => {
|
|
11819
11915
|
const seen = /* @__PURE__ */ new Set();
|
|
11820
11916
|
return hunks.flatMap(
|
|
@@ -11833,12 +11929,12 @@ var created2 = (diff) => diff?.status === "added" || diff?.status === "copied";
|
|
|
11833
11929
|
var resultPathOf = (context, pair) => [pair.ours?.newPath, pair.theirs?.newPath, pair.key].find(
|
|
11834
11930
|
(path) => path !== void 0 && context.resultText(path) !== void 0
|
|
11835
11931
|
);
|
|
11836
|
-
var finding2 = (kind, file, side,
|
|
11932
|
+
var finding2 = (kind, file, side, text8) => ({
|
|
11837
11933
|
kind,
|
|
11838
11934
|
file,
|
|
11839
11935
|
side,
|
|
11840
11936
|
line: void 0,
|
|
11841
|
-
text:
|
|
11937
|
+
text: text8,
|
|
11842
11938
|
weak: false
|
|
11843
11939
|
});
|
|
11844
11940
|
var binaryFindings = (context, pair, path) => {
|
|
@@ -11857,8 +11953,8 @@ var binaryFindings = (context, pair, path) => {
|
|
|
11857
11953
|
return result === expected ? [] : [finding2("binary", file, side, file)];
|
|
11858
11954
|
};
|
|
11859
11955
|
var elsewhereOf = (context) => (lines3) => context.resultFiles().some((path) => containsSequence(contentLines(context.resultText(path)), lines3));
|
|
11860
|
-
var symbolFindings = (context, pair, path,
|
|
11861
|
-
const present2 = (symbol) =>
|
|
11956
|
+
var symbolFindings = (context, pair, path, text8) => {
|
|
11957
|
+
const present2 = (symbol) => text8 !== void 0 && containsSymbol(text8, symbol) || context.resultFiles().some((other) => containsSymbol(context.resultText(other) ?? "", symbol));
|
|
11862
11958
|
return [
|
|
11863
11959
|
...missingSymbols(path, "ours", pair.ours?.hunks ?? [], present2),
|
|
11864
11960
|
...missingSymbols(path, "theirs", pair.theirs?.hunks ?? [], present2)
|
|
@@ -11874,19 +11970,19 @@ var verifyFile = (context, pair) => {
|
|
|
11874
11970
|
const copied = [pair.ours, pair.theirs].find((diff) => diff?.status === "copied");
|
|
11875
11971
|
const baseSource = copied?.oldPath ?? (created2(pair.ours) || created2(pair.theirs) ? void 0 : pair.key);
|
|
11876
11972
|
const baseText = baseSource === void 0 ? void 0 : blobText(context.runtime, context.repo, context.inputs.base, baseSource);
|
|
11877
|
-
const
|
|
11973
|
+
const text8 = path === void 0 ? void 0 : context.resultText(path);
|
|
11878
11974
|
const file = path ?? pair.key;
|
|
11879
11975
|
const lines3 = checkFile(
|
|
11880
11976
|
{
|
|
11881
11977
|
path: file,
|
|
11882
11978
|
base: contentLines(baseText),
|
|
11883
|
-
result: contentLines(
|
|
11979
|
+
result: contentLines(text8),
|
|
11884
11980
|
ours: pair.ours?.hunks ?? [],
|
|
11885
11981
|
theirs: pair.theirs?.hunks ?? []
|
|
11886
11982
|
},
|
|
11887
11983
|
elsewhereOf(context)
|
|
11888
11984
|
);
|
|
11889
|
-
return [...lines3, ...symbolFindings(context, pair, file,
|
|
11985
|
+
return [...lines3, ...symbolFindings(context, pair, file, text8)];
|
|
11890
11986
|
};
|
|
11891
11987
|
|
|
11892
11988
|
// src/git/merge/verify.ts
|
|
@@ -12006,8 +12102,8 @@ var hashesOf = (value) => isRecord(value) ? Object.fromEntries(
|
|
|
12006
12102
|
Object.entries(value).filter((entry2) => typeof entry2[1] === "string")
|
|
12007
12103
|
) : {};
|
|
12008
12104
|
var readObject = (runtime, path) => {
|
|
12009
|
-
const
|
|
12010
|
-
return
|
|
12105
|
+
const text8 = runtime.readText(path);
|
|
12106
|
+
return text8.ok ? parseJsonObject(text8.value) : text8;
|
|
12011
12107
|
};
|
|
12012
12108
|
var readBaseline2 = (runtime, repo, owner) => {
|
|
12013
12109
|
const parsed = readObject(runtime, fileOf(repo, "baseline", owner));
|
|
@@ -12073,7 +12169,7 @@ var foreignFiles = (runtime, repo, owner, targets2) => {
|
|
|
12073
12169
|
};
|
|
12074
12170
|
|
|
12075
12171
|
// src/git/gate-status.ts
|
|
12076
|
-
var lines = (
|
|
12172
|
+
var lines = (text8) => text8.split("\n").filter((line2) => line2.trim() !== "");
|
|
12077
12173
|
var unpushedSince = (runtime, repo, since) => {
|
|
12078
12174
|
if (lines(runtime.git(["remote"], repo.root).stdout).length === 0) return [];
|
|
12079
12175
|
const result = runtime.git(["rev-list", `${since}..HEAD`, "--not", "--remotes"], repo.root);
|
|
@@ -12477,8 +12573,8 @@ var subagentStart = (input) => {
|
|
|
12477
12573
|
const active = readState(runtime, paths).active;
|
|
12478
12574
|
if (active === void 0) return { kind: "allow" };
|
|
12479
12575
|
const disk = (relative11) => {
|
|
12480
|
-
const
|
|
12481
|
-
return
|
|
12576
|
+
const text8 = runtime.readText(toAbsolutePath(join29(paths.root, relative11)));
|
|
12577
|
+
return text8.ok ? text8.value : void 0;
|
|
12482
12578
|
};
|
|
12483
12579
|
const loaded = loadTask(runtime, paths, { disk, base: () => void 0 }, active);
|
|
12484
12580
|
if (!loaded.ok) return { kind: "allow" };
|
|
@@ -12504,8 +12600,8 @@ import { join as join31 } from "node:path";
|
|
|
12504
12600
|
|
|
12505
12601
|
// src/git/command-text.ts
|
|
12506
12602
|
var MAX_SHOWN = 160;
|
|
12507
|
-
var shown = (
|
|
12508
|
-
const flat =
|
|
12603
|
+
var shown = (text8) => {
|
|
12604
|
+
const flat = text8.replace(/\s+/g, " ").trim();
|
|
12509
12605
|
return flat.length > MAX_SHOWN ? `${flat.slice(0, MAX_SHOWN - 3)}...` : flat;
|
|
12510
12606
|
};
|
|
12511
12607
|
var commandText = (command) => shown([command.program, ...command.args].join(" "));
|
|
@@ -12855,9 +12951,9 @@ var SSH_URL = /ssh:\/\/(?:[^@\s/]+@)?([A-Za-z0-9.-]+)/g;
|
|
|
12855
12951
|
var HOST_KEY = /^\s*-?\s*(?:host|hostname|server|ssh_host|deploy_host|remote_host)\s*:\s*["']?([A-Za-z0-9][A-Za-z0-9.-]*)["']?\s*$/i;
|
|
12856
12952
|
var hostKey = (raw) => raw.trim().toLowerCase().replace(/^[^@]*@/, "").replace(/^\[([^\]]+)\].*$/, "$1").replace(/:\d+$/, "").replace(/\.$/, "");
|
|
12857
12953
|
var shellLine = (line2) => line2.replace(/^\s*(?:-\s*)?(?:run:\s*\|?)?/, "");
|
|
12858
|
-
var hostsInText = (
|
|
12859
|
-
const urls = [...
|
|
12860
|
-
const lines3 =
|
|
12954
|
+
var hostsInText = (text8) => {
|
|
12955
|
+
const urls = [...text8.matchAll(SSH_URL)].map((match) => match[1] ?? "");
|
|
12956
|
+
const lines3 = text8.split(/\r?\n/);
|
|
12861
12957
|
const keyed = lines3.flatMap((line2) => {
|
|
12862
12958
|
const match = HOST_KEY.exec(line2);
|
|
12863
12959
|
return match?.[1] === void 0 ? [] : [match[1]];
|
|
@@ -12871,8 +12967,8 @@ var workflowFiles = (runtime, root) => {
|
|
|
12871
12967
|
return listed4.value.filter((name) => /deploy/i.test(name) && /\.ya?ml$/i.test(name)).map((name) => `.github/workflows/${name}`);
|
|
12872
12968
|
};
|
|
12873
12969
|
var detectedHosts = (runtime, root, files) => files.flatMap((file) => {
|
|
12874
|
-
const
|
|
12875
|
-
return
|
|
12970
|
+
const text8 = runtime.readText(toAbsolutePath(join30(root, file)));
|
|
12971
|
+
return text8.ok ? hostsInText(text8.value) : [];
|
|
12876
12972
|
});
|
|
12877
12973
|
var loadProdTargets = (runtime, root, config) => {
|
|
12878
12974
|
const workflows = workflowFiles(runtime, root);
|
|
@@ -13046,8 +13142,8 @@ var prodGuard = (runtime, root, t) => {
|
|
|
13046
13142
|
if (!PROD_PROGRAMS.has(command.program)) return void 0;
|
|
13047
13143
|
const hit3 = prodHit(command, targets2(), isProd);
|
|
13048
13144
|
if (hit3 === void 0) return void 0;
|
|
13049
|
-
const
|
|
13050
|
-
return hit3.effect === "read" ? { kind: "read", hit: hit3, command:
|
|
13145
|
+
const text8 = commandText(command);
|
|
13146
|
+
return hit3.effect === "read" ? { kind: "read", hit: hit3, command: text8 } : blockOf(t, hit3, text8, targets2().deployPath);
|
|
13051
13147
|
}
|
|
13052
13148
|
};
|
|
13053
13149
|
};
|
|
@@ -13067,8 +13163,8 @@ var recordEvidence = (runtime, root, owner, reads) => {
|
|
|
13067
13163
|
const path = toAbsolutePath(join31(root, EVIDENCE_FILE));
|
|
13068
13164
|
runtime.mkdir(toAbsolutePath(join31(root, ".finitemonkey")));
|
|
13069
13165
|
const before = runtime.readText(path);
|
|
13070
|
-
const
|
|
13071
|
-
runtime.writeAtomic(path, `${
|
|
13166
|
+
const text8 = before.ok ? before.value : "";
|
|
13167
|
+
runtime.writeAtomic(path, `${text8}${text8 === "" || text8.endsWith("\n") ? "" : "\n"}${lines3.join("\n")}
|
|
13072
13168
|
`);
|
|
13073
13169
|
};
|
|
13074
13170
|
|
|
@@ -13083,15 +13179,15 @@ var editTexts = (input, file) => {
|
|
|
13083
13179
|
if (!Array.isArray(edits)) return [];
|
|
13084
13180
|
return edits.flatMap((edit) => {
|
|
13085
13181
|
if (!isRecord(edit)) return [];
|
|
13086
|
-
const
|
|
13087
|
-
return
|
|
13182
|
+
const text8 = optionalString(edit, "new_string");
|
|
13183
|
+
return text8 === void 0 ? [] : [{ file, text: text8, whole: false }];
|
|
13088
13184
|
});
|
|
13089
13185
|
};
|
|
13090
13186
|
var writtenTexts = (tool, input) => {
|
|
13091
13187
|
const file = optionalString(input, "file_path") ?? optionalString(input, "notebook_path") ?? "";
|
|
13092
13188
|
const single2 = (key, whole) => {
|
|
13093
|
-
const
|
|
13094
|
-
return
|
|
13189
|
+
const text8 = optionalString(input, key);
|
|
13190
|
+
return text8 === void 0 ? [] : [{ file, text: text8, whole }];
|
|
13095
13191
|
};
|
|
13096
13192
|
switch (tool) {
|
|
13097
13193
|
case "Write":
|
|
@@ -13773,24 +13869,24 @@ var withChain = (facts, chain) => {
|
|
|
13773
13869
|
const branch = chain?.branch;
|
|
13774
13870
|
return branch === void 0 ? facts : { ...facts, currentBranch: () => branch };
|
|
13775
13871
|
};
|
|
13776
|
-
var decide = (context, repo, verdict, facts,
|
|
13872
|
+
var decide = (context, repo, verdict, facts, text8) => {
|
|
13777
13873
|
switch (verdict.kind) {
|
|
13778
13874
|
case "pass":
|
|
13779
13875
|
return { kind: "pass" };
|
|
13780
13876
|
case "block":
|
|
13781
|
-
return { kind: "block", rule: verdict.rule, subject: verdict.subject, command:
|
|
13877
|
+
return { kind: "block", rule: verdict.rule, subject: verdict.subject, command: text8 };
|
|
13782
13878
|
case "snapshot":
|
|
13783
|
-
return { kind: "snapshot", repo, op: verdict.op, command:
|
|
13879
|
+
return { kind: "snapshot", repo, op: verdict.op, command: text8 };
|
|
13784
13880
|
case "discard": {
|
|
13785
13881
|
const entries = facts.dirty();
|
|
13786
|
-
if (entries === void 0) return { kind: "unknown", command:
|
|
13882
|
+
if (entries === void 0) return { kind: "unknown", command: text8 };
|
|
13787
13883
|
const foreign = foreignFiles(
|
|
13788
13884
|
context.runtime,
|
|
13789
13885
|
repo,
|
|
13790
13886
|
context.owner,
|
|
13791
13887
|
targetsOf(entries, verdict.discard, facts.prefix)
|
|
13792
13888
|
);
|
|
13793
|
-
return foreign.length > 0 ? { kind: "foreign", files: foreign, command:
|
|
13889
|
+
return foreign.length > 0 ? { kind: "foreign", files: foreign, command: text8 } : { kind: "snapshot", repo, op: verdict.op, command: text8 };
|
|
13794
13890
|
}
|
|
13795
13891
|
}
|
|
13796
13892
|
};
|
|
@@ -13907,9 +14003,9 @@ var parseJournalLine = (line2) => {
|
|
|
13907
14003
|
};
|
|
13908
14004
|
};
|
|
13909
14005
|
var readJournal = (runtime, root) => {
|
|
13910
|
-
const
|
|
13911
|
-
if (!
|
|
13912
|
-
return
|
|
14006
|
+
const text8 = runtime.readText(journalPath(root));
|
|
14007
|
+
if (!text8.ok) return [];
|
|
14008
|
+
return text8.value.split("\n").flatMap((line2) => {
|
|
13913
14009
|
const entry2 = line2.trim() === "" ? void 0 : parseJournalLine(line2);
|
|
13914
14010
|
return entry2 === void 0 ? [] : [entry2];
|
|
13915
14011
|
});
|
|
@@ -14101,9 +14197,9 @@ var review = (input, commands, owner) => {
|
|
|
14101
14197
|
return { blocked: void 0, snapshots, reads };
|
|
14102
14198
|
};
|
|
14103
14199
|
var gitPreToolUse = (input) => {
|
|
14104
|
-
const
|
|
14105
|
-
if (
|
|
14106
|
-
const commands = normalizeCommand(
|
|
14200
|
+
const text8 = shellText(input.payload);
|
|
14201
|
+
if (text8 === void 0) return ALLOW;
|
|
14202
|
+
const commands = normalizeCommand(text8, dialectOf(toolName2(input.payload))).commands;
|
|
14107
14203
|
if (commands.length === 0) return ALLOW;
|
|
14108
14204
|
const owner = ownerOf2(input.payload);
|
|
14109
14205
|
const result = review(input, commands, owner);
|
|
@@ -14165,8 +14261,8 @@ var GIT_HANDLERS = {
|
|
|
14165
14261
|
var SHADOW_FILE = "shadow.json";
|
|
14166
14262
|
var numberOf = (value) => typeof value === "number" && Number.isInteger(value) ? value : 0;
|
|
14167
14263
|
var readShadow = (runtime, paths) => {
|
|
14168
|
-
const
|
|
14169
|
-
const parsed =
|
|
14264
|
+
const text8 = runtime.readText(paths.cache(SHADOW_FILE));
|
|
14265
|
+
const parsed = text8.ok ? parseJsonObject(text8.value) : void 0;
|
|
14170
14266
|
if (parsed?.ok !== true) return {};
|
|
14171
14267
|
return Object.fromEntries(
|
|
14172
14268
|
Object.entries(parsed.value).flatMap(
|
|
@@ -14250,11 +14346,11 @@ var ASSIGNMENT3 = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
|
14250
14346
|
var WRAPPERS2 = /* @__PURE__ */ new Set(["sudo", "command", "exec", "time", "nice", "nohup", "builtin", "env"]);
|
|
14251
14347
|
var liftHeredocs = (command) => {
|
|
14252
14348
|
const heredocs = [];
|
|
14253
|
-
const
|
|
14349
|
+
const text8 = command.replace(HEREDOC2, (_match, _quote, _tag, body2) => {
|
|
14254
14350
|
heredocs.push(body2);
|
|
14255
14351
|
return `<<__FM_HEREDOC_${String(heredocs.length - 1)}__`;
|
|
14256
14352
|
});
|
|
14257
|
-
return { text:
|
|
14353
|
+
return { text: text8, heredocs };
|
|
14258
14354
|
};
|
|
14259
14355
|
var endWord = (scan) => {
|
|
14260
14356
|
if (scan.word !== void 0) scan.words.push(scan.word);
|
|
@@ -14265,23 +14361,23 @@ var endSegment = (scan) => {
|
|
|
14265
14361
|
if (scan.words.length > 0) scan.segments.push(scan.words);
|
|
14266
14362
|
scan.words = [];
|
|
14267
14363
|
};
|
|
14268
|
-
var quotedEnd2 = (
|
|
14364
|
+
var quotedEnd2 = (text8, from, quote) => {
|
|
14269
14365
|
let index = from;
|
|
14270
|
-
while (index <
|
|
14366
|
+
while (index < text8.length && text8[index] !== quote) index += quote === '"' && text8[index] === "\\" ? 2 : 1;
|
|
14271
14367
|
return index;
|
|
14272
14368
|
};
|
|
14273
14369
|
var unescape = (value) => value.replace(/\\(["\\$`])/g, "$1");
|
|
14274
|
-
var splitWords = (
|
|
14370
|
+
var splitWords = (text8) => {
|
|
14275
14371
|
const scan = { words: [], segments: [], word: void 0 };
|
|
14276
|
-
for (let index = 0; index <
|
|
14277
|
-
const char =
|
|
14372
|
+
for (let index = 0; index < text8.length; index += 1) {
|
|
14373
|
+
const char = text8[index] ?? "";
|
|
14278
14374
|
if (char === '"' || char === "'") {
|
|
14279
|
-
const end = quotedEnd2(
|
|
14280
|
-
const inner =
|
|
14375
|
+
const end = quotedEnd2(text8, index + 1, char);
|
|
14376
|
+
const inner = text8.slice(index + 1, end);
|
|
14281
14377
|
scan.word = (scan.word ?? "") + (char === '"' ? unescape(inner) : inner);
|
|
14282
14378
|
index = end;
|
|
14283
|
-
} else if (char === "\\" && index + 1 <
|
|
14284
|
-
scan.word = (scan.word ?? "") + (
|
|
14379
|
+
} else if (char === "\\" && index + 1 < text8.length) {
|
|
14380
|
+
scan.word = (scan.word ?? "") + (text8[index + 1] === "\n" ? "" : text8[index + 1] ?? "");
|
|
14285
14381
|
index += 1;
|
|
14286
14382
|
} else if (SEPARATOR.test(char)) {
|
|
14287
14383
|
endSegment(scan);
|
|
@@ -14302,8 +14398,8 @@ var segmentOf = (words) => {
|
|
|
14302
14398
|
return { program: program.split(/[\\/]/).pop() ?? program, args: words.slice(index + 1) };
|
|
14303
14399
|
};
|
|
14304
14400
|
var shellWords = (command) => {
|
|
14305
|
-
const { text:
|
|
14306
|
-
const segments = splitWords(
|
|
14401
|
+
const { text: text8, heredocs } = liftHeredocs(command);
|
|
14402
|
+
const segments = splitWords(text8).flatMap((words) => {
|
|
14307
14403
|
const segment = segmentOf(words);
|
|
14308
14404
|
return segment === void 0 ? [] : [segment];
|
|
14309
14405
|
});
|
|
@@ -14408,7 +14504,7 @@ var sourceOf = (value, isFile, segment, heredocs) => {
|
|
|
14408
14504
|
if (inline3 !== void 0) return { kind: "inline", text: inline3 };
|
|
14409
14505
|
if (!isFile) return { kind: "inline", text: value };
|
|
14410
14506
|
if (value !== "-") return { kind: "file", path: value };
|
|
14411
|
-
const piped = segment.args.map((arg) => heredocIn(arg, heredocs)).find((
|
|
14507
|
+
const piped = segment.args.map((arg) => heredocIn(arg, heredocs)).find((text8) => text8 !== void 0);
|
|
14412
14508
|
return { kind: "inline", text: piped ?? "" };
|
|
14413
14509
|
};
|
|
14414
14510
|
var collect3 = (target2, segment, args2, spec2, heredocs) => {
|
|
@@ -14505,15 +14601,15 @@ var textOf2 = (input, found) => {
|
|
|
14505
14601
|
return accept(parts.join("\n\n"));
|
|
14506
14602
|
};
|
|
14507
14603
|
var decisionFor = (input, found, blocking2) => {
|
|
14508
|
-
const
|
|
14509
|
-
if (!
|
|
14604
|
+
const text8 = textOf2(input, found);
|
|
14605
|
+
if (!text8.ok) {
|
|
14510
14606
|
return blocking2 ? {
|
|
14511
14607
|
kind: "block",
|
|
14512
|
-
reason: modelReason(input.t, "prose.block.unreadable", { ...
|
|
14608
|
+
reason: modelReason(input.t, "prose.block.unreadable", { ...text8.error }),
|
|
14513
14609
|
human: input.t("prose.block.human")
|
|
14514
14610
|
} : void 0;
|
|
14515
14611
|
}
|
|
14516
|
-
const report2 = scoreProse(
|
|
14612
|
+
const report2 = scoreProse(text8.value, { context: "record" });
|
|
14517
14613
|
if (report2.allowed || report2.spans.length === 0) return void 0;
|
|
14518
14614
|
const params2 = {
|
|
14519
14615
|
target: input.t(TARGET_KEYS[found.target]),
|
|
@@ -14560,7 +14656,7 @@ var HOOK_ACTOR = "finitemonkey";
|
|
|
14560
14656
|
var liveFindings = (input, texts2) => {
|
|
14561
14657
|
const baseline = loadBaseline(input.runtime, input.cwd);
|
|
14562
14658
|
const accepted2 = acceptedFingerprints(baseline.ok ? baseline.value : EMPTY_BASELINE, input.runtime.now());
|
|
14563
|
-
return texts2.flatMap((
|
|
14659
|
+
return texts2.flatMap((text8) => scanText(text8, { rules: CREDENTIAL_RULES })).filter((finding4) => !accepted2.has(finding4.fingerprint));
|
|
14564
14660
|
};
|
|
14565
14661
|
var record2 = (input, findings, draft, where) => {
|
|
14566
14662
|
const ids2 = findings.map((finding4) => {
|
|
@@ -14821,12 +14917,12 @@ var secretsSessionStart = (input) => {
|
|
|
14821
14917
|
const remotes = remotesWithCredentials(input.runtime, input.cwd);
|
|
14822
14918
|
if (remotes.length === 0) return { kind: "allow" };
|
|
14823
14919
|
const params2 = { remotes: remotes.join(", "), remote: remotes[0] ?? "origin" };
|
|
14824
|
-
const
|
|
14920
|
+
const text8 = input.t("secrets.session.remote_credential", params2);
|
|
14825
14921
|
return {
|
|
14826
14922
|
kind: "allow",
|
|
14827
14923
|
output: {
|
|
14828
|
-
systemMessage: `finitemonkey: ${
|
|
14829
|
-
hookSpecificOutput: { hookEventName: "SessionStart", additionalContext:
|
|
14924
|
+
systemMessage: `finitemonkey: ${text8}`,
|
|
14925
|
+
hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: text8 }
|
|
14830
14926
|
}
|
|
14831
14927
|
};
|
|
14832
14928
|
};
|
|
@@ -14915,9 +15011,9 @@ var EMPTY_PAYLOAD = {
|
|
|
14915
15011
|
stopHookActive: false,
|
|
14916
15012
|
raw: {}
|
|
14917
15013
|
};
|
|
14918
|
-
var parseHookPayload = (event,
|
|
14919
|
-
if (interactive &&
|
|
14920
|
-
const parsed = parseJsonObject(
|
|
15014
|
+
var parseHookPayload = (event, text8, interactive) => {
|
|
15015
|
+
if (interactive && text8.trim() === "") return accept(EMPTY_PAYLOAD);
|
|
15016
|
+
const parsed = parseJsonObject(text8);
|
|
14921
15017
|
if (!parsed.ok) return reject(`stdin: ${parsed.error}`);
|
|
14922
15018
|
const payload = {
|
|
14923
15019
|
hookEventName: optionalString(parsed.value, "hook_event_name"),
|
|
@@ -14977,8 +15073,8 @@ var HOOK_PROBE_ENV = "FINITEMONKEY_HOOK_PROBE";
|
|
|
14977
15073
|
var messageOf2 = (error) => error instanceof Error ? error.message : String(error);
|
|
14978
15074
|
var decide2 = (input, handlers) => composeDecisions(input, handlers[input.event] ?? [allow]);
|
|
14979
15075
|
var evaluate = async (event, options) => {
|
|
14980
|
-
const
|
|
14981
|
-
const parsed = parseHookPayload(event,
|
|
15076
|
+
const text8 = await readAll(options.stdin);
|
|
15077
|
+
const parsed = parseHookPayload(event, text8, options.stdin.isTTY === true);
|
|
14982
15078
|
if (!parsed.ok) return { kind: "failed", payload: void 0, detail: parsed.error };
|
|
14983
15079
|
const payload = parsed.value;
|
|
14984
15080
|
if (options.env?.[HOOK_PROBE_ENV] === "1") return { kind: "decided", payload, decision: { kind: "allow" } };
|
|
@@ -15055,7 +15151,7 @@ var runHook = async (event, options) => {
|
|
|
15055
15151
|
var PROBE_TIMEOUT_MS2 = 1e4;
|
|
15056
15152
|
var SLOW_HOOK_MS = 1500;
|
|
15057
15153
|
var DEFAULT_TIMEOUT_S = 60;
|
|
15058
|
-
var expand = (
|
|
15154
|
+
var expand = (text8, vars) => text8.replace(/\$\{(\w+)\}|\$(\w+)/g, (match, braced, bare) => {
|
|
15059
15155
|
const name = braced ?? bare ?? "";
|
|
15060
15156
|
return vars[name] ?? match;
|
|
15061
15157
|
});
|
|
@@ -15104,7 +15200,7 @@ var run2 = (exec, invocation, cwd, env, input) => exec({
|
|
|
15104
15200
|
env: { ...env, [HOOK_PROBE_ENV]: "1" },
|
|
15105
15201
|
...input === void 0 ? {} : { input }
|
|
15106
15202
|
});
|
|
15107
|
-
var firstLine = (
|
|
15203
|
+
var firstLine = (text8) => maskText(text8.trim().split("\n")[0] ?? "").slice(0, 160);
|
|
15108
15204
|
var classify2 = (result) => {
|
|
15109
15205
|
if (!result.found) return { kind: "failed", problem: "missing", detail: "" };
|
|
15110
15206
|
if (result.timedOut) return { kind: "failed", problem: "timeout", detail: "" };
|
|
@@ -15335,8 +15431,8 @@ var installRecord = (value, root) => {
|
|
|
15335
15431
|
return records.find((record3) => record3["projectPath"] === root) ?? records[0];
|
|
15336
15432
|
};
|
|
15337
15433
|
var readJson = (env, path) => {
|
|
15338
|
-
const
|
|
15339
|
-
const parsed =
|
|
15434
|
+
const text8 = env.runtime.readText(path);
|
|
15435
|
+
const parsed = text8.ok ? parseJsonObject(text8.value) : void 0;
|
|
15340
15436
|
return parsed?.ok === true ? parsed.value : void 0;
|
|
15341
15437
|
};
|
|
15342
15438
|
var installedPlugin = (env) => {
|
|
@@ -15347,13 +15443,13 @@ var installedPlugin = (env) => {
|
|
|
15347
15443
|
const root = toAbsolutePath(installPath);
|
|
15348
15444
|
const manifest = readJson(env, toAbsolutePath(join33(root, ".claude-plugin", "plugin.json")));
|
|
15349
15445
|
const hooksPath = toAbsolutePath(join33(root, "hooks", "hooks.json"));
|
|
15350
|
-
const
|
|
15351
|
-
const parsed =
|
|
15446
|
+
const text8 = env.runtime.readText(hooksPath);
|
|
15447
|
+
const parsed = text8.ok ? parseJsonObject(text8.value) : void 0;
|
|
15352
15448
|
return {
|
|
15353
15449
|
root,
|
|
15354
15450
|
version: (manifest === void 0 ? void 0 : optionalString(manifest, "version")) ?? optionalString(record3, "version"),
|
|
15355
15451
|
hooksFile: parsed?.ok === true ? { source: "plugin", path: hooksPath, hooks: parsed.value["hooks"] } : void 0,
|
|
15356
|
-
hooksText:
|
|
15452
|
+
hooksText: text8.ok ? text8.value : void 0
|
|
15357
15453
|
};
|
|
15358
15454
|
};
|
|
15359
15455
|
var PRECEDENCE2 = ["managed", "local", "project", "user"];
|
|
@@ -15383,8 +15479,8 @@ var schemaFinding = (file, problems, claude) => problems.length === 0 ? [] : [
|
|
|
15383
15479
|
)
|
|
15384
15480
|
];
|
|
15385
15481
|
var unreadableProjectFiles = (env) => settingsPaths(env).filter(({ scope: scope2 }) => scope2 === "project" || scope2 === "local").flatMap(({ path }) => {
|
|
15386
|
-
const
|
|
15387
|
-
return
|
|
15482
|
+
const text8 = env.runtime.readText(path);
|
|
15483
|
+
return text8.ok && text8.value.trim() !== "" && !parseJsonObject(text8.value).ok ? [path] : [];
|
|
15388
15484
|
});
|
|
15389
15485
|
var schemaFindings = (env, plugin, claude) => {
|
|
15390
15486
|
const label2 = claude === void 0 ? "?" : claude.join(".");
|
|
@@ -15470,15 +15566,15 @@ var TOP_INSTRUCTIONS = ["AGENTS.md", "CLAUDE.md", ".claude/CLAUDE.md", "CLAUDE.l
|
|
|
15470
15566
|
var RULES_DIR = ".claude/rules";
|
|
15471
15567
|
var SHOWN = 3;
|
|
15472
15568
|
var readProjectFile = (env, relative11) => {
|
|
15473
|
-
const
|
|
15474
|
-
return
|
|
15569
|
+
const text8 = env.runtime.readText(toAbsolutePath(join35(env.root, ...relative11.split("/"))));
|
|
15570
|
+
return text8.ok ? text8.value : void 0;
|
|
15475
15571
|
};
|
|
15476
15572
|
var instructionFiles = (env) => {
|
|
15477
15573
|
const listed4 = env.runtime.listDir(toAbsolutePath(join35(env.root, ...RULES_DIR.split("/"))));
|
|
15478
15574
|
const rules = listed4.ok ? listed4.value.filter((name) => name.endsWith(".md")).map((name) => `${RULES_DIR}/${name}`) : [];
|
|
15479
15575
|
return [...TOP_INSTRUCTIONS, ...rules].flatMap((path) => {
|
|
15480
|
-
const
|
|
15481
|
-
return
|
|
15576
|
+
const text8 = readProjectFile(env, path);
|
|
15577
|
+
return text8 === void 0 ? [] : [{ path, text: text8 }];
|
|
15482
15578
|
});
|
|
15483
15579
|
};
|
|
15484
15580
|
var shortList = (items) => items.length <= SHOWN ? items.join(", ") : `${items.slice(0, SHOWN).join(", ")} (+${String(items.length - SHOWN)})`;
|
|
@@ -15526,10 +15622,10 @@ var hiddenInstructions = (env, deny2) => {
|
|
|
15526
15622
|
];
|
|
15527
15623
|
};
|
|
15528
15624
|
var localFile = (env) => readProjectFile(env, "CLAUDE.local.md") === void 0 ? [] : [finding("instructions.local", "warn", "doctor.instructions.local", {}, "doctor.instructions.fix_local")];
|
|
15529
|
-
var lineCount = (
|
|
15625
|
+
var lineCount = (text8) => text8.split("\n").length - (text8.endsWith("\n") ? 1 : 0);
|
|
15530
15626
|
var oversized = (env) => ["AGENTS.md", "CLAUDE.md"].flatMap((file) => {
|
|
15531
|
-
const
|
|
15532
|
-
const lines3 =
|
|
15627
|
+
const text8 = readProjectFile(env, file);
|
|
15628
|
+
const lines3 = text8 === void 0 ? 0 : lineCount(text8);
|
|
15533
15629
|
if (lines3 <= INSTRUCTION_LINE_CEILING) return [];
|
|
15534
15630
|
return [
|
|
15535
15631
|
finding(
|
|
@@ -15542,13 +15638,13 @@ var oversized = (env) => ["AGENTS.md", "CLAUDE.md"].flatMap((file) => {
|
|
|
15542
15638
|
];
|
|
15543
15639
|
});
|
|
15544
15640
|
var MIN_RULE_WORDS = 6;
|
|
15545
|
-
var ruleLines = (
|
|
15641
|
+
var ruleLines = (text8) => text8.split("\n").map((raw) => withoutCarriageReturn(raw).trim()).filter((line2) => !/^(#|\||```|@|>)/.test(line2)).map(
|
|
15546
15642
|
(line2) => line2.replace(/^([-*+]|\d+[.)])\s+/, "").replace(/\s+/g, " ").toLowerCase()
|
|
15547
15643
|
).filter((line2) => line2.split(" ").length >= MIN_RULE_WORDS);
|
|
15548
15644
|
var duplicatedRules = (files) => {
|
|
15549
15645
|
const seen = /* @__PURE__ */ new Map();
|
|
15550
|
-
for (const { path, text:
|
|
15551
|
-
for (const line2 of ruleLines(
|
|
15646
|
+
for (const { path, text: text8 } of files) {
|
|
15647
|
+
for (const line2 of ruleLines(text8)) seen.set(line2, (seen.get(line2) ?? /* @__PURE__ */ new Set()).add(path));
|
|
15552
15648
|
}
|
|
15553
15649
|
return [...seen].filter(([, paths]) => paths.size > 1).map(([line2]) => line2);
|
|
15554
15650
|
};
|
|
@@ -15598,13 +15694,13 @@ var ceilingOf = (config) => {
|
|
|
15598
15694
|
const parsed = typeof value === "string" ? Number.parseInt(value, 10) : Number.NaN;
|
|
15599
15695
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : AGENTS_MAX_LINES;
|
|
15600
15696
|
};
|
|
15601
|
-
var lineCount2 = (
|
|
15697
|
+
var lineCount2 = (text8) => text8.replace(/\r?\n$/, "").split(/\r?\n/).length;
|
|
15602
15698
|
var checkAgentsFile = ({ root, runtime }) => {
|
|
15603
|
-
const
|
|
15604
|
-
if (!
|
|
15699
|
+
const text8 = runtime.readText(toAbsolutePath(join37(root, AGENTS_FILE)));
|
|
15700
|
+
if (!text8.ok) return [];
|
|
15605
15701
|
const config = runtime.readText(toAbsolutePath(join37(root, CONFIG_FILE)));
|
|
15606
15702
|
const max = ceilingOf(config.ok ? config.value : void 0);
|
|
15607
|
-
const lines3 = lineCount2(
|
|
15703
|
+
const lines3 = lineCount2(text8.value);
|
|
15608
15704
|
const params2 = { file: AGENTS_FILE, lines: lines3, max };
|
|
15609
15705
|
return lines3 > max ? [finding("memory.agents_lines", "fail", "doctor.memory.too_long", params2, "doctor.memory.fix_too_long")] : [finding("memory.agents_lines", "ok", "doctor.memory.lines", params2)];
|
|
15610
15706
|
};
|
|
@@ -15785,9 +15881,9 @@ var manualLines = (ctx, report2) => report2.checks.some((item2) => item2.status
|
|
|
15785
15881
|
var writeReport = (ctx, data, result) => {
|
|
15786
15882
|
const env = doctorEnvFrom(ctx);
|
|
15787
15883
|
const path = reportPath(env);
|
|
15788
|
-
const
|
|
15884
|
+
const text8 = reportMarkdown(env, ctx, toEnvelope("doctor", result));
|
|
15789
15885
|
const dir = ctx.runtime.mkdir(toAbsolutePath(dirname7(path)));
|
|
15790
|
-
const written = dir.ok ? ctx.runtime.writeAtomic(path,
|
|
15886
|
+
const written = dir.ok ? ctx.runtime.writeAtomic(path, text8) : dir;
|
|
15791
15887
|
if (!written.ok) return failureFrom(ctx.t, applyProblem({ path, detail: written.error }));
|
|
15792
15888
|
const human2 = [...result.human ?? [], ctx.t("doctor.report.written", { path })];
|
|
15793
15889
|
return { ...result, data: { ...data, reportPath: path }, human: human2 };
|
|
@@ -16113,15 +16209,15 @@ var commitMsgCommand = {
|
|
|
16113
16209
|
usageProblem("invalid_arguments", "error.invalid_arguments", COMMIT_MSG_USAGE, { detail: "<message-file>" })
|
|
16114
16210
|
)
|
|
16115
16211
|
);
|
|
16116
|
-
const
|
|
16117
|
-
if (!
|
|
16212
|
+
const text8 = ctx.runtime.readText(toAbsolutePath(file, ctx.cwd));
|
|
16213
|
+
if (!text8.ok)
|
|
16118
16214
|
return Promise.resolve(
|
|
16119
16215
|
failureFrom(
|
|
16120
16216
|
ctx.t,
|
|
16121
16217
|
usageProblem("invalid_arguments", "error.invalid_arguments", COMMIT_MSG_USAGE, { detail: file })
|
|
16122
16218
|
)
|
|
16123
16219
|
);
|
|
16124
|
-
const failures = commitMessageProblems(
|
|
16220
|
+
const failures = commitMessageProblems(text8.value);
|
|
16125
16221
|
const fix = "git commit --amend, using type(scope): subject and no AI attribution lines";
|
|
16126
16222
|
return Promise.resolve(
|
|
16127
16223
|
checksResult(ctx.t, COMMIT_MSG_SCHEMA, "githook_failed", [{ id: "commit-messages", failures, fix }])
|
|
@@ -16259,7 +16355,7 @@ var mergeVerifyCommand = {
|
|
|
16259
16355
|
var REFLOG_LIMIT = 300;
|
|
16260
16356
|
var LIST_LIMIT = 50;
|
|
16261
16357
|
var SHA = /^[0-9a-f]{40,64}$/;
|
|
16262
|
-
var linesOf = (
|
|
16358
|
+
var linesOf = (text8) => text8.split("\n").filter((line2) => line2.trim() !== "");
|
|
16263
16359
|
var reflogLines = (runtime, repo) => {
|
|
16264
16360
|
const result = runtime.git(["reflog", "show", "--all", `-n${String(REFLOG_LIMIT)}`, "--format=%H %gD"], repo.root);
|
|
16265
16361
|
if (!result.ok) return [];
|
|
@@ -16548,7 +16644,7 @@ var GLOBAL_FLAGS = [
|
|
|
16548
16644
|
{ flag: "--help, -h", key: "flag.help" }
|
|
16549
16645
|
];
|
|
16550
16646
|
var exitCodeHelp = (ctx) => EXIT_CODE_NAMES.map((name) => ({ code: ExitCode[name], name, summary: ctx.t(exitCodeDocs[ExitCode[name]]) }));
|
|
16551
|
-
var pad = (
|
|
16647
|
+
var pad = (text8, width) => text8.padEnd(Math.max(width, text8.length + 1));
|
|
16552
16648
|
var describe2 = (ctx, spec2) => ({
|
|
16553
16649
|
name: commandName(spec2),
|
|
16554
16650
|
usage: spec2.usage,
|
|
@@ -16690,10 +16786,10 @@ var parseBranches = (body2, inPlural) => {
|
|
|
16690
16786
|
};
|
|
16691
16787
|
var parseNodes = (source, inPlural) => {
|
|
16692
16788
|
const nodes = [];
|
|
16693
|
-
let
|
|
16789
|
+
let text8 = "";
|
|
16694
16790
|
const flush2 = () => {
|
|
16695
|
-
if (
|
|
16696
|
-
|
|
16791
|
+
if (text8 !== "") nodes.push({ kind: "text", text: text8 });
|
|
16792
|
+
text8 = "";
|
|
16697
16793
|
};
|
|
16698
16794
|
for (let index = 0; index < source.length; index += 1) {
|
|
16699
16795
|
const char = source.charAt(index);
|
|
@@ -16703,7 +16799,7 @@ var parseNodes = (source, inPlural) => {
|
|
|
16703
16799
|
continue;
|
|
16704
16800
|
}
|
|
16705
16801
|
if (char !== "{") {
|
|
16706
|
-
|
|
16802
|
+
text8 += char;
|
|
16707
16803
|
continue;
|
|
16708
16804
|
}
|
|
16709
16805
|
const cursor = { source, index: index + 1 };
|
|
@@ -16711,18 +16807,18 @@ var parseNodes = (source, inPlural) => {
|
|
|
16711
16807
|
const inner = end < 0 ? void 0 : source.slice(index + 1, end);
|
|
16712
16808
|
const match = inner === void 0 ? null : ARG.exec(inner);
|
|
16713
16809
|
if (inner === void 0 || match === null) {
|
|
16714
|
-
|
|
16810
|
+
text8 += char;
|
|
16715
16811
|
continue;
|
|
16716
16812
|
}
|
|
16717
16813
|
const name = match[1] ?? "";
|
|
16718
16814
|
const type = match[2] === "plural" || match[2] === "select" ? match[2] : void 0;
|
|
16719
16815
|
if (type === void 0 && match[0].trim().length !== inner.trim().length) {
|
|
16720
|
-
|
|
16816
|
+
text8 += char;
|
|
16721
16817
|
continue;
|
|
16722
16818
|
}
|
|
16723
16819
|
const branches = type === void 0 ? void 0 : parseBranches(inner.slice(match[0].length), type === "plural");
|
|
16724
16820
|
if (type !== void 0 && branches === void 0) {
|
|
16725
|
-
|
|
16821
|
+
text8 += char;
|
|
16726
16822
|
continue;
|
|
16727
16823
|
}
|
|
16728
16824
|
flush2();
|
|
@@ -16845,8 +16941,8 @@ var RELEASE_HINTS = [
|
|
|
16845
16941
|
/\bFINITEMONKEY_[A-Z_]+/,
|
|
16846
16942
|
/\b[A-Z][A-Z0-9_]{2,}=/
|
|
16847
16943
|
];
|
|
16848
|
-
var releaseHints = (
|
|
16849
|
-
const match = pattern.exec(
|
|
16944
|
+
var releaseHints = (text8) => RELEASE_HINTS.flatMap((pattern) => {
|
|
16945
|
+
const match = pattern.exec(text8);
|
|
16850
16946
|
return match === null ? [] : [match[0]];
|
|
16851
16947
|
});
|
|
16852
16948
|
var hintProblems = (lang, catalog) => Object.keys(catalog).filter((key) => MODEL_FACING.test(key)).sort().flatMap((key) => {
|
|
@@ -16885,9 +16981,9 @@ var unreadable = (dir, file, detail) => ({
|
|
|
16885
16981
|
});
|
|
16886
16982
|
var readCatalog = (ctx, dir, lang) => {
|
|
16887
16983
|
const file = toAbsolutePath(join40(dir, `${lang}.json`));
|
|
16888
|
-
const
|
|
16889
|
-
if (!
|
|
16890
|
-
const parsed = parseJsonObject(
|
|
16984
|
+
const text8 = ctx.runtime.readText(file);
|
|
16985
|
+
if (!text8.ok) return reject(unreadable(dir, file, text8.error));
|
|
16986
|
+
const parsed = parseJsonObject(text8.value);
|
|
16891
16987
|
return parsed.ok ? parsed : reject(unreadable(dir, file, parsed.error));
|
|
16892
16988
|
};
|
|
16893
16989
|
var loadCatalogs = (ctx, dir) => {
|
|
@@ -16907,8 +17003,8 @@ var describeProblem = (ctx, problem4) => {
|
|
|
16907
17003
|
return ` ${problem4.lang} ${problem4.key} ${kind}`;
|
|
16908
17004
|
};
|
|
16909
17005
|
var loadReview = (ctx, dir) => {
|
|
16910
|
-
const
|
|
16911
|
-
const parsed =
|
|
17006
|
+
const text8 = ctx.runtime.readText(toAbsolutePath(join40(dir, "review.json")));
|
|
17007
|
+
const parsed = text8.ok ? parseJsonObject(text8.value) : void 0;
|
|
16912
17008
|
if (parsed?.ok !== true) return void 0;
|
|
16913
17009
|
const statuses = (lang) => {
|
|
16914
17010
|
const value = parsed.value[lang];
|
|
@@ -17053,8 +17149,8 @@ var addResults = (draft, blocks) => {
|
|
|
17053
17149
|
let any = false;
|
|
17054
17150
|
for (const block4 of blocks) {
|
|
17055
17151
|
if (!isRecord(block4) || block4["type"] !== "tool_result" || typeof block4["tool_use_id"] !== "string") continue;
|
|
17056
|
-
const
|
|
17057
|
-
draft.results.set(block4["tool_use_id"], { failed: block4["is_error"] === true || FAILED_EXIT.test(
|
|
17152
|
+
const text8 = textOf3(block4["content"]);
|
|
17153
|
+
draft.results.set(block4["tool_use_id"], { failed: block4["is_error"] === true || FAILED_EXIT.test(text8), text: text8 });
|
|
17058
17154
|
any = true;
|
|
17059
17155
|
}
|
|
17060
17156
|
return any;
|
|
@@ -17105,9 +17201,9 @@ var lookBack = (runtime, root, env) => {
|
|
|
17105
17201
|
};
|
|
17106
17202
|
let turns = 0;
|
|
17107
17203
|
for (const name of files) {
|
|
17108
|
-
const
|
|
17109
|
-
if (!
|
|
17110
|
-
for (const turn of parseTranscript(
|
|
17204
|
+
const text8 = runtime.readText(toAbsolutePath(join41(dir, name)));
|
|
17205
|
+
if (!text8.ok) continue;
|
|
17206
|
+
for (const turn of parseTranscript(text8.value)) {
|
|
17111
17207
|
turns += 1;
|
|
17112
17208
|
for (const hit3 of hitsIn(turn)) {
|
|
17113
17209
|
counts[hit3.pattern] += 1;
|
|
@@ -17155,7 +17251,7 @@ var walk2 = (a, b) => {
|
|
|
17155
17251
|
}
|
|
17156
17252
|
return ops;
|
|
17157
17253
|
};
|
|
17158
|
-
var splitLines = (
|
|
17254
|
+
var splitLines = (text8) => text8 === "" ? [] : text8.replace(/\r?\n$/, "").split(/\r?\n/);
|
|
17159
17255
|
var sharedPrefix = (a, b) => {
|
|
17160
17256
|
let count4 = 0;
|
|
17161
17257
|
while (count4 < a.length && count4 < b.length && a[count4] === b[count4]) count4 += 1;
|
|
@@ -17232,7 +17328,7 @@ var planData = (t, plan, mode, applied, backup) => ({
|
|
|
17232
17328
|
diff: planDiff(plan),
|
|
17233
17329
|
...backup === void 0 ? {} : { backup }
|
|
17234
17330
|
});
|
|
17235
|
-
var pad2 = (
|
|
17331
|
+
var pad2 = (text8, width) => text8.padEnd(width);
|
|
17236
17332
|
var planLines = (t, data, withDiff) => [
|
|
17237
17333
|
t("install.plan.title", { root: data.root, preset: data.preset }),
|
|
17238
17334
|
...data.actions.map(({ path, action }) => ` ${pad2(action, 13)}${path}`),
|
|
@@ -17368,8 +17464,8 @@ var measurePage = (doc) => {
|
|
|
17368
17464
|
const walker = doc.createTreeWalker(doc.body, SHOW_TEXT);
|
|
17369
17465
|
const keys = /* @__PURE__ */ new Set();
|
|
17370
17466
|
for (let node = walker.nextNode(); node !== null; node = walker.nextNode()) {
|
|
17371
|
-
const
|
|
17372
|
-
if (KEY2.test(
|
|
17467
|
+
const text8 = (node.textContent ?? "").trim();
|
|
17468
|
+
if (KEY2.test(text8) && !NOT_KEY.test(text8) || PLACEHOLDER2.test(text8)) keys.add(text8.slice(0, 80));
|
|
17373
17469
|
}
|
|
17374
17470
|
const small = [...doc.querySelectorAll("a, button, input, select, textarea, [role=button], [role=link]")].filter((element) => {
|
|
17375
17471
|
const box = element.getBoundingClientRect();
|
|
@@ -17402,8 +17498,8 @@ var slugOf = (route) => {
|
|
|
17402
17498
|
var watch = (page) => {
|
|
17403
17499
|
const errors = [];
|
|
17404
17500
|
const failed4 = [];
|
|
17405
|
-
const push = (list4,
|
|
17406
|
-
if (list4.length < MAX_EVENTS) list4.push(
|
|
17501
|
+
const push = (list4, text8) => {
|
|
17502
|
+
if (list4.length < MAX_EVENTS) list4.push(text8.slice(0, 200));
|
|
17407
17503
|
};
|
|
17408
17504
|
page.on("console", (message) => {
|
|
17409
17505
|
if (message.type() === "error" && !RESOURCE_ERROR.test(message.text())) push(errors, message.text());
|
|
@@ -17487,7 +17583,7 @@ var launchBrowser = async (playwright) => {
|
|
|
17487
17583
|
// src/look/node-sheet.ts
|
|
17488
17584
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
17489
17585
|
import { join as join44 } from "node:path";
|
|
17490
|
-
var escapeHtml = (
|
|
17586
|
+
var escapeHtml = (text8) => text8.replace(/[&<>"]/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[char] ?? char);
|
|
17491
17587
|
var card = (result) => {
|
|
17492
17588
|
const image = (() => {
|
|
17493
17589
|
try {
|
|
@@ -17866,7 +17962,7 @@ var git = (runtime, root, args2) => {
|
|
|
17866
17962
|
const result = runtime.git(args2, root);
|
|
17867
17963
|
return result.ok ? result.stdout : void 0;
|
|
17868
17964
|
};
|
|
17869
|
-
var lastLines = (
|
|
17965
|
+
var lastLines = (text8, max) => text8.split("\n").slice(-max).join("\n");
|
|
17870
17966
|
var section = (title, body2, empty) => `## ${title}
|
|
17871
17967
|
|
|
17872
17968
|
${body2 === void 0 || body2.trim() === "" ? empty : body2.trimEnd()}
|
|
@@ -17884,8 +17980,8 @@ var taskSections = (runtime, root) => {
|
|
|
17884
17980
|
];
|
|
17885
17981
|
};
|
|
17886
17982
|
var reviewFile = (runtime, root, base) => {
|
|
17887
|
-
const
|
|
17888
|
-
return
|
|
17983
|
+
const text8 = git(runtime, root, ["show", `${base}:REVIEW.md`]);
|
|
17984
|
+
return text8 === void 0 ? void 0 : text8.split("\n").slice(0, REVIEW_FILE_MAX_LINES).join("\n");
|
|
17889
17985
|
};
|
|
17890
17986
|
var nextState = (previous, base, head) => {
|
|
17891
17987
|
if (previous?.base !== base) return { base, rounds: 1, lastHead: head };
|
|
@@ -17898,7 +17994,7 @@ var buildPacket = (runtime, root, base, head) => {
|
|
|
17898
17994
|
const range = `${from}...${head}`;
|
|
17899
17995
|
const diff = git(runtime, root, ["diff", "--no-color", "--no-ext-diff", range, "--", ".", ":(exclude).finitemonkey"]);
|
|
17900
17996
|
const owners = reviewFile(runtime, root, base);
|
|
17901
|
-
const
|
|
17997
|
+
const text8 = [
|
|
17902
17998
|
`# Review packet (round ${String(state.rounds)}, ${range})`,
|
|
17903
17999
|
"",
|
|
17904
18000
|
...state.rounds > FULL_ROUNDS ? ["Only the diff since the last review round is included.", ""] : [],
|
|
@@ -17909,7 +18005,7 @@ var buildPacket = (runtime, root, base, head) => {
|
|
|
17909
18005
|
runtime.mkdir(toAbsolutePath(join45(root, ".finitemonkey", "review")));
|
|
17910
18006
|
runtime.writeAtomic(statePath(root), `${JSON.stringify(state, null, 2)}
|
|
17911
18007
|
`);
|
|
17912
|
-
return { round: state.rounds, base, head, range, text:
|
|
18008
|
+
return { round: state.rounds, base, head, range, text: text8 };
|
|
17913
18009
|
};
|
|
17914
18010
|
|
|
17915
18011
|
// src/commands/review.ts
|
|
@@ -18444,6 +18540,204 @@ var secretsScanCommand = {
|
|
|
18444
18540
|
}
|
|
18445
18541
|
};
|
|
18446
18542
|
|
|
18543
|
+
// src/statusline/gate-state.ts
|
|
18544
|
+
var GATE_HOOKS = /* @__PURE__ */ new Set(["Stop", "SubagentStop"]);
|
|
18545
|
+
var TAIL_BYTES = 64 * 1024;
|
|
18546
|
+
var lastGateFailure = (runtime, paths) => {
|
|
18547
|
+
const log = runtime.readText(paths.log);
|
|
18548
|
+
if (!log.ok) return void 0;
|
|
18549
|
+
const lines3 = log.value.slice(-TAIL_BYTES).split("\n").reverse();
|
|
18550
|
+
for (const line2 of lines3) {
|
|
18551
|
+
if (!line2.includes(HOOK_FAILURE_EVENT)) continue;
|
|
18552
|
+
const parsed = parseJsonObject(line2);
|
|
18553
|
+
if (!parsed.ok || !isRecord(parsed.value)) continue;
|
|
18554
|
+
const { event, hook, at } = parsed.value;
|
|
18555
|
+
if (event === HOOK_FAILURE_EVENT && typeof hook === "string" && GATE_HOOKS.has(hook) && typeof at === "string")
|
|
18556
|
+
return at;
|
|
18557
|
+
}
|
|
18558
|
+
return void 0;
|
|
18559
|
+
};
|
|
18560
|
+
var gateLight = (runtime, paths) => {
|
|
18561
|
+
const status = readGateStatus(runtime, paths);
|
|
18562
|
+
const failure4 = lastGateFailure(runtime, paths);
|
|
18563
|
+
const greenSince = status?.status === "passed" ? Date.parse(status.at) : Number.NEGATIVE_INFINITY;
|
|
18564
|
+
if (failure4 !== void 0 && Date.parse(failure4) >= greenSince) return "did_not_run";
|
|
18565
|
+
if (status === void 0) return "none";
|
|
18566
|
+
switch (status.status) {
|
|
18567
|
+
case "passed":
|
|
18568
|
+
return "green";
|
|
18569
|
+
case "failed":
|
|
18570
|
+
case "not_done":
|
|
18571
|
+
return "red";
|
|
18572
|
+
case "incomplete":
|
|
18573
|
+
return "incomplete";
|
|
18574
|
+
case "not_run":
|
|
18575
|
+
return "did_not_run";
|
|
18576
|
+
}
|
|
18577
|
+
};
|
|
18578
|
+
|
|
18579
|
+
// src/statusline/input.ts
|
|
18580
|
+
var text7 = (value) => typeof value === "string" && value !== "" ? value : void 0;
|
|
18581
|
+
var num = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
18582
|
+
var usedTokens = (usage) => {
|
|
18583
|
+
if (!isRecord(usage)) return void 0;
|
|
18584
|
+
return (num(usage["input_tokens"]) ?? 0) + (num(usage["cache_creation_input_tokens"]) ?? 0) + (num(usage["cache_read_input_tokens"]) ?? 0);
|
|
18585
|
+
};
|
|
18586
|
+
var contextPercent = (record3) => {
|
|
18587
|
+
const window = record3["context_window"];
|
|
18588
|
+
if (!isRecord(window)) return void 0;
|
|
18589
|
+
const direct = window["used_percentage"];
|
|
18590
|
+
if (typeof direct === "number" && Number.isFinite(direct)) return Math.round(direct);
|
|
18591
|
+
const size = window["context_window_size"];
|
|
18592
|
+
const used = usedTokens(window["current_usage"]);
|
|
18593
|
+
return typeof size === "number" && size > 0 && used !== void 0 ? Math.round(used / size * 100) : void 0;
|
|
18594
|
+
};
|
|
18595
|
+
var parseStatusInput = (raw) => {
|
|
18596
|
+
const parsed = parseJsonObject(raw.trim() === "" ? "{}" : raw);
|
|
18597
|
+
const record3 = parsed.ok ? parsed.value : {};
|
|
18598
|
+
const workspace = isRecord(record3["workspace"]) ? record3["workspace"] : {};
|
|
18599
|
+
return {
|
|
18600
|
+
sessionId: text7(record3["session_id"]),
|
|
18601
|
+
dir: text7(workspace["project_dir"]) ?? text7(workspace["current_dir"]) ?? text7(record3["cwd"]),
|
|
18602
|
+
contextPercent: contextPercent(record3),
|
|
18603
|
+
raw
|
|
18604
|
+
};
|
|
18605
|
+
};
|
|
18606
|
+
|
|
18607
|
+
// src/statusline/render.ts
|
|
18608
|
+
var SEPARATOR2 = " | ";
|
|
18609
|
+
var segmentText = (t, segment) => [
|
|
18610
|
+
"fm",
|
|
18611
|
+
...segment.task === void 0 ? [] : [segment.task],
|
|
18612
|
+
...segment.gate === "none" ? [] : [t(`statusline.gate.${segment.gate}`)],
|
|
18613
|
+
...segment.contextPercent === void 0 ? [] : [t("statusline.context", { percent: segment.contextPercent })]
|
|
18614
|
+
].join(" · ");
|
|
18615
|
+
var ANSI3 = new RegExp(`${String.fromCharCode(27)}\\[[0-9;?]*[A-Za-z]`, "g");
|
|
18616
|
+
var graphemes = (text8) => Array.from(new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(text8), (part2) => part2.segment);
|
|
18617
|
+
var fit = (line2, columns) => {
|
|
18618
|
+
if (columns === void 0) return line2;
|
|
18619
|
+
const visible = graphemes(line2.replace(ANSI3, ""));
|
|
18620
|
+
return visible.length <= columns ? line2 : `${visible.slice(0, Math.max(0, columns - 1)).join("")}…`;
|
|
18621
|
+
};
|
|
18622
|
+
var composeLine = (wrapped, segment, columns) => {
|
|
18623
|
+
const lines3 = wrapped === "" ? [] : wrapped.split(/\r?\n/);
|
|
18624
|
+
const last = lines3.pop();
|
|
18625
|
+
const joined = last === void 0 || last.trim() === "" ? segment : `${last}${SEPARATOR2}${segment}`;
|
|
18626
|
+
return [...lines3, joined].map((line2) => fit(line2, columns)).join("\n");
|
|
18627
|
+
};
|
|
18628
|
+
|
|
18629
|
+
// src/statusline/node-shell.ts
|
|
18630
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
18631
|
+
var killTree = (child2) => {
|
|
18632
|
+
const pid = child2.pid;
|
|
18633
|
+
if (pid === void 0) return;
|
|
18634
|
+
try {
|
|
18635
|
+
if (process.platform === "win32") {
|
|
18636
|
+
spawn4("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true }).unref();
|
|
18637
|
+
} else process.kill(-pid, "SIGKILL");
|
|
18638
|
+
} catch {
|
|
18639
|
+
child2.kill("SIGKILL");
|
|
18640
|
+
}
|
|
18641
|
+
};
|
|
18642
|
+
var nodeShell = (command, input, cwd, timeoutMs) => new Promise((resolve2) => {
|
|
18643
|
+
const child2 = spawn4(command, {
|
|
18644
|
+
cwd,
|
|
18645
|
+
shell: true,
|
|
18646
|
+
detached: process.platform !== "win32",
|
|
18647
|
+
windowsHide: true,
|
|
18648
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
18649
|
+
});
|
|
18650
|
+
let out = "";
|
|
18651
|
+
const timer = setTimeout(() => {
|
|
18652
|
+
killTree(child2);
|
|
18653
|
+
resolve2({ text: void 0, timedOut: true });
|
|
18654
|
+
}, timeoutMs);
|
|
18655
|
+
child2.stdout.on("data", (chunk) => {
|
|
18656
|
+
out += chunk.toString("utf8");
|
|
18657
|
+
});
|
|
18658
|
+
child2.once("error", () => {
|
|
18659
|
+
clearTimeout(timer);
|
|
18660
|
+
resolve2({ text: void 0, timedOut: false });
|
|
18661
|
+
});
|
|
18662
|
+
child2.once("close", () => {
|
|
18663
|
+
clearTimeout(timer);
|
|
18664
|
+
resolve2({ text: out, timedOut: false });
|
|
18665
|
+
});
|
|
18666
|
+
child2.stdin.on("error", () => void 0);
|
|
18667
|
+
child2.stdin.end(input);
|
|
18668
|
+
});
|
|
18669
|
+
|
|
18670
|
+
// src/statusline/wrap.ts
|
|
18671
|
+
var WRAP_CACHE = "statusline.json";
|
|
18672
|
+
var KEEP3 = 20;
|
|
18673
|
+
var cached2 = (runtime, paths) => {
|
|
18674
|
+
const raw = readJsonFile(runtime, paths.cache(WRAP_CACHE))?.["sessions"];
|
|
18675
|
+
return isRecord(raw) ? Object.fromEntries(Object.entries(raw).filter((entry2) => typeof entry2[1] === "string")) : {};
|
|
18676
|
+
};
|
|
18677
|
+
var remember = (runtime, paths, session, text8) => {
|
|
18678
|
+
const sessions = Object.entries({ ...cached2(runtime, paths), [session]: text8 }).slice(-KEEP3);
|
|
18679
|
+
writeJsonFile(runtime, paths.cache(WRAP_CACHE), { sessions: Object.fromEntries(sessions) });
|
|
18680
|
+
};
|
|
18681
|
+
var runWrapped = async (runtime, paths, request, shell = nodeShell) => {
|
|
18682
|
+
const result = await shell(request.command, request.input, request.cwd, request.timeoutMs);
|
|
18683
|
+
if (result.text !== void 0) {
|
|
18684
|
+
const text8 = result.text.replace(/\s+$/, "");
|
|
18685
|
+
if (paths !== void 0) remember(runtime, paths, request.session, text8);
|
|
18686
|
+
return text8;
|
|
18687
|
+
}
|
|
18688
|
+
return paths === void 0 ? "" : cached2(runtime, paths)[request.session] ?? "";
|
|
18689
|
+
};
|
|
18690
|
+
|
|
18691
|
+
// src/statusline/run.ts
|
|
18692
|
+
var STDIN_MS = 300;
|
|
18693
|
+
var WRAP_MS = 700;
|
|
18694
|
+
var wrapOf = (ctx, root) => {
|
|
18695
|
+
const text8 = ctx.runtime.readText(toAbsolutePath(`${root}/${LOCK_FILE}`));
|
|
18696
|
+
const lock = text8.ok ? parseLock(text8.value) : void 0;
|
|
18697
|
+
if (!lock?.ok) return void 0;
|
|
18698
|
+
return lock.value.entries.find((entry2) => entry2.added?.statusLine !== void 0)?.added?.statusLine?.wrap ?? void 0;
|
|
18699
|
+
};
|
|
18700
|
+
var columnsOf = (ctx) => {
|
|
18701
|
+
const columns = Number.parseInt(ctx.env["COLUMNS"] ?? "", 10);
|
|
18702
|
+
return Number.isInteger(columns) && columns > 0 ? columns : void 0;
|
|
18703
|
+
};
|
|
18704
|
+
var lineFor = async (ctx, input) => {
|
|
18705
|
+
const start = input.dir === void 0 ? ctx.cwd : toAbsolutePath(input.dir, ctx.cwd);
|
|
18706
|
+
const root = findGitRoot(start, ctx.runtime);
|
|
18707
|
+
const paths = root === void 0 ? void 0 : fmPaths(root);
|
|
18708
|
+
const wrap = root === void 0 ? void 0 : wrapOf(ctx, root);
|
|
18709
|
+
const wrapped = wrap === void 0 || root === void 0 ? "" : await runWrapped(ctx.runtime, paths, {
|
|
18710
|
+
command: wrap,
|
|
18711
|
+
input: input.raw,
|
|
18712
|
+
cwd: root,
|
|
18713
|
+
timeoutMs: WRAP_MS,
|
|
18714
|
+
session: input.sessionId ?? "none"
|
|
18715
|
+
});
|
|
18716
|
+
const segment = segmentText(ctx.t, {
|
|
18717
|
+
task: paths === void 0 ? void 0 : readState(ctx.runtime, paths).active,
|
|
18718
|
+
gate: paths === void 0 ? "none" : gateLight(ctx.runtime, paths),
|
|
18719
|
+
contextPercent: input.contextPercent
|
|
18720
|
+
});
|
|
18721
|
+
return composeLine(wrapped, segment, columnsOf(ctx));
|
|
18722
|
+
};
|
|
18723
|
+
var renderStatusLine = async (ctx) => {
|
|
18724
|
+
try {
|
|
18725
|
+
const raw = await withDeadline(readAll(ctx.io.stdin), STDIN_MS, ctx.runtime.startTimer).catch(() => "");
|
|
18726
|
+
return await lineFor(ctx, parseStatusInput(raw));
|
|
18727
|
+
} catch {
|
|
18728
|
+
return "fm";
|
|
18729
|
+
}
|
|
18730
|
+
};
|
|
18731
|
+
|
|
18732
|
+
// src/commands/statusline.ts
|
|
18733
|
+
var statuslineCommand = {
|
|
18734
|
+
path: ["statusline"],
|
|
18735
|
+
summaryKey: "command.statusline.summary",
|
|
18736
|
+
usage: "finitemonkey statusline",
|
|
18737
|
+
status: "ready",
|
|
18738
|
+
run: async (ctx) => success({}, [await renderStatusLine(ctx)])
|
|
18739
|
+
};
|
|
18740
|
+
|
|
18447
18741
|
// src/task/create.ts
|
|
18448
18742
|
import { join as join47 } from "node:path";
|
|
18449
18743
|
|
|
@@ -18534,8 +18828,8 @@ var explicitChecks = (draft) => [
|
|
|
18534
18828
|
var draftChecks = (runtime, paths, draft) => {
|
|
18535
18829
|
const disk = {
|
|
18536
18830
|
read: (relative11) => {
|
|
18537
|
-
const
|
|
18538
|
-
return
|
|
18831
|
+
const text8 = runtime.readText(toAbsolutePath(join47(paths.root, relative11)));
|
|
18832
|
+
return text8.ok ? text8.value : void 0;
|
|
18539
18833
|
},
|
|
18540
18834
|
exists: (relative11) => runtime.stat(toAbsolutePath(join47(paths.root, relative11))) !== void 0
|
|
18541
18835
|
};
|
|
@@ -18578,19 +18872,19 @@ var createTask = (runtime, paths, draft) => {
|
|
|
18578
18872
|
decisionsNeeded: [],
|
|
18579
18873
|
implicit: false
|
|
18580
18874
|
};
|
|
18581
|
-
const
|
|
18875
|
+
const text8 = stringifyYaml(contractYaml(shape));
|
|
18582
18876
|
const valid = validateContract(contractYaml(shape));
|
|
18583
18877
|
if (!valid.ok) return reject({ kind: "invalid", issues: valid.error });
|
|
18584
|
-
const wrote = runtime.writeText(paths.task(draft.id),
|
|
18878
|
+
const wrote = runtime.writeText(paths.task(draft.id), text8);
|
|
18585
18879
|
if (!wrote.ok) return reject({ kind: "write", detail: wrote.error });
|
|
18586
18880
|
const lock = readTrust(runtime, paths);
|
|
18587
18881
|
writeTrust(runtime, paths, {
|
|
18588
18882
|
...lock,
|
|
18589
18883
|
contracts: { ...lock.contracts, [draft.id]: contractHash(valid.value) },
|
|
18590
|
-
approved: { ...lock.approved, [draft.id]:
|
|
18884
|
+
approved: { ...lock.approved, [draft.id]: text8 }
|
|
18591
18885
|
});
|
|
18592
18886
|
writeState(runtime, paths, { ...readState(runtime, paths), active: draft.id });
|
|
18593
|
-
return accept({ contract: valid.value, text:
|
|
18887
|
+
return accept({ contract: valid.value, text: text8 });
|
|
18594
18888
|
};
|
|
18595
18889
|
|
|
18596
18890
|
// src/commands/task.ts
|
|
@@ -18741,7 +19035,7 @@ var taskDoneCommand = {
|
|
|
18741
19035
|
};
|
|
18742
19036
|
|
|
18743
19037
|
// src/install/githook-block.ts
|
|
18744
|
-
var withoutHookBlock = (
|
|
19038
|
+
var withoutHookBlock = (text8) => withoutManagedBlock(text8, { begin: BLOCK_BEGIN, end: BLOCK_END });
|
|
18745
19039
|
|
|
18746
19040
|
// src/install/uninstall.ts
|
|
18747
19041
|
var blockless = (kind, current2) => {
|
|
@@ -18750,8 +19044,8 @@ var blockless = (kind, current2) => {
|
|
|
18750
19044
|
};
|
|
18751
19045
|
var structural = (entry2, current2) => {
|
|
18752
19046
|
if (entry2.kind === "gitignore" || entry2.kind === "markdown" || entry2.kind === "githook") {
|
|
18753
|
-
const
|
|
18754
|
-
return
|
|
19047
|
+
const text8 = blockless(entry2.kind, current2);
|
|
19048
|
+
return text8.trim() === "" && !entry2.existed ? void 0 : text8;
|
|
18755
19049
|
}
|
|
18756
19050
|
const parsed = parseSettings(current2);
|
|
18757
19051
|
if (!parsed.ok || entry2.added === void 0) return current2;
|
|
@@ -18955,6 +19249,7 @@ var REGISTRY = [
|
|
|
18955
19249
|
ciGateCommand,
|
|
18956
19250
|
lookCommand,
|
|
18957
19251
|
reviewPacketCommand,
|
|
19252
|
+
statuslineCommand,
|
|
18958
19253
|
versionCommand,
|
|
18959
19254
|
helpCommand
|
|
18960
19255
|
];
|
|
@@ -18962,16 +19257,16 @@ var REGISTRY = [
|
|
|
18962
19257
|
// src/i18n/lang-settings.ts
|
|
18963
19258
|
import { join as join48 } from "node:path";
|
|
18964
19259
|
var read3 = (runtime, path) => {
|
|
18965
|
-
const
|
|
18966
|
-
return
|
|
19260
|
+
const text8 = runtime.readText(toAbsolutePath(path));
|
|
19261
|
+
return text8.ok ? text8.value : void 0;
|
|
18967
19262
|
};
|
|
18968
19263
|
var configText = (tree, ...path) => {
|
|
18969
19264
|
const value = configAt(tree, ...path);
|
|
18970
19265
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
18971
19266
|
};
|
|
18972
|
-
var languageIn = (
|
|
18973
|
-
if (
|
|
18974
|
-
const parsed = parseJsonObject(
|
|
19267
|
+
var languageIn = (text8) => {
|
|
19268
|
+
if (text8 === void 0) return void 0;
|
|
19269
|
+
const parsed = parseJsonObject(text8);
|
|
18975
19270
|
const value = parsed.ok && isRecord(parsed.value) ? parsed.value["language"] : void 0;
|
|
18976
19271
|
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
18977
19272
|
};
|
|
@@ -19069,8 +19364,8 @@ var resultFromThrown = (thrown, t) => {
|
|
|
19069
19364
|
};
|
|
19070
19365
|
var block3 = (items) => items.length > 0 ? `${items.join("\n")}
|
|
19071
19366
|
` : "";
|
|
19072
|
-
var write2 = (sink,
|
|
19073
|
-
if (
|
|
19367
|
+
var write2 = (sink, text8) => {
|
|
19368
|
+
if (text8 !== "") sink.write(maskText(text8));
|
|
19074
19369
|
};
|
|
19075
19370
|
var render2 = (ctx, command, result) => {
|
|
19076
19371
|
if (result.raw !== void 0) {
|
|
@@ -19139,9 +19434,9 @@ import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
|
19139
19434
|
var UNKNOWN_VERSION = "0.0.0-unknown";
|
|
19140
19435
|
var VERSION_SOURCES = ["../package.json", "../.claude-plugin/plugin.json"];
|
|
19141
19436
|
var versionAt = (readText, moduleUrl, relative11) => {
|
|
19142
|
-
const
|
|
19143
|
-
if (!
|
|
19144
|
-
const parsed = parseJson(
|
|
19437
|
+
const text8 = readText(toAbsolutePath(fileURLToPath4(new URL(relative11, moduleUrl))));
|
|
19438
|
+
if (!text8.ok) return void 0;
|
|
19439
|
+
const parsed = parseJson(text8.value);
|
|
19145
19440
|
if (!parsed.ok || !isRecord(parsed.value)) return void 0;
|
|
19146
19441
|
const version = parsed.value["version"];
|
|
19147
19442
|
return typeof version === "string" ? version : void 0;
|