@payconductor/houndsman 0.11.0 → 0.13.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.
- package/README.md +14 -13
- package/package.json +1 -1
- package/src/cli/commands/doctor-command.ts +22 -0
- package/src/cli/commands/hunt-command.ts +440 -29
- package/src/cli/commands/review-command.ts +20 -2
- package/src/cli/help.ts +16 -8
- package/src/cli/index.ts +15 -2
- package/src/cli/progress.ts +45 -0
- package/src/core/ai/ai-client.ts +3 -7
- package/src/core/ai/ai-sdk-model-provider.ts +43 -24
- package/src/core/ai/features/brief-enricher.ts +0 -1
- package/src/core/ai/features/classifier.ts +0 -1
- package/src/core/ai/features/context-summarizer.ts +0 -1
- package/src/core/ai/features/pre-analyzer.ts +0 -1
- package/src/core/ai/features/technical-summarizer.ts +0 -1
- package/src/core/ai/features/verifier.ts +0 -1
- package/src/core/ai/index.ts +6 -4
- package/src/core/ai/prompts/pre-analysis.ts +3 -2
- package/src/core/ai/schemas.ts +1 -23
- package/src/core/ai/types.ts +4 -15
- package/src/core/ai/usage-budget.ts +1 -1
- package/src/core/ast/diff.ts +37 -2
- package/src/core/ast/service.ts +1 -1
- package/src/core/brief.ts +54 -5
- package/src/core/changed-scope.ts +207 -0
- package/src/core/commands/scaffold.ts +12 -18
- package/src/core/config.ts +30 -15
- package/src/core/defaults.ts +14 -5
- package/src/core/engine/review-scope.ts +131 -17
- package/src/core/engine/review-session.ts +7 -3
- package/src/core/engine/review-workspace.ts +14 -0
- package/src/core/env.ts +14 -0
- package/src/core/hunt/hunt-runner.ts +328 -0
- package/src/core/hunt/index.ts +59 -0
- package/src/core/hunt/maki-install.ts +331 -0
- package/src/core/hunt/maki-model.ts +101 -0
- package/src/core/hunt/maki-prompt.ts +71 -0
- package/src/core/hunt/maki-release.ts +104 -0
- package/src/core/hunt/maki-runner.ts +276 -0
- package/src/core/hunt/pool.ts +30 -0
- package/src/core/jev/jev-detector.ts +7 -2
- package/src/core/logging/index.ts +3 -1
- package/src/core/logging/logger.ts +22 -3
- package/src/core/logging/progress.ts +282 -0
- package/src/core/orchestrator.ts +173 -59
- package/src/core/project-config.ts +34 -24
- package/src/core/registry-check.ts +2 -12
- package/src/core/rule-text.ts +3 -55
- package/src/core/services/git-repository.ts +8 -0
- package/src/core/storage/types.ts +1 -1
- package/src/core/types.ts +3 -14
- package/src/index.ts +74 -3
- package/src/server/client/utils/constants.ts +3 -6
- package/src/server/client/utils/types.ts +0 -1
- package/src/skill/OUTPUT-FORMAT.md +5 -0
- package/src/skill/README.md +14 -1
- package/src/skill/SETUP.md +22 -2
- package/src/skill/SKILL.md +4 -0
- package/src/skill/fix.md +1 -1
- package/src/skill/hunt.md +38 -6
- package/src/tests/__snapshots__/baseline.test.ts.snap +69 -32
- package/src/tests/ai-core.test.ts +38 -1
- package/src/tests/changed-scope.test.ts +197 -0
- package/src/tests/cli.test.ts +1 -0
- package/src/tests/fallback.test.ts +1 -96
- package/src/tests/fixtures/fake-model-provider.ts +0 -1
- package/src/tests/hunt-cli.test.ts +185 -0
- package/src/tests/hunt-install.test.ts +153 -0
- package/src/tests/hunt-maki.test.ts +467 -0
- package/src/tests/progress.test.ts +117 -0
- package/src/tests/review-scope.test.ts +95 -0
- package/src/tests/worktree.test.ts +1 -3
- package/src/harness/README.md +0 -15
- package/src/harness/agent/agent-context.ts +0 -33
- package/src/harness/agent/agent-errors.ts +0 -30
- package/src/harness/agent/agent-factory.ts +0 -46
- package/src/harness/agent/agent-reporter.ts +0 -34
- package/src/harness/agent/agent-result.ts +0 -16
- package/src/harness/agent/agent-runner.ts +0 -32
- package/src/harness/agent/agent-scheduler.ts +0 -37
- package/src/harness/agent/review-agent.ts +0 -401
- package/src/harness/config/harness-config.ts +0 -89
- package/src/harness/hunt/hunt-harness.ts +0 -83
- package/src/harness/hunt/hunt-options.ts +0 -92
- package/src/harness/hunt/hunt-result.ts +0 -17
- package/src/harness/hunt/hunt-session.ts +0 -359
- package/src/harness/hunt/review-planner.ts +0 -98
- package/src/harness/index.ts +0 -36
- package/src/harness/investigation/agent-state.ts +0 -134
- package/src/harness/investigation/evidence-verifier.ts +0 -129
- package/src/harness/investigation/evidence.ts +0 -110
- package/src/harness/investigation/finding-critic.ts +0 -96
- package/src/harness/investigation/investigation-planner.ts +0 -118
- package/src/harness/investigation/investigation-task.ts +0 -10
- package/src/harness/investigation/review-journal.ts +0 -87
- package/src/harness/investigation/rule-analyzer.ts +0 -178
- package/src/harness/investigation/rule-signals.ts +0 -110
- package/src/harness/prompts/agent-schemas.ts +0 -57
- package/src/harness/prompts/reviewer-prompt-builder.ts +0 -101
- package/src/harness/prompts/states/conclude-prompt.ts +0 -16
- package/src/harness/prompts/states/investigate-prompt.ts +0 -37
- package/src/harness/prompts/states/orient-prompt.ts +0 -15
- package/src/harness/prompts/states/verify-prompt.ts +0 -22
- package/src/harness/tools/agent-tool.ts +0 -102
- package/src/harness/tools/builtin/changed-symbols-tool.ts +0 -48
- package/src/harness/tools/builtin/doc-context-tool.ts +0 -74
- package/src/harness/tools/builtin/file-outline-tool.ts +0 -66
- package/src/harness/tools/builtin/find-references-tool.ts +0 -66
- package/src/harness/tools/builtin/find-symbol-tool.ts +0 -91
- package/src/harness/tools/builtin/helpers.ts +0 -115
- package/src/harness/tools/builtin/impact-tool.ts +0 -48
- package/src/harness/tools/builtin/imports-exports-tool.ts +0 -53
- package/src/harness/tools/builtin/index.ts +0 -59
- package/src/harness/tools/builtin/list-files-tool.ts +0 -85
- package/src/harness/tools/builtin/pr-context-tool.ts +0 -41
- package/src/harness/tools/builtin/read-file-range-tool.ts +0 -73
- package/src/harness/tools/builtin/rule-signals-tool.ts +0 -36
- package/src/harness/tools/builtin/search-code-tool.ts +0 -65
- package/src/harness/tools/builtin/symbol-context-tool.ts +0 -106
- package/src/harness/tools/builtin/tests-for-symbol-tool.ts +0 -61
- package/src/harness/tools/path-guard.ts +0 -90
- package/src/harness/tools/result-limiter.ts +0 -49
- package/src/harness/tools/secret-redactor.ts +0 -54
- package/src/harness/tools/tool-cache.ts +0 -50
- package/src/harness/tools/tool-call-budget.ts +0 -60
- package/src/harness/tools/tool-context.ts +0 -5
- package/src/harness/tools/tool-middleware.ts +0 -105
- package/src/harness/tools/tool-policy.ts +0 -51
- package/src/harness/tools/tool-registry.ts +0 -112
- package/src/harness/tools/tool-result.ts +0 -15
- package/src/harness/tools/toolbox.ts +0 -36
- package/src/harness/validation/finding-validator.ts +0 -119
- package/src/tests/fixtures/fake-agent-tools.ts +0 -69
- package/src/tests/fixtures/fake-investigation.ts +0 -64
- package/src/tests/harness-agent.test.ts +0 -141
- package/src/tests/harness-investigation.test.ts +0 -206
- package/src/tests/harness-tools.test.ts +0 -148
- package/src/tests/hunt-command.test.ts +0 -212
- package/src/tests/rule-analyzer.test.ts +0 -61
- package/src/tests/tool-contracts.test.ts +0 -82
package/src/index.ts
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
export type {
|
|
9
9
|
AiResult,
|
|
10
|
-
AiTool,
|
|
11
10
|
AiUsage,
|
|
12
11
|
ModelProvider,
|
|
13
12
|
ModelRequest,
|
|
@@ -26,7 +25,14 @@ export {
|
|
|
26
25
|
} from "./core/ai";
|
|
27
26
|
export { ArgParser } from "./core/arg-parser";
|
|
28
27
|
export { assetPath, OUTPUT_FORMAT_FILE } from "./core/assets";
|
|
29
|
-
export {
|
|
28
|
+
export {
|
|
29
|
+
changedAnchorLines,
|
|
30
|
+
changedAnchors,
|
|
31
|
+
changedNewLines,
|
|
32
|
+
computeDelta,
|
|
33
|
+
emptyDelta,
|
|
34
|
+
parseHunks,
|
|
35
|
+
} from "./core/ast/diff";
|
|
30
36
|
export { buildImpact, resolveImport } from "./core/ast/impact";
|
|
31
37
|
export { AstParser, languageForPath } from "./core/ast/parser";
|
|
32
38
|
export { AstService } from "./core/ast/service";
|
|
@@ -44,6 +50,23 @@ export type {
|
|
|
44
50
|
AstSymbolKind,
|
|
45
51
|
} from "./core/ast/types";
|
|
46
52
|
export { defaultRenderBrief, PROCEDURE, renderBrief } from "./core/brief";
|
|
53
|
+
export type {
|
|
54
|
+
BuildChangedScopeInput,
|
|
55
|
+
ChangedScope,
|
|
56
|
+
ChangedScopeSource,
|
|
57
|
+
ChangedSymbol,
|
|
58
|
+
FileChangedScope,
|
|
59
|
+
LineRange,
|
|
60
|
+
ScopeEntry,
|
|
61
|
+
} from "./core/changed-scope";
|
|
62
|
+
export {
|
|
63
|
+
buildChangedScope,
|
|
64
|
+
formatRanges,
|
|
65
|
+
formatSymbols,
|
|
66
|
+
isLineInScope,
|
|
67
|
+
mergeRanges,
|
|
68
|
+
summarizeScope,
|
|
69
|
+
} from "./core/changed-scope";
|
|
47
70
|
export type { FindingsCommandResult } from "./core/commands/findings";
|
|
48
71
|
export { runFindingsCommand, runVerifyCommand } from "./core/commands/findings";
|
|
49
72
|
export { ProjectScaffolder } from "./core/commands/scaffold";
|
|
@@ -57,13 +80,18 @@ export type {
|
|
|
57
80
|
HoundsmanConcurrency,
|
|
58
81
|
HoundsmanConfig,
|
|
59
82
|
HoundsmanConfigInput,
|
|
83
|
+
HoundsmanHunt,
|
|
60
84
|
HoundsmanStorage,
|
|
61
85
|
} from "./core/config";
|
|
62
86
|
export {
|
|
63
87
|
DEFAULT_ALWAYS_INCLUDE_DOCS,
|
|
64
88
|
DEFAULT_AST_MAX_FILE_BYTES,
|
|
65
89
|
DEFAULT_AST_MAX_IMPACT_FILES,
|
|
90
|
+
DEFAULT_HUNT_CONCURRENCY,
|
|
91
|
+
DEFAULT_HUNT_RETRIES,
|
|
92
|
+
DEFAULT_HUNT_TIMEOUT_MS,
|
|
66
93
|
DEFAULT_JEV_CONCURRENCY,
|
|
94
|
+
DEFAULT_MAKI_VERSION,
|
|
67
95
|
DEFAULT_MAX_FILES_PER_BRIEF,
|
|
68
96
|
defineHoundsmanConfig,
|
|
69
97
|
resolveJevConcurrency,
|
|
@@ -158,6 +186,50 @@ export {
|
|
|
158
186
|
syncState,
|
|
159
187
|
} from "./core/findings-state";
|
|
160
188
|
export type { GitResult, GitRunner } from "./core/git-runner";
|
|
189
|
+
export type {
|
|
190
|
+
HuntEvent,
|
|
191
|
+
HuntReport,
|
|
192
|
+
HuntRunnerOptions,
|
|
193
|
+
HuntTotals,
|
|
194
|
+
HuntWatchdogResult,
|
|
195
|
+
InstallMakiOptions,
|
|
196
|
+
InstallMakiResult,
|
|
197
|
+
MakiBinary,
|
|
198
|
+
MakiBinarySource,
|
|
199
|
+
MakiInstallManifest,
|
|
200
|
+
MakiModel,
|
|
201
|
+
MakiProcessRunner,
|
|
202
|
+
MakiRunMetrics,
|
|
203
|
+
MakiRunRequest,
|
|
204
|
+
MakiRunResult,
|
|
205
|
+
MakiUsage,
|
|
206
|
+
} from "./core/hunt";
|
|
207
|
+
export {
|
|
208
|
+
extractJsonObject,
|
|
209
|
+
HuntRunner,
|
|
210
|
+
houndsmanKeyEnvFor,
|
|
211
|
+
installMaki,
|
|
212
|
+
MAKI_API_KEY_ENV,
|
|
213
|
+
MAKI_DISALLOWED_TOOLS,
|
|
214
|
+
makiArgs,
|
|
215
|
+
makiCurrentFile,
|
|
216
|
+
makiInstallDir,
|
|
217
|
+
makiSourceLabel,
|
|
218
|
+
makiToolsRoot,
|
|
219
|
+
mapPool,
|
|
220
|
+
metricsFrom,
|
|
221
|
+
parseMakiOutput,
|
|
222
|
+
probeMakiVersion,
|
|
223
|
+
readMakiInstall,
|
|
224
|
+
renderHuntPrompt,
|
|
225
|
+
renderRetrySuffix,
|
|
226
|
+
requireMakiBinary,
|
|
227
|
+
requireMakiModel,
|
|
228
|
+
resolveMakiBinary,
|
|
229
|
+
resolveMakiModel,
|
|
230
|
+
SpawnMakiRunner,
|
|
231
|
+
uninstallMaki,
|
|
232
|
+
} from "./core/hunt";
|
|
161
233
|
export {
|
|
162
234
|
CORE_DIR,
|
|
163
235
|
CORE_SKILL_DIR,
|
|
@@ -231,7 +303,6 @@ export type {
|
|
|
231
303
|
FileStatus,
|
|
232
304
|
FileStatusMap,
|
|
233
305
|
Rule,
|
|
234
|
-
RuleHints,
|
|
235
306
|
Severity,
|
|
236
307
|
WatchdogDefinition,
|
|
237
308
|
WatchdogMeta,
|
|
@@ -97,7 +97,6 @@ const KIND_ORDER: ArtifactKind[] = [
|
|
|
97
97
|
"ai",
|
|
98
98
|
"ai-usage",
|
|
99
99
|
"ai-brief",
|
|
100
|
-
"harness-transcript",
|
|
101
100
|
"context",
|
|
102
101
|
"context-brief",
|
|
103
102
|
"context-summary",
|
|
@@ -119,10 +118,9 @@ const GROUP_BY_KIND: Record<ArtifactKind, { key: string; label: string; order: n
|
|
|
119
118
|
candidates: { key: "core", label: "Núcleo da revisão", order: 3 },
|
|
120
119
|
ast: { key: "core", label: "Núcleo da revisão", order: 3 },
|
|
121
120
|
"ast-impact": { key: "core", label: "Núcleo da revisão", order: 3 },
|
|
122
|
-
ai: { key: "ai", label: "IA
|
|
123
|
-
"ai-usage": { key: "ai", label: "IA
|
|
124
|
-
"ai-brief": { key: "ai", label: "IA
|
|
125
|
-
"harness-transcript": { key: "ai", label: "IA e harness", order: 4 },
|
|
121
|
+
ai: { key: "ai", label: "IA", order: 4 },
|
|
122
|
+
"ai-usage": { key: "ai", label: "IA", order: 4 },
|
|
123
|
+
"ai-brief": { key: "ai", label: "IA", order: 4 },
|
|
126
124
|
context: { key: "context", label: "Contexto da PR", order: 5 },
|
|
127
125
|
"context-brief": { key: "context", label: "Contexto da PR", order: 5 },
|
|
128
126
|
"context-summary": { key: "context", label: "Contexto da PR", order: 5 },
|
|
@@ -146,7 +144,6 @@ export const ARTIFACT_KIND_LABELS: Record<ArtifactKind, string> = {
|
|
|
146
144
|
ai: "ia",
|
|
147
145
|
"ai-usage": "uso ia",
|
|
148
146
|
"ai-brief": "plano ia",
|
|
149
|
-
"harness-transcript": "transcript",
|
|
150
147
|
context: "contexto",
|
|
151
148
|
"context-brief": "brief ctx",
|
|
152
149
|
"context-summary": "resumo ctx",
|
|
@@ -69,6 +69,11 @@ staging global da review:
|
|
|
69
69
|
- Sem achados → `"findings": []` (arquivo **obrigatório**).
|
|
70
70
|
- Um achado por regra violada; não agrupar regras diferentes.
|
|
71
71
|
- `file:line` sempre que possível; `evidence` quando o achado não é óbvio.
|
|
72
|
+
- **Escopo do diff:** a `line` deve cair dentro das faixas listadas em
|
|
73
|
+
*Escopo do diff (símbolos alterados)* no brief. Código fora delas é contexto — não é
|
|
74
|
+
achado desta revisão. Se a alteração quebra código não alterado, ancore o finding na
|
|
75
|
+
linha alterada que causou o problema.
|
|
76
|
+
- Achado **sem linha** só quando for inerente à alteração (vira comentário de arquivo).
|
|
72
77
|
- Não inventar achados — se não houver violação, o array fica vazio.
|
|
73
78
|
|
|
74
79
|
## Findings emergentes (opt-in)
|
package/src/skill/README.md
CHANGED
|
@@ -14,11 +14,22 @@ Um único skill (`/houndsman`), quatro capabilities (detalhadas em `hunt.md`, `t
|
|
|
14
14
|
| `fix` | Correção dos findings marcados como `execute`. |
|
|
15
15
|
| `verify` | Confere se as violações foram resolvidas, sem re-revisar a PR. |
|
|
16
16
|
|
|
17
|
+
## Dois caminhos para o `hunt`
|
|
18
|
+
|
|
19
|
+
| Caminho | Quem usa | Requisitos |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| Skill `/houndsman hunt` | agente externo (Copilot/Claude/etc.) | nenhum |
|
|
22
|
+
| CLI `houndsman hunt` | operador/CI, sem agente | `houndsman hunt install` |
|
|
23
|
+
|
|
24
|
+
Os dois usam o mesmo `prepare`/`finalize`, o mesmo staging e o mesmo schema de findings.
|
|
25
|
+
O CLI só substitui o despacho manual dos subagentes por processos maki headless.
|
|
26
|
+
|
|
17
27
|
## Terminologia
|
|
18
28
|
|
|
19
29
|
- **houndsman** — o orquestrador/treinador (CLI + motor).
|
|
20
30
|
- **watchdog** — cada agente especialista por domínio que audita o diff.
|
|
21
|
-
- **brief** — instruções prontas para um watchdog (o prompt do subagente)
|
|
31
|
+
- **brief** — instruções prontas para um watchdog (o prompt do subagente), incluindo o
|
|
32
|
+
**escopo do diff** (faixas/símbolos alterados que podem virar finding).
|
|
22
33
|
- **findings** — os achados que o subagente grava em JSON (único output consumido).
|
|
23
34
|
- **candidato (Jev)** — indício automático; **não** é achado (o watchdog confirma ou refuta).
|
|
24
35
|
- **churn** — linhas adicionadas/removidas por arquivo; usado para priorizar a leitura.
|
|
@@ -52,6 +63,8 @@ Um único skill (`/houndsman`), quatro capabilities (detalhadas em `hunt.md`, `t
|
|
|
52
63
|
| `houndsman` | Passo 1 — preparar (gera os briefs) |
|
|
53
64
|
| `houndsman --pr <n>` | Passo 1 em worktree dedicado (revisões paralelas) |
|
|
54
65
|
| `houndsman --finalize` | Passo 3 — gerar o relatório (`--pr <n>` reusa o worktree) |
|
|
66
|
+
| `houndsman hunt [--pr <n>]` | Harness local opcional (maki): prepare → watchdogs → finalize |
|
|
67
|
+
| `houndsman hunt install` | Baixa o maki fixado para `<HOUNDSMAN_HOME>/tools/maki` |
|
|
55
68
|
| `houndsman worktree <ação>` | `list`/`add`/`remove`/`prune`/`path` dos worktrees |
|
|
56
69
|
| `houndsman watchdog <id>` | Contexto de um watchdog (`--json`, `--rules`) |
|
|
57
70
|
| `houndsman findings <sub>` | Triagem/correção dos findings (`list`/`set`/`done`/`sync`/`batch`/`verify`/...) |
|
package/src/skill/SETUP.md
CHANGED
|
@@ -9,7 +9,7 @@ no seu projeto é **autocontida** — não exige nenhuma dependência local do p
|
|
|
9
9
|
- **git** — o diff usa `git diff <base>...<head> --name-status`.
|
|
10
10
|
- **gh** (Opcional) — Obtém contexto da PR e dispara comentários para o GitHub
|
|
11
11
|
- **`HOUNDSMAN_TYPE_SAFE_API_KEY`** (opcional) — pré-análise Jev.
|
|
12
|
-
- **`HOUNDSMAN_DEEP_SEEK_API_KEY`** (opcional) —
|
|
12
|
+
- **`HOUNDSMAN_DEEP_SEEK_API_KEY`** (opcional) — features de IA (briefs, contexto, classificação, resumo técnico).
|
|
13
13
|
- **`HOUNDSMAN_OPENAI_API_KEY`** / **`HOUNDSMAN_ANTHROPIC_API_KEY`** (opcional) — apenas se
|
|
14
14
|
`ai.provider` for `openai`/`anthropic`.
|
|
15
15
|
|
|
@@ -76,6 +76,25 @@ Depois do setup, invoque o skill `/houndsman` no seu harness:
|
|
|
76
76
|
| `/houndsman train` | Adicionar/ajustar/remover regras dos watchdogs. |
|
|
77
77
|
| `/houndsman fix` | Corrigir os findings marcados como `execute`. |
|
|
78
78
|
|
|
79
|
+
## Harness local (opcional) — `houndsman hunt`
|
|
80
|
+
|
|
81
|
+
Quem não quer rodar a skill dentro de um agente externo pode executar a revisão 100% pelo
|
|
82
|
+
CLI. O maki é instalado sob demanda, fora do projeto, e reaproveita a credencial já existente:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
houndsman hunt install # baixa o maki fixado (sha256) em <HOUNDSMAN_HOME>/tools/maki
|
|
86
|
+
houndsman hunt doctor # binário, modelo e credencial (opcional; não falha sem maki)
|
|
87
|
+
houndsman hunt --pr 456 # prepare → maki (um processo por brief) → finalize
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- A skill `/houndsman hunt` continua sendo o caminho canônico e não depende do maki.
|
|
91
|
+
- `HOUNDSMAN_MAKI_PATH` aponta um binário já instalado; `HOUNDSMAN_MAKI_VERSION` troca a
|
|
92
|
+
versão baixada.
|
|
93
|
+
- Config opcional em `houndsman.config.ts`: `hunt: { model?, concurrency?, timeoutMs?,
|
|
94
|
+
retries?, binaryPath?, enabled? }`.
|
|
95
|
+
- Se algum watchdog falhar, o comando **não finaliza** (preserva o staging); use
|
|
96
|
+
`--allow-partial` para finalizar com findings vazios registrados em `skipped`.
|
|
97
|
+
|
|
79
98
|
## Contrato do motor (`HoundsmanConfig`)
|
|
80
99
|
|
|
81
100
|
Definido em `src/core/config.ts` (pacote) e espelhado em `.houndsman/core/types.ts` (gerado):
|
|
@@ -91,6 +110,7 @@ Definido em `src/core/config.ts` (pacote) e espelhado em `.houndsman/core/types.
|
|
|
91
110
|
| `budgets` | **Opcional** — teto de arquivos por brief (`maxFilesPerBrief`, default `40`); o excedente vira "fora do orçamento" (registrar em `skipped`). |
|
|
92
111
|
| `concurrency` | **Opcional** — chamadas Jev simultâneas (`jev`, default `5`). |
|
|
93
112
|
| `ast` | **Opcional** — AST determinístico para TS/JS (`enabled`, `maxFileBytes`, `maxImpactFiles`, `languages`, `aliases`). Default: ligado; falhas são fail-open. |
|
|
113
|
+
| `hunt` | **Opcional** — harness local (`model`, `concurrency`, `timeoutMs`, `retries`, `binaryPath`, `enabled`). Só afeta `houndsman hunt`; a skill não depende. |
|
|
94
114
|
|
|
95
115
|
> O motor **não contém** ids, paths ou regras do projeto — tudo chega por `HoundsmanConfig`,
|
|
96
116
|
> carregado em runtime a partir de `houndsman.config.ts` (ou `--config <path>`).
|
|
@@ -103,7 +123,7 @@ houndsman/
|
|
|
103
123
|
└── src/
|
|
104
124
|
├── index.ts # API pública (defineWatchdog, defineHoundsmanConfig, tipos)
|
|
105
125
|
├── cli/index.ts # CLI único — bin `houndsman`
|
|
106
|
-
├── core/ # bibliotecas genéricas (config, orchestrator, brief, jev/, …)
|
|
126
|
+
├── core/ # bibliotecas genéricas (config, orchestrator, brief, jev/, hunt/, …)
|
|
107
127
|
├── skill/*.md # assets markdown (embarcados no pacote)
|
|
108
128
|
└── tests/ # suíte da lib (project-agnóstica, "project fake")
|
|
109
129
|
```
|
package/src/skill/SKILL.md
CHANGED
|
@@ -38,6 +38,10 @@ especialista por domínio · **finding** = um achado da revisão · **Jev** = pr
|
|
|
38
38
|
Um argumento extra é o alvo da capability. Escolha a capability pelo que o usuário quer,
|
|
39
39
|
leia o documento correspondente em `.houndsman/core/skill/<capability>.md` e siga-o.
|
|
40
40
|
|
|
41
|
+
> **Harness local (opcional):** para rodar sem agente externo, o operador pode instalar o
|
|
42
|
+
> maki (`houndsman hunt install`) e usar `houndsman hunt --pr 456`. Isso não muda esta
|
|
43
|
+
> skill: se você é o agente, siga o fluxo normal e não rode `houndsman hunt`.
|
|
44
|
+
|
|
41
45
|
### Alvo da revisão (PR × branch)
|
|
42
46
|
|
|
43
47
|
Interprete o alvo em linguagem natural **antes** de rodar o CLI:
|
package/src/skill/fix.md
CHANGED
|
@@ -132,7 +132,7 @@ Volte ao passo 1. A fila encolhe a cada volta; o `batch` traz o próximo grupo s
|
|
|
132
132
|
|
|
133
133
|
## Perguntas de decisão ao usuário
|
|
134
134
|
|
|
135
|
-
Pergunte (ferramenta de perguntas do
|
|
135
|
+
Pergunte (ferramenta de perguntas do agente) **antes** de corrigir quando o achado for:
|
|
136
136
|
|
|
137
137
|
- ambíguo ou com **múltiplas correções válidas**;
|
|
138
138
|
- uma mudança de **produto/arquitetura** (não é "só código");
|
package/src/skill/hunt.md
CHANGED
|
@@ -8,6 +8,20 @@ Invocação: `/houndsman` (default), `/houndsman hunt` ou `/houndsman hunt pr 45
|
|
|
8
8
|
O motor é o CLI **`houndsman`**; as regras do projeto ficam em `houndsman.config.ts` +
|
|
9
9
|
`.houndsman/`.
|
|
10
10
|
|
|
11
|
+
## Dois modos de execução
|
|
12
|
+
|
|
13
|
+
| Modo | Quem usa | Requisitos | Quem despacha os briefs |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| **Skill `/houndsman hunt`** (padrão) | agente externo (Copilot/Claude/etc.) | nenhum | o próprio agente, via subagentes |
|
|
16
|
+
| **CLI `houndsman hunt`** | operador/CI, sem agente | `houndsman hunt install` uma vez | o houndsman, via maki headless |
|
|
17
|
+
|
|
18
|
+
Os dois modos produzem os mesmos artefatos, usam o mesmo staging e o mesmo ciclo
|
|
19
|
+
`prepare → findings → finalize`. Nada muda no fluxo abaixo para quem usa a skill.
|
|
20
|
+
|
|
21
|
+
> **Se você é o agente executando esta skill, NÃO rode `houndsman hunt`.** Ele instala/usa o
|
|
22
|
+
> maki e despacha outro harness. Siga os passos 0–3 normalmente; o comando CLI é para quem
|
|
23
|
+
> quer rodar tudo no terminal.
|
|
24
|
+
|
|
11
25
|
## Alvo da revisão
|
|
12
26
|
|
|
13
27
|
Traduza o pedido do usuário para flags **antes** de começar:
|
|
@@ -25,12 +39,6 @@ Traduza o pedido do usuário para flags **antes** de começar:
|
|
|
25
39
|
**Quando usar:** revisar PR antes de merge · code review de feature branch · validar
|
|
26
40
|
mudanças antes de push.
|
|
27
41
|
|
|
28
|
-
> **Harness nativo (opcional):** além deste skill, o CLI tem `houndsman hunt` — o mesmo
|
|
29
|
-
> fluxo executado pelo próprio houndsman, com tools read-only, investigação por evidência
|
|
30
|
-
> e `VERIFY` obrigatório. Use `houndsman hunt --dry-run` para inspecionar sem IA. Para uma
|
|
31
|
-
> PR específica, `houndsman hunt --pr 456` roda no worktree automaticamente. Detalhes em
|
|
32
|
-
> `docs/HARNESS.md`.
|
|
33
|
-
|
|
34
42
|
## Quem executa o quê
|
|
35
43
|
|
|
36
44
|
- **Você** só invoca o skill: `/houndsman [hunt]`. Não precisa rodar nenhum script à mão.
|
|
@@ -62,6 +70,8 @@ mudanças antes de push.
|
|
|
62
70
|
- **As regras refletem os padrões APLICADOS hoje** — não validar práticas que o projeto
|
|
63
71
|
não adota. Regra sem aplicação real no código gera falso positivo.
|
|
64
72
|
- Cada watchdog recebe apenas seus arquivos relevantes (brief pronto) — nunca o diff completo.
|
|
73
|
+
- O brief traz o **escopo do diff** (símbolos alterados e faixas revisáveis); achado fora
|
|
74
|
+
dessas faixas é código pré-existente, não escopo desta revisão.
|
|
65
75
|
- Saída estruturada (JSON) por watchdog → consolidada e deduplicada automaticamente.
|
|
66
76
|
|
|
67
77
|
---
|
|
@@ -310,6 +320,28 @@ completo) · `--no-jev` · `--no-ast` · `--fail-on-blocking` (com `--finalize`)
|
|
|
310
320
|
|
|
311
321
|
---
|
|
312
322
|
|
|
323
|
+
## Harness local (opcional, fora da skill)
|
|
324
|
+
|
|
325
|
+
Para rodar a revisão inteira pelo terminal, sem agente externo, o mesmo `hunt` existe como
|
|
326
|
+
comando. A instalação é única e fica fora do projeto:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
houndsman hunt install # baixa o maki fixado em <HOUNDSMAN_HOME>/tools/maki
|
|
330
|
+
houndsman hunt doctor # diagnóstico (não falha se o maki não existir)
|
|
331
|
+
houndsman hunt --pr 456 # prepare → um processo maki por brief → finalize
|
|
332
|
+
houndsman hunt --pr 456 --allow-partial # finaliza mesmo se algum watchdog falhar
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
- Reaproveita a credencial já configurada (`HOUNDSMAN_DEEP_SEEK_API_KEY` → `DEEPSEEK_API_KEY`)
|
|
336
|
+
e o modelo de `ai.model` (default `deepseek/deepseek-v4-pro`).
|
|
337
|
+
- O watchdog **não recebe escrita**: o maki devolve o JSON na resposta final e o houndsman
|
|
338
|
+
valida e grava `findings/<watchdog>.json`. `bash`, rede e edição ficam negados.
|
|
339
|
+
- Sem maki instalado, nada muda para a skill: `setup`, `doctor` e `/houndsman hunt` seguem
|
|
340
|
+
funcionando.
|
|
341
|
+
- O relatório do harness fica em `hunt-report.json` (sessões, custo e tokens por watchdog).
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
313
345
|
## Anti-padrões
|
|
314
346
|
|
|
315
347
|
- ❌ Enviar git diff completo para qualquer watchdog
|
|
@@ -11,7 +11,7 @@ exports[`baseline — brief defaultRenderBrief (contexto, churn, overflow, candi
|
|
|
11
11
|
|
|
12
12
|
Watchdog baseline.
|
|
13
13
|
|
|
14
|
-
## Escopo
|
|
14
|
+
## Escopo do domínio
|
|
15
15
|
|
|
16
16
|
src/alpha/**
|
|
17
17
|
|
|
@@ -63,10 +63,10 @@ src/alpha/**
|
|
|
63
63
|
## Procedimento
|
|
64
64
|
|
|
65
65
|
1. **FILTER** — descarte o que não for do seu domínio (ver *Prioridade de leitura* e *Não carregar*).
|
|
66
|
-
2. **READ
|
|
67
|
-
3. **GREP** — use as regras críticas/anti-padrões como heurística para localizar violações.
|
|
68
|
-
4. **DEEP-READ** — aprofunde apenas
|
|
69
|
-
5. **CONCLUDE** — grave o JSON no caminho de output, com \`reviewedFiles\` preenchido. Sem achados → \`"findings": []\` (arquivo obrigatório). Não escreva markdown livre."
|
|
66
|
+
2. **READ SCOPE** — carregue apenas as faixas alteradas em *Escopo do diff*; o restante do arquivo é só contexto.
|
|
67
|
+
3. **GREP** — use as regras críticas/anti-padrões como heurística para localizar violações nas faixas alteradas.
|
|
68
|
+
4. **DEEP-READ** — aprofunde apenas as faixas com suspeita de violação dentro do escopo.
|
|
69
|
+
5. **CONCLUDE** — grave o JSON no caminho de output, com \`reviewedFiles\` preenchido e \`line\` dentro das faixas alteradas. Sem achados → \`"findings": []\` (arquivo obrigatório). Não escreva markdown livre."
|
|
70
70
|
`;
|
|
71
71
|
|
|
72
72
|
exports[`baseline — relatório renderReport consolidado 1`] = `
|
|
@@ -238,6 +238,10 @@ especialista por domínio · **finding** = um achado da revisão · **Jev** = pr
|
|
|
238
238
|
Um argumento extra é o alvo da capability. Escolha a capability pelo que o usuário quer,
|
|
239
239
|
leia o documento correspondente em \`.houndsman/core/skill/<capability>.md\` e siga-o.
|
|
240
240
|
|
|
241
|
+
> **Harness local (opcional):** para rodar sem agente externo, o operador pode instalar o
|
|
242
|
+
> maki (\`houndsman hunt install\`) e usar \`houndsman hunt --pr 456\`. Isso não muda esta
|
|
243
|
+
> skill: se você é o agente, siga o fluxo normal e não rode \`houndsman hunt\`.
|
|
244
|
+
|
|
241
245
|
### Alvo da revisão (PR × branch)
|
|
242
246
|
|
|
243
247
|
Interprete o alvo em linguagem natural **antes** de rodar o CLI:
|
|
@@ -323,6 +327,10 @@ especialista por domínio · **finding** = um achado da revisão · **Jev** = pr
|
|
|
323
327
|
Um argumento extra é o alvo da capability. Escolha a capability pelo que o usuário quer,
|
|
324
328
|
leia o documento correspondente em \`.houndsman/core/skill/<capability>.md\` e siga-o.
|
|
325
329
|
|
|
330
|
+
> **Harness local (opcional):** para rodar sem agente externo, o operador pode instalar o
|
|
331
|
+
> maki (\`houndsman hunt install\`) e usar \`houndsman hunt --pr 456\`. Isso não muda esta
|
|
332
|
+
> skill: se você é o agente, siga o fluxo normal e não rode \`houndsman hunt\`.
|
|
333
|
+
|
|
326
334
|
### Alvo da revisão (PR × branch)
|
|
327
335
|
|
|
328
336
|
Interprete o alvo em linguagem natural **antes** de rodar o CLI:
|
|
@@ -405,16 +413,6 @@ export type Rule = {
|
|
|
405
413
|
severity: Severity;
|
|
406
414
|
text: string;
|
|
407
415
|
jev?: JevRuleSpec;
|
|
408
|
-
hints?: RuleHints;
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
/** Sinais opcionais de uma regra (símbolos, imports, decorators, paths, checks). */
|
|
412
|
-
export type RuleHints = {
|
|
413
|
-
symbols?: string[];
|
|
414
|
-
imports?: string[];
|
|
415
|
-
decorators?: string[];
|
|
416
|
-
paths?: string[];
|
|
417
|
-
checks?: string[];
|
|
418
416
|
};
|
|
419
417
|
|
|
420
418
|
/** Como o watchdog casa um arquivo alterado. \`value\` é sempre regex. */
|
|
@@ -509,20 +507,15 @@ export type HoundsmanAiFeatures = {
|
|
|
509
507
|
/** Overrides de IA por watchdog. */
|
|
510
508
|
export type HoundsmanAiWatchdog = {
|
|
511
509
|
model?: string;
|
|
512
|
-
maxSteps?: number;
|
|
513
|
-
maxOutputTokens?: number;
|
|
514
510
|
};
|
|
515
511
|
|
|
516
|
-
/** Configuração da camada de IA (briefs, contexto, classificação
|
|
512
|
+
/** Configuração da camada de IA (briefs, contexto, classificação, pré-análise, verify). */
|
|
517
513
|
export type HoundsmanAi = {
|
|
518
514
|
enabled?: boolean;
|
|
519
515
|
provider?: AiProviderKind;
|
|
520
516
|
model?: string;
|
|
521
517
|
baseURL?: string;
|
|
522
518
|
concurrency?: number;
|
|
523
|
-
maxSteps?: number;
|
|
524
|
-
maxOutputTokens?: number;
|
|
525
|
-
temperature?: number;
|
|
526
519
|
providerOptions?: AiProviderOptions;
|
|
527
520
|
timeoutMs?: number;
|
|
528
521
|
maxCallsPerReview?: number;
|
|
@@ -531,6 +524,16 @@ export type HoundsmanAi = {
|
|
|
531
524
|
watchdogs?: Record<string, HoundsmanAiWatchdog>;
|
|
532
525
|
};
|
|
533
526
|
|
|
527
|
+
/** Harness local da capability \`hunt\` (\`houndsman hunt\`) — opcional. */
|
|
528
|
+
export type HoundsmanHunt = {
|
|
529
|
+
enabled?: boolean;
|
|
530
|
+
model?: string;
|
|
531
|
+
concurrency?: number;
|
|
532
|
+
timeoutMs?: number;
|
|
533
|
+
retries?: number;
|
|
534
|
+
binaryPath?: string;
|
|
535
|
+
};
|
|
536
|
+
|
|
534
537
|
/** Contrato de configuração do motor. */
|
|
535
538
|
export type HoundsmanConfig<TId extends string = string> = {
|
|
536
539
|
projectName: string;
|
|
@@ -544,6 +547,7 @@ export type HoundsmanConfig<TId extends string = string> = {
|
|
|
544
547
|
concurrency?: HoundsmanConcurrency;
|
|
545
548
|
ast?: HoundsmanAst;
|
|
546
549
|
ai?: HoundsmanAi;
|
|
550
|
+
hunt?: HoundsmanHunt;
|
|
547
551
|
};
|
|
548
552
|
|
|
549
553
|
/** Helper de autoria (identidade) — apenas tipagem. */
|
|
@@ -665,15 +669,15 @@ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 3
|
|
|
665
669
|
},
|
|
666
670
|
{
|
|
667
671
|
"file": ".houndsman/core/skill/OUTPUT-FORMAT.md",
|
|
668
|
-
"sha256": "
|
|
672
|
+
"sha256": "a78ed16d4d211889",
|
|
669
673
|
},
|
|
670
674
|
{
|
|
671
675
|
"file": ".houndsman/core/skill/README.md",
|
|
672
|
-
"sha256": "
|
|
676
|
+
"sha256": "2ecf43f34a624011",
|
|
673
677
|
},
|
|
674
678
|
{
|
|
675
679
|
"file": ".houndsman/core/skill/SETUP.md",
|
|
676
|
-
"sha256": "
|
|
680
|
+
"sha256": "5720c48ede6c84ea",
|
|
677
681
|
},
|
|
678
682
|
{
|
|
679
683
|
"file": ".houndsman/core/skill/example-review.md",
|
|
@@ -681,11 +685,11 @@ exports[`baseline — camada gerada setup gera os mesmos arquivos e conteúdos 3
|
|
|
681
685
|
},
|
|
682
686
|
{
|
|
683
687
|
"file": ".houndsman/core/skill/fix.md",
|
|
684
|
-
"sha256": "
|
|
688
|
+
"sha256": "5782f4880af78d29",
|
|
685
689
|
},
|
|
686
690
|
{
|
|
687
691
|
"file": ".houndsman/core/skill/hunt.md",
|
|
688
|
-
"sha256": "
|
|
692
|
+
"sha256": "d31198580d894427",
|
|
689
693
|
},
|
|
690
694
|
{
|
|
691
695
|
"file": ".houndsman/core/skill/train.md",
|
|
@@ -702,6 +706,7 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
|
|
|
702
706
|
"Discovery: 1 watchdog(s) ativado(s), 3 arquivo(s), 1 deletado(s).
|
|
703
707
|
Briefs: <cwd>/.home/work/<uuid>/briefs/
|
|
704
708
|
Deletado (breaking change): src/alpha/old.ts
|
|
709
|
+
Escopo: 2 arquivo(s), 0 símbolo(s) em 2 faixa(s) alterada(s).
|
|
705
710
|
Jev: pulado (desativado (--no-jev)).
|
|
706
711
|
AST: desabilitado ou sem grammar compatível.
|
|
707
712
|
Sem contexto da PR (rode \`bun run houndsman context\` antes, se houver PR).
|
|
@@ -753,7 +758,29 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
|
|
|
753
758
|
},
|
|
754
759
|
"excludedCount": 0,
|
|
755
760
|
"headSha": "<sha>",
|
|
756
|
-
"mode": "full"
|
|
761
|
+
"mode": "full",
|
|
762
|
+
"changedScope": {
|
|
763
|
+
"src/alpha/a.ts": {
|
|
764
|
+
"ranges": [
|
|
765
|
+
{
|
|
766
|
+
"start": 1,
|
|
767
|
+
"end": 2
|
|
768
|
+
}
|
|
769
|
+
],
|
|
770
|
+
"symbols": [],
|
|
771
|
+
"source": "hunks"
|
|
772
|
+
},
|
|
773
|
+
"src/alpha/b.ts": {
|
|
774
|
+
"ranges": [
|
|
775
|
+
{
|
|
776
|
+
"start": 1,
|
|
777
|
+
"end": 1
|
|
778
|
+
}
|
|
779
|
+
],
|
|
780
|
+
"symbols": [],
|
|
781
|
+
"source": "hunks"
|
|
782
|
+
}
|
|
783
|
+
}
|
|
757
784
|
}
|
|
758
785
|
"
|
|
759
786
|
`;
|
|
@@ -827,10 +854,20 @@ exports[`baseline — artefatos de prepare/finalize gera classification, brief,
|
|
|
827
854
|
|
|
828
855
|
Watchdog baseline.
|
|
829
856
|
|
|
830
|
-
## Escopo
|
|
857
|
+
## Escopo do domínio
|
|
831
858
|
|
|
832
859
|
src/alpha/**
|
|
833
860
|
|
|
861
|
+
## Escopo do diff (símbolos alterados)
|
|
862
|
+
|
|
863
|
+
> **Regra de escopo:** um finding só é válido quando a \`line\` está nas faixas
|
|
864
|
+
> abaixo. Código fora delas é contexto — use para entender o impacto, nunca
|
|
865
|
+
> como achado. Se a mudança quebra código não alterado, ancore o finding na
|
|
866
|
+
> linha alterada que causou o problema.
|
|
867
|
+
|
|
868
|
+
- \`src/alpha/a.ts\` — linhas 1-2 _(faixas do diff)_
|
|
869
|
+
- \`src/alpha/b.ts\` — linhas 1 _(faixas do diff)_
|
|
870
|
+
|
|
834
871
|
## Regras (por severidade)
|
|
835
872
|
|
|
836
873
|
- ❌ **blocking** — Nunca usar \`any\`.
|
|
@@ -852,10 +889,10 @@ src/alpha/**
|
|
|
852
889
|
## Procedimento
|
|
853
890
|
|
|
854
891
|
1. **FILTER** — descarte o que não for do seu domínio (ver *Prioridade de leitura* e *Não carregar*).
|
|
855
|
-
2. **READ
|
|
856
|
-
3. **GREP** — use as regras críticas/anti-padrões como heurística para localizar violações.
|
|
857
|
-
4. **DEEP-READ** — aprofunde apenas
|
|
858
|
-
5. **CONCLUDE** — grave o JSON no caminho de output, com \`reviewedFiles\` preenchido. Sem achados → \`"findings": []\` (arquivo obrigatório). Não escreva markdown livre.
|
|
892
|
+
2. **READ SCOPE** — carregue apenas as faixas alteradas em *Escopo do diff*; o restante do arquivo é só contexto.
|
|
893
|
+
3. **GREP** — use as regras críticas/anti-padrões como heurística para localizar violações nas faixas alteradas.
|
|
894
|
+
4. **DEEP-READ** — aprofunde apenas as faixas com suspeita de violação dentro do escopo.
|
|
895
|
+
5. **CONCLUDE** — grave o JSON no caminho de output, com \`reviewedFiles\` preenchido e \`line\` dentro das faixas alteradas. Sem achados → \`"findings": []\` (arquivo obrigatório). Não escreva markdown livre.
|
|
859
896
|
"
|
|
860
897
|
`;
|
|
861
898
|
|
|
@@ -6,7 +6,11 @@ import { describe, expect, test } from "bun:test";
|
|
|
6
6
|
import type { LanguageModel } from "ai";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { AiClient, AiUsageBudget, AiUsageRecorder } from "../core/ai";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
buildGenerateTextArgs,
|
|
11
|
+
formatSdkWarning,
|
|
12
|
+
formatSdkWarnings,
|
|
13
|
+
} from "../core/ai/ai-sdk-model-provider";
|
|
10
14
|
import { temperatureApplies } from "../core/ai/provider-capabilities";
|
|
11
15
|
import { defineHoundsmanConfig } from "../core/config";
|
|
12
16
|
import { DEFAULT_AI_MODEL } from "../core/defaults";
|
|
@@ -153,6 +157,39 @@ describe("temperature e providerOptions", () => {
|
|
|
153
157
|
});
|
|
154
158
|
});
|
|
155
159
|
|
|
160
|
+
describe("avisos do AI SDK", () => {
|
|
161
|
+
test("normaliza os avisos do provider em texto", () => {
|
|
162
|
+
expect(
|
|
163
|
+
formatSdkWarning({
|
|
164
|
+
type: "compatibility",
|
|
165
|
+
feature: "responseFormat JSON schema",
|
|
166
|
+
details: "JSON response schema is injected into the system message.",
|
|
167
|
+
}),
|
|
168
|
+
).toBe(
|
|
169
|
+
"compatibility: responseFormat JSON schema — JSON response schema is injected into the system message.",
|
|
170
|
+
);
|
|
171
|
+
expect(
|
|
172
|
+
formatSdkWarning({
|
|
173
|
+
type: "unsupported",
|
|
174
|
+
feature: "user message part type: image",
|
|
175
|
+
}),
|
|
176
|
+
).toBe("unsupported: user message part type: image");
|
|
177
|
+
expect(
|
|
178
|
+
formatSdkWarning({
|
|
179
|
+
type: "deprecated",
|
|
180
|
+
setting: "temperature",
|
|
181
|
+
message: "gone",
|
|
182
|
+
}),
|
|
183
|
+
).toBe("deprecated: temperature — gone");
|
|
184
|
+
expect(formatSdkWarning(null)).toBe("aviso");
|
|
185
|
+
expect(formatSdkWarnings(undefined)).toEqual([]);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("logger default do SDK fica silencioso após carregar o adapter", () => {
|
|
189
|
+
expect(typeof globalThis.AI_SDK_LOG_WARNINGS).toBe("function");
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
156
193
|
describe("AiUsageBudget / AiUsageRecorder", () => {
|
|
157
194
|
test("acumula uso e bloqueia no teto", () => {
|
|
158
195
|
const budget = new AiUsageBudget({ maxCalls: 2 });
|