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.
Files changed (2) hide show
  1. package/dist/finitemonkey.mjs +756 -461
  2. package/package.json +1 -1
@@ -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 = (text7) => {
31
+ var parseJson = (text8) => {
32
32
  try {
33
- return accept(JSON.parse(text7));
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 = (text7) => {
39
- const parsed = parseJson(text7);
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, text7) => {
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, text7);
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 = (text7) => `sha256:${createHash("sha256").update(text7, "utf8").digest("hex")}`;
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 added = { schema, attribution, deny: deny2, ask: ask2, blockReads, marketplace, plugin };
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 = (text7) => {
867
- const parsed = parseJsonObject(text7);
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 = (text7) => {
1009
+ var parseConfigYaml = (text8) => {
930
1010
  const root = {};
931
1011
  const stack = [{ indent: -1, tree: root, key: void 0 }];
932
- for (const raw of text7.split(/\r?\n/)) {
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 text7 = runtime.readText(toAbsolutePath(join2(root, CONFIG_FILE2)));
956
- return text7.ok ? parseConfigYaml(text7.value) : {};
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 = (text7) => text7.includes("\r\n") ? "\r\n" : "\n";
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 = (text7, markers, body2) => {
968
- const eol = text7 === void 0 ? "\n" : lineBreak(text7);
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 (text7 === void 0 || text7 === "") return `${block4.join(eol)}${eol}`;
971
- const lines3 = text7.split(eol);
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 = text7.endsWith(eol) ? "" : eol;
975
- return `${text7}${separator}${block4.join(eol)}${eol}`;
1054
+ const separator = text8.endsWith(eol) ? "" : eol;
1055
+ return `${text8}${separator}${block4.join(eol)}${eol}`;
976
1056
  };
977
- var withoutManagedBlock = (text7, markers) => {
978
- const eol = lineBreak(text7);
979
- const lines3 = text7.split(eol);
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 text7;
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 = (text7) => text7.includes(GENERATED_MARKER);
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 = (text7) => GIT_HOOK_NAMES.some((hook) => new RegExp(`^${hook}:`, "m").test(withoutManagedBlock(text7, HOOK_MARKERS)));
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 = (text7) => {
1210
- const keys = withoutManagedBlock(text7, HOOK_MARKERS).split(/\r?\n/).filter((line2) => TOP_KEY.test(line2));
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 = (text7) => {
1249
- const tree = parseConfigYaml(text7);
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 text7 = runtime.readText(policyPath(root));
1269
- return text7.ok ? parsePolicy(text7.value) : DEFAULT_POLICY;
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 = (text7, runner, lang) => withManagedBlock(
1335
- text7,
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 = (text7) => text7 !== void 0 && IMPORT_LINE.test(withoutManagedBlock(text7, MARKDOWN_MARKERS)) ? text7 : withManagedBlock(text7, MARKDOWN_MARKERS, [AGENTS_IMPORT]);
1343
- var withoutMarkdownBlock = (text7) => withoutManagedBlock(text7, MARKDOWN_MARKERS);
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((text7) => (text7 ?? "").split("\n")).map(ruleFor).filter((rule) => rule !== void 0)
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 = (text7) => {
1453
- const indented = /\n([ \t]+)\S/.exec(text7);
1454
- return { indent: indented?.[1] ?? DEFAULT_STYLE.indent, finalNewline: text7.endsWith("\n") };
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 = (text7) => text7 === void 0 || text7.trim() === "" ? { ok: true, value: {} } : parseJsonObject(text7);
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 text7 = project.read("package.json");
1495
- const parsed = text7 === void 0 ? void 0 : parseJsonObject(text7);
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 = (text7) => {
1512
- if (text7 === void 0) return { exists: false, valid: true, userHooks: 0, ownHooks: 0 };
1513
- const parsed = text7.trim() === "" ? { ok: true, value: {} } : parseJsonObject(text7);
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 = (text7, source) => {
1528
- const parsed = text7 === void 0 ? void 0 : parseJsonObject(text7);
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 text7 = project.runtime.readText(toAbsolutePath(file));
1543
- return text7.ok ? text7.value : void 0;
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 = (text7) => withManagedBlock(text7, MARKERS, body());
1564
- var withoutBlock = (text7) => withoutManagedBlock(text7, MARKERS);
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((text7, step3) => step3(text7), item2.after);
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 added = { schema, deny: deny2, ask: ask2, blockReads, attribution, marketplace, plugin };
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 = (text7) => text7.startsWith("#!/usr/bin/env node") && text7.includes("finitemonkey");
1749
- var isOwnPackage = (text7) => {
1750
- const parsed = parseJsonObject(text7);
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 text7 = project.read(LOCK_FILE);
1782
- if (text7 === void 0) return accept(void 0);
1783
- const parsed = parseLock(text7);
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: (text7) => withAgentsBlock(text7, runner, lang) },
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: (text7) => text7.includes(GENERATED_MARKER) }];
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, text7) => {
1971
+ var writeText = (project, relative11, text8) => {
1906
1972
  const parent = ensureParent(project, relative11);
1907
- const written = parent.ok ? project.runtime.writeAtomic(project.abs(relative11), text7) : parent;
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 text7 = runtime.readText(abs(relative11));
2056
- return text7.ok ? text7.value : void 0;
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 text7 = ctx.runtime.readText(ctx.runtime.selfPath);
2130
- return text7.ok ? text7.value : void 0;
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 = (text7) => {
2235
- if (text7.length === 0) return 0;
2300
+ var shannonEntropy = (text8) => {
2301
+ if (text8.length === 0) return 0;
2236
2302
  const counts = /* @__PURE__ */ new Map();
2237
- for (const char of text7) counts.set(char, (counts.get(char) ?? 0) + 1);
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 / text7.length;
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 = (text7) => createHash2("sha256").update(text7).digest("hex");
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 = (text7) => {
2324
+ var lineLocator = (text8) => {
2259
2325
  const starts = [0];
2260
- for (let index = text7.indexOf("\n"); index !== -1; index = text7.indexOf("\n", index + 1)) starts.push(index + 1);
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 = (text7, at) => {
2620
+ var nameAround = (text8, at) => {
2555
2621
  let start = at;
2556
- while (start > 0 && NAME_CHAR.test(text7.charAt(start - 1))) start -= 1;
2622
+ while (start > 0 && NAME_CHAR.test(text8.charAt(start - 1))) start -= 1;
2557
2623
  let end = at;
2558
- while (end < text7.length && NAME_CHAR.test(text7.charAt(end))) end += 1;
2559
- return text7.slice(start, end).toLowerCase();
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, text7) => {
2635
+ var ruleSpans = (rule, text8) => {
2570
2636
  const spans = [];
2571
- for (const match of text7.matchAll(rule.pattern)) {
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 = (text7, options = {}) => {
2598
- if (text7.length === 0) return [];
2599
- const rules = applicable(options.rules ?? RULES, text7.toLowerCase(), options.path);
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, text7)) if (!overlaps(taken, span)) taken.push(span);
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(text7);
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 = (text7) => {
2613
- const findings = scanText(text7, { rules: CREDENTIAL_RULES });
2614
- if (findings.length === 0) return text7;
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 += text7.slice(cursor, finding4.start) + maskToken(finding4);
2684
+ out += text8.slice(cursor, finding4.start) + maskToken(finding4);
2619
2685
  cursor = finding4.end;
2620
2686
  }
2621
- return out + text7.slice(cursor);
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 text7 = env.runtime.readText(fmPaths(env.root).log);
2840
- if (!text7.ok) return [];
2841
- return text7.value.split("\n").filter((line2) => {
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 = (text7, home) => home.length > 1 ? text7.split(home).join("~") : text7;
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 text7 = ctx.runtime.readText(toAbsolutePath(join8(root, ...SETTINGS_FILE.split("/"))));
2883
- if (!text7.ok) return false;
2884
- const parsed = parseJsonObject(text7.value);
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 text7 = env.runtime.readText(path);
2919
- const parsed = text7.ok ? parseJsonObject(text7.value) : void 0;
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
- (text7, edit) => edit.all ? text7.split(edit.oldText).join(edit.newText) : text7.replace(edit.oldText, () => edit.newText),
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 = (text7) => text7.length <= REASON_LIMIT ? text7 : `${text7.slice(0, REASON_LIMIT - 1)}…`;
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 text7 = runtime.readText(path);
3253
- if (!text7.ok) return void 0;
3254
- const parsed = parseJsonObject(text7.value);
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 = (text7) => ({ text: text7, pos: 0, incomplete: false, subs: [] });
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 = (text7) => {
3583
- const cursor = cursorOf(text7.replace(/\r\n/g, "\n"));
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 text7 = op ?? "&";
3732
- cursor.pos += text7.length;
3733
- tokens.push({ kind: "op", text: text7 });
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 = (text7, cmd = false) => {
3743
- const cursor = cursorOf(text7.replace(/\r\n/g, "\n"));
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 = (text7, language) => language === "bash" ? lexBash(text7) : lexPowerShell(text7, language === "cmd");
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 = (text7, language, context, depth, collector) => {
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(text7, language);
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 = (text7, dialect = "bash") => {
4095
+ var normalizeCommand = (text8, dialect = "bash") => {
4030
4096
  const collector = { out: [], incomplete: false };
4031
- collect(text7, dialect, { env: {}, dir: void 0, via: [] }, 0, collector);
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 = (text7) => normalizeCommand(text7).commands.map((command) => ({
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 = (text7) => {
4206
- if (/\.finitemonkey[\\/]allow/.test(text7)) return "allow_store";
4207
- if (/\.finitemonkey|\.gitleaksignore/.test(text7)) return "policy";
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 text7 = input.runtime.readText(path);
4412
- return text7.ok ? text7.value : void 0;
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 = (text7) => `finitemonkey: ${text7}`;
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 text7 = runtime.readText(paths.cache(PAUSE_FILE));
4550
- const parsed = text7.ok ? parseJsonObject(text7.value) : void 0;
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 = (text7) => {
4606
- if (text7 === void 0) return { hooks: 0, disabled: false };
4607
- const parsed = parseJsonObject(text7);
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 text7 = runtime.readText(path);
4618
- return text7.ok ? text7.value : void 0;
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 text7 = files.read("package.json");
4674
- if (text7 === void 0) return [];
4675
- const parsed = parseJsonObject(text7);
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 = (text7, start) => {
4766
- const quote = text7[start];
4767
- for (let index = start + 1; index < text7.length; index += 1) {
4768
- const char = text7[index];
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 === "'" && text7[index + 1] === "'") {
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 = (text7) => {
4783
- const end = quotedEnd(text7, 0);
4784
- if (end !== text7.length - 1) return reject(`unterminated or trailing text after quoted string`);
4785
- const body2 = text7.slice(1, -1);
4786
- return text7.startsWith('"') ? unescapeDouble(body2) : accept(body2.replace(/''/g, "'"));
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 = (text7) => {
4791
- if (UNSUPPORTED.test(text7)) return reject(`unsupported YAML syntax "${text7.slice(0, 1)}"`);
4792
- if (text7 === "true" || text7 === "false") return accept(text7 === "true");
4793
- if (text7 === "null" || text7 === "~") return accept(null);
4794
- if (NUMBER.test(text7)) return accept(Number(text7));
4795
- return accept(text7);
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 = (text7) => {
4888
+ var splitKey = (text8) => {
4823
4889
  let index = 0;
4824
- if (text7.startsWith('"') || text7.startsWith("'")) {
4825
- index = quotedEnd(text7, 0) + 1;
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 < text7.length; index += 1) {
4829
- const char = text7[index];
4830
- if (char === "#" && text7[index - 1] === " ") return void 0;
4831
- if (char === ":" && (index + 1 === text7.length || text7[index + 1] === " ")) {
4832
- return { key: text7.slice(0, index).trim(), rest: text7.slice(index + 1).trim() };
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 = (text7) => {
4862
- if (text7 === "") return accept(null);
4863
- const first = text7[0] ?? "";
4864
- if (first === '"' || first === "'") return parseQuoted(text7);
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(text7);
4867
- if (!text7.endsWith(close2)) return reject(`flow collection must end on the same line with "${close2}"`);
4868
- const parts = splitTop(text7.slice(1, -1));
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 = (text7) => {
4876
- for (let index = 0; index < text7.length; index += 1) {
4877
- const char = text7[index];
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(text7, index);
4880
- if (end < 0) return text7;
4945
+ const end = quotedEnd(text8, index);
4946
+ if (end < 0) return text8;
4881
4947
  index = end;
4882
- } else if (char === "#" && (index === 0 || text7[index - 1] === " ")) return text7.slice(0, index);
4948
+ } else if (char === "#" && (index === 0 || text8[index - 1] === " ")) return text8.slice(0, index);
4883
4949
  }
4884
- return text7;
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 text7 = stripComment2(full).trimEnd();
4891
- const body2 = text7.trimStart();
4956
+ const text8 = stripComment2(full).trimEnd();
4957
+ const body2 = text8.trimStart();
4892
4958
  if (body2 === "" || body2 === "---" && lines3.length === 0) continue;
4893
- const indentText = text7.slice(0, text7.length - body2.length);
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, text7) => {
4903
- const value = parseValue(text7);
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 = (text7) => text7 === "-" || text7.startsWith("- ");
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, text7) => {
5150
- const yaml = parseYaml(text7);
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 = (text7) => text7.split("\0").filter((part2) => part2 !== "");
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 = (text7) => {
5263
- const fields = nulFields(text7);
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 text7 = runtime.readText(toAbsolutePath(join14(root, change.path)));
5332
- return sum + (text7.ok ? text7.value.split("\n").length : 0);
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 = (text7) => {
5356
- const parsed = parseJsonObject(text7);
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 text7 = runtime.readText(toAbsolutePath(join15(root, relative11)));
5538
- return text7.ok ? text7.value : void 0;
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 text7 = runtime.readText(paths.task(task));
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 || !text7.ok ? lock.approved : { ...lock.approved, [task]: text7.value }
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 = (text7) => {
5716
- const parsed = parseJson(text7);
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 text7 = runtime.readText(paths.log);
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 text7.ok ? text7.value.split("\n") : []) {
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 = (text7) => [...text7.matchAll(JS_SPECIFIER)].map((match) => match[1] ?? "");
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, text7) => {
9639
+ var definitionsIn = (language, text8) => {
9544
9640
  const names = /* @__PURE__ */ new Set();
9545
- for (const line2 of text7.split(/\r?\n/)) {
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 text7 = runtime.readText(toAbsolutePath(join16(root, path)));
9559
- return text7.ok ? text7.value : "";
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 = (text7, name) => new RegExp(`(?<![\\w$])${name.replace(/[$?!]/g, "\\$&")}(?![\\w$])`).test(text7);
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 cached2 = texts2.get(file) ?? current(runtime, git2.cwd, file);
9606
- texts2.set(file, cached2);
9607
- return cached2;
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 = (text7) => {
9676
- const line2 = /^=+ (.*) in [\d.]+s.*=+$/m.exec(text7)?.[1];
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 = (text7) => {
9779
+ var counted = (text8) => {
9684
9780
  for (const counter of COUNTERS) {
9685
- const total = counter.total.exec(text7)?.[1];
9781
+ const total = counter.total.exec(text8)?.[1];
9686
9782
  if (total === void 0) continue;
9687
- const failed4 = counter.failed?.exec(text7)?.[1];
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(text7);
9786
+ const py = pyTotal(text8);
9691
9787
  return py === void 0 ? {} : { total: py };
9692
9788
  };
9693
9789
  var parseTestSummary = (output) => {
9694
- const text7 = output.replace(ANSI2, "");
9790
+ const text8 = output.replace(ANSI2, "");
9695
9791
  const failures = [
9696
- ...new Set(FAILURE_LINES.flatMap((pattern) => [...text7.matchAll(pattern)].map((match) => (match[1] ?? "").trim())))
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(text7))) return { total: 0, failures };
9699
- return { ...counted(text7), failures };
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 = (text7) => {
9711
- const lines3 = text7.split(/\r?\n/).filter((line2) => line2.trim() !== "");
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 text7 = ctx.runtime.readText(summaryPath(ctx.paths, ctx.treeHash));
9926
- const parsed = text7.ok ? parseJsonObject(text7.value) : void 0;
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 text7 = ctx.runtime.readText(toAbsolutePath(join20(ctx.paths.root, change.path)));
9996
- return text7.ok ? text7.value.split("\n").map((line2, index) => ({ path: change.path, line: index + 1, text: line2 })) : [];
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 = (text7) => parsePreset(PRESET_LINE.exec(text7)?.[1]) ?? "neutral";
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 = (text7) => {
10328
+ var unfencedLines = (text8) => {
10233
10329
  let fenced = false;
10234
- return text7.split("\n").filter((line2) => {
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 = (text7) => unfencedLines(text7).some((line2) => FILE_MARKER.test(outsideCode(line2)));
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 = (text7) => text7.match(ANY_MARKER)?.length ?? 0;
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((text7, [pattern, replacement]) => text7.replace(pattern, replacement), line2);
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 text7 = sentence.trim();
10353
- return text7 === "" ? [] : [{ text: text7, line: lineAt(at) }];
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 = (text7) => {
10375
- if (allowsWholeFile(text7)) return { units: [], allowed: true };
10376
- const lines3 = text7.split("\n").map(withoutCarriageReturn);
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 = (text7) => text7.split(/\s+/).filter((word2) => WORD.test(word2));
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 = (text7, options = {}) => {
10630
- const { units, allowed: allowed2 } = extractProse(text7);
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 text7 = runtime.readText(toAbsolutePath(file, root));
10663
- if (!text7.ok) return reject(`${file}: ${text7.error}`);
10664
- reports.push({ file: toPosixPath(file), report: scoreProse(text7.value, { context: forced ?? contextOf(file) }) });
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 = (text7) => {
10764
- const rows = text7.split(/\r?\n/).filter((row) => row.trim() !== "" && !/^\s*at\s|^Node\.js v\d/.test(row));
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 = (text7) => text7.slice(0, 8e3).includes("\0");
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 text7 = runtime.readText(toAbsolutePath(file, root));
11121
- if (!text7.ok || text7.value.length > MAX_FILE_BYTES || binary(text7.value)) return [];
11122
- return scanText(text7.value, { path: file }).map((finding4) => locate(finding4, file, finding4.line));
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 text7 = ctx.runtime.readText(toAbsolutePath(join24(ctx.paths.root, path)));
11220
- return text7.ok ? text7.value : void 0;
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 = (text7) => {
11480
+ var parseUnifiedDiff = (text8) => {
11385
11481
  const out = [];
11386
11482
  let draft;
11387
- for (const raw of text7.split("\n")) {
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 cached2;
11584
+ let cached3;
11489
11585
  return () => {
11490
- cached2 ??= { value: compute() };
11491
- return cached2.value;
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 = (text7) => text7 === void 0 ? [] : meaningful(text7.split("\n"));
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, text7) => ({
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: text7,
11688
+ text: text8,
11593
11689
  weak: false
11594
11690
  });
11595
- var parseDropped = (text7) => {
11596
- const parsed = parseJson(text7);
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 text7 = runtime.readText(path);
11613
- if (!text7.ok) return file === void 0 ? accept({ items: [], invalid: [] }) : reject(`${file}: ${text7.error}`);
11614
- return parseDropped(text7.value);
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 text7 = added.find((line2) => !isWeak(line2) && !present2.has(line2));
11738
- if (text7 === void 0 || containsSequence(file.result, added) || elsewhere(added)) return [];
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) === text7)
11837
+ hunk.added.findIndex((line2) => normalizeLine(line2) === text8)
11742
11838
  );
11743
- return [{ kind: "missing-addition", file: file.path, side, line: hunk.newStart + offset, text: text7, weak: false }];
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 = (text7) => text7.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
11817
- var containsSymbol = (text7, symbol) => symbol.test ? text7.includes(symbol.name) : new RegExp(`(?<![\\w$])${escapeRegex(symbol.name)}(?![\\w$])`).test(text7);
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, text7) => ({
11932
+ var finding2 = (kind, file, side, text8) => ({
11837
11933
  kind,
11838
11934
  file,
11839
11935
  side,
11840
11936
  line: void 0,
11841
- text: text7,
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, text7) => {
11861
- const present2 = (symbol) => text7 !== void 0 && containsSymbol(text7, symbol) || context.resultFiles().some((other) => containsSymbol(context.resultText(other) ?? "", 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 text7 = path === void 0 ? void 0 : context.resultText(path);
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(text7),
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, text7)];
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 text7 = runtime.readText(path);
12010
- return text7.ok ? parseJsonObject(text7.value) : text7;
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 = (text7) => text7.split("\n").filter((line2) => line2.trim() !== "");
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 text7 = runtime.readText(toAbsolutePath(join29(paths.root, relative11)));
12481
- return text7.ok ? text7.value : void 0;
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 = (text7) => {
12508
- const flat = text7.replace(/\s+/g, " ").trim();
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 = (text7) => {
12859
- const urls = [...text7.matchAll(SSH_URL)].map((match) => match[1] ?? "");
12860
- const lines3 = text7.split(/\r?\n/);
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 text7 = runtime.readText(toAbsolutePath(join30(root, file)));
12875
- return text7.ok ? hostsInText(text7.value) : [];
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 text7 = commandText(command);
13050
- return hit3.effect === "read" ? { kind: "read", hit: hit3, command: text7 } : blockOf(t, hit3, text7, targets2().deployPath);
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 text7 = before.ok ? before.value : "";
13071
- runtime.writeAtomic(path, `${text7}${text7 === "" || text7.endsWith("\n") ? "" : "\n"}${lines3.join("\n")}
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 text7 = optionalString(edit, "new_string");
13087
- return text7 === void 0 ? [] : [{ file, text: text7, whole: false }];
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 text7 = optionalString(input, key);
13094
- return text7 === void 0 ? [] : [{ file, text: text7, whole }];
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, text7) => {
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: text7 };
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: text7 };
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: text7 };
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: text7 } : { kind: "snapshot", repo, op: verdict.op, command: text7 };
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 text7 = runtime.readText(journalPath(root));
13911
- if (!text7.ok) return [];
13912
- return text7.value.split("\n").flatMap((line2) => {
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 text7 = shellText(input.payload);
14105
- if (text7 === void 0) return ALLOW;
14106
- const commands = normalizeCommand(text7, dialectOf(toolName2(input.payload))).commands;
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 text7 = runtime.readText(paths.cache(SHADOW_FILE));
14169
- const parsed = text7.ok ? parseJsonObject(text7.value) : void 0;
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 text7 = command.replace(HEREDOC2, (_match, _quote, _tag, body2) => {
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: text7, heredocs };
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 = (text7, from, quote) => {
14364
+ var quotedEnd2 = (text8, from, quote) => {
14269
14365
  let index = from;
14270
- while (index < text7.length && text7[index] !== quote) index += quote === '"' && text7[index] === "\\" ? 2 : 1;
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 = (text7) => {
14370
+ var splitWords = (text8) => {
14275
14371
  const scan = { words: [], segments: [], word: void 0 };
14276
- for (let index = 0; index < text7.length; index += 1) {
14277
- const char = text7[index] ?? "";
14372
+ for (let index = 0; index < text8.length; index += 1) {
14373
+ const char = text8[index] ?? "";
14278
14374
  if (char === '"' || char === "'") {
14279
- const end = quotedEnd2(text7, index + 1, char);
14280
- const inner = text7.slice(index + 1, end);
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 < text7.length) {
14284
- scan.word = (scan.word ?? "") + (text7[index + 1] === "\n" ? "" : text7[index + 1] ?? "");
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: text7, heredocs } = liftHeredocs(command);
14306
- const segments = splitWords(text7).flatMap((words) => {
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((text7) => text7 !== void 0);
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 text7 = textOf2(input, found);
14509
- if (!text7.ok) {
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", { ...text7.error }),
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(text7.value, { context: "record" });
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((text7) => scanText(text7, { rules: CREDENTIAL_RULES })).filter((finding4) => !accepted2.has(finding4.fingerprint));
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 text7 = input.t("secrets.session.remote_credential", params2);
14920
+ const text8 = input.t("secrets.session.remote_credential", params2);
14825
14921
  return {
14826
14922
  kind: "allow",
14827
14923
  output: {
14828
- systemMessage: `finitemonkey: ${text7}`,
14829
- hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: text7 }
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, text7, interactive) => {
14919
- if (interactive && text7.trim() === "") return accept(EMPTY_PAYLOAD);
14920
- const parsed = parseJsonObject(text7);
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 text7 = await readAll(options.stdin);
14981
- const parsed = parseHookPayload(event, text7, options.stdin.isTTY === true);
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 = (text7, vars) => text7.replace(/\$\{(\w+)\}|\$(\w+)/g, (match, braced, bare) => {
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 = (text7) => maskText(text7.trim().split("\n")[0] ?? "").slice(0, 160);
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 text7 = env.runtime.readText(path);
15339
- const parsed = text7.ok ? parseJsonObject(text7.value) : void 0;
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 text7 = env.runtime.readText(hooksPath);
15351
- const parsed = text7.ok ? parseJsonObject(text7.value) : void 0;
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: text7.ok ? text7.value : void 0
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 text7 = env.runtime.readText(path);
15387
- return text7.ok && text7.value.trim() !== "" && !parseJsonObject(text7.value).ok ? [path] : [];
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 text7 = env.runtime.readText(toAbsolutePath(join35(env.root, ...relative11.split("/"))));
15474
- return text7.ok ? text7.value : void 0;
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 text7 = readProjectFile(env, path);
15481
- return text7 === void 0 ? [] : [{ path, text: text7 }];
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 = (text7) => text7.split("\n").length - (text7.endsWith("\n") ? 1 : 0);
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 text7 = readProjectFile(env, file);
15532
- const lines3 = text7 === void 0 ? 0 : lineCount(text7);
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 = (text7) => text7.split("\n").map((raw) => withoutCarriageReturn(raw).trim()).filter((line2) => !/^(#|\||```|@|>)/.test(line2)).map(
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: text7 } of files) {
15551
- for (const line2 of ruleLines(text7)) seen.set(line2, (seen.get(line2) ?? /* @__PURE__ */ new Set()).add(path));
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 = (text7) => text7.replace(/\r?\n$/, "").split(/\r?\n/).length;
15697
+ var lineCount2 = (text8) => text8.replace(/\r?\n$/, "").split(/\r?\n/).length;
15602
15698
  var checkAgentsFile = ({ root, runtime }) => {
15603
- const text7 = runtime.readText(toAbsolutePath(join37(root, AGENTS_FILE)));
15604
- if (!text7.ok) return [];
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(text7.value);
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 text7 = reportMarkdown(env, ctx, toEnvelope("doctor", result));
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, text7) : dir;
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 text7 = ctx.runtime.readText(toAbsolutePath(file, ctx.cwd));
16117
- if (!text7.ok)
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(text7.value);
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 = (text7) => text7.split("\n").filter((line2) => line2.trim() !== "");
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 = (text7, width) => text7.padEnd(Math.max(width, text7.length + 1));
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 text7 = "";
16789
+ let text8 = "";
16694
16790
  const flush2 = () => {
16695
- if (text7 !== "") nodes.push({ kind: "text", text: text7 });
16696
- text7 = "";
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
- text7 += char;
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
- text7 += char;
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
- text7 += char;
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
- text7 += char;
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 = (text7) => RELEASE_HINTS.flatMap((pattern) => {
16849
- const match = pattern.exec(text7);
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 text7 = ctx.runtime.readText(file);
16889
- if (!text7.ok) return reject(unreadable(dir, file, text7.error));
16890
- const parsed = parseJsonObject(text7.value);
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 text7 = ctx.runtime.readText(toAbsolutePath(join40(dir, "review.json")));
16911
- const parsed = text7.ok ? parseJsonObject(text7.value) : void 0;
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 text7 = textOf3(block4["content"]);
17057
- draft.results.set(block4["tool_use_id"], { failed: block4["is_error"] === true || FAILED_EXIT.test(text7), text: text7 });
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 text7 = runtime.readText(toAbsolutePath(join41(dir, name)));
17109
- if (!text7.ok) continue;
17110
- for (const turn of parseTranscript(text7.value)) {
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 = (text7) => text7 === "" ? [] : text7.replace(/\r?\n$/, "").split(/\r?\n/);
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 = (text7, width) => text7.padEnd(width);
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 text7 = (node.textContent ?? "").trim();
17372
- if (KEY2.test(text7) && !NOT_KEY.test(text7) || PLACEHOLDER2.test(text7)) keys.add(text7.slice(0, 80));
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, text7) => {
17406
- if (list4.length < MAX_EVENTS) list4.push(text7.slice(0, 200));
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 = (text7) => text7.replace(/[&<>"]/g, (char) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[char] ?? char);
17586
+ var escapeHtml = (text8) => text8.replace(/[&<>"]/g, (char) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[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 = (text7, max) => text7.split("\n").slice(-max).join("\n");
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 text7 = git(runtime, root, ["show", `${base}:REVIEW.md`]);
17888
- return text7 === void 0 ? void 0 : text7.split("\n").slice(0, REVIEW_FILE_MAX_LINES).join("\n");
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 text7 = [
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: text7 };
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 text7 = runtime.readText(toAbsolutePath(join47(paths.root, relative11)));
18538
- return text7.ok ? text7.value : void 0;
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 text7 = stringifyYaml(contractYaml(shape));
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), text7);
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]: text7 }
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: text7 });
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 = (text7) => withoutManagedBlock(text7, { begin: BLOCK_BEGIN, end: BLOCK_END });
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 text7 = blockless(entry2.kind, current2);
18754
- return text7.trim() === "" && !entry2.existed ? void 0 : text7;
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 text7 = runtime.readText(toAbsolutePath(path));
18966
- return text7.ok ? text7.value : void 0;
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 = (text7) => {
18973
- if (text7 === void 0) return void 0;
18974
- const parsed = parseJsonObject(text7);
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, text7) => {
19073
- if (text7 !== "") sink.write(maskText(text7));
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 text7 = readText(toAbsolutePath(fileURLToPath4(new URL(relative11, moduleUrl))));
19143
- if (!text7.ok) return void 0;
19144
- const parsed = parseJson(text7.value);
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;