@payconductor/houndsman 0.1.0 → 0.1.1
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.md +39 -78
- package/assets/logo-legacy.png +0 -0
- package/assets/logo.png +0 -0
- package/package.json +3 -2
- package/src/cli/index.ts +89 -9
- package/src/core/assets.ts +8 -0
- package/src/core/brief.ts +25 -2
- package/src/core/commands/findings.ts +390 -0
- package/src/core/commands/scaffold.ts +20 -0
- package/src/core/config.ts +42 -0
- package/src/core/diff-source.ts +140 -0
- package/src/core/file-classifier.ts +50 -2
- package/src/core/finding-anchor.ts +147 -0
- package/src/core/findings-state.ts +538 -0
- package/src/core/jev/jev-client.ts +72 -11
- package/src/core/jev/jev-detector.ts +21 -19
- package/src/core/orchestrator.ts +169 -17
- package/src/core/paths.ts +3 -0
- package/src/core/registry-check.ts +15 -0
- package/src/core/report-builder.ts +113 -9
- package/src/core/types.ts +10 -0
- package/src/index.ts +78 -2
- package/src/server/artifacts.ts +66 -0
- package/src/server/client/App.tsx +158 -0
- package/src/server/client/ArtifactsPanel.tsx +48 -0
- package/src/server/client/Filters.tsx +83 -0
- package/src/server/client/FindingCard.tsx +122 -0
- package/src/server/client/FindingsList.tsx +54 -0
- package/src/server/client/RunList.tsx +43 -0
- package/src/server/client/SummaryBar.tsx +21 -0
- package/src/server/client/api.ts +37 -0
- package/src/server/client/constants.ts +63 -0
- package/src/server/client/index.tsx +12 -0
- package/src/server/client/types.ts +48 -0
- package/src/server/client-build.ts +47 -0
- package/src/server/index.ts +365 -0
- package/src/skill/README.md +14 -6
- package/src/skill/SETUP.md +5 -3
- package/src/skill/houndsman-update.md +1 -1
- package/src/skill/houndsman.md +87 -10
- package/src/tests/findings-anchor.test.ts +120 -0
- package/src/tests/findings-commands.test.ts +226 -0
- package/src/tests/findings-state.test.ts +274 -0
- package/src/tests/review-scripts.test.ts +299 -0
- package/src/tests/server.test.ts +212 -0
package/README.md
CHANGED
|
@@ -12,7 +12,8 @@ relatório único.
|
|
|
12
12
|
|
|
13
13
|
**Terminologia:** **houndsman** = orquestrador/treinador (CLI + motor) · **watchdog** = cada
|
|
14
14
|
agente especialista por domínio que audita o diff · **review/revisão** = o processo ·
|
|
15
|
-
**Jev** = pré-análise opcional.
|
|
15
|
+
**Jev** = pré-análise opcional. O vocabulário completo (brief, findings, manifest, budget,
|
|
16
|
+
overflow, churn, candidato…) está em [`docs/GLOSSARY.md`](docs/GLOSSARY.md).
|
|
16
17
|
|
|
17
18
|
---
|
|
18
19
|
|
|
@@ -25,8 +26,8 @@ diferente das PRs. O motor só coordena a caçada — as regras são problema se
|
|
|
25
26
|
|
|
26
27
|
- **Bun** — runtime obrigatório.
|
|
27
28
|
- **git** — o diff usa `git diff <base>...<head>`.
|
|
28
|
-
- Opcionais
|
|
29
|
-
|
|
29
|
+
- Opcionais: **`gh`** (contexto da PR) e **`TYPESAFE_API_KEY`** (pré-análise Jev). A revisão
|
|
30
|
+
funciona normalmente sem eles; o `houndsman doctor` valida a credencial Jev quando presente.
|
|
30
31
|
|
|
31
32
|
### 2. Instale o CLI (global)
|
|
32
33
|
|
|
@@ -51,15 +52,13 @@ Cria a camada `.houndsman/`, que é **autocontida** (não instala nada no seu pr
|
|
|
51
52
|
| `.houndsman/exclusions.ts` | você | Arquivos que nunca entram na revisão |
|
|
52
53
|
| `.houndsman/doc-mappings.ts` | você | path → documentação de contexto |
|
|
53
54
|
| `.houndsman/core/**` | auto | Tipos + docs do skill (sincronizados por `houndsman update`) |
|
|
54
|
-
| `.agents/` · `.claude/` | auto | Ponteiros de skill dos harnesses |
|
|
55
|
-
| `package.json` | — | Adiciona o script `"houndsman"` |
|
|
56
55
|
|
|
57
56
|
> **Não existe "modo completo".** O `setup` já cria a camada inicial com um watchdog de
|
|
58
57
|
> exemplo — troque o exemplo pelas regras reais do seu projeto (ou use `/houndsman-update`).
|
|
59
58
|
|
|
60
59
|
### 4. Escreva suas regras
|
|
61
60
|
|
|
62
|
-
Edite `.houndsman/watchdogs/` — veja [Escrevendo boas regras](#escrevendo-boas-regras).
|
|
61
|
+
Edite `.houndsman/watchdogs/` — veja [Escrevendo boas regras](docs/AVANCADO.md#escrevendo-boas-regras).
|
|
63
62
|
|
|
64
63
|
### 5. Valide
|
|
65
64
|
|
|
@@ -87,7 +86,8 @@ Não precisa rodar nenhum script à mão.
|
|
|
87
86
|
├─ Passo 0 contexto da PR (gh, opcional)
|
|
88
87
|
├─ Passo 1 classifica o diff → briefs por watchdog
|
|
89
88
|
├─ Passo 2 N subagentes revisam em paralelo
|
|
90
|
-
|
|
89
|
+
├─ Passo 3 consolida em review.md + state.json
|
|
90
|
+
└─ Passo 4 triagem (UI local ou agente)
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
- Revisão normal: só `/houndsman` (a branch é detectada; base default `main`).
|
|
@@ -98,6 +98,32 @@ Não precisa rodar nenhum script à mão.
|
|
|
98
98
|
|
|
99
99
|
---
|
|
100
100
|
|
|
101
|
+
## Triando os findings (opcional)
|
|
102
|
+
|
|
103
|
+
Depois do `--finalize`, cada finding tem um `id` curto e um `fingerprint` de **conteúdo**
|
|
104
|
+
no `.houndsman/.runs/<branch-slug>/state.json`. Você decide o que fazer com cada um — pela
|
|
105
|
+
**UI local** ou pelo **agente** (auto-fix) — sem abrir o JSON à mão:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
bun run houndsman server --open # UI: triar, comentar, marcar feito, ler artefatos
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- **decision:** `pending` · `execute` · `ignore` (+ comentário).
|
|
112
|
+
- **execState:** `pending` · `in_progress` · `done` · `stale`.
|
|
113
|
+
|
|
114
|
+
**Auto-fix pelo agente** — as linhas mudam depois do fix, e o motor reancora por conteúdo:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
bun run houndsman findings list --decision execute --json
|
|
118
|
+
bun run houndsman findings sync
|
|
119
|
+
bun run houndsman findings done <id>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
> A identidade do finding é o **conteúdo** (fingerprint), não a linha: itens deslocados
|
|
123
|
+
> pelo fix não se perdem. O estado é local e mora em `.runs/<slug>/state.json` (gitignored).
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
101
127
|
## Mantendo a configuração
|
|
102
128
|
|
|
103
129
|
- **Alterar regras** → use o skill **`/houndsman-update`**. Ele prova no código que o padrão
|
|
@@ -116,80 +142,15 @@ Não precisa rodar nenhum script à mão.
|
|
|
116
142
|
|
|
117
143
|
---
|
|
118
144
|
|
|
119
|
-
## Avançado
|
|
120
|
-
|
|
121
|
-
### Comandos do dia a dia
|
|
122
|
-
|
|
123
|
-
| Comando | Função |
|
|
124
|
-
|---|---|
|
|
125
|
-
| `houndsman setup` | Cria a configuração inicial do projeto |
|
|
126
|
-
| `houndsman update` | Sincroniza os arquivos auto-gerados (`.houndsman/core`) |
|
|
127
|
-
| `houndsman doctor` | Valida a configuração e o ambiente (anti-drift) |
|
|
128
|
-
| `houndsman context` | Passo 0 — contexto da PR via `gh` |
|
|
129
|
-
| `houndsman --base main` | Passo 1 — prepara os briefs |
|
|
130
|
-
| `houndsman --finalize` | Passo 3 — gera o relatório |
|
|
131
|
-
| `houndsman watchdog <id>` | Contexto de um watchdog (`--rules`, `--json`) |
|
|
132
|
-
|
|
133
|
-
Flags: `--base <branch>` (default `main`) · `--head <ref>` (default `HEAD`) ·
|
|
134
|
-
`--branch <nome>` · `--dir <dir>` · `--config <path>` · `--clean` · `--no-jev` ·
|
|
135
|
-
`--fail-on-blocking` (com `--finalize`).
|
|
136
|
-
|
|
137
|
-
### Escrevendo boas regras
|
|
138
|
-
|
|
139
|
-
O texto da regra é renderizado **literalmente** no brief do subagente — ambiguidade vira
|
|
140
|
-
ruído na revisão. Toda regra começa com um **prefixo de polaridade**:
|
|
141
|
-
|
|
142
|
-
- `Promover:` → algo que **DEVE** acontecer (o padrão precisa existir no código).
|
|
143
|
-
- `Evitar:` → algo que **NÃO DEVE** acontecer. `Não` e `Nunca` no início são equivalentes.
|
|
144
|
-
|
|
145
|
-
Boas práticas:
|
|
146
|
-
|
|
147
|
-
1. **Só regra que o projeto aplica hoje** — prove com evidência (`arquivo:linha` para
|
|
148
|
-
afirmativas; `0 ocorrências via grep` do anti-padrão para negativas). Regra afirmativa sem
|
|
149
|
-
aplicação real gera falso positivo.
|
|
150
|
-
2. **Geral e reutilizável** — descreva um padrão do domínio, não uma regra de negócio
|
|
151
|
-
amarrada a uma única classe/use-case (isso é papel de teste automatizado).
|
|
152
|
-
3. **Condição inequívoca e critério concreto** — duas IAs chegam à mesma conclusão; use
|
|
153
|
-
limite/lista explícita ou símbolo real do código.
|
|
154
|
-
4. **Sem jargão vago nem qualificador vazio** — nada de "o antigo", "isso", "apenas por
|
|
155
|
-
compatibilidade".
|
|
156
|
-
5. **Declare o `classify`** do watchdog — regex de path (`filename`) ou de conteúdo
|
|
157
|
-
(`content`) para o motor achar os arquivos do domínio.
|
|
158
|
-
6. **Prefira editar via `/houndsman-update`** — ele aplica a rubrica completa e roda as
|
|
159
|
-
verificações (`doctor`, `test`).
|
|
160
|
-
|
|
161
|
-
> `houndsman doctor` emite um aviso (não bloqueante) para regra sem prefixo de polaridade.
|
|
162
|
-
|
|
163
|
-
Exemplo:
|
|
164
|
-
|
|
165
|
-
```ts
|
|
166
|
-
{ severity: "blocking", text: "Evitar: handler de webhook processa o payload antes de validar a assinatura do provider." }
|
|
167
|
-
{ severity: "attention", text: "Promover: rotas validam a entrada com o schema do domínio." }
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Estrutura gerada por `setup`
|
|
171
|
-
|
|
172
|
-
```
|
|
173
|
-
houndsman.config.ts
|
|
174
|
-
.houndsman/
|
|
175
|
-
├── .gitignore # AUTO
|
|
176
|
-
├── core/ # AUTO — sincronizado por `update`
|
|
177
|
-
│ ├── types.ts
|
|
178
|
-
│ └── skill/*.md
|
|
179
|
-
├── watchdogs/ # você — 1 módulo .ts por watchdog
|
|
180
|
-
│ └── index.ts
|
|
181
|
-
├── exclusions.ts # você
|
|
182
|
-
└── doc-mappings.ts # você
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
Os artefatos de cada review ficam em `.houndsman/.runs/<branch-slug>/` (auto-ignorados).
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
145
|
## Documentação
|
|
190
146
|
|
|
191
|
-
-
|
|
147
|
+
- `docs/AVANCADO.md` — como funciona por dentro (diagrama do fluxo e onde o Jev entra),
|
|
148
|
+
referência de comandos e boas práticas para escrever regras.
|
|
149
|
+
- `docs/GLOSSARY.md` — glossário do vocabulário de domínio (brief, findings, manifest,
|
|
150
|
+
budget, overflow, churn, candidato, Jev…): o que cada termo significa **neste** projeto.
|
|
151
|
+
- `docs/CONTRIBUTING.md` — arquitetura, fluxos internos, princípios e desenvolvimento da
|
|
192
152
|
lib (para quem vai contribuir).
|
|
153
|
+
|
|
193
154
|
- `src/skill/SETUP.md` — referência de configuração passo a passo.
|
|
194
155
|
- `src/skill/houndsman.md` — orquestração do skill `/houndsman`.
|
|
195
156
|
- `src/skill/houndsman-update.md` — manutenção das regras dos watchdogs.
|
|
Binary file
|
package/assets/logo.png
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payconductor/houndsman",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Orquestrador de revisão de Pull Requests: classifica o diff, despacha watchdogs especializados por domínio e consolida o relatório.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,7 +54,8 @@
|
|
|
54
54
|
"ci:format:fix": "biome format --fix"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"axios": "^1.12.2"
|
|
57
|
+
"axios": "^1.12.2",
|
|
58
|
+
"preact": "^11.0.1"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
60
61
|
"@biomejs/biome": "2.2.4",
|
package/src/cli/index.ts
CHANGED
|
@@ -11,9 +11,11 @@
|
|
|
11
11
|
* (default) Passo 1 — preparar (classificação + briefs + manifesto)
|
|
12
12
|
* --finalize Passo 3 — consolidar os findings em review.md
|
|
13
13
|
* context Passo 0 — coletar o contexto da PR via `gh`
|
|
14
|
+
* findings <sub> Triagem dos findings (list/set/done/sync/...)
|
|
15
|
+
* server Sobe a UI local de triagem (Bun.serve)
|
|
14
16
|
* setup Cria a configuração inicial do projeto (config + skills)
|
|
15
17
|
* update Sincroniza os arquivos auto-gerados (.houndsman/core)
|
|
16
|
-
* doctor Valida a configuração
|
|
18
|
+
* doctor Valida a configuração, o ambiente e a credencial Jev (anti-drift)
|
|
17
19
|
* test Roda a suíte de testes da lib
|
|
18
20
|
* watchdog <id> Contexto de um watchdog (`--rules`, `--json`)
|
|
19
21
|
*
|
|
@@ -22,6 +24,7 @@
|
|
|
22
24
|
*/
|
|
23
25
|
|
|
24
26
|
import { runContextCommand } from "../core/commands/context";
|
|
27
|
+
import { runFindingsCommand } from "../core/commands/findings";
|
|
25
28
|
import { parseReviewArgs } from "../core/commands/review";
|
|
26
29
|
import { runSetupCommand } from "../core/commands/setup";
|
|
27
30
|
import { runLibTests } from "../core/commands/test";
|
|
@@ -29,9 +32,11 @@ import { runUpdateCommand } from "../core/commands/update";
|
|
|
29
32
|
import { renderWatchdogContext } from "../core/commands/watchdog";
|
|
30
33
|
import { type HoundsmanConfig, resolveArtifactDir } from "../core/config";
|
|
31
34
|
import { loadConfig } from "../core/config-loader";
|
|
35
|
+
import { JevClient } from "../core/jev";
|
|
32
36
|
import { finalize, prepare, resolveBranch } from "../core/orchestrator";
|
|
33
37
|
import { relFromRoot } from "../core/paths";
|
|
34
38
|
import { checkRegistry } from "../core/registry-check";
|
|
39
|
+
import { startServer } from "../server";
|
|
35
40
|
|
|
36
41
|
const HELP = `Uso: houndsman [comando] [flags]
|
|
37
42
|
|
|
@@ -39,9 +44,11 @@ Comandos:
|
|
|
39
44
|
(nenhum) Prepara a revisão (classification + briefs + manifesto)
|
|
40
45
|
--finalize Consolida os findings em review.md
|
|
41
46
|
context Coleta o contexto da PR via gh (Passo 0)
|
|
47
|
+
findings <sub> Triagem dos findings (list · show · set · done · reset · sync · summary · path)
|
|
48
|
+
server Sobe a UI local de triagem (--port, --host, --open)
|
|
42
49
|
setup Cria a configuração inicial do projeto (config + skills)
|
|
43
50
|
update Sincroniza os arquivos auto-gerados (.houndsman/core)
|
|
44
|
-
doctor Valida a configuração
|
|
51
|
+
doctor Valida a configuração, o ambiente e a credencial Jev
|
|
45
52
|
test Roda a suíte de testes da lib
|
|
46
53
|
watchdog <id> Contexto de um watchdog (--rules, --json)
|
|
47
54
|
|
|
@@ -53,7 +60,18 @@ Flags:
|
|
|
53
60
|
--dir <dir> Diretório dos artefatos
|
|
54
61
|
--clean Descarta findings anteriores
|
|
55
62
|
--no-jev Desativa a pré-análise Jev
|
|
56
|
-
--fail-on-blocking Exit 1 se houver bloqueantes (com --finalize)
|
|
63
|
+
--fail-on-blocking Exit 1 se houver bloqueantes (com --finalize)
|
|
64
|
+
|
|
65
|
+
Flags de findings:
|
|
66
|
+
--decision <d> pending | execute | ignore
|
|
67
|
+
--exec <e> pending | in_progress | done | stale
|
|
68
|
+
--comment <text> Comentário/instrução adicional
|
|
69
|
+
--watchdog <id> Filtra por watchdog (list)
|
|
70
|
+
--severity <s> Filtra por severidade (list)
|
|
71
|
+
--file <text> Filtra por trecho do caminho (list)
|
|
72
|
+
--all Inclui findings ausentes do último relatório
|
|
73
|
+
--json Saída JSON
|
|
74
|
+
--limit <n> Limita o nº de itens (list)`;
|
|
57
75
|
|
|
58
76
|
function readFlag(args: string[], flag: string): string | undefined {
|
|
59
77
|
const index = args.indexOf(flag);
|
|
@@ -88,8 +106,8 @@ function runContext(config: HoundsmanConfig, args: string[]): void {
|
|
|
88
106
|
}
|
|
89
107
|
}
|
|
90
108
|
|
|
91
|
-
/** Valida a configuração do projeto e o ambiente
|
|
92
|
-
function runDoctor(config: HoundsmanConfig): void {
|
|
109
|
+
/** Valida a configuração do projeto e o ambiente. */
|
|
110
|
+
async function runDoctor(config: HoundsmanConfig): Promise<void> {
|
|
93
111
|
console.log("→ Validando configuração do projeto...");
|
|
94
112
|
const { problems, warnings, jevQuestions } = checkRegistry(config);
|
|
95
113
|
|
|
@@ -110,9 +128,27 @@ function runDoctor(config: HoundsmanConfig): void {
|
|
|
110
128
|
console.log("\n→ Ambiente:");
|
|
111
129
|
console.log(` ${Bun.which("git") ? "✅" : "❌"} git`);
|
|
112
130
|
console.log(` ${Bun.which("gh") ? "✅" : "⚠️ "} gh (opcional — contexto da PR)`);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
131
|
+
await reportJevCredential();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Reporta o estado da credencial Jev: presença e validade (chamada mínima).
|
|
136
|
+
* Fail-open — nunca altera o exit code (`doctor` é diagnóstico).
|
|
137
|
+
*/
|
|
138
|
+
async function reportJevCredential(): Promise<void> {
|
|
139
|
+
const client = new JevClient();
|
|
140
|
+
if (!client.isConfigured()) {
|
|
141
|
+
console.log(" ⚠️ TYPESAFE_API_KEY (opcional — pré-análise Jev)");
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const check = await client.validateCredential();
|
|
145
|
+
if (check.ok) {
|
|
146
|
+
console.log(` ✅ Jev: credencial válida (modelo ${check.model}).`);
|
|
147
|
+
} else if (check.kind === "invalid") {
|
|
148
|
+
console.log(` ❌ Jev: credencial inválida — ${check.detail}`);
|
|
149
|
+
} else {
|
|
150
|
+
console.log(` ⚠️ Jev: não foi possível validar — ${check.detail}`);
|
|
151
|
+
}
|
|
116
152
|
}
|
|
117
153
|
|
|
118
154
|
/** Contexto de um watchdog. */
|
|
@@ -137,6 +173,44 @@ function runWatchdog(config: HoundsmanConfig, args: string[]): void {
|
|
|
137
173
|
);
|
|
138
174
|
}
|
|
139
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Subcomando `findings` — triagem dos findings (list/show/set/done/reset/
|
|
178
|
+
* sync/summary/path). Deixa o agente interagir com o estado sem abrir o JSON.
|
|
179
|
+
*/
|
|
180
|
+
function runFindings(config: HoundsmanConfig, args: string[]): void {
|
|
181
|
+
const result = runFindingsCommand(config, args);
|
|
182
|
+
if (result.exitCode !== 0) {
|
|
183
|
+
console.error(result.output);
|
|
184
|
+
process.exit(result.exitCode);
|
|
185
|
+
}
|
|
186
|
+
console.log(result.output);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Abre a URL no navegador padrão (best-effort, por plataforma). */
|
|
190
|
+
function openBrowser(url: string): void {
|
|
191
|
+
try {
|
|
192
|
+
const command =
|
|
193
|
+
process.platform === "win32"
|
|
194
|
+
? ["cmd", "/c", "start", "", url]
|
|
195
|
+
: process.platform === "darwin"
|
|
196
|
+
? ["open", url]
|
|
197
|
+
: ["xdg-open", url];
|
|
198
|
+
Bun.spawn(command, { stdout: "ignore", stderr: "ignore" });
|
|
199
|
+
} catch {
|
|
200
|
+
// best-effort — se não abrir, o usuário copia a URL.
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Subcomando `server` — sobe a UI local de triagem. */
|
|
205
|
+
function runServer(config: HoundsmanConfig, args: string[]): void {
|
|
206
|
+
const port = Number(readFlag(args, "--port")) || 7331;
|
|
207
|
+
const host = readFlag(args, "--host") ?? "127.0.0.1";
|
|
208
|
+
const { url } = startServer({ config, port, host });
|
|
209
|
+
console.log(`[houndsman] servidor em ${url}`);
|
|
210
|
+
console.log("[houndsman] Ctrl+C para encerrar.");
|
|
211
|
+
if (args.includes("--open")) openBrowser(url);
|
|
212
|
+
}
|
|
213
|
+
|
|
140
214
|
/** Passo 1/3 — preparar ou finalizar. */
|
|
141
215
|
async function runReview(config: HoundsmanConfig, args: string[]): Promise<void> {
|
|
142
216
|
const opts = parseReviewArgs(args, resolveArtifactDir(config));
|
|
@@ -187,11 +261,17 @@ export async function main(): Promise<void> {
|
|
|
187
261
|
return;
|
|
188
262
|
case "doctor":
|
|
189
263
|
case "check":
|
|
190
|
-
runDoctor(config);
|
|
264
|
+
await runDoctor(config);
|
|
191
265
|
return;
|
|
192
266
|
case "watchdog":
|
|
193
267
|
runWatchdog(config, rest);
|
|
194
268
|
return;
|
|
269
|
+
case "findings":
|
|
270
|
+
runFindings(config, rest);
|
|
271
|
+
return;
|
|
272
|
+
case "server":
|
|
273
|
+
runServer(config, rest);
|
|
274
|
+
return;
|
|
195
275
|
case undefined:
|
|
196
276
|
await runReview(config, rest);
|
|
197
277
|
return;
|
package/src/core/assets.ts
CHANGED
|
@@ -11,6 +11,9 @@ import { join } from "node:path";
|
|
|
11
11
|
/** Diretório de assets markdown embarcados no pacote. */
|
|
12
12
|
export const SKILL_DIR = join(import.meta.dir, "..", "skill");
|
|
13
13
|
|
|
14
|
+
/** Diretório de assets de mídia do pacote (root `assets/` — logo etc.). */
|
|
15
|
+
export const MEDIA_DIR = join(import.meta.dir, "..", "..", "assets");
|
|
16
|
+
|
|
14
17
|
/** Nome do arquivo de schema de output dos watchdogs. */
|
|
15
18
|
export const OUTPUT_FORMAT_FILE = "OUTPUT-FORMAT.md";
|
|
16
19
|
|
|
@@ -18,3 +21,8 @@ export const OUTPUT_FORMAT_FILE = "OUTPUT-FORMAT.md";
|
|
|
18
21
|
export function assetPath(fileName: string): string {
|
|
19
22
|
return join(SKILL_DIR, fileName);
|
|
20
23
|
}
|
|
24
|
+
|
|
25
|
+
/** Caminho absoluto de um asset de mídia em `assets/` (ex.: a logo). */
|
|
26
|
+
export function mediaPath(fileName: string): string {
|
|
27
|
+
return join(MEDIA_DIR, fileName);
|
|
28
|
+
}
|
package/src/core/brief.ts
CHANGED
|
@@ -78,14 +78,35 @@ function optionalList(title: string, items: readonly string[] | undefined): stri
|
|
|
78
78
|
return [`## ${title}`, "", ...items.map((item) => `- ${item}`), ""];
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
/** Lista de arquivos do domínio com status. */
|
|
81
|
+
/** Lista de arquivos do domínio com status (e churn, quando disponível). */
|
|
82
82
|
function fileItems(args: WatchdogRenderArgs): string[] {
|
|
83
83
|
return args.files.map((file) => {
|
|
84
84
|
const status = args.statuses[file]?.status ?? "modified";
|
|
85
|
-
|
|
85
|
+
const churn = args.churn?.[file];
|
|
86
|
+
const delta = churn ? `, +${churn.additions}/−${churn.deletions}` : "";
|
|
87
|
+
return `- \`${file}\` (${status}${delta})`;
|
|
86
88
|
});
|
|
87
89
|
}
|
|
88
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Arquivos do domínio fora do orçamento (triage de PRs grandes): o watchdog NÃO
|
|
93
|
+
* deve lê-los, mas precisa registrá-los em `skipped` — cobertura honesta.
|
|
94
|
+
*/
|
|
95
|
+
function overflowSection(args: WatchdogRenderArgs): string[] {
|
|
96
|
+
const overflow = args.overflow ?? [];
|
|
97
|
+
if (overflow.length === 0) return [];
|
|
98
|
+
return [
|
|
99
|
+
"## Fora do orçamento (NÃO revisar)",
|
|
100
|
+
"",
|
|
101
|
+
`> ${overflow.length} arquivo(s) do seu domínio ficaram fora do orçamento`,
|
|
102
|
+
"> (menor churn). Não os leia: registre-os em `skipped` com o motivo",
|
|
103
|
+
'> "budget" para que a cobertura do relatório fique honesta.',
|
|
104
|
+
"",
|
|
105
|
+
...overflow.map(codeItem),
|
|
106
|
+
"",
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
|
|
89
110
|
/** Seção de deletados (breaking change) — só p/ watchdogs com `breakingChange`. */
|
|
90
111
|
function deletedSection(args: WatchdogRenderArgs, def: WatchdogDefinition): string[] {
|
|
91
112
|
if (!def.breakingChange || args.deleted.length === 0) return [];
|
|
@@ -141,6 +162,8 @@ export function defaultRenderBrief(
|
|
|
141
162
|
"",
|
|
142
163
|
);
|
|
143
164
|
|
|
165
|
+
lines.push(...overflowSection(args));
|
|
166
|
+
|
|
144
167
|
if (args.candidates && args.candidates.length > 0) {
|
|
145
168
|
lines.push(...renderBriefCandidates(args.candidates));
|
|
146
169
|
}
|