finitemonkey 0.1.0-next.12 → 0.1.0-next.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.es.md CHANGED
@@ -133,6 +133,7 @@ Generado desde `src/core/footprint.ts`, la lista que los tests exigen al código
133
133
  | Lee | `stdin` | El evento que Claude Code pasa a cada hook: la llamada a la herramienta, el prompt o la petición de parada. |
134
134
  | Lee | `.claude/settings.json`, `.claude/settings.local.json`, `~/.claude/settings.json` | La configuración de Claude Code, para comprobar que los hooks están instalados y que nada los desactiva. `$CLAUDE_CONFIG_DIR` reemplaza `~/.claude` si está definido. |
135
135
  | Lee | `CLAUDE.md`, `.claude/CLAUDE.md`, `CLAUDE.local.md`, `AGENTS.md`, `.claude/rules/`, `.claudeignore` | Archivos de instrucciones, que `doctor` lee para señalar reglas que solo existen como texto. |
136
+ | Lee | `~/.claude/projects/` | Los logs locales de sesión de Claude Code de este proyecto, leídos una vez y solo con `init --look-back`. |
136
137
  | Lee | `.git/` | El repositorio a través del comando `git`: estado, diffs, refs y el reflog. |
137
138
  | Lee | `git diff` | Archivos modificados, revisados en busca de secretos, tests saltados, placeholders y patrones de prosa. |
138
139
  | Lee | `.finitemonkey/config.yml`, `.finitemonkey/briefing.md` | La configuración del proyecto y el briefing opcional para subagentes. |
package/README.md CHANGED
@@ -133,6 +133,7 @@ Generated from `src/core/footprint.ts`, the list the tests hold the code to. No
133
133
  | Reads | `stdin` | The event Claude Code passes to each hook: the tool call, the prompt or the stop request. |
134
134
  | Reads | `.claude/settings.json`, `.claude/settings.local.json`, `~/.claude/settings.json` | Claude Code settings, to check that the hooks are installed and nothing switches them off. `$CLAUDE_CONFIG_DIR` replaces `~/.claude` when set. |
135
135
  | Reads | `CLAUDE.md`, `.claude/CLAUDE.md`, `CLAUDE.local.md`, `AGENTS.md`, `.claude/rules/`, `.claudeignore` | Instruction files, read by `doctor` to report rules that exist only as text. |
136
+ | Reads | `~/.claude/projects/` | This project's local Claude Code session logs, read once and only with `init --look-back`. |
136
137
  | Reads | `.git/` | The repository through the `git` command: status, diffs, refs and the reflog. |
137
138
  | Reads | `git diff` | Changed files, scanned for secrets, test skips, placeholders and prose patterns. |
138
139
  | Reads | `.finitemonkey/config.yml`, `.finitemonkey/briefing.md` | Project configuration and the optional briefing for subagents. |
package/README.pt-BR.md CHANGED
@@ -133,6 +133,7 @@ Gerado a partir de `src/core/footprint.ts`, a lista que os testes cobram do cód
133
133
  | Lê | `stdin` | O evento que o Claude Code passa a cada hook: a chamada de ferramenta, o prompt ou o pedido de parada. |
134
134
  | Lê | `.claude/settings.json`, `.claude/settings.local.json`, `~/.claude/settings.json` | As configurações do Claude Code, para conferir que os hooks estão instalados e que nada os desliga. `$CLAUDE_CONFIG_DIR` substitui `~/.claude` quando definido. |
135
135
  | Lê | `CLAUDE.md`, `.claude/CLAUDE.md`, `CLAUDE.local.md`, `AGENTS.md`, `.claude/rules/`, `.claudeignore` | Arquivos de instrução, lidos pelo `doctor` para apontar regras que só existem como texto. |
136
+ | Lê | `~/.claude/projects/` | Os logs locais de sessão do Claude Code deste projeto, lidos uma vez e só com `init --look-back`. |
136
137
  | Lê | `.git/` | O repositório pelo comando `git`: status, diffs, refs e o reflog. |
137
138
  | Lê | `git diff` | Arquivos alterados, varridos atrás de segredos, testes pulados, placeholders e padrões de prosa. |
138
139
  | Lê | `.finitemonkey/config.yml`, `.finitemonkey/briefing.md` | A configuração do projeto e o briefing opcional para subagentes. |
@@ -5413,7 +5413,14 @@ var en_default = {
5413
5413
  "doctor.memory.too_long": "{file}: {lines, plural, one {# line} other {# lines}}, above the ceiling of {max}; long instruction files get followed less",
5414
5414
  "doctor.memory.fix_too_long": "Move details out of {file} into docs or skills until it has at most {max} lines, or raise memory.maxLines in .finitemonkey/config.yml",
5415
5415
  "doctor.git.autocrlf": 'git converts line endings to CRLF on checkout (core.autocrlf=true) and {file} does not pin LF; shell hooks and scripts checked out with CRLF fail with "bad interpreter"',
5416
- "doctor.git.fix_autocrlf": "add `* text=auto eol=lf` to {file}, commit it, then run `git add --renormalize .`"
5416
+ "doctor.git.fix_autocrlf": "add `* text=auto eol=lf` to {file}, commit it, then run `git add --renormalize .`",
5417
+ "history.title": "Looking back at this project's local Claude Code sessions: {sessions, plural, one {# session} other {# sessions}}, {turns, plural, one {# turn} other {# turns}}.",
5418
+ "history.pattern.done_after_failing_tests": '{count, plural, one {# turn} other {# turns}} ended with "done" right after a failing test run',
5419
+ "history.pattern.env_read": "{count, plural, one {# read} other {# reads}} of a .env file",
5420
+ "history.pattern.no_verify": "{count, plural, one {# git command} other {# git commands}} with --no-verify",
5421
+ "history.pattern.force_push": "{count, plural, one {# force push} other {# force pushes}}",
5422
+ "history.pattern.test_skip": "{count, plural, one {# test edit} other {# test edits}} that added .skip, .only or a skip marker",
5423
+ "history.estimate": "These are estimates from pattern matching, not evidence; nothing was saved and nothing left this machine."
5417
5424
  };
5418
5425
 
5419
5426
  // src/i18n/es.json
@@ -5917,7 +5924,14 @@ var es_default = {
5917
5924
  "doctor.memory.too_long": "{file}: {lines, plural, one {# línea} other {# líneas}}, por encima del techo de {max}; un archivo de instrucciones largo se sigue menos",
5918
5925
  "doctor.memory.fix_too_long": "Lleva detalles de {file} a docs o skills hasta que tenga como máximo {max} líneas, o sube memory.maxLines en .finitemonkey/config.yml",
5919
5926
  "doctor.git.autocrlf": 'git convierte los saltos de línea a CRLF al hacer checkout (core.autocrlf=true) y {file} no fija LF; los hooks y scripts de shell con CRLF fallan con "bad interpreter"',
5920
- "doctor.git.fix_autocrlf": "añade `* text=auto eol=lf` a {file}, haz commit y ejecuta `git add --renormalize .`"
5927
+ "doctor.git.fix_autocrlf": "añade `* text=auto eol=lf` a {file}, haz commit y ejecuta `git add --renormalize .`",
5928
+ "history.title": "Revisando las sesiones locales de Claude Code en este proyecto: {sessions, plural, one {# sesión} other {# sesiones}}, {turns, plural, one {# turno} other {# turnos}}.",
5929
+ "history.pattern.done_after_failing_tests": '{count, plural, one {# turno terminó} other {# turnos terminaron}} con "terminado" justo después de pruebas fallidas',
5930
+ "history.pattern.env_read": "{count, plural, one {# lectura} other {# lecturas}} de un archivo .env",
5931
+ "history.pattern.no_verify": "{count, plural, one {# comando git} other {# comandos git}} con --no-verify",
5932
+ "history.pattern.force_push": "{count, plural, one {# push forzado} other {# push forzados}}",
5933
+ "history.pattern.test_skip": "{count, plural, one {# edición} other {# ediciones}} de pruebas que añadieron .skip, .only o una marca para saltar",
5934
+ "history.estimate": "Son estimaciones por patrones de texto, no evidencia; no se guardó nada y nada salió de esta máquina."
5921
5935
  };
5922
5936
 
5923
5937
  // src/i18n/pt-BR.json
@@ -6421,7 +6435,14 @@ var pt_BR_default = {
6421
6435
  "doctor.memory.too_long": "{file}: {lines, plural, one {# linha} other {# linhas}}, acima do teto de {max}; arquivo de instruções longo é menos seguido",
6422
6436
  "doctor.memory.fix_too_long": "Leve detalhes de {file} para docs ou skills até ficar com no máximo {max} linhas, ou aumente memory.maxLines em .finitemonkey/config.yml",
6423
6437
  "doctor.git.autocrlf": 'o git converte quebras de linha para CRLF no checkout (core.autocrlf=true) e o {file} não fixa LF; hooks e scripts de shell com CRLF falham com "bad interpreter"',
6424
- "doctor.git.fix_autocrlf": "acrescente `* text=auto eol=lf` ao {file}, faça commit e rode `git add --renormalize .`"
6438
+ "doctor.git.fix_autocrlf": "acrescente `* text=auto eol=lf` ao {file}, faça commit e rode `git add --renormalize .`",
6439
+ "history.title": "Olhando as sessões locais do Claude Code neste projeto: {sessions, plural, one {# sessão} other {# sessões}}, {turns, plural, one {# turno} other {# turnos}}.",
6440
+ "history.pattern.done_after_failing_tests": '{count, plural, one {# turno terminou} other {# turnos terminaram}} com "pronto" logo depois de testes falhando',
6441
+ "history.pattern.env_read": "{count, plural, one {# leitura} other {# leituras}} de arquivo .env",
6442
+ "history.pattern.no_verify": "{count, plural, one {# comando git} other {# comandos git}} com --no-verify",
6443
+ "history.pattern.force_push": "{count, plural, one {# push forçado} other {# pushes forçados}}",
6444
+ "history.pattern.test_skip": "{count, plural, one {# edição} other {# edições}} de teste que acrescentaram .skip, .only ou marcador de pular",
6445
+ "history.estimate": "São estimativas por padrão de texto, não evidência; nada foi salvo e nada saiu desta máquina."
6425
6446
  };
6426
6447
 
6427
6448
  // src/i18n/review.json
@@ -6926,7 +6947,14 @@ var review_default = {
6926
6947
  "doctor.memory.too_long": "machine",
6927
6948
  "doctor.memory.fix_too_long": "machine",
6928
6949
  "doctor.git.autocrlf": "machine",
6929
- "doctor.git.fix_autocrlf": "machine"
6950
+ "doctor.git.fix_autocrlf": "machine",
6951
+ "history.title": "machine",
6952
+ "history.pattern.done_after_failing_tests": "machine",
6953
+ "history.pattern.env_read": "machine",
6954
+ "history.pattern.no_verify": "machine",
6955
+ "history.pattern.force_push": "machine",
6956
+ "history.pattern.test_skip": "machine",
6957
+ "history.estimate": "machine"
6930
6958
  },
6931
6959
  es: {
6932
6960
  "command.init.summary": "machine",
@@ -7428,7 +7456,14 @@ var review_default = {
7428
7456
  "doctor.memory.too_long": "machine",
7429
7457
  "doctor.memory.fix_too_long": "machine",
7430
7458
  "doctor.git.autocrlf": "machine",
7431
- "doctor.git.fix_autocrlf": "machine"
7459
+ "doctor.git.fix_autocrlf": "machine",
7460
+ "history.title": "machine",
7461
+ "history.pattern.done_after_failing_tests": "machine",
7462
+ "history.pattern.env_read": "machine",
7463
+ "history.pattern.no_verify": "machine",
7464
+ "history.pattern.force_push": "machine",
7465
+ "history.pattern.test_skip": "machine",
7466
+ "history.estimate": "machine"
7432
7467
  }
7433
7468
  };
7434
7469
 
@@ -14424,6 +14459,178 @@ var i18nCheckCommand = {
14424
14459
  }
14425
14460
  };
14426
14461
 
14462
+ // src/history/look-back.ts
14463
+ import { join as join36 } from "node:path";
14464
+
14465
+ // src/history/patterns.ts
14466
+ import { posix as posix4 } from "node:path";
14467
+ var PATTERNS = ["done_after_failing_tests", "env_read", "no_verify", "force_push", "test_skip"];
14468
+ var TEST_COMMAND = /(^|[\s;&|(])((npm|pnpm|yarn|bun)\s+(run\s+)?(test|check)\b|npx\s+(vitest|jest)\b|vitest\b|jest\b|pytest\b|go\s+test\b|cargo\s+test\b|node\s+--test\b|mocha\b)/;
14469
+ var DONE_CLAIM = /\b(done|all (tests|checks) (pass|passed|are passing)|everything (passes|works)|it works|pronto|feito|conclu[ií]do|listo|terminado)\b/i;
14470
+ var ENV_FILE2 = /(^|[\s"'=/])\.env(\.[A-Za-z0-9_-]+)?(?=$|[\s"';|&)])/;
14471
+ var ENV_TEMPLATE = /\.env\.(example|sample|template|dist|defaults)\b/;
14472
+ var READ_COMMAND = /(^|[\s;&|(])(cat|less|more|head|tail|bat|type|Get-Content|source|\.)\s/;
14473
+ var PUSH = /(^|[\s;&|(])git\s+push\b([^;&|\n]*)/;
14474
+ var FORCE = /\s(--force(-with-lease)?(=\S*)?|-f|-[A-Za-z]*f[A-Za-z]*)(?=\s|$)|\s\+\S/;
14475
+ var NO_VERIFY = /(^|[\s;&|(])git\s+(commit|push|merge|rebase|am|cherry-pick)\b[^;&|\n]*\s--no-verify\b/;
14476
+ var TEST_FILE = /(\.(test|spec)\.[cm]?[jt]sx?$|(^|\/)__tests__\/|_test\.(go|py)$|(^|\/)test_[^/]+\.py$)/;
14477
+ var SKIP = /\b(it|test|describe)\.skip\s*\(|\bx(it|describe|test)\s*\(|@pytest\.mark\.skip|\bt\.Skip\(|\.only\s*\(/;
14478
+ var commandOf = (tool) => {
14479
+ if (tool.name !== "Bash" && tool.name !== "PowerShell") return void 0;
14480
+ const command = tool.input["command"];
14481
+ return typeof command === "string" ? command : void 0;
14482
+ };
14483
+ var stringField = (tool, name) => {
14484
+ const value = tool.input[name];
14485
+ return typeof value === "string" ? value : "";
14486
+ };
14487
+ var isEnvPath = (path) => {
14488
+ const name = posix4.basename(path.replace(/\\/g, "/"));
14489
+ return /^\.env(\.[A-Za-z0-9_-]+)?$/.test(name) && !ENV_TEMPLATE.test(name);
14490
+ };
14491
+ var envRead = (tool) => {
14492
+ if (tool.name === "Read") return isEnvPath(stringField(tool, "file_path"));
14493
+ const command = commandOf(tool);
14494
+ if (command === void 0 || !READ_COMMAND.test(command)) return false;
14495
+ const match = ENV_FILE2.exec(command);
14496
+ return match !== null && !ENV_TEMPLATE.test(command.slice(match.index, match.index + match[0].length + 12));
14497
+ };
14498
+ var forcePush = (command) => {
14499
+ const match = PUSH.exec(command);
14500
+ return match !== null && FORCE.test(match[2] ?? "");
14501
+ };
14502
+ var addedSkip = (tool) => {
14503
+ const path = stringField(tool, "file_path");
14504
+ if (!TEST_FILE.test(path.replace(/\\/g, "/"))) return false;
14505
+ if (tool.name === "Write") return SKIP.test(stringField(tool, "content"));
14506
+ if (tool.name === "Edit")
14507
+ return SKIP.test(stringField(tool, "new_string")) && !SKIP.test(stringField(tool, "old_string"));
14508
+ if (tool.name !== "MultiEdit") return false;
14509
+ const edits = tool.input["edits"];
14510
+ return Array.isArray(edits) && edits.some((edit) => {
14511
+ if (typeof edit !== "object" || edit === null) return false;
14512
+ const next2 = "new_string" in edit && typeof edit.new_string === "string" ? edit.new_string : "";
14513
+ const before = "old_string" in edit && typeof edit.old_string === "string" ? edit.old_string : "";
14514
+ return SKIP.test(next2) && !SKIP.test(before);
14515
+ });
14516
+ };
14517
+ var doneAfterFailure = (turn) => {
14518
+ const runs = turn.tools.filter((tool) => TEST_COMMAND.test(commandOf(tool) ?? ""));
14519
+ const last = runs.at(-1);
14520
+ if (last === void 0 || turn.results.get(last.id)?.failed !== true) return void 0;
14521
+ return DONE_CLAIM.test(turn.finalText) ? last : void 0;
14522
+ };
14523
+ var sampleOf = (tool) => (commandOf(tool) ?? stringField(tool, "file_path")).split("\n")[0]?.slice(0, 120) ?? "";
14524
+ var hitsIn = (turn) => {
14525
+ const hits = [];
14526
+ const done = doneAfterFailure(turn);
14527
+ if (done !== void 0) hits.push({ pattern: "done_after_failing_tests", sample: sampleOf(done) });
14528
+ for (const tool of turn.tools) {
14529
+ const command = commandOf(tool);
14530
+ if (envRead(tool)) hits.push({ pattern: "env_read", sample: sampleOf(tool) });
14531
+ if (command !== void 0 && NO_VERIFY.test(command)) hits.push({ pattern: "no_verify", sample: sampleOf(tool) });
14532
+ if (command !== void 0 && forcePush(command)) hits.push({ pattern: "force_push", sample: sampleOf(tool) });
14533
+ if (addedSkip(tool)) hits.push({ pattern: "test_skip", sample: sampleOf(tool) });
14534
+ }
14535
+ return hits;
14536
+ };
14537
+
14538
+ // src/history/transcript.ts
14539
+ var blocksOf = (message) => {
14540
+ if (!isRecord(message)) return [];
14541
+ const content = message["content"];
14542
+ if (typeof content === "string") return [{ type: "text", text: content }];
14543
+ return Array.isArray(content) ? content : [];
14544
+ };
14545
+ var textOf3 = (value) => {
14546
+ if (typeof value === "string") return value;
14547
+ if (Array.isArray(value)) return value.map(textOf3).join("\n");
14548
+ return isRecord(value) && typeof value["text"] === "string" ? value["text"] : "";
14549
+ };
14550
+ var FAILED_EXIT = /^Exit code [1-9]\d*/m;
14551
+ var startTurn = (prompt) => ({ prompt, tools: [], results: /* @__PURE__ */ new Map(), finalText: "" });
14552
+ var addAssistant = (draft, blocks) => {
14553
+ for (const block4 of blocks) {
14554
+ if (!isRecord(block4)) continue;
14555
+ if (block4["type"] === "text" && typeof block4["text"] === "string" && block4["text"].trim() !== "") {
14556
+ draft.finalText = block4["text"];
14557
+ }
14558
+ const { id, name, input } = block4;
14559
+ if (block4["type"] === "tool_use" && typeof id === "string" && typeof name === "string" && isRecord(input)) {
14560
+ draft.tools.push({ id, name, input });
14561
+ }
14562
+ }
14563
+ };
14564
+ var addResults = (draft, blocks) => {
14565
+ let any = false;
14566
+ for (const block4 of blocks) {
14567
+ if (!isRecord(block4) || block4["type"] !== "tool_result" || typeof block4["tool_use_id"] !== "string") continue;
14568
+ const text6 = textOf3(block4["content"]);
14569
+ draft.results.set(block4["tool_use_id"], { failed: block4["is_error"] === true || FAILED_EXIT.test(text6), text: text6 });
14570
+ any = true;
14571
+ }
14572
+ return any;
14573
+ };
14574
+ var parseTranscript = (jsonl) => {
14575
+ const turns = [];
14576
+ let current;
14577
+ for (const line2 of jsonl.split(/\r?\n/)) {
14578
+ if (line2.trim() === "") continue;
14579
+ const parsed = parseJsonObject(line2);
14580
+ if (!parsed.ok) continue;
14581
+ const entry2 = parsed.value;
14582
+ const blocks = blocksOf(entry2["message"]);
14583
+ if (entry2["type"] === "user") {
14584
+ if (current !== void 0 && addResults(current, blocks)) continue;
14585
+ const prompt = blocks.map(textOf3).join("\n").trim();
14586
+ if (prompt === "") continue;
14587
+ current = startTurn(prompt);
14588
+ turns.push(current);
14589
+ } else if (entry2["type"] === "assistant" && current !== void 0) {
14590
+ addAssistant(current, blocks);
14591
+ }
14592
+ }
14593
+ return turns;
14594
+ };
14595
+
14596
+ // src/history/look-back.ts
14597
+ var SAMPLES = 3;
14598
+ var projectLogKey = (root) => root.replace(/[^A-Za-z0-9-]/g, "-");
14599
+ var projectLogDir = (runtime, root, env) => join36(env["CLAUDE_CONFIG_DIR"] ?? join36(runtime.homeDir(), ".claude"), "projects", projectLogKey(root));
14600
+ var lookBack = (runtime, root, env) => {
14601
+ const dir = projectLogDir(runtime, root, env);
14602
+ const listed4 = runtime.listDir(toAbsolutePath(dir));
14603
+ const files = listed4.ok ? listed4.value.filter((name) => name.endsWith(".jsonl")).sort() : [];
14604
+ const counts = {
14605
+ done_after_failing_tests: 0,
14606
+ env_read: 0,
14607
+ no_verify: 0,
14608
+ force_push: 0,
14609
+ test_skip: 0
14610
+ };
14611
+ const samples = {
14612
+ done_after_failing_tests: [],
14613
+ env_read: [],
14614
+ no_verify: [],
14615
+ force_push: [],
14616
+ test_skip: []
14617
+ };
14618
+ let turns = 0;
14619
+ for (const name of files) {
14620
+ const text6 = runtime.readText(toAbsolutePath(join36(dir, name)));
14621
+ if (!text6.ok) continue;
14622
+ for (const turn of parseTranscript(text6.value)) {
14623
+ turns += 1;
14624
+ for (const hit3 of hitsIn(turn)) {
14625
+ counts[hit3.pattern] += 1;
14626
+ const list4 = samples[hit3.pattern];
14627
+ if (list4.length < SAMPLES) list4.push(maskText(hit3.sample));
14628
+ }
14629
+ }
14630
+ }
14631
+ return { estimate: true, sessions: files.length, turns, counts, samples };
14632
+ };
14633
+
14427
14634
  // src/install/diff.ts
14428
14635
  var MAX_DIFF_LINES = 120;
14429
14636
  var table = (a, b) => {
@@ -14578,17 +14785,32 @@ var initRequest = (args) => ({
14578
14785
  marketplace: args.values["marketplace"] === true,
14579
14786
  showDiff: false
14580
14787
  });
14788
+ var withLookBack = (ctx, result) => {
14789
+ if (!result.ok) return result;
14790
+ const root = openProject(ctx).project.root;
14791
+ const found = lookBack(ctx.runtime, root, ctx.env);
14792
+ const lines3 = [
14793
+ ctx.t("history.title", { sessions: found.sessions, turns: found.turns }),
14794
+ ...PATTERNS.map((pattern) => ` ${ctx.t(`history.pattern.${pattern}`, { count: found.counts[pattern] })}`),
14795
+ ctx.t("history.estimate")
14796
+ ];
14797
+ return { ...result, data: { ...result.data, lookBack: found }, human: [...result.human ?? [], ...lines3] };
14798
+ };
14581
14799
  var initCommand = {
14582
14800
  path: ["init"],
14583
14801
  summaryKey: "command.init.summary",
14584
- usage: "finitemonkey init [--preset neutral|gabriel] [--bin <path>] [--marketplace] [--dry-run] [--yes]",
14802
+ usage: "finitemonkey init [--preset neutral|gabriel] [--bin <path>] [--marketplace] [--look-back] [--dry-run] [--yes]",
14585
14803
  status: "ready",
14586
14804
  options: {
14587
14805
  preset: { type: "string" },
14588
14806
  bin: { type: "string" },
14589
- marketplace: { type: "boolean" }
14807
+ marketplace: { type: "boolean" },
14808
+ "look-back": { type: "boolean" }
14590
14809
  },
14591
- run: (ctx, args) => Promise.resolve(runInstall(ctx, initRequest(args), "neutral"))
14810
+ run: (ctx, args) => {
14811
+ const result = runInstall(ctx, initRequest(args), "neutral");
14812
+ return Promise.resolve(args.values["look-back"] === true ? withLookBack(ctx, result) : result);
14813
+ }
14592
14814
  };
14593
14815
 
14594
14816
  // src/commands/prose-check.ts
@@ -15066,7 +15288,7 @@ var secretsScanCommand = {
15066
15288
  };
15067
15289
 
15068
15290
  // src/task/create.ts
15069
- import { join as join36 } from "node:path";
15291
+ import { join as join37 } from "node:path";
15070
15292
 
15071
15293
  // src/core/yaml/write.ts
15072
15294
  var PLAIN_SAFE = /^[A-Za-z_./][A-Za-z0-9_./ ()-]*$/;
@@ -15150,10 +15372,10 @@ var explicitChecks = (draft) => [
15150
15372
  var draftChecks = (runtime, paths, draft) => {
15151
15373
  const disk = {
15152
15374
  read: (relative9) => {
15153
- const text6 = runtime.readText(toAbsolutePath(join36(paths.root, relative9)));
15375
+ const text6 = runtime.readText(toAbsolutePath(join37(paths.root, relative9)));
15154
15376
  return text6.ok ? text6.value : void 0;
15155
15377
  },
15156
- exists: (relative9) => runtime.stat(toAbsolutePath(join36(paths.root, relative9))) !== void 0
15378
+ exists: (relative9) => runtime.stat(toAbsolutePath(join37(paths.root, relative9))) !== void 0
15157
15379
  };
15158
15380
  const detected = detectChecks(disk);
15159
15381
  const base = draft.runs.length > 0 || draft.tests !== void 0 ? explicitChecks(draft) : detected;
@@ -15557,7 +15779,7 @@ var REGISTRY = [
15557
15779
  ];
15558
15780
 
15559
15781
  // src/i18n/lang-settings.ts
15560
- import { join as join37 } from "node:path";
15782
+ import { join as join38 } from "node:path";
15561
15783
  var read3 = (runtime, path) => {
15562
15784
  const text6 = runtime.readText(toAbsolutePath(path));
15563
15785
  return text6.ok ? text6.value : void 0;
@@ -15572,14 +15794,14 @@ var languageIn = (text6) => {
15572
15794
  const value = parsed.ok && isRecord(parsed.value) ? parsed.value["language"] : void 0;
15573
15795
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
15574
15796
  };
15575
- var claudeDir = (runtime, env) => env["CLAUDE_CONFIG_DIR"] ?? join37(runtime.homeDir(), ".claude");
15797
+ var claudeDir = (runtime, env) => env["CLAUDE_CONFIG_DIR"] ?? join38(runtime.homeDir(), ".claude");
15576
15798
  var langSettings = (runtime, cwd, env, platform) => {
15577
15799
  const root = findGitRoot(cwd, runtime) ?? cwd;
15578
- const config = parseConfigYaml(read3(runtime, join37(root, CONFIG_FILE)) ?? "");
15800
+ const config = parseConfigYaml(read3(runtime, join38(root, CONFIG_FILE)) ?? "");
15579
15801
  const claudeFiles = [
15580
- join37(root, ".claude", "settings.local.json"),
15581
- join37(root, ".claude", "settings.json"),
15582
- join37(claudeDir(runtime, env), "settings.json")
15802
+ join38(root, ".claude", "settings.local.json"),
15803
+ join38(root, ".claude", "settings.json"),
15804
+ join38(claudeDir(runtime, env), "settings.json")
15583
15805
  ];
15584
15806
  return {
15585
15807
  config: configText(config, "lang"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "finitemonkey",
3
- "version": "0.1.0-next.12",
3
+ "version": "0.1.0-next.13",
4
4
  "description": "Claude Code hooks that stop a coding agent from saying done before the tests pass: a machine-checked definition of done, plus guardrails for secrets, git safety and production. Pre-release.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",