@payconductor/houndsman 0.1.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/package.json +1 -1
  2. package/src/cli/arg-parser.ts +8 -0
  3. package/src/cli/commands/command.ts +23 -0
  4. package/src/cli/commands/context-command.ts +38 -0
  5. package/src/cli/commands/doctor-command.ts +55 -0
  6. package/src/cli/commands/findings-command.ts +28 -0
  7. package/src/cli/commands/help-command.ts +13 -0
  8. package/src/cli/commands/registry.ts +34 -0
  9. package/src/cli/commands/review-command.ts +22 -0
  10. package/src/cli/commands/server-command.ts +37 -0
  11. package/src/cli/commands/setup-command.ts +34 -0
  12. package/src/cli/commands/watchdog-command.ts +34 -0
  13. package/src/cli/help.ts +43 -0
  14. package/src/cli/index.ts +62 -260
  15. package/src/core/arg-parser.ts +48 -0
  16. package/src/core/commands/findings.ts +163 -147
  17. package/src/core/commands/review.ts +18 -35
  18. package/src/core/commands/scaffold.ts +174 -64
  19. package/src/core/commands/setup.ts +16 -11
  20. package/src/core/commands/update.ts +7 -7
  21. package/src/core/commands/watchdog.ts +8 -80
  22. package/src/core/config.ts +9 -19
  23. package/src/core/defaults.ts +20 -0
  24. package/src/core/diff-source.ts +1 -13
  25. package/src/core/doc-discoverer.ts +25 -15
  26. package/src/core/domain/budget.ts +42 -0
  27. package/src/core/domain/classification.ts +94 -0
  28. package/src/core/domain/diff.ts +53 -0
  29. package/src/core/domain/watchdog.ts +96 -0
  30. package/src/core/engine/carryover.ts +67 -0
  31. package/src/core/engine/houndsman-engine.ts +51 -0
  32. package/src/core/engine/review-scope.ts +95 -0
  33. package/src/core/engine/review-session.ts +51 -0
  34. package/src/core/file-classifier.ts +11 -67
  35. package/src/core/findings-state.ts +189 -38
  36. package/src/core/git-revision.ts +14 -40
  37. package/src/core/git-runner.ts +46 -0
  38. package/src/core/github-review.ts +423 -0
  39. package/src/core/orchestrator.ts +116 -337
  40. package/src/core/paths.ts +9 -0
  41. package/src/core/pr-context.ts +28 -54
  42. package/src/core/project-config.ts +57 -0
  43. package/src/core/renderers/batch-presenter.ts +40 -0
  44. package/src/core/renderers/brief-renderer.ts +23 -0
  45. package/src/core/renderers/findings-presenter.ts +74 -0
  46. package/src/core/renderers/manifest-writer.ts +112 -0
  47. package/src/core/renderers/report-renderer.ts +66 -0
  48. package/src/core/renderers/verify-presenter.ts +50 -0
  49. package/src/core/renderers/watchdog-presenter.ts +100 -0
  50. package/src/core/report-builder.ts +12 -7
  51. package/src/core/run-layout.ts +108 -0
  52. package/src/core/run-status.ts +6 -11
  53. package/src/core/services/clock.ts +12 -0
  54. package/src/core/services/file-classifier.ts +34 -0
  55. package/src/core/services/fix-batch-builder.ts +13 -0
  56. package/src/core/services/gh-client.ts +54 -0
  57. package/src/core/services/git-repository.ts +123 -0
  58. package/src/core/services/project-files.ts +79 -0
  59. package/src/core/services/verifier.ts +58 -0
  60. package/src/core/verify.ts +2 -1
  61. package/src/core/watchdog-registry.ts +58 -16
  62. package/src/index.ts +31 -1
  63. package/src/server/client/App.tsx +174 -49
  64. package/src/server/client/ArtifactsPanel.tsx +2 -2
  65. package/src/server/client/AutoRefresh.tsx +38 -0
  66. package/src/server/client/Filters.tsx +72 -53
  67. package/src/server/client/FindingCard.tsx +212 -71
  68. package/src/server/client/FindingsList.tsx +8 -6
  69. package/src/server/client/RunList.tsx +30 -7
  70. package/src/server/client/SubmitModal.tsx +418 -0
  71. package/src/server/client/SummaryBar.tsx +65 -12
  72. package/src/server/client/constants.ts +9 -12
  73. package/src/server/client/format.ts +40 -0
  74. package/src/server/client/icons.tsx +143 -0
  75. package/src/server/client/types.ts +69 -0
  76. package/src/server/index.ts +316 -222
  77. package/src/server/run-repository.ts +291 -0
  78. package/src/tests/__snapshots__/baseline.test.ts.snap +814 -0
  79. package/src/tests/baseline.test.ts +513 -0
  80. package/src/tests/cli.test.ts +167 -0
  81. package/src/tests/domain.test.ts +328 -0
  82. package/src/tests/github-review.test.ts +320 -0
  83. package/src/tests/infrastructure.test.ts +210 -0
  84. package/src/tests/server.test.ts +117 -0
@@ -0,0 +1,814 @@
1
+ // Bun Snapshot v1, https://bun.sh/docs/test/snapshots
2
+
3
+ exports[`baseline — brief defaultRenderBrief (contexto, churn, overflow, candidatos e deletados) 1`] = `
4
+ "# Brief — Alpha (\`alpha\`)
5
+
6
+ **Branch:** feature/x
7
+ **Output obrigatório:** \`.houndsman/.runs/feature-x/findings/alpha.json\`
8
+ **Schema do output:** \`.houndsman/core/skill/OUTPUT-FORMAT.md\`
9
+
10
+ ## Objetivo
11
+
12
+ Watchdog baseline.
13
+
14
+ ## Escopo
15
+
16
+ src/alpha/**
17
+
18
+ ## Contexto da PR
19
+
20
+ **Objetivo:** Entregar X
21
+ **Motivação:** Reduzir Y
22
+
23
+ **Resumo das alterações:**
24
+
25
+ - Faz A
26
+ - Remove B
27
+
28
+ ## Regras (por severidade)
29
+
30
+ - ❌ **blocking** — Nunca usar \`any\`.
31
+ - ⚠️ **attention** — Promover: validar a entrada.
32
+
33
+ ## Docs de contexto (carregar sob demanda)
34
+
35
+ - \`AGENTS.md\`
36
+ - \`README.md\`
37
+
38
+ ## Arquivos do seu domínio (2)
39
+
40
+ - \`src/alpha/a.ts\` (modified, +3/−1)
41
+ - \`src/alpha/b.ts\` (added, +2/−0)
42
+
43
+ ## Fora do orçamento (NÃO revisar)
44
+
45
+ > 1 arquivo(s) do seu domínio ficaram fora do orçamento
46
+ > (menor churn). Não os leia: registre-os em \`skipped\` com o motivo
47
+ > "budget" para que a cobertura do relatório fique honesta.
48
+
49
+ - \`src/alpha/c.ts\`
50
+
51
+ ## Candidatos pré-analisados (Jev) — confirme ou refute
52
+
53
+ > Indícios automáticos com confiança calibrada. **NÃO** são achados:
54
+ > confirme (virando finding, com a \`rule\` abaixo) ou ignore se for falso positivo.
55
+
56
+ - [ ] \`src/alpha/a.ts\` · **blocking** · confiança 0.82
57
+ Regra: Nunca usar \`any\`.
58
+
59
+ ## Deletados — checar breaking change
60
+
61
+ - \`src/alpha/old.ts\`
62
+
63
+ ## Procedimento
64
+
65
+ 1. **FILTER** — descarte o que não for do seu domínio (ver *Prioridade de leitura* e *Não carregar*).
66
+ 2. **READ HEAD** — leia os arquivos seletivamente (primeiras ~30 linhas). NUNCA o diff completo.
67
+ 3. **GREP** — use as regras críticas/anti-padrões como heurística para localizar violações.
68
+ 4. **DEEP-READ** — aprofunde apenas os arquivos com suspeita de violação.
69
+ 5. **CONCLUDE** — grave o JSON no caminho de output, com \`reviewedFiles\` preenchido. Sem achados → \`"findings": []\` (arquivo obrigatório). Não escreva markdown livre."
70
+ `;
71
+
72
+ exports[`baseline — relatório renderReport consolidado 1`] = `
73
+ "# PR Review — feature/x
74
+
75
+ **Data:** <date>
76
+ **Watchdogs ativos:** alpha, beta
77
+ **Achados:** 1 bloqueantes · 1 atenção · 0 sugestões · 0 nits
78
+
79
+ ## Contexto da PR
80
+
81
+ **PR:** #42 Entrega X — https://example.test/pull/42
82
+ **Branch:** \`feature/x\` → \`main\`
83
+ **Objetivo:** Entregar X
84
+ **Motivação:** Reduzir Y
85
+
86
+ **Resumo das alterações:**
87
+
88
+ - Faz A
89
+ - Remove B
90
+
91
+ ## ❌ blocking
92
+
93
+ ### \`src/alpha/a.ts\`
94
+
95
+ - **Nunca usar \`any\`.** — \`src/alpha/a.ts:1\` · _Alpha_ · \`id-alpha\`
96
+ any detectado
97
+ **Ação:** tipar
98
+ **Evidência:** \`export const a: any = 1;\`
99
+
100
+ ## ⚠️ attention
101
+
102
+ ### \`src/alpha/b.ts\`
103
+
104
+ - **Promover: validar a entrada.** — \`src/alpha/b.ts:2\` · _Alpha, Beta_ · \`id-beta\`
105
+ sem validação
106
+ **Ação:** adicionar schema
107
+
108
+ ## Relatórios por domínio
109
+
110
+ | Watchdog | Achados | Revisados | Relatório |
111
+ |---|---|---|---|
112
+ | Alpha | 2 | 2/2 | [\`review.alpha.md\`](review.alpha.md) |
113
+
114
+ ## Cobertura
115
+
116
+ | Watchdog | Arquivos revisados | Findings |
117
+ |---|---|---|
118
+ | Alpha | 2 | 2 |
119
+ | Beta | 1 | 0 |
120
+
121
+ ## Conclusão
122
+
123
+ **Status:** ❌ Mudanças Necessárias
124
+ **Resumo:** 1 violações bloqueantes, 1 pontos de atenção, 0 sugestões e 0 nits."
125
+ `;
126
+
127
+ exports[`baseline — relatório renderDomainReport isolado 1`] = `
128
+ "# Review — Alpha (\`alpha\`) — feature/x
129
+
130
+ **Data:** <date>
131
+ **Arquivos revisados:** 2/2
132
+ **Achados:** 2
133
+
134
+ ## Contexto da PR
135
+
136
+ **PR:** #42 Entrega X — https://example.test/pull/42
137
+ **Branch:** \`feature/x\` → \`main\`
138
+ **Objetivo:** Entregar X
139
+ **Motivação:** Reduzir Y
140
+
141
+ **Resumo das alterações:**
142
+
143
+ - Faz A
144
+ - Remove B
145
+
146
+ ## ❌ blocking
147
+
148
+ ### \`src/alpha/a.ts\`
149
+
150
+ - **Nunca usar \`any\`.** — \`src/alpha/a.ts:1\` · _Alpha_ · \`id-alpha\`
151
+ any detectado
152
+ **Ação:** tipar
153
+ **Evidência:** \`export const a: any = 1;\`
154
+
155
+ ## ⚠️ attention
156
+
157
+ ### \`src/alpha/b.ts\`
158
+
159
+ - **Promover: validar a entrada.** — \`src/alpha/b.ts:2\` · _Alpha, Beta_ · \`id-beta\`
160
+ sem validação
161
+ **Ação:** adicionar schema
162
+
163
+ ## Não revisados
164
+
165
+ - \`src/alpha/c.ts\`
166
+ "
167
+ `;
168
+
169
+ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 1`] = `
170
+ [
171
+ ".agents/skills/houndsman/SKILL.md",
172
+ ".claude/skills/houndsman/SKILL.md",
173
+ ".houndsman/.gitignore",
174
+ ".houndsman/core/skill/AUDIT-PROTOCOL.md",
175
+ ".houndsman/core/skill/OUTPUT-FORMAT.md",
176
+ ".houndsman/core/skill/README.md",
177
+ ".houndsman/core/skill/SETUP.md",
178
+ ".houndsman/core/skill/example-review.md",
179
+ ".houndsman/core/skill/fix.md",
180
+ ".houndsman/core/skill/hunt.md",
181
+ ".houndsman/core/skill/train.md",
182
+ ".houndsman/core/skill/verify.md",
183
+ ".houndsman/core/types.ts",
184
+ ".houndsman/doc-mappings.ts",
185
+ ".houndsman/exclusions.ts",
186
+ ".houndsman/watchdogs/example.ts",
187
+ ".houndsman/watchdogs/index.ts",
188
+ "houndsman.config.ts",
189
+ ]
190
+ `;
191
+
192
+ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 2`] = `
193
+ {
194
+ ".agents/skills/houndsman/SKILL.md":
195
+ "---
196
+ name: houndsman
197
+ description: 'Revisa Pull Requests com watchdogs especializados por domínio de negócio e mantém essas regras alinhadas ao projeto. Use para revisar/code review de PR, atualizar as regras de revisão dos watchdogs e corrigir/verificar os findings da revisão. Capabilities: \`hunt\` (revisar a PR), \`train\` (atualizar regras), \`fix\` (corrigir achados), \`verify\` (violações resolvidas?).'
198
+ argument-hint: 'Capability: hunt | train | fix | verify (default: hunt)'
199
+ ---
200
+
201
+ # houndsman — acme
202
+
203
+ O **houndsman** revisa Pull Requests com **watchdogs** — agentes especialistas por domínio de
204
+ negócio. Cada watchdog audita a parte do diff que é sua e grava **findings** (achados); o motor
205
+ consolida tudo num relatório. O motor é o CLI **\`houndsman\`**; as regras do projeto vivem em
206
+ \`houndsman.config.ts\` + \`.houndsman/\`.
207
+
208
+ **Terminologia:** **houndsman** = orquestrador/treinador (CLI + motor) · **watchdog** = agente
209
+ especialista por domínio · **finding** = um achado da revisão · **Jev** = pré-análise opcional.
210
+
211
+ ## Capabilities
212
+
213
+ | Capability | Objetivo | Documento |
214
+ |---|---|---|
215
+ | **\`hunt\`** | Revisar uma Pull Request e produzir o relatório de achados. | \`.houndsman/core/skill/hunt.md\` |
216
+ | **\`train\`** | Manter as regras dos watchdogs alinhadas ao que o projeto aplica. | \`.houndsman/core/skill/train.md\` |
217
+ | **\`fix\`** | Corrigir os achados de uma revisão já finalizada. | \`.houndsman/core/skill/fix.md\` |
218
+ | **\`verify\`** | Conferir se as violações foram resolvidas, sem re-revisar a PR. | \`.houndsman/core/skill/verify.md\` |
219
+
220
+ ## Invocação
221
+
222
+ \`\`\`
223
+ /houndsman → hunt (default)
224
+ /houndsman hunt → revisar a Pull Request
225
+ /houndsman train → atualizar as regras dos watchdogs
226
+ /houndsman fix → corrigir os findings
227
+ /houndsman verify → conferir se as violações foram resolvidas
228
+ \`\`\`
229
+
230
+ Um argumento extra é o alvo da capability (ex.: \`/houndsman hunt feature/minha-branch\`).
231
+ Escolha a capability pelo que o usuário quer, leia o documento correspondente em
232
+ \`.houndsman/core/skill/<capability>.md\` e siga-o.
233
+
234
+ > **Depois de revisar (\`hunt\`), valide na UI:** \`bun run houndsman server --open\` — revise os
235
+ > achados e marque os que devem ser executados (\`execute\`) antes de rodar \`fix\`.
236
+
237
+ ## Referências
238
+
239
+ - \`.houndsman/core/skill/OUTPUT-FORMAT.md\` — schema do JSON de saída dos watchdogs.
240
+ - \`.houndsman/core/skill/AUDIT-PROTOCOL.md\` — taxonomia da auditoria de regras (Modo B do \`train\`).
241
+ - \`.houndsman/core/skill/SETUP.md\` · \`.houndsman/core/skill/README.md\` — configuração e visão geral.
242
+ - \`.houndsman/core/skill/example-review.md\` — exemplo de relatório.
243
+ "
244
+ ,
245
+ ".claude/skills/houndsman/SKILL.md":
246
+ "---
247
+ name: houndsman
248
+ description: 'Revisa Pull Requests com watchdogs especializados por domínio de negócio e mantém essas regras alinhadas ao projeto. Use para revisar/code review de PR, atualizar as regras de revisão dos watchdogs e corrigir/verificar os findings da revisão. Capabilities: \`hunt\` (revisar a PR), \`train\` (atualizar regras), \`fix\` (corrigir achados), \`verify\` (violações resolvidas?).'
249
+ argument-hint: 'Capability: hunt | train | fix | verify (default: hunt)'
250
+ ---
251
+
252
+ # houndsman — acme
253
+
254
+ O **houndsman** revisa Pull Requests com **watchdogs** — agentes especialistas por domínio de
255
+ negócio. Cada watchdog audita a parte do diff que é sua e grava **findings** (achados); o motor
256
+ consolida tudo num relatório. O motor é o CLI **\`houndsman\`**; as regras do projeto vivem em
257
+ \`houndsman.config.ts\` + \`.houndsman/\`.
258
+
259
+ **Terminologia:** **houndsman** = orquestrador/treinador (CLI + motor) · **watchdog** = agente
260
+ especialista por domínio · **finding** = um achado da revisão · **Jev** = pré-análise opcional.
261
+
262
+ ## Capabilities
263
+
264
+ | Capability | Objetivo | Documento |
265
+ |---|---|---|
266
+ | **\`hunt\`** | Revisar uma Pull Request e produzir o relatório de achados. | \`.houndsman/core/skill/hunt.md\` |
267
+ | **\`train\`** | Manter as regras dos watchdogs alinhadas ao que o projeto aplica. | \`.houndsman/core/skill/train.md\` |
268
+ | **\`fix\`** | Corrigir os achados de uma revisão já finalizada. | \`.houndsman/core/skill/fix.md\` |
269
+ | **\`verify\`** | Conferir se as violações foram resolvidas, sem re-revisar a PR. | \`.houndsman/core/skill/verify.md\` |
270
+
271
+ ## Invocação
272
+
273
+ \`\`\`
274
+ /houndsman → hunt (default)
275
+ /houndsman hunt → revisar a Pull Request
276
+ /houndsman train → atualizar as regras dos watchdogs
277
+ /houndsman fix → corrigir os findings
278
+ /houndsman verify → conferir se as violações foram resolvidas
279
+ \`\`\`
280
+
281
+ Um argumento extra é o alvo da capability (ex.: \`/houndsman hunt feature/minha-branch\`).
282
+ Escolha a capability pelo que o usuário quer, leia o documento correspondente em
283
+ \`.houndsman/core/skill/<capability>.md\` e siga-o.
284
+
285
+ > **Depois de revisar (\`hunt\`), valide na UI:** \`bun run houndsman server --open\` — revise os
286
+ > achados e marque os que devem ser executados (\`execute\`) antes de rodar \`fix\`.
287
+
288
+ ## Referências
289
+
290
+ - \`.houndsman/core/skill/OUTPUT-FORMAT.md\` — schema do JSON de saída dos watchdogs.
291
+ - \`.houndsman/core/skill/AUDIT-PROTOCOL.md\` — taxonomia da auditoria de regras (Modo B do \`train\`).
292
+ - \`.houndsman/core/skill/SETUP.md\` · \`.houndsman/core/skill/README.md\` — configuração e visão geral.
293
+ - \`.houndsman/core/skill/example-review.md\` — exemplo de relatório.
294
+ "
295
+ ,
296
+ ".houndsman/.gitignore":
297
+ "# Diretórios gerados pelo houndsman — \`core/\` é regenerado por \`houndsman update\`
298
+ # e \`.runs/\` guarda os artefatos de revisão.
299
+ core/
300
+ .runs/
301
+ "
302
+ ,
303
+ ".houndsman/core/types.ts":
304
+ "/**
305
+ * Tipos e helpers locais do houndsman (GERADO — não edite).
306
+ *
307
+ * Snapshot do contrato público, para tipar a camada de projeto sem depender de um
308
+ * install local do pacote. Sincronize com \`houndsman update\`.
309
+ */
310
+
311
+ export type Severity = "blocking" | "attention" | "suggestion" | "nit";
312
+
313
+ /** Tipo de pergunta aceito pela API Jev. */
314
+ export type JevQuestionType = "noul" | "choice" | "score";
315
+
316
+ /**
317
+ * Spec de pré-análise Jev (opcional) — sempre um objeto; \`kind\` é obrigatório.
318
+ * \`criteria\`: objeto para \`choice\`, lista para \`score\`.
319
+ */
320
+ export type JevRuleSpec = {
321
+ kind: JevQuestionType;
322
+ instructions?: string;
323
+ criteria?: string[] | Record<string, string>;
324
+ };
325
+
326
+ /** Regra do watchdog: severidade + texto — o texto declara a polaridade
327
+ * (\`Promover:\` = deve acontecer; \`Evitar:\`/\`Não\`/\`Nunca\` = não deve acontecer). */
328
+ export type Rule = {
329
+ severity: Severity;
330
+ text: string;
331
+ jev?: JevRuleSpec;
332
+ };
333
+
334
+ /** Como o watchdog casa um arquivo alterado. \`value\` é sempre regex. */
335
+ export type ClassifyRule = {
336
+ type?: "filename" | "content";
337
+ value: string;
338
+ };
339
+
340
+ export type WatchdogMeta = {
341
+ name: string;
342
+ scope: string;
343
+ classify?: readonly ClassifyRule[];
344
+ rules: readonly Rule[];
345
+ contextFiles: string[];
346
+ };
347
+
348
+ /** Definição completa de um watchdog — 1 por arquivo em \`.houndsman/watchdogs/\`. */
349
+ export type WatchdogDefinition = WatchdogMeta & {
350
+ id: string;
351
+ description: string;
352
+ breakingChange?: boolean;
353
+ reviewFocus?: readonly string[];
354
+ exclude?: readonly string[];
355
+ };
356
+
357
+ export type FileStatus =
358
+ | "added"
359
+ | "modified"
360
+ | "deleted"
361
+ | "renamed"
362
+ | "copied"
363
+ | "unknown";
364
+
365
+ export type FileStatusMap = Record<string, { status: FileStatus; oldPath?: string }>;
366
+
367
+ /** Linhas adicionadas/removidas de um arquivo no diff (churn). */
368
+ export type FileChurn = { additions: number; deletions: number };
369
+
370
+ /** Churn por caminho de arquivo. */
371
+ export type ChurnMap = Record<string, FileChurn>;
372
+
373
+ /** Limites de triage para PRs grandes. */
374
+ export type HoundsmanBudgets = {
375
+ /** Máx. de arquivos por brief (default: 40). Excedente vai para "fora do orçamento". */
376
+ maxFilesPerBrief?: number;
377
+ };
378
+
379
+ /** Concorrência das fases paralelas internas. */
380
+ export type HoundsmanConcurrency = {
381
+ /** Chamadas Jev simultâneas (default: 5). */
382
+ jev?: number;
383
+ };
384
+
385
+ /** Contrato de configuração do motor. */
386
+ export type HoundsmanConfig<TId extends string = string> = {
387
+ projectName: string;
388
+ artifactDir?: string;
389
+ watchdogIds?: readonly TId[];
390
+ watchdogs: Record<TId, WatchdogDefinition>;
391
+ exclusions: readonly RegExp[];
392
+ docMappings: readonly (readonly [RegExp, readonly string[]])[];
393
+ alwaysIncludeDocs?: readonly string[];
394
+ budgets?: HoundsmanBudgets;
395
+ concurrency?: HoundsmanConcurrency;
396
+ };
397
+
398
+ /** Helper de autoria (identidade) — apenas tipagem. */
399
+ export function defineWatchdog(definition: WatchdogDefinition): WatchdogDefinition {
400
+ return definition;
401
+ }
402
+
403
+ /** Helper de autoria — deriva \`watchdogIds\` das chaves de \`watchdogs\`. */
404
+ export function defineHoundsmanConfig<TId extends string>(
405
+ input: Omit<HoundsmanConfig<TId>, "watchdogIds">,
406
+ ): HoundsmanConfig<TId> {
407
+ return { ...input, watchdogIds: Object.keys(input.watchdogs) as TId[] };
408
+ }
409
+ "
410
+ ,
411
+ ".houndsman/doc-mappings.ts":
412
+ "/**
413
+ * Mapeamento de padrões nos paths → documentação relevante.
414
+ * Consumido pelo motor via \`HoundsmanConfig.docMappings\`.
415
+ */
416
+ export const DOC_MAPPINGS: readonly (readonly [RegExp, readonly string[]])[] = [
417
+ [/^src\\//, ["AGENTS.md"]],
418
+ ];
419
+ "
420
+ ,
421
+ ".houndsman/exclusions.ts":
422
+ "/** Arquivos que nunca entram na revisão — gerados, locks, builds. */
423
+ export const EXCLUSION_PATTERNS: readonly RegExp[] = [
424
+ /bun\\.lockb?$/,
425
+ /^package-lock\\.json$/,
426
+ /^dist\\//,
427
+ /^build\\//,
428
+ ];
429
+
430
+ /** \`true\` se o caminho é excluído da revisão. */
431
+ export function isExcluded(filePath: string): boolean {
432
+ return EXCLUSION_PATTERNS.some((pattern) => pattern.test(filePath));
433
+ }
434
+ "
435
+ ,
436
+ ".houndsman/watchdogs/example.ts":
437
+ "import { defineWatchdog } from "../core/types";
438
+
439
+ /**
440
+ * Watchdog de exemplo — substitua pelas regras reais do projeto.
441
+ * Um watchdog declara seus arquivos via \`classify\` (regex de path ou conteúdo).
442
+ * O texto de cada regra começa com a polaridade: \`Promover:\` (DEVE acontecer)
443
+ * ou \`Evitar:\`/\`Não\`/\`Nunca\` (NÃO DEVE acontecer).
444
+ */
445
+ export const exampleWatchdog = defineWatchdog({
446
+ id: "example",
447
+ name: "Exemplo",
448
+ description: "Watchdog de exemplo — descreva o propósito em uma frase.",
449
+ scope: "Todo o repositório (ajuste o escopo)",
450
+ classify: [{ value: "^src/" }],
451
+ rules: [
452
+ {
453
+ severity: "attention",
454
+ text: "Promover: descreva aqui um padrão do projeto (algo que DEVE acontecer).",
455
+ jev: { kind: "noul" },
456
+ },
457
+ {
458
+ severity: "nit",
459
+ text: "Evitar: descreva aqui um anti-padrão (algo que NÃO DEVE acontecer).",
460
+ },
461
+ ],
462
+ contextFiles: ["AGENTS.md"],
463
+ });
464
+ "
465
+ ,
466
+ ".houndsman/watchdogs/index.ts":
467
+ "import { exampleWatchdog } from "./example";
468
+
469
+ /**
470
+ * Definições dos watchdogs — as chaves definem o union \`WatchdogId\`.
471
+ * Adicionar um watchdog = criar \`<id>.ts\` e registrá-lo aqui.
472
+ */
473
+ export const WATCHDOG_DEFINITIONS = {
474
+ example: exampleWatchdog,
475
+ };
476
+
477
+ export type WatchdogId = keyof typeof WATCHDOG_DEFINITIONS;
478
+ "
479
+ ,
480
+ "houndsman.config.ts":
481
+ "import { DOC_MAPPINGS } from "./.houndsman/doc-mappings";
482
+ import { EXCLUSION_PATTERNS } from "./.houndsman/exclusions";
483
+ import { WATCHDOG_DEFINITIONS } from "./.houndsman/watchdogs";
484
+ import type { HoundsmanConfig } from "./.houndsman/core/types";
485
+
486
+ /**
487
+ * Configuração do houndsman para acme.
488
+ *
489
+ * Caminhos são resolvidos pela camada: artefatos em .houndsman/.runs e schema de
490
+ * output em .houndsman/core/skill/OUTPUT-FORMAT.md. Ajuste watchdogs, exclusões e mapeamentos de
491
+ * docs conforme o projeto.
492
+ */
493
+ export const houndsmanConfig = {
494
+ projectName: "acme",
495
+ watchdogs: WATCHDOG_DEFINITIONS,
496
+ exclusions: EXCLUSION_PATTERNS,
497
+ docMappings: DOC_MAPPINGS,
498
+ } satisfies HoundsmanConfig;
499
+
500
+ export default houndsmanConfig;
501
+ "
502
+ ,
503
+ }
504
+ `;
505
+
506
+ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 3`] = `
507
+ [
508
+ {
509
+ "file": ".houndsman/core/skill/AUDIT-PROTOCOL.md",
510
+ "sha256": "190bc9f6417f54d0",
511
+ },
512
+ {
513
+ "file": ".houndsman/core/skill/OUTPUT-FORMAT.md",
514
+ "sha256": "3c6f261de0ca6d31",
515
+ },
516
+ {
517
+ "file": ".houndsman/core/skill/README.md",
518
+ "sha256": "7cc26ec5e1917a62",
519
+ },
520
+ {
521
+ "file": ".houndsman/core/skill/SETUP.md",
522
+ "sha256": "5d6a4b56b1033970",
523
+ },
524
+ {
525
+ "file": ".houndsman/core/skill/example-review.md",
526
+ "sha256": "a2627e99ac5caead",
527
+ },
528
+ {
529
+ "file": ".houndsman/core/skill/fix.md",
530
+ "sha256": "f16c0383ad1767fb",
531
+ },
532
+ {
533
+ "file": ".houndsman/core/skill/hunt.md",
534
+ "sha256": "7e7d7e5535381b9b",
535
+ },
536
+ {
537
+ "file": ".houndsman/core/skill/train.md",
538
+ "sha256": "564a1fd38d8e4836",
539
+ },
540
+ {
541
+ "file": ".houndsman/core/skill/verify.md",
542
+ "sha256": "f8fcf8e12b142482",
543
+ },
544
+ ]
545
+ `;
546
+
547
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state 1`] = `
548
+ "Discovery: 1 watchdog(s) ativado(s), 3 arquivo(s), 1 deletado(s).
549
+ Briefs: .houndsman/.runs/main/briefs/
550
+ Deletado (breaking change): src/alpha/old.ts
551
+ Jev: pulado (desativado (--no-jev)).
552
+ Sem contexto da PR (rode \`bun run houndsman context\` antes, se houver PR).
553
+
554
+ Próximo passo: despachar os sub-agentes (um por brief em .houndsman/.runs/main/briefs/).
555
+ Quando os findings estiverem gravados: bun run houndsman --finalize"
556
+ `;
557
+
558
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: classification.json 1`] = `
559
+ "{
560
+ "watchdogs": {
561
+ "alpha": [
562
+ "src/alpha/a.ts",
563
+ "src/alpha/b.ts"
564
+ ]
565
+ },
566
+ "files": {
567
+ "src/alpha/a.ts": {
568
+ "status": "modified"
569
+ },
570
+ "src/alpha/b.ts": {
571
+ "status": "added"
572
+ },
573
+ "src/alpha/old.ts": {
574
+ "status": "deleted"
575
+ }
576
+ },
577
+ "churn": {
578
+ "src/alpha/a.ts": {
579
+ "additions": 2,
580
+ "deletions": 1
581
+ },
582
+ "src/alpha/b.ts": {
583
+ "additions": 1,
584
+ "deletions": 0
585
+ },
586
+ "src/alpha/old.ts": {
587
+ "additions": 0,
588
+ "deletions": 1
589
+ }
590
+ },
591
+ "unclassified": [],
592
+ "excluded": [],
593
+ "deleted": [
594
+ "src/alpha/old.ts"
595
+ ],
596
+ "stats": {
597
+ "alpha": 2
598
+ },
599
+ "excludedCount": 0,
600
+ "base": "<sha>",
601
+ "head": "HEAD",
602
+ "headSha": "<sha>",
603
+ "mode": "full"
604
+ }
605
+ "
606
+ `;
607
+
608
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: manifest.json 1`] = `
609
+ "{
610
+ "branch": "main",
611
+ "slug": "main",
612
+ "base": "<sha>",
613
+ "head": "HEAD",
614
+ "headSha": "<sha>",
615
+ "generatedAt": "<timestamp>",
616
+ "outputFormat": ".houndsman/core/skill/OUTPUT-FORMAT.md",
617
+ "budget": {
618
+ "maxFilesPerBrief": 40,
619
+ "filesOverBudget": 0
620
+ },
621
+ "churn": {
622
+ "additions": 3,
623
+ "deletions": 2
624
+ },
625
+ "watchdogs": [
626
+ {
627
+ "id": "alpha",
628
+ "name": "Alpha",
629
+ "files": [
630
+ "src/alpha/a.ts",
631
+ "src/alpha/b.ts"
632
+ ],
633
+ "overflow": 0,
634
+ "brief": ".houndsman/.runs/main/briefs/alpha.md",
635
+ "findings": ".houndsman/.runs/main/findings/alpha.json",
636
+ "status": "pending"
637
+ }
638
+ ],
639
+ "context": {
640
+ "summarized": false,
641
+ "source": null
642
+ },
643
+ "jev": {
644
+ "available": false,
645
+ "reason": "desativado (--no-jev)"
646
+ },
647
+ "deleted": [
648
+ "src/alpha/old.ts"
649
+ ],
650
+ "unclassified": [],
651
+ "excludedCount": 0
652
+ }
653
+ "
654
+ `;
655
+
656
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: briefs/alpha.md 1`] = `
657
+ "# Brief — Alpha (\`alpha\`)
658
+
659
+ **Branch:** main
660
+ **Output obrigatório:** \`.houndsman/.runs/main/findings/alpha.json\`
661
+ **Schema do output:** \`.houndsman/core/skill/OUTPUT-FORMAT.md\`
662
+
663
+ ## Objetivo
664
+
665
+ Watchdog baseline.
666
+
667
+ ## Escopo
668
+
669
+ src/alpha/**
670
+
671
+ ## Regras (por severidade)
672
+
673
+ - ❌ **blocking** — Nunca usar \`any\`.
674
+ - ⚠️ **attention** — Promover: validar a entrada.
675
+
676
+ ## Docs de contexto (carregar sob demanda)
677
+
678
+ - \`README.md\`
679
+
680
+ ## Arquivos do seu domínio (2)
681
+
682
+ - \`src/alpha/a.ts\` (modified, +2/−1)
683
+ - \`src/alpha/b.ts\` (added, +1/−0)
684
+
685
+ ## Deletados — checar breaking change
686
+
687
+ - \`src/alpha/old.ts\`
688
+
689
+ ## Procedimento
690
+
691
+ 1. **FILTER** — descarte o que não for do seu domínio (ver *Prioridade de leitura* e *Não carregar*).
692
+ 2. **READ HEAD** — leia os arquivos seletivamente (primeiras ~30 linhas). NUNCA o diff completo.
693
+ 3. **GREP** — use as regras críticas/anti-padrões como heurística para localizar violações.
694
+ 4. **DEEP-READ** — aprofunde apenas os arquivos com suspeita de violação.
695
+ 5. **CONCLUDE** — grave o JSON no caminho de output, com \`reviewedFiles\` preenchido. Sem achados → \`"findings": []\` (arquivo obrigatório). Não escreva markdown livre.
696
+ "
697
+ `;
698
+
699
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state 2`] = `
700
+ "Triagem: .houndsman/.runs/main/state.json — 1 finding(s).
701
+ Relatório: .houndsman/.runs/main/review.md — 1 bloqueante(s), 0 atenção."
702
+ `;
703
+
704
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: review.md 1`] = `
705
+ "# PR Review — main
706
+
707
+ **Data:** <date>
708
+ **Watchdogs ativos:** alpha
709
+ **Achados:** 1 bloqueantes · 0 atenção · 0 sugestões · 0 nits
710
+
711
+ ## ❌ blocking
712
+
713
+ ### \`src/alpha/a.ts\`
714
+
715
+ - **Nunca usar \`any\`.** — \`src/alpha/a.ts:1\` · _Alpha_ · \`<id>\`
716
+ any detectado
717
+ **Ação:** tipar
718
+ **Evidência:** \`export const a: any = 1;\`
719
+
720
+ ## Relatórios por domínio
721
+
722
+ | Watchdog | Achados | Revisados | Relatório |
723
+ |---|---|---|---|
724
+ | Alpha | 1 | 2/2 | [\`review.alpha.md\`](review.alpha.md) |
725
+
726
+ ## Cobertura
727
+
728
+ | Watchdog | Arquivos revisados | Findings |
729
+ |---|---|---|
730
+ | Alpha | 2 | 1 |
731
+
732
+ ## Conclusão
733
+
734
+ **Status:** ❌ Mudanças Necessárias
735
+ **Resumo:** 1 violações bloqueantes, 0 pontos de atenção, 0 sugestões e 0 nits.
736
+ "
737
+ `;
738
+
739
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: review.alpha.md 1`] = `
740
+ "# Review — Alpha (\`alpha\`) — main
741
+
742
+ **Data:** <date>
743
+ **Arquivos revisados:** 2/2
744
+ **Achados:** 1
745
+
746
+ ## ❌ blocking
747
+
748
+ ### \`src/alpha/a.ts\`
749
+
750
+ - **Nunca usar \`any\`.** — \`src/alpha/a.ts:1\` · _Alpha_
751
+ any detectado
752
+ **Ação:** tipar
753
+ **Evidência:** \`export const a: any = 1;\`
754
+
755
+ "
756
+ `;
757
+
758
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: state.json 1`] = `
759
+ "{
760
+ "version": 2,
761
+ "branch": "main",
762
+ "slug": "main",
763
+ "updatedAt": "<timestamp>",
764
+ "order": [
765
+ "<id>"
766
+ ],
767
+ "reviewed": {
768
+ "headSha": "<sha>",
769
+ "at": "<timestamp>"
770
+ },
771
+ "findings": {
772
+ "<id>": {
773
+ "id": "<id>",
774
+ "fingerprint": "<fingerprint>",
775
+ "watchdogIds": [
776
+ "alpha"
777
+ ],
778
+ "rule": "Nunca usar \`any\`.",
779
+ "severity": "blocking",
780
+ "file": "src/alpha/a.ts",
781
+ "line": 1,
782
+ "message": "any detectado",
783
+ "action": "tipar",
784
+ "evidence": "export const a: any = 1;",
785
+ "anchor": {
786
+ "snippet": "export const a: any = 1;",
787
+ "line": 1,
788
+ "contextAfter": "export const b = 2;"
789
+ },
790
+ "foundAtSha": "<sha>",
791
+ "count": 1,
792
+ "present": true,
793
+ "decision": "pending",
794
+ "execState": "pending",
795
+ "createdAt": "<timestamp>",
796
+ "updatedAt": "<timestamp>",
797
+ "history": []
798
+ }
799
+ }
800
+ }
801
+ "
802
+ `;
803
+
804
+ exports[`baseline — artefatos de prepare/finalize gera classification, brief, manifest, review e state: run.json 1`] = `
805
+ "{
806
+ "version": 1,
807
+ "slug": "main",
808
+ "branch": "main",
809
+ "status": "review_done",
810
+ "startedAt": "<timestamp>",
811
+ "updatedAt": "<timestamp>"
812
+ }
813
+ "
814
+ `;