finitemonkey 0.1.0-next.11 → 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 +25 -1
- package/README.md +25 -1
- package/README.pt-BR.md +25 -1
- package/dist/finitemonkey.mjs +402 -110
- package/package.json +4 -2
package/README.es.md
CHANGED
|
@@ -123,6 +123,30 @@ La comparación completa, con fuentes, está en [docs/compare.es.md](docs/compar
|
|
|
123
123
|
- **Métodos como superpowers, GSD, Spec Kit u OpenSpec** le dicen al agente cómo planificar y construir. Finite Monkey no los sustituye: comprueba el resultado al final, uses el método que uses.
|
|
124
124
|
- **Guardas sueltos como tdd-guard, cc-safety-net o dcg** hacen un trabajo cada uno, y lo hacen bien. Finite Monkey cubre cuatro daños con un control, una instalación y un `undo`. Si solo necesitas uno de esos trabajos, un guarda suelto puede ser lo más sencillo.
|
|
125
125
|
|
|
126
|
+
<!-- generated:footprint:start -->
|
|
127
|
+
## Qué lee, escribe y envía
|
|
128
|
+
|
|
129
|
+
Generado desde `src/core/footprint.ts`, la lista que los tests exigen al código. Sin telemetría. Las rutas son relativas al proyecto salvo las que empiezan con `~`.
|
|
130
|
+
|
|
131
|
+
| | Qué | Para qué |
|
|
132
|
+
|---|---|---|
|
|
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
|
+
| 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
|
+
| 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`. |
|
|
137
|
+
| Lee | `.git/` | El repositorio a través del comando `git`: estado, diffs, refs y el reflog. |
|
|
138
|
+
| Lee | `git diff` | Archivos modificados, revisados en busca de secretos, tests saltados, placeholders y patrones de prosa. |
|
|
139
|
+
| Lee | `.finitemonkey/config.yml`, `.finitemonkey/briefing.md` | La configuración del proyecto y el briefing opcional para subagentes. |
|
|
140
|
+
| Escribe | `.claude/settings.json`, `.claude/skills/verify/SKILL.md`, `AGENTS.md`, `CLAUDE.md`, `.gitignore`, `.finitemonkey/config.yml`, `.finitemonkey/lock.json`, `.finitemonkey/locks/`, `.finitemonkey/runtime/`, `.finitemonkey/backups/` | `init` y `update`: la configuración de los hooks, la skill verify, un bloque gestionado corto en `AGENTS.md` que `CLAUDE.md` importa, una línea en `.gitignore`, el runtime fijado y una copia de cada archivo que cambian. |
|
|
141
|
+
| Escribe | `.finitemonkey/tasks/`, `.finitemonkey/state.json` | Contratos de tarea y cuál tarea está activa. |
|
|
142
|
+
| Escribe | `.finitemonkey/evidence/`, `.finitemonkey/log.jsonl`, `.finitemonkey/prod-evidence.jsonl` | La evidencia de cada comprobación, ligada al hash del árbol, y el log de la puerta. |
|
|
143
|
+
| Escribe | `.finitemonkey/trust.json`, `.finitemonkey/allow/`, `.finitemonkey/cache/` | Aprobaciones y permisos escritos por la persona, y una caché breve de los pull requests abiertos. |
|
|
144
|
+
| Escribe | `.finitemonkey/findings/baseline.json`, `.finitemonkey/incidents/` | La línea base de hallazgos aceptados y los incidentes de exposición. Ambos guardan huellas y máscaras, nunca el valor de un secreto. |
|
|
145
|
+
| Escribe | `.finitemonkey/git/`, `.finitemonkey/git-journal.jsonl`, `.finitemonkey/merge-dropped.json`, `refs/finitemonkey/backup/` | Snapshots antes de comandos git destructivos, el diario que lee `undo` y las decisiones sobre líneas descartadas en merges. |
|
|
146
|
+
| Escribe | `.finitemonkey/reports/` | Informes de error enmascarados que escribe `doctor --report`, solo cuando se pide. |
|
|
147
|
+
| Envía | `api.github.com` | A través de `gh`, solo si está instalado y con sesión iniciada: el estado del pull request indicado en una tarea y tus pull requests abiertos para la línea de la sesión. El código nunca se sube. |
|
|
148
|
+
<!-- generated:footprint:end -->
|
|
149
|
+
|
|
126
150
|
## Preguntas frecuentes
|
|
127
151
|
|
|
128
152
|
Más preguntas, una por cada búsqueda real, en [docs/faq.es.md](docs/faq.es.md).
|
|
@@ -131,7 +155,7 @@ Más preguntas, una por cada búsqueda real, en [docs/faq.es.md](docs/faq.es.md)
|
|
|
131
155
|
No. Son hooks y comprobaciones que se ejecutan aunque el modelo no se acuerde.
|
|
132
156
|
|
|
133
157
|
**¿Envía mi código a algún sitio?**
|
|
134
|
-
No.
|
|
158
|
+
No. Tu código nunca sale de tu máquina y no hay telemetría. La única llamada de red es `gh` preguntando a GitHub por pull requests, y solo si `gh` tiene sesión iniciada. La lista completa está en [Qué lee, escribe y envía](#qué-lee-escribe-y-envía).
|
|
135
159
|
|
|
136
160
|
**¿Me va a ralentizar?**
|
|
137
161
|
Las tareas pequeñas no tienen ceremonia, solo el control al final. Los hooks rápidos siguen siendo rápidos; la comprobación costosa va en `Stop`. El CI rechaza un pull request que lleve un guard de `PreToolUse` por encima de 50 ms en el p95 o que agregue contexto al inicio de la sesión; los límites están en [budgets.json](budgets.json). Publicaremos los tiempos de punta a punta junto con el benchmark.
|
package/README.md
CHANGED
|
@@ -123,6 +123,30 @@ The full comparison, with sources, is in [docs/compare.md](docs/compare.md).
|
|
|
123
123
|
- **Methods like superpowers, GSD, Spec Kit or OpenSpec** tell the agent how to plan and build. Finite Monkey doesn't replace them. It checks the result at the end, whatever method you used.
|
|
124
124
|
- **Single guards like tdd-guard, cc-safety-net or dcg** each do one job well. Finite Monkey covers four damages with one gate, one install and one `undo`. If you only need one of those jobs, a single guard may be the simpler choice.
|
|
125
125
|
|
|
126
|
+
<!-- generated:footprint:start -->
|
|
127
|
+
## What it reads, writes and sends
|
|
128
|
+
|
|
129
|
+
Generated from `src/core/footprint.ts`, the list the tests hold the code to. No telemetry. Paths are relative to the project unless they start with `~`.
|
|
130
|
+
|
|
131
|
+
| | What | Why |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| Reads | `stdin` | The event Claude Code passes to each hook: the tool call, the prompt or the stop request. |
|
|
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
|
+
| 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`. |
|
|
137
|
+
| Reads | `.git/` | The repository through the `git` command: status, diffs, refs and the reflog. |
|
|
138
|
+
| Reads | `git diff` | Changed files, scanned for secrets, test skips, placeholders and prose patterns. |
|
|
139
|
+
| Reads | `.finitemonkey/config.yml`, `.finitemonkey/briefing.md` | Project configuration and the optional briefing for subagents. |
|
|
140
|
+
| Writes | `.claude/settings.json`, `.claude/skills/verify/SKILL.md`, `AGENTS.md`, `CLAUDE.md`, `.gitignore`, `.finitemonkey/config.yml`, `.finitemonkey/lock.json`, `.finitemonkey/locks/`, `.finitemonkey/runtime/`, `.finitemonkey/backups/` | `init` and `update`: hook settings, the verify skill, a short managed block in `AGENTS.md` that `CLAUDE.md` imports, one `.gitignore` line, the pinned runtime and a backup of every file it changes. |
|
|
141
|
+
| Writes | `.finitemonkey/tasks/`, `.finitemonkey/state.json` | Task contracts and which task is active. |
|
|
142
|
+
| Writes | `.finitemonkey/evidence/`, `.finitemonkey/log.jsonl`, `.finitemonkey/prod-evidence.jsonl` | Evidence of each check, tied to the tree hash, and the gate log. |
|
|
143
|
+
| Writes | `.finitemonkey/trust.json`, `.finitemonkey/allow/`, `.finitemonkey/cache/` | Approvals and grants typed by the person, and a short-lived cache of open pull requests. |
|
|
144
|
+
| Writes | `.finitemonkey/findings/baseline.json`, `.finitemonkey/incidents/` | The accepted-findings baseline and exposure incidents. Both hold fingerprints and masks, never a secret value. |
|
|
145
|
+
| Writes | `.finitemonkey/git/`, `.finitemonkey/git-journal.jsonl`, `.finitemonkey/merge-dropped.json`, `refs/finitemonkey/backup/` | Snapshots before destructive git commands, the journal that `undo` reads and dropped-line decisions from merges. |
|
|
146
|
+
| Writes | `.finitemonkey/reports/` | Masked bug reports that `doctor --report` writes, only when asked. |
|
|
147
|
+
| Sends | `api.github.com` | Through `gh`, only when it is installed and logged in: the state of the pull request named in a task, and your open pull requests for the session line. Code is never uploaded. |
|
|
148
|
+
<!-- generated:footprint:end -->
|
|
149
|
+
|
|
126
150
|
## FAQ
|
|
127
151
|
|
|
128
152
|
More questions, one per real search, in [docs/faq.md](docs/faq.md).
|
|
@@ -131,7 +155,7 @@ More questions, one per real search, in [docs/faq.md](docs/faq.md).
|
|
|
131
155
|
No. It is hooks and checks that run whether or not the model remembers them.
|
|
132
156
|
|
|
133
157
|
**Does it send my code anywhere?**
|
|
134
|
-
No.
|
|
158
|
+
No. Your code never leaves your machine, and there is no telemetry. The one network call is `gh` asking GitHub about pull requests, and only when `gh` is logged in. The full list is in [What it reads, writes and sends](#what-it-reads-writes-and-sends).
|
|
135
159
|
|
|
136
160
|
**Will it slow me down?**
|
|
137
161
|
Small tasks get no ceremony, only the gate at the end. Fast hooks stay fast; the expensive check runs at `Stop`. CI fails a pull request that pushes a `PreToolUse` guard past 50 ms at p95 or adds context at session start; the ceilings are in [budgets.json](budgets.json). We'll publish end-to-end timings with the benchmark.
|
package/README.pt-BR.md
CHANGED
|
@@ -123,6 +123,30 @@ A comparação completa, com fontes, está em [docs/compare.pt-BR.md](docs/compa
|
|
|
123
123
|
- **Métodos como superpowers, GSD, Spec Kit ou OpenSpec** dizem ao agente como planejar e construir. O Finite Monkey não substitui nenhum deles: confere o resultado no fim, seja qual for o método.
|
|
124
124
|
- **Guardas avulsos como tdd-guard, cc-safety-net ou dcg** fazem um trabalho cada um, e bem. O Finite Monkey cobre quatro danos com um portão, uma instalação e um `undo`. Se você só precisa de um desses trabalhos, um guarda avulso pode ser a escolha mais simples.
|
|
125
125
|
|
|
126
|
+
<!-- generated:footprint:start -->
|
|
127
|
+
## O que ele lê, grava e envia
|
|
128
|
+
|
|
129
|
+
Gerado a partir de `src/core/footprint.ts`, a lista que os testes cobram do código. Sem telemetria. Caminhos são relativos ao projeto, exceto os que começam com `~`.
|
|
130
|
+
|
|
131
|
+
| | O quê | Para quê |
|
|
132
|
+
|---|---|---|
|
|
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
|
+
| 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
|
+
| 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`. |
|
|
137
|
+
| Lê | `.git/` | O repositório pelo comando `git`: status, diffs, refs e o reflog. |
|
|
138
|
+
| Lê | `git diff` | Arquivos alterados, varridos atrás de segredos, testes pulados, placeholders e padrões de prosa. |
|
|
139
|
+
| Lê | `.finitemonkey/config.yml`, `.finitemonkey/briefing.md` | A configuração do projeto e o briefing opcional para subagentes. |
|
|
140
|
+
| Grava | `.claude/settings.json`, `.claude/skills/verify/SKILL.md`, `AGENTS.md`, `CLAUDE.md`, `.gitignore`, `.finitemonkey/config.yml`, `.finitemonkey/lock.json`, `.finitemonkey/locks/`, `.finitemonkey/runtime/`, `.finitemonkey/backups/` | `init` e `update`: configuração dos hooks, a skill verify, um bloco gerenciado curto no `AGENTS.md` que o `CLAUDE.md` importa, uma linha no `.gitignore`, o runtime fixado e um backup de cada arquivo que alteram. |
|
|
141
|
+
| Grava | `.finitemonkey/tasks/`, `.finitemonkey/state.json` | Contratos de tarefa e qual tarefa está ativa. |
|
|
142
|
+
| Grava | `.finitemonkey/evidence/`, `.finitemonkey/log.jsonl`, `.finitemonkey/prod-evidence.jsonl` | A evidência de cada checagem, ligada ao hash da árvore, e o log do portão. |
|
|
143
|
+
| Grava | `.finitemonkey/trust.json`, `.finitemonkey/allow/`, `.finitemonkey/cache/` | Aprovações e liberações digitadas pela pessoa, e um cache curto dos pull requests abertos. |
|
|
144
|
+
| Grava | `.finitemonkey/findings/baseline.json`, `.finitemonkey/incidents/` | A baseline de achados aceitos e os incidentes de exposição. Os dois guardam impressões e máscaras, nunca o valor de um segredo. |
|
|
145
|
+
| Grava | `.finitemonkey/git/`, `.finitemonkey/git-journal.jsonl`, `.finitemonkey/merge-dropped.json`, `refs/finitemonkey/backup/` | Snapshots antes de comandos git destrutivos, o diário que o `undo` lê e as decisões sobre linhas descartadas em merges. |
|
|
146
|
+
| Grava | `.finitemonkey/reports/` | Relatórios de bug mascarados que o `doctor --report` grava, só quando pedido. |
|
|
147
|
+
| Envia | `api.github.com` | Pelo `gh`, só quando ele está instalado e logado: o estado do pull request citado numa tarefa e os seus pull requests abertos para a linha da sessão. Código nunca é enviado. |
|
|
148
|
+
<!-- generated:footprint:end -->
|
|
149
|
+
|
|
126
150
|
## Perguntas frequentes
|
|
127
151
|
|
|
128
152
|
Mais perguntas, uma para cada busca real, em [docs/faq.pt-BR.md](docs/faq.pt-BR.md).
|
|
@@ -131,7 +155,7 @@ Mais perguntas, uma para cada busca real, em [docs/faq.pt-BR.md](docs/faq.pt-BR.
|
|
|
131
155
|
Não. São hooks e checagens que rodam lembrando o modelo ou não.
|
|
132
156
|
|
|
133
157
|
**Ele manda meu código para algum lugar?**
|
|
134
|
-
Não.
|
|
158
|
+
Não. Seu código nunca sai da sua máquina, e não há telemetria. A única chamada de rede é o `gh` perguntando ao GitHub sobre pull requests, e só quando o `gh` está logado. A lista completa está em [O que ele lê, grava e envia](#o-que-ele-lê-grava-e-envia).
|
|
135
159
|
|
|
136
160
|
**Vai me deixar mais lento?**
|
|
137
161
|
Tarefa pequena não tem cerimônia, só o portão no fim. Hook rápido continua rápido; a checagem cara roda no `Stop`. O CI reprova um pull request que leve um guard de `PreToolUse` acima de 50 ms no p95 ou que acrescente contexto no início da sessão; os limites estão em [budgets.json](budgets.json). Os tempos de ponta a ponta saem junto com o benchmark.
|
package/dist/finitemonkey.mjs
CHANGED
|
@@ -21,7 +21,7 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
|
21
21
|
|
|
22
22
|
// src/core/node-exec.ts
|
|
23
23
|
import { spawn, spawnSync } from "node:child_process";
|
|
24
|
-
import { appendFileSync, mkdirSync } from "node:fs";
|
|
24
|
+
import { appendFileSync, existsSync, mkdirSync } from "node:fs";
|
|
25
25
|
import { dirname } from "node:path";
|
|
26
26
|
|
|
27
27
|
// src/core/parsed.ts
|
|
@@ -45,6 +45,32 @@ var optionalString = (record2, key) => {
|
|
|
45
45
|
return typeof value === "string" ? value : void 0;
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
+
// src/core/windows-command.ts
|
|
49
|
+
import { win32 } from "node:path";
|
|
50
|
+
var DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD";
|
|
51
|
+
var NEEDS_SHELL = /\.(cmd|bat)$/i;
|
|
52
|
+
var NEEDS_QUOTES = /[\s"&|<>^()%!]/;
|
|
53
|
+
var envValue = (env, name) => {
|
|
54
|
+
const key = Object.keys(env).find((candidate) => candidate.toUpperCase() === name);
|
|
55
|
+
return key === void 0 ? void 0 : env[key];
|
|
56
|
+
};
|
|
57
|
+
var quoteForCmd = (arg) => arg !== "" && !NEEDS_QUOTES.test(arg) ? arg : `"${arg.replace(/"/g, '""')}"`;
|
|
58
|
+
var resolveWindowsCommand = (command, env, exists) => {
|
|
59
|
+
if (/[\\/]/.test(command) || win32.extname(command) !== "") {
|
|
60
|
+
return { command, shell: NEEDS_SHELL.test(command) };
|
|
61
|
+
}
|
|
62
|
+
const dirs = (envValue(env, "PATH") ?? "").split(";").filter((dir) => dir !== "");
|
|
63
|
+
const extensions = (envValue(env, "PATHEXT") ?? DEFAULT_PATHEXT).split(";").filter((ext) => ext !== "");
|
|
64
|
+
for (const dir of dirs) {
|
|
65
|
+
for (const ext of extensions) {
|
|
66
|
+
const candidate = win32.join(dir, `${command}${ext.toLowerCase()}`);
|
|
67
|
+
if (exists(candidate)) return { command: candidate, shell: NEEDS_SHELL.test(candidate) };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { command, shell: false };
|
|
71
|
+
};
|
|
72
|
+
var windowsCommandLine = (resolved, args) => [quoteForCmd(resolved.command), ...args.map(quoteForCmd)].join(" ");
|
|
73
|
+
|
|
48
74
|
// src/core/node-exec.ts
|
|
49
75
|
var SHELL_NOT_FOUND = /* @__PURE__ */ new Set([127, 9009]);
|
|
50
76
|
var CMD_NOT_FOUND = /is not recognized as an internal or external command|não é reconhecido como um comando interno|no se reconoce como un comando interno/i;
|
|
@@ -67,7 +93,8 @@ var nodeExec = (request) => {
|
|
|
67
93
|
Object.entries({ ...process.env, ...request.env }).filter(([name]) => !(request.unset ?? []).includes(name))
|
|
68
94
|
)
|
|
69
95
|
};
|
|
70
|
-
const
|
|
96
|
+
const resolved = process.platform === "win32" && request.shell !== true ? resolveWindowsCommand(request.command, options.env, existsSync) : void 0;
|
|
97
|
+
const result = request.shell === true ? spawnSync([request.command, ...request.args].join(" "), { ...options, shell: true }) : resolved?.shell === true ? spawnSync(windowsCommandLine(resolved, request.args), { ...options, shell: true }) : spawnSync(resolved?.command ?? request.command, [...request.args], options);
|
|
71
98
|
const code = errnoCode(result.error);
|
|
72
99
|
const exitCode = result.status;
|
|
73
100
|
const shellMissing = request.shell === true && exitCode !== null && (SHELL_NOT_FOUND.has(exitCode) || exitCode === 1 && CMD_NOT_FOUND.test(text(result.stderr)));
|
|
@@ -1132,6 +1159,12 @@ var isBundlePath = (path) => path.endsWith(".mjs");
|
|
|
1132
1159
|
|
|
1133
1160
|
// src/install/plan.ts
|
|
1134
1161
|
var CHANGING = ["create", "merge", "update"];
|
|
1162
|
+
var WSL_MOUNT = /^\/mnt\/[a-z](\/|$)/i;
|
|
1163
|
+
var SYNCED = /(OneDrive|Dropbox|iCloud ?Drive|Mobile Documents|Google ?Drive)/i;
|
|
1164
|
+
var locationOf = (root, env) => ({
|
|
1165
|
+
wslMount: WSL_MOUNT.test(root) && (env["WSL_DISTRO_NAME"] !== void 0 || env["WSL_INTEROP"] !== void 0),
|
|
1166
|
+
synced: SYNCED.test(root)
|
|
1167
|
+
});
|
|
1135
1168
|
var detect = (project, gitRoot2, input) => ({
|
|
1136
1169
|
root: project.root,
|
|
1137
1170
|
gitRoot: gitRoot2,
|
|
@@ -1140,7 +1173,8 @@ var detect = (project, gitRoot2, input) => ({
|
|
|
1140
1173
|
settings: settingsInfo(project.read(SETTINGS_FILE)),
|
|
1141
1174
|
authorities: detectAuthorities(project, input.env),
|
|
1142
1175
|
runner: chooseRunner(project, input.bin),
|
|
1143
|
-
claude: detectClaude(project.runtime.probe)
|
|
1176
|
+
claude: detectClaude(project.runtime.probe),
|
|
1177
|
+
location: locationOf(project.root, input.env)
|
|
1144
1178
|
});
|
|
1145
1179
|
var readPreviousLock = (project) => {
|
|
1146
1180
|
const text6 = project.read(LOCK_FILE);
|
|
@@ -1996,20 +2030,20 @@ var detectOs = ({ platform, env, runtime }) => {
|
|
|
1996
2030
|
const version = runtime.readText(toAbsolutePath("/proc/version"));
|
|
1997
2031
|
return version.ok && /microsoft/i.test(version.value) ? "wsl" : "linux";
|
|
1998
2032
|
};
|
|
1999
|
-
var
|
|
2000
|
-
var
|
|
2033
|
+
var WSL_MOUNT2 = /^\/mnt\/[a-z](\/|$)/i;
|
|
2034
|
+
var SYNCED2 = /(OneDrive|Dropbox|iCloud ?Drive|Mobile Documents|Google ?Drive)/i;
|
|
2001
2035
|
var NON_ASCII = /[^\x20-\x7e]/;
|
|
2002
2036
|
var pathTraits = (path) => ({
|
|
2003
2037
|
spaces: path.includes(" "),
|
|
2004
2038
|
nonAscii: NON_ASCII.test(path),
|
|
2005
|
-
synced:
|
|
2039
|
+
synced: SYNCED2.test(path)
|
|
2006
2040
|
});
|
|
2007
2041
|
var checkOs = (env) => {
|
|
2008
2042
|
const os = detectOs(env);
|
|
2009
2043
|
const findings = [
|
|
2010
2044
|
{ check: "os", status: "ok", messageKey: `doctor.os.${os}`, params: { platform: env.platform } }
|
|
2011
2045
|
];
|
|
2012
|
-
if (os === "wsl" &&
|
|
2046
|
+
if (os === "wsl" && WSL_MOUNT2.test(env.cwd)) {
|
|
2013
2047
|
findings.push({
|
|
2014
2048
|
check: "path.wsl_mount",
|
|
2015
2049
|
status: "warn",
|
|
@@ -5088,6 +5122,8 @@ var en_default = {
|
|
|
5088
5122
|
"install.plan.title": "Finite Monkey plan for {root} (preset {preset}):",
|
|
5089
5123
|
"install.warning": "warning: {message}",
|
|
5090
5124
|
"install.warn.not_git": "this folder is not inside a git repository; installing here anyway",
|
|
5125
|
+
"install.warn.wsl_mount": "{path} is on a Windows drive mounted in WSL: git and hooks run several times slower and file watching misses changes; move the project to the Linux disk (for example ~/projects) and run init there",
|
|
5126
|
+
"install.warn.synced_folder": "{path} is inside a synced folder (OneDrive, Dropbox, iCloud or Google Drive): sync can lock or rewrite files while git and hooks use them; move the project out of the synced folder",
|
|
5091
5127
|
"install.warn.fail_open": "Claude Code {version} cannot block an action when a hook crashes (needs 2.1.295 or newer); guards fail open until you update Claude Code",
|
|
5092
5128
|
"install.warn.authority": "{name} ({source}) also decides when a session may stop; Finite Monkey works alongside it and never turns it off",
|
|
5093
5129
|
"install.warn.plugin": "the finitemonkey plugin is enabled ({source}); its hooks step aside while this project has its own Finite Monkey hooks",
|
|
@@ -5375,7 +5411,16 @@ var en_default = {
|
|
|
5375
5411
|
"gate.merge.clean": "{count, plural, one {# merge checked} other {# merges checked}}, nothing lost",
|
|
5376
5412
|
"doctor.memory.lines": "{file}: {lines, plural, one {# line} other {# lines}} of {max}. Edits made during a session apply only after /clear, /compact or a restart.",
|
|
5377
5413
|
"doctor.memory.too_long": "{file}: {lines, plural, one {# line} other {# lines}}, above the ceiling of {max}; long instruction files get followed less",
|
|
5378
|
-
"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"
|
|
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
|
+
"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 .`",
|
|
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."
|
|
5379
5424
|
};
|
|
5380
5425
|
|
|
5381
5426
|
// src/i18n/es.json
|
|
@@ -5588,6 +5633,8 @@ var es_default = {
|
|
|
5588
5633
|
"install.plan.title": "Plan de Finite Monkey para {root} (preset {preset}):",
|
|
5589
5634
|
"install.warning": "aviso: {message}",
|
|
5590
5635
|
"install.warn.not_git": "esta carpeta no está dentro de un repositorio git; se instala aquí de todos modos",
|
|
5636
|
+
"install.warn.wsl_mount": "{path} está en un disco de Windows montado en WSL: git y los hooks van varias veces más lentos y la vigilancia de archivos pierde cambios; mueve el proyecto al disco de Linux (por ejemplo ~/proyectos) y ejecuta init allí",
|
|
5637
|
+
"install.warn.synced_folder": "{path} está dentro de una carpeta sincronizada (OneDrive, Dropbox, iCloud o Google Drive): la sincronización puede bloquear o reescribir archivos mientras git y los hooks los usan; saca el proyecto de la carpeta sincronizada",
|
|
5591
5638
|
"install.warn.fail_open": "Claude Code {version} no puede bloquear la acción cuando un hook falla (necesita 2.1.295 o más nueva); los guardas fallan abiertos hasta que actualices Claude Code",
|
|
5592
5639
|
"install.warn.authority": "{name} ({source}) también decide cuándo puede terminar la sesión; Finite Monkey convive con él y nunca lo desactiva",
|
|
5593
5640
|
"install.warn.plugin": "el plugin finitemonkey está habilitado ({source}); sus hooks ceden el paso mientras este proyecto tenga sus propios hooks de Finite Monkey",
|
|
@@ -5875,7 +5922,16 @@ var es_default = {
|
|
|
5875
5922
|
"gate.merge.clean": "{count, plural, one {# fusión revisada} other {# fusiones revisadas}}, no se perdió nada",
|
|
5876
5923
|
"doctor.memory.lines": "{file}: {lines, plural, one {# línea} other {# líneas}} de {max}. Los cambios hechos durante una sesión solo se aplican tras /clear, /compact o reiniciar.",
|
|
5877
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",
|
|
5878
|
-
"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"
|
|
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",
|
|
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"',
|
|
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."
|
|
5879
5935
|
};
|
|
5880
5936
|
|
|
5881
5937
|
// src/i18n/pt-BR.json
|
|
@@ -6088,6 +6144,8 @@ var pt_BR_default = {
|
|
|
6088
6144
|
"install.plan.title": "Plano do Finite Monkey para {root} (preset {preset}):",
|
|
6089
6145
|
"install.warning": "aviso: {message}",
|
|
6090
6146
|
"install.warn.not_git": "esta pasta não está dentro de um repositório git; instalando aqui mesmo assim",
|
|
6147
|
+
"install.warn.wsl_mount": "{path} está num disco do Windows montado no WSL: git e hooks ficam várias vezes mais lentos e a observação de arquivos perde mudanças; mova o projeto para o disco do Linux (por exemplo ~/projetos) e rode o init lá",
|
|
6148
|
+
"install.warn.synced_folder": "{path} está dentro de uma pasta sincronizada (OneDrive, Dropbox, iCloud ou Google Drive): a sincronização pode travar ou reescrever arquivos enquanto o git e os hooks os usam; tire o projeto da pasta sincronizada",
|
|
6091
6149
|
"install.warn.fail_open": "o Claude Code {version} não consegue barrar a ação quando um hook quebra (precisa da 2.1.295 ou mais nova); as travas falham abertas até você atualizar o Claude Code",
|
|
6092
6150
|
"install.warn.authority": "{name} ({source}) também decide quando a sessão pode parar; o Finite Monkey convive com ele e nunca o desliga",
|
|
6093
6151
|
"install.warn.plugin": "o plugin finitemonkey está habilitado ({source}); os hooks dele cedem a vez enquanto este projeto tiver os próprios hooks do Finite Monkey",
|
|
@@ -6375,7 +6433,16 @@ var pt_BR_default = {
|
|
|
6375
6433
|
"gate.merge.clean": "{count, plural, one {# mescla conferida} other {# mesclas conferidas}}, nada se perdeu",
|
|
6376
6434
|
"doctor.memory.lines": "{file}: {lines, plural, one {# linha} other {# linhas}} de {max}. Edições feitas durante a sessão só valem depois de /clear, /compact ou reiniciar.",
|
|
6377
6435
|
"doctor.memory.too_long": "{file}: {lines, plural, one {# linha} other {# linhas}}, acima do teto de {max}; arquivo de instruções longo é menos seguido",
|
|
6378
|
-
"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"
|
|
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",
|
|
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"',
|
|
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."
|
|
6379
6446
|
};
|
|
6380
6447
|
|
|
6381
6448
|
// src/i18n/review.json
|
|
@@ -6493,6 +6560,43 @@ var review_default = {
|
|
|
6493
6560
|
"doctor.project.fix_lockfiles": "machine",
|
|
6494
6561
|
"doctor.project.configs": "machine",
|
|
6495
6562
|
"doctor.project.fix_configs": "machine",
|
|
6563
|
+
"doctor.hooks.ok": "machine",
|
|
6564
|
+
"doctor.hooks.no_command": "machine",
|
|
6565
|
+
"doctor.hooks.not_found": "machine",
|
|
6566
|
+
"doctor.hooks.timeout": "machine",
|
|
6567
|
+
"doctor.hooks.exit": "machine",
|
|
6568
|
+
"doctor.hooks.output": "machine",
|
|
6569
|
+
"doctor.hooks.fix_broken": "machine",
|
|
6570
|
+
"doctor.hooks.fix_broken_plugin": "machine",
|
|
6571
|
+
"doctor.hooks.slow": "machine",
|
|
6572
|
+
"doctor.hooks.fix_slow": "machine",
|
|
6573
|
+
"doctor.hooks.fail_open": "machine",
|
|
6574
|
+
"doctor.hooks.fix_fail_open": "machine",
|
|
6575
|
+
"doctor.hooks.matcher": "machine",
|
|
6576
|
+
"doctor.hooks.fix_matcher": "machine",
|
|
6577
|
+
"doctor.hooks.not_fired": "machine",
|
|
6578
|
+
"doctor.hooks.fix_not_fired": "machine",
|
|
6579
|
+
"doctor.hooks.schema": "machine",
|
|
6580
|
+
"doctor.hooks.fix_schema": "machine",
|
|
6581
|
+
"doctor.hooks.plugin_disabled": "machine",
|
|
6582
|
+
"doctor.hooks.fix_plugin_disabled": "machine",
|
|
6583
|
+
"doctor.hooks.none": "machine",
|
|
6584
|
+
"doctor.hooks.fix_none": "machine",
|
|
6585
|
+
"doctor.hooks.absent": "machine",
|
|
6586
|
+
"doctor.hooks.fix_absent": "machine",
|
|
6587
|
+
"doctor.hooks.version_ok": "machine",
|
|
6588
|
+
"doctor.hooks.version_plugin": "machine",
|
|
6589
|
+
"doctor.hooks.fix_version_plugin": "machine",
|
|
6590
|
+
"doctor.hooks.version_cli": "machine",
|
|
6591
|
+
"doctor.hooks.fix_version_cli": "machine",
|
|
6592
|
+
"doctor.hooks.fix_version_cli_plugin": "machine",
|
|
6593
|
+
"doctor.fix.not_installed": "machine",
|
|
6594
|
+
"doctor.fix.nothing": "machine",
|
|
6595
|
+
"doctor.fix.would": "machine",
|
|
6596
|
+
"doctor.fix.applied": "machine",
|
|
6597
|
+
"doctor.fix.backup": "machine",
|
|
6598
|
+
"doctor.fix.manual": "machine",
|
|
6599
|
+
"doctor.report.written": "machine",
|
|
6496
6600
|
"hook.failed_closed": "machine",
|
|
6497
6601
|
"hook.failed_open": "machine",
|
|
6498
6602
|
"exit.ok": "machine",
|
|
@@ -6552,6 +6656,8 @@ var review_default = {
|
|
|
6552
6656
|
"install.plan.title": "machine",
|
|
6553
6657
|
"install.warning": "machine",
|
|
6554
6658
|
"install.warn.not_git": "machine",
|
|
6659
|
+
"install.warn.wsl_mount": "machine",
|
|
6660
|
+
"install.warn.synced_folder": "machine",
|
|
6555
6661
|
"install.warn.fail_open": "machine",
|
|
6556
6662
|
"install.warn.authority": "machine",
|
|
6557
6663
|
"install.warn.plugin": "machine",
|
|
@@ -6840,43 +6946,15 @@ var review_default = {
|
|
|
6840
6946
|
"doctor.memory.lines": "machine",
|
|
6841
6947
|
"doctor.memory.too_long": "machine",
|
|
6842
6948
|
"doctor.memory.fix_too_long": "machine",
|
|
6843
|
-
"doctor.
|
|
6844
|
-
"doctor.
|
|
6845
|
-
"
|
|
6846
|
-
"
|
|
6847
|
-
"
|
|
6848
|
-
"
|
|
6849
|
-
"
|
|
6850
|
-
"
|
|
6851
|
-
"
|
|
6852
|
-
"doctor.hooks.fix_slow": "machine",
|
|
6853
|
-
"doctor.hooks.fail_open": "machine",
|
|
6854
|
-
"doctor.hooks.fix_fail_open": "machine",
|
|
6855
|
-
"doctor.hooks.matcher": "machine",
|
|
6856
|
-
"doctor.hooks.fix_matcher": "machine",
|
|
6857
|
-
"doctor.hooks.not_fired": "machine",
|
|
6858
|
-
"doctor.hooks.fix_not_fired": "machine",
|
|
6859
|
-
"doctor.hooks.schema": "machine",
|
|
6860
|
-
"doctor.hooks.fix_schema": "machine",
|
|
6861
|
-
"doctor.hooks.plugin_disabled": "machine",
|
|
6862
|
-
"doctor.hooks.fix_plugin_disabled": "machine",
|
|
6863
|
-
"doctor.hooks.none": "machine",
|
|
6864
|
-
"doctor.hooks.fix_none": "machine",
|
|
6865
|
-
"doctor.hooks.absent": "machine",
|
|
6866
|
-
"doctor.hooks.fix_absent": "machine",
|
|
6867
|
-
"doctor.hooks.version_ok": "machine",
|
|
6868
|
-
"doctor.hooks.version_plugin": "machine",
|
|
6869
|
-
"doctor.hooks.fix_version_plugin": "machine",
|
|
6870
|
-
"doctor.hooks.version_cli": "machine",
|
|
6871
|
-
"doctor.hooks.fix_version_cli": "machine",
|
|
6872
|
-
"doctor.hooks.fix_version_cli_plugin": "machine",
|
|
6873
|
-
"doctor.fix.not_installed": "machine",
|
|
6874
|
-
"doctor.fix.nothing": "machine",
|
|
6875
|
-
"doctor.fix.would": "machine",
|
|
6876
|
-
"doctor.fix.applied": "machine",
|
|
6877
|
-
"doctor.fix.backup": "machine",
|
|
6878
|
-
"doctor.fix.manual": "machine",
|
|
6879
|
-
"doctor.report.written": "machine"
|
|
6949
|
+
"doctor.git.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"
|
|
6880
6958
|
},
|
|
6881
6959
|
es: {
|
|
6882
6960
|
"command.init.summary": "machine",
|
|
@@ -6991,6 +7069,43 @@ var review_default = {
|
|
|
6991
7069
|
"doctor.project.fix_lockfiles": "machine",
|
|
6992
7070
|
"doctor.project.configs": "machine",
|
|
6993
7071
|
"doctor.project.fix_configs": "machine",
|
|
7072
|
+
"doctor.hooks.ok": "machine",
|
|
7073
|
+
"doctor.hooks.no_command": "machine",
|
|
7074
|
+
"doctor.hooks.not_found": "machine",
|
|
7075
|
+
"doctor.hooks.timeout": "machine",
|
|
7076
|
+
"doctor.hooks.exit": "machine",
|
|
7077
|
+
"doctor.hooks.output": "machine",
|
|
7078
|
+
"doctor.hooks.fix_broken": "machine",
|
|
7079
|
+
"doctor.hooks.fix_broken_plugin": "machine",
|
|
7080
|
+
"doctor.hooks.slow": "machine",
|
|
7081
|
+
"doctor.hooks.fix_slow": "machine",
|
|
7082
|
+
"doctor.hooks.fail_open": "machine",
|
|
7083
|
+
"doctor.hooks.fix_fail_open": "machine",
|
|
7084
|
+
"doctor.hooks.matcher": "machine",
|
|
7085
|
+
"doctor.hooks.fix_matcher": "machine",
|
|
7086
|
+
"doctor.hooks.not_fired": "machine",
|
|
7087
|
+
"doctor.hooks.fix_not_fired": "machine",
|
|
7088
|
+
"doctor.hooks.schema": "machine",
|
|
7089
|
+
"doctor.hooks.fix_schema": "machine",
|
|
7090
|
+
"doctor.hooks.plugin_disabled": "machine",
|
|
7091
|
+
"doctor.hooks.fix_plugin_disabled": "machine",
|
|
7092
|
+
"doctor.hooks.none": "machine",
|
|
7093
|
+
"doctor.hooks.fix_none": "machine",
|
|
7094
|
+
"doctor.hooks.absent": "machine",
|
|
7095
|
+
"doctor.hooks.fix_absent": "machine",
|
|
7096
|
+
"doctor.hooks.version_ok": "machine",
|
|
7097
|
+
"doctor.hooks.version_plugin": "machine",
|
|
7098
|
+
"doctor.hooks.fix_version_plugin": "machine",
|
|
7099
|
+
"doctor.hooks.version_cli": "machine",
|
|
7100
|
+
"doctor.hooks.fix_version_cli": "machine",
|
|
7101
|
+
"doctor.hooks.fix_version_cli_plugin": "machine",
|
|
7102
|
+
"doctor.fix.not_installed": "machine",
|
|
7103
|
+
"doctor.fix.nothing": "machine",
|
|
7104
|
+
"doctor.fix.would": "machine",
|
|
7105
|
+
"doctor.fix.applied": "machine",
|
|
7106
|
+
"doctor.fix.backup": "machine",
|
|
7107
|
+
"doctor.fix.manual": "machine",
|
|
7108
|
+
"doctor.report.written": "machine",
|
|
6994
7109
|
"hook.failed_closed": "machine",
|
|
6995
7110
|
"hook.failed_open": "machine",
|
|
6996
7111
|
"exit.ok": "machine",
|
|
@@ -7050,6 +7165,8 @@ var review_default = {
|
|
|
7050
7165
|
"install.plan.title": "machine",
|
|
7051
7166
|
"install.warning": "machine",
|
|
7052
7167
|
"install.warn.not_git": "machine",
|
|
7168
|
+
"install.warn.wsl_mount": "machine",
|
|
7169
|
+
"install.warn.synced_folder": "machine",
|
|
7053
7170
|
"install.warn.fail_open": "machine",
|
|
7054
7171
|
"install.warn.authority": "machine",
|
|
7055
7172
|
"install.warn.plugin": "machine",
|
|
@@ -7338,43 +7455,15 @@ var review_default = {
|
|
|
7338
7455
|
"doctor.memory.lines": "machine",
|
|
7339
7456
|
"doctor.memory.too_long": "machine",
|
|
7340
7457
|
"doctor.memory.fix_too_long": "machine",
|
|
7341
|
-
"doctor.
|
|
7342
|
-
"doctor.
|
|
7343
|
-
"
|
|
7344
|
-
"
|
|
7345
|
-
"
|
|
7346
|
-
"
|
|
7347
|
-
"
|
|
7348
|
-
"
|
|
7349
|
-
"
|
|
7350
|
-
"doctor.hooks.fix_slow": "machine",
|
|
7351
|
-
"doctor.hooks.fail_open": "machine",
|
|
7352
|
-
"doctor.hooks.fix_fail_open": "machine",
|
|
7353
|
-
"doctor.hooks.matcher": "machine",
|
|
7354
|
-
"doctor.hooks.fix_matcher": "machine",
|
|
7355
|
-
"doctor.hooks.not_fired": "machine",
|
|
7356
|
-
"doctor.hooks.fix_not_fired": "machine",
|
|
7357
|
-
"doctor.hooks.schema": "machine",
|
|
7358
|
-
"doctor.hooks.fix_schema": "machine",
|
|
7359
|
-
"doctor.hooks.plugin_disabled": "machine",
|
|
7360
|
-
"doctor.hooks.fix_plugin_disabled": "machine",
|
|
7361
|
-
"doctor.hooks.none": "machine",
|
|
7362
|
-
"doctor.hooks.fix_none": "machine",
|
|
7363
|
-
"doctor.hooks.absent": "machine",
|
|
7364
|
-
"doctor.hooks.fix_absent": "machine",
|
|
7365
|
-
"doctor.hooks.version_ok": "machine",
|
|
7366
|
-
"doctor.hooks.version_plugin": "machine",
|
|
7367
|
-
"doctor.hooks.fix_version_plugin": "machine",
|
|
7368
|
-
"doctor.hooks.version_cli": "machine",
|
|
7369
|
-
"doctor.hooks.fix_version_cli": "machine",
|
|
7370
|
-
"doctor.hooks.fix_version_cli_plugin": "machine",
|
|
7371
|
-
"doctor.fix.not_installed": "machine",
|
|
7372
|
-
"doctor.fix.nothing": "machine",
|
|
7373
|
-
"doctor.fix.would": "machine",
|
|
7374
|
-
"doctor.fix.applied": "machine",
|
|
7375
|
-
"doctor.fix.backup": "machine",
|
|
7376
|
-
"doctor.fix.manual": "machine",
|
|
7377
|
-
"doctor.report.written": "machine"
|
|
7458
|
+
"doctor.git.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"
|
|
7378
7467
|
}
|
|
7379
7468
|
};
|
|
7380
7469
|
|
|
@@ -10952,11 +11041,11 @@ var withAlias = (invocation, expansion) => ({
|
|
|
10952
11041
|
|
|
10953
11042
|
// src/git/path-key.ts
|
|
10954
11043
|
import { posix as posix2 } from "node:path";
|
|
10955
|
-
var
|
|
11044
|
+
var WSL_MOUNT3 = /^\/mnt\/([a-zA-Z])(\/|$)/;
|
|
10956
11045
|
var DRIVE = /^([a-zA-Z]):(\/|$)/;
|
|
10957
11046
|
var pathKey = (path) => {
|
|
10958
11047
|
const posixPath = toPosixPath(path).replace(
|
|
10959
|
-
|
|
11048
|
+
WSL_MOUNT3,
|
|
10960
11049
|
(_match, letter, slash) => `${letter}:${slash || "/"}`
|
|
10961
11050
|
);
|
|
10962
11051
|
const drive = DRIVE.exec(posixPath);
|
|
@@ -13185,8 +13274,21 @@ var checkInstructions = (env) => {
|
|
|
13185
13274
|
];
|
|
13186
13275
|
};
|
|
13187
13276
|
|
|
13188
|
-
// src/doctor/
|
|
13277
|
+
// src/doctor/line-endings.ts
|
|
13189
13278
|
import { join as join30 } from "node:path";
|
|
13279
|
+
var LF_RULE = /^\*\s.*\beol=lf\b/m;
|
|
13280
|
+
var checkLineEndings = ({ root, runtime }) => {
|
|
13281
|
+
const autocrlf = runtime.git(["config", "--get", "core.autocrlf"], root);
|
|
13282
|
+
if (!autocrlf.ok || autocrlf.stdout.trim().toLowerCase() !== "true") return [];
|
|
13283
|
+
const attributes = runtime.readText(toAbsolutePath(join30(root, ".gitattributes")));
|
|
13284
|
+
if (attributes.ok && LF_RULE.test(attributes.value)) return [];
|
|
13285
|
+
return [
|
|
13286
|
+
finding("git.autocrlf", "warn", "doctor.git.autocrlf", { file: ".gitattributes" }, "doctor.git.fix_autocrlf")
|
|
13287
|
+
];
|
|
13288
|
+
};
|
|
13289
|
+
|
|
13290
|
+
// src/doctor/memory.ts
|
|
13291
|
+
import { join as join31 } from "node:path";
|
|
13190
13292
|
var ceilingOf = (config) => {
|
|
13191
13293
|
const value = configAt(parseConfigYaml(config ?? ""), "memory", "maxLines");
|
|
13192
13294
|
const parsed = typeof value === "string" ? Number.parseInt(value, 10) : Number.NaN;
|
|
@@ -13194,9 +13296,9 @@ var ceilingOf = (config) => {
|
|
|
13194
13296
|
};
|
|
13195
13297
|
var lineCount2 = (text6) => text6.replace(/\r?\n$/, "").split(/\r?\n/).length;
|
|
13196
13298
|
var checkAgentsFile = ({ root, runtime }) => {
|
|
13197
|
-
const text6 = runtime.readText(toAbsolutePath(
|
|
13299
|
+
const text6 = runtime.readText(toAbsolutePath(join31(root, AGENTS_FILE)));
|
|
13198
13300
|
if (!text6.ok) return [];
|
|
13199
|
-
const config = runtime.readText(toAbsolutePath(
|
|
13301
|
+
const config = runtime.readText(toAbsolutePath(join31(root, CONFIG_FILE)));
|
|
13200
13302
|
const max = ceilingOf(config.ok ? config.value : void 0);
|
|
13201
13303
|
const lines3 = lineCount2(text6.value);
|
|
13202
13304
|
const params2 = { file: AGENTS_FILE, lines: lines3, max };
|
|
@@ -13204,7 +13306,7 @@ var checkAgentsFile = ({ root, runtime }) => {
|
|
|
13204
13306
|
};
|
|
13205
13307
|
|
|
13206
13308
|
// src/doctor/project-files.ts
|
|
13207
|
-
import { join as
|
|
13309
|
+
import { join as join32 } from "node:path";
|
|
13208
13310
|
var variants = (base, extensions) => extensions.map((extension) => `${base}${extension}`);
|
|
13209
13311
|
var SCRIPT = [".js", ".cjs", ".mjs", ".ts", ".cts", ".mts"];
|
|
13210
13312
|
var DATA = ["", ".json", ".yml", ".yaml"];
|
|
@@ -13235,7 +13337,7 @@ var CONFIG_GROUPS = [
|
|
|
13235
13337
|
files: [...variants("commitlint.config", SCRIPT), ...variants(".commitlintrc", [...DATA, ".js"])]
|
|
13236
13338
|
}
|
|
13237
13339
|
];
|
|
13238
|
-
var present = (env, files) => files.filter((file) => env.runtime.stat(toAbsolutePath(
|
|
13340
|
+
var present = (env, files) => files.filter((file) => env.runtime.stat(toAbsolutePath(join32(env.root, file)))?.kind === "file");
|
|
13239
13341
|
var crowded = (env, groups, build) => groups.flatMap(({ name, files }) => {
|
|
13240
13342
|
const found = present(env, files);
|
|
13241
13343
|
return found.length > 1 ? [build(name, found.join(", "))] : [];
|
|
@@ -13273,6 +13375,7 @@ var CHECKS = [
|
|
|
13273
13375
|
checkClaudeSettings,
|
|
13274
13376
|
checkInstructions,
|
|
13275
13377
|
checkProjectFiles,
|
|
13378
|
+
checkLineEndings,
|
|
13276
13379
|
checkAgentsFile,
|
|
13277
13380
|
checkHooks
|
|
13278
13381
|
];
|
|
@@ -13800,7 +13903,7 @@ var rescueCommand = {
|
|
|
13800
13903
|
};
|
|
13801
13904
|
|
|
13802
13905
|
// src/git/undo.ts
|
|
13803
|
-
import { basename as basename3, dirname as dirname8, join as
|
|
13906
|
+
import { basename as basename3, dirname as dirname8, join as join33 } from "node:path";
|
|
13804
13907
|
var INDEX_SUBJECT = "finitemonkey index:";
|
|
13805
13908
|
var gitLine = (runtime, repo, args) => {
|
|
13806
13909
|
const result = runtime.git(args, repo.root);
|
|
@@ -13843,7 +13946,7 @@ var findSnapshot = (views, wanted) => {
|
|
|
13843
13946
|
};
|
|
13844
13947
|
var stampOf2 = (iso) => iso.replace(/[:.]/g, "-");
|
|
13845
13948
|
var worktreePath = (runtime, repo) => {
|
|
13846
|
-
const base =
|
|
13949
|
+
const base = join33(dirname8(repo.root), `${basename3(repo.root)}-undo-${stampOf2(runtime.now())}`);
|
|
13847
13950
|
return toAbsolutePath(runtime.stat(toAbsolutePath(base)) === void 0 ? base : `${base}-2`);
|
|
13848
13951
|
};
|
|
13849
13952
|
var intoWorktree = (runtime, repo, view2) => {
|
|
@@ -14032,13 +14135,13 @@ var helpCommand = {
|
|
|
14032
14135
|
};
|
|
14033
14136
|
|
|
14034
14137
|
// src/install/plugin-yield.ts
|
|
14035
|
-
import { join as
|
|
14138
|
+
import { join as join34 } from "node:path";
|
|
14036
14139
|
var PLUGIN_VIA = "plugin";
|
|
14037
14140
|
var YIELD_STDOUT = `${JSON.stringify({ continue: true })}
|
|
14038
14141
|
`;
|
|
14039
14142
|
var projectOwnsHooks = (ctx) => {
|
|
14040
14143
|
const root = ctx.env["CLAUDE_PROJECT_DIR"] ?? ctx.cwd;
|
|
14041
|
-
const text6 = ctx.runtime.readText(toAbsolutePath(
|
|
14144
|
+
const text6 = ctx.runtime.readText(toAbsolutePath(join34(root, ...SETTINGS_FILE.split("/"))));
|
|
14042
14145
|
if (!text6.ok) return false;
|
|
14043
14146
|
const parsed = parseJsonObject(text6.value);
|
|
14044
14147
|
return parsed.ok && ownHandlersIn(parsed.value) > 0;
|
|
@@ -14091,7 +14194,7 @@ var hookCommand = {
|
|
|
14091
14194
|
};
|
|
14092
14195
|
|
|
14093
14196
|
// src/commands/i18n-check.ts
|
|
14094
|
-
import { join as
|
|
14197
|
+
import { join as join35 } from "node:path";
|
|
14095
14198
|
|
|
14096
14199
|
// src/i18n/message.ts
|
|
14097
14200
|
var ARG = /^\s*([a-zA-Z][a-zA-Z0-9_]*)\s*(?:,\s*(plural|select)\s*,)?/;
|
|
@@ -14293,7 +14396,7 @@ var unreadable = (dir, file, detail) => ({
|
|
|
14293
14396
|
exitCode: ExitCode.NotConfigured
|
|
14294
14397
|
});
|
|
14295
14398
|
var readCatalog = (ctx, dir, lang) => {
|
|
14296
|
-
const file = toAbsolutePath(
|
|
14399
|
+
const file = toAbsolutePath(join35(dir, `${lang}.json`));
|
|
14297
14400
|
const text6 = ctx.runtime.readText(file);
|
|
14298
14401
|
if (!text6.ok) return reject(unreadable(dir, file, text6.error));
|
|
14299
14402
|
const parsed = parseJsonObject(text6.value);
|
|
@@ -14316,7 +14419,7 @@ var describeProblem = (ctx, problem4) => {
|
|
|
14316
14419
|
return ` ${problem4.lang} ${problem4.key} ${kind}`;
|
|
14317
14420
|
};
|
|
14318
14421
|
var loadReview = (ctx, dir) => {
|
|
14319
|
-
const text6 = ctx.runtime.readText(toAbsolutePath(
|
|
14422
|
+
const text6 = ctx.runtime.readText(toAbsolutePath(join35(dir, "review.json")));
|
|
14320
14423
|
const parsed = text6.ok ? parseJsonObject(text6.value) : void 0;
|
|
14321
14424
|
if (parsed?.ok !== true) return void 0;
|
|
14322
14425
|
const statuses = (lang) => {
|
|
@@ -14356,6 +14459,178 @@ var i18nCheckCommand = {
|
|
|
14356
14459
|
}
|
|
14357
14460
|
};
|
|
14358
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
|
+
|
|
14359
14634
|
// src/install/diff.ts
|
|
14360
14635
|
var MAX_DIFF_LINES = 120;
|
|
14361
14636
|
var table = (a, b) => {
|
|
@@ -14429,6 +14704,8 @@ var itemWarning = (t, item) => {
|
|
|
14429
14704
|
var planWarnings = (t, plan) => [
|
|
14430
14705
|
...plan.detection.gitRoot ? [] : [{ code: "not_git", message: t("install.warn.not_git") }],
|
|
14431
14706
|
...plan.detection.claude.failClosed ? [] : [{ code: "fail_open", message: t("install.warn.fail_open", { version: plan.detection.claude.version ?? "?" }) }],
|
|
14707
|
+
...plan.detection.location.wslMount ? [{ code: "wsl_mount", message: t("install.warn.wsl_mount", { path: plan.detection.root }) }] : [],
|
|
14708
|
+
...plan.detection.location.synced ? [{ code: "synced_folder", message: t("install.warn.synced_folder", { path: plan.detection.root }) }] : [],
|
|
14432
14709
|
...plan.detection.authorities.map((authority) => authorityWarning(t, authority)),
|
|
14433
14710
|
...plan.items.flatMap((item) => itemWarning(t, item))
|
|
14434
14711
|
];
|
|
@@ -14508,17 +14785,32 @@ var initRequest = (args) => ({
|
|
|
14508
14785
|
marketplace: args.values["marketplace"] === true,
|
|
14509
14786
|
showDiff: false
|
|
14510
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
|
+
};
|
|
14511
14799
|
var initCommand = {
|
|
14512
14800
|
path: ["init"],
|
|
14513
14801
|
summaryKey: "command.init.summary",
|
|
14514
|
-
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]",
|
|
14515
14803
|
status: "ready",
|
|
14516
14804
|
options: {
|
|
14517
14805
|
preset: { type: "string" },
|
|
14518
14806
|
bin: { type: "string" },
|
|
14519
|
-
marketplace: { type: "boolean" }
|
|
14807
|
+
marketplace: { type: "boolean" },
|
|
14808
|
+
"look-back": { type: "boolean" }
|
|
14520
14809
|
},
|
|
14521
|
-
run: (ctx, args) =>
|
|
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
|
+
}
|
|
14522
14814
|
};
|
|
14523
14815
|
|
|
14524
14816
|
// src/commands/prose-check.ts
|
|
@@ -14996,7 +15288,7 @@ var secretsScanCommand = {
|
|
|
14996
15288
|
};
|
|
14997
15289
|
|
|
14998
15290
|
// src/task/create.ts
|
|
14999
|
-
import { join as
|
|
15291
|
+
import { join as join37 } from "node:path";
|
|
15000
15292
|
|
|
15001
15293
|
// src/core/yaml/write.ts
|
|
15002
15294
|
var PLAIN_SAFE = /^[A-Za-z_./][A-Za-z0-9_./ ()-]*$/;
|
|
@@ -15080,10 +15372,10 @@ var explicitChecks = (draft) => [
|
|
|
15080
15372
|
var draftChecks = (runtime, paths, draft) => {
|
|
15081
15373
|
const disk = {
|
|
15082
15374
|
read: (relative9) => {
|
|
15083
|
-
const text6 = runtime.readText(toAbsolutePath(
|
|
15375
|
+
const text6 = runtime.readText(toAbsolutePath(join37(paths.root, relative9)));
|
|
15084
15376
|
return text6.ok ? text6.value : void 0;
|
|
15085
15377
|
},
|
|
15086
|
-
exists: (relative9) => runtime.stat(toAbsolutePath(
|
|
15378
|
+
exists: (relative9) => runtime.stat(toAbsolutePath(join37(paths.root, relative9))) !== void 0
|
|
15087
15379
|
};
|
|
15088
15380
|
const detected = detectChecks(disk);
|
|
15089
15381
|
const base = draft.runs.length > 0 || draft.tests !== void 0 ? explicitChecks(draft) : detected;
|
|
@@ -15487,7 +15779,7 @@ var REGISTRY = [
|
|
|
15487
15779
|
];
|
|
15488
15780
|
|
|
15489
15781
|
// src/i18n/lang-settings.ts
|
|
15490
|
-
import { join as
|
|
15782
|
+
import { join as join38 } from "node:path";
|
|
15491
15783
|
var read3 = (runtime, path) => {
|
|
15492
15784
|
const text6 = runtime.readText(toAbsolutePath(path));
|
|
15493
15785
|
return text6.ok ? text6.value : void 0;
|
|
@@ -15502,14 +15794,14 @@ var languageIn = (text6) => {
|
|
|
15502
15794
|
const value = parsed.ok && isRecord(parsed.value) ? parsed.value["language"] : void 0;
|
|
15503
15795
|
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
15504
15796
|
};
|
|
15505
|
-
var claudeDir = (runtime, env) => env["CLAUDE_CONFIG_DIR"] ??
|
|
15797
|
+
var claudeDir = (runtime, env) => env["CLAUDE_CONFIG_DIR"] ?? join38(runtime.homeDir(), ".claude");
|
|
15506
15798
|
var langSettings = (runtime, cwd, env, platform) => {
|
|
15507
15799
|
const root = findGitRoot(cwd, runtime) ?? cwd;
|
|
15508
|
-
const config = parseConfigYaml(read3(runtime,
|
|
15800
|
+
const config = parseConfigYaml(read3(runtime, join38(root, CONFIG_FILE)) ?? "");
|
|
15509
15801
|
const claudeFiles = [
|
|
15510
|
-
|
|
15511
|
-
|
|
15512
|
-
|
|
15802
|
+
join38(root, ".claude", "settings.local.json"),
|
|
15803
|
+
join38(root, ".claude", "settings.json"),
|
|
15804
|
+
join38(claudeDir(runtime, env), "settings.json")
|
|
15513
15805
|
];
|
|
15514
15806
|
return {
|
|
15515
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.
|
|
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",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"i18n:check": "node dist/finitemonkey.mjs i18n check --dir src/i18n",
|
|
56
56
|
"bench:startup": "node scripts/bench-startup.mjs",
|
|
57
57
|
"smoke:install": "node scripts/smoke-install.mjs",
|
|
58
|
-
"check": "npm run typecheck && npm run lint && npm run format:check && npm run check:dist && npm test && npm run i18n:check && npm run plugin:validate && npm pack --dry-run && npm run llms:check && npm run schema:check",
|
|
58
|
+
"check": "npm run typecheck && npm run lint && npm run format:check && npm run check:dist && npm test && npm run i18n:check && npm run plugin:validate && npm pack --dry-run && npm run llms:check && npm run schema:check && npm run docs:check",
|
|
59
59
|
"prepublishOnly": "npm run typecheck && npm run check:dist && npm test",
|
|
60
60
|
"prepare": "husky",
|
|
61
61
|
"gif": "tsc -p assets/scripts && node --experimental-strip-types assets/scripts/render.ts",
|
|
@@ -66,6 +66,8 @@
|
|
|
66
66
|
"schema": "tsx scripts/build-schemas.ts",
|
|
67
67
|
"schema:check": "tsx scripts/build-schemas.ts --check",
|
|
68
68
|
"budgets": "tsx scripts/budgets.ts",
|
|
69
|
+
"docs": "tsx scripts/build-docs.ts",
|
|
70
|
+
"docs:check": "tsc -p scripts && tsx scripts/build-docs.ts --check",
|
|
69
71
|
"plugin:sync": "node scripts/plugin-sync.mjs",
|
|
70
72
|
"plugin:validate": "node scripts/plugin-validate.mjs",
|
|
71
73
|
"version": "node scripts/plugin-sync.mjs"
|