@payconductor/houndsman 0.4.0 → 0.6.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 +35 -41
- package/assets/grammars/tree-sitter-javascript.wasm +0 -0
- package/assets/grammars/tree-sitter-tsx.wasm +0 -0
- package/assets/grammars/tree-sitter-typescript.wasm +0 -0
- package/assets/grammars/web-tree-sitter.wasm +0 -0
- package/package.json +11 -3
- package/src/cli/commands/command.ts +5 -0
- package/src/cli/commands/doctor-command.ts +116 -24
- package/src/cli/commands/hunt-command.ts +25 -0
- package/src/cli/commands/status-command.ts +46 -0
- package/src/cli/help.ts +18 -1
- package/src/cli/index.ts +13 -6
- package/src/core/ai/ai-client.ts +221 -0
- package/src/core/ai/ai-sdk-model-provider.ts +101 -0
- package/src/core/ai/errors.ts +36 -0
- package/src/core/ai/features/brief-enricher.ts +62 -0
- package/src/core/ai/features/classifier.ts +50 -0
- package/src/core/ai/features/context-summarizer.ts +31 -0
- package/src/core/ai/features/pre-analyzer.ts +51 -0
- package/src/core/ai/features/verifier.ts +45 -0
- package/src/core/ai/index.ts +56 -0
- package/src/core/ai/model-factory.ts +137 -0
- package/src/core/ai/prompts/base.ts +36 -0
- package/src/core/ai/prompts/brief.ts +87 -0
- package/src/core/ai/prompts/classification.ts +36 -0
- package/src/core/ai/prompts/context.ts +29 -0
- package/src/core/ai/prompts/pre-analysis.ts +49 -0
- package/src/core/ai/prompts/verify.ts +40 -0
- package/src/core/ai/schemas.ts +110 -0
- package/src/core/ai/types.ts +76 -0
- package/src/core/ai/usage-budget.ts +75 -0
- package/src/core/ai/usage-recorder.ts +79 -0
- package/src/core/assets.ts +16 -0
- package/src/core/ast/diff.ts +220 -0
- package/src/core/ast/impact.ts +127 -0
- package/src/core/ast/parser.ts +167 -0
- package/src/core/ast/service.ts +233 -0
- package/src/core/ast/symbols.ts +294 -0
- package/src/core/ast/types.ts +125 -0
- package/src/core/brief.ts +138 -0
- package/src/core/commands/findings.ts +120 -6
- package/src/core/commands/review.ts +2 -0
- package/src/core/commands/scaffold.ts +159 -10
- package/src/core/commands/status.ts +63 -0
- package/src/core/commands/update.ts +5 -3
- package/src/core/config.ts +85 -0
- package/src/core/defaults.ts +27 -0
- package/src/core/domain/watchdog.ts +43 -5
- package/src/core/engine/houndsman-engine.ts +16 -1
- package/src/core/engine/review-scope.ts +77 -13
- package/src/core/engine/review-session.ts +27 -2
- package/src/core/env.ts +101 -0
- package/src/core/file-classifier.ts +25 -4
- package/src/core/findings-state.ts +21 -4
- package/src/core/github-review.ts +620 -57
- package/src/core/jev/jev-client.ts +8 -7
- package/src/core/jev/jev-verify.ts +2 -1
- package/src/core/logging/index.ts +17 -0
- package/src/core/logging/logger.ts +187 -0
- package/src/core/orchestrator.ts +454 -16
- package/src/core/paths.ts +3 -0
- package/src/core/project-config.ts +123 -1
- package/src/core/registry-check.ts +148 -6
- package/src/core/renderers/manifest-writer.ts +33 -0
- package/src/core/renderers/resume-renderer.ts +151 -0
- package/src/core/report-builder.ts +7 -4
- package/src/core/rule-text.ts +97 -0
- package/src/core/run-status.ts +39 -5
- package/src/core/services/file-classifier.ts +10 -3
- package/src/core/services/verifier.ts +14 -3
- package/src/core/storage/file/file-storage.ts +2 -0
- package/src/core/storage/paths.ts +6 -5
- package/src/core/storage/sqlite/mappers.ts +2 -0
- package/src/core/storage/sqlite/schema.ts +9 -1
- package/src/core/storage/sqlite/sqlite-storage.ts +5 -1
- package/src/core/storage/types.ts +15 -0
- package/src/core/storage/work-area.ts +12 -0
- package/src/core/types.ts +37 -1
- package/src/core/verify.ts +17 -5
- package/src/harness/README.md +15 -0
- package/src/harness/agent/agent-context.ts +33 -0
- package/src/harness/agent/agent-errors.ts +30 -0
- package/src/harness/agent/agent-factory.ts +45 -0
- package/src/harness/agent/agent-reporter.ts +34 -0
- package/src/harness/agent/agent-result.ts +16 -0
- package/src/harness/agent/agent-runner.ts +32 -0
- package/src/harness/agent/agent-scheduler.ts +37 -0
- package/src/harness/agent/review-agent.ts +391 -0
- package/src/harness/config/harness-config.ts +84 -0
- package/src/harness/hunt/hunt-harness.ts +83 -0
- package/src/harness/hunt/hunt-options.ts +75 -0
- package/src/harness/hunt/hunt-result.ts +17 -0
- package/src/harness/hunt/hunt-session.ts +372 -0
- package/src/harness/hunt/review-planner.ts +98 -0
- package/src/harness/index.ts +36 -0
- package/src/harness/investigation/agent-state.ts +134 -0
- package/src/harness/investigation/evidence-verifier.ts +129 -0
- package/src/harness/investigation/evidence.ts +110 -0
- package/src/harness/investigation/finding-critic.ts +96 -0
- package/src/harness/investigation/investigation-planner.ts +118 -0
- package/src/harness/investigation/investigation-task.ts +10 -0
- package/src/harness/investigation/review-journal.ts +87 -0
- package/src/harness/investigation/rule-analyzer.ts +178 -0
- package/src/harness/investigation/rule-signals.ts +110 -0
- package/src/harness/prompts/agent-schemas.ts +57 -0
- package/src/harness/prompts/reviewer-prompt-builder.ts +101 -0
- package/src/harness/prompts/states/conclude-prompt.ts +16 -0
- package/src/harness/prompts/states/investigate-prompt.ts +37 -0
- package/src/harness/prompts/states/orient-prompt.ts +15 -0
- package/src/harness/prompts/states/verify-prompt.ts +22 -0
- package/src/harness/tools/agent-tool.ts +102 -0
- package/src/harness/tools/builtin/changed-symbols-tool.ts +48 -0
- package/src/harness/tools/builtin/doc-context-tool.ts +74 -0
- package/src/harness/tools/builtin/file-outline-tool.ts +66 -0
- package/src/harness/tools/builtin/find-references-tool.ts +66 -0
- package/src/harness/tools/builtin/find-symbol-tool.ts +91 -0
- package/src/harness/tools/builtin/helpers.ts +115 -0
- package/src/harness/tools/builtin/impact-tool.ts +48 -0
- package/src/harness/tools/builtin/imports-exports-tool.ts +53 -0
- package/src/harness/tools/builtin/index.ts +59 -0
- package/src/harness/tools/builtin/list-files-tool.ts +85 -0
- package/src/harness/tools/builtin/pr-context-tool.ts +41 -0
- package/src/harness/tools/builtin/read-file-range-tool.ts +73 -0
- package/src/harness/tools/builtin/rule-signals-tool.ts +36 -0
- package/src/harness/tools/builtin/search-code-tool.ts +65 -0
- package/src/harness/tools/builtin/symbol-context-tool.ts +106 -0
- package/src/harness/tools/builtin/tests-for-symbol-tool.ts +61 -0
- package/src/harness/tools/path-guard.ts +90 -0
- package/src/harness/tools/result-limiter.ts +49 -0
- package/src/harness/tools/secret-redactor.ts +54 -0
- package/src/harness/tools/tool-cache.ts +50 -0
- package/src/harness/tools/tool-call-budget.ts +60 -0
- package/src/harness/tools/tool-context.ts +5 -0
- package/src/harness/tools/tool-middleware.ts +105 -0
- package/src/harness/tools/tool-policy.ts +51 -0
- package/src/harness/tools/tool-registry.ts +112 -0
- package/src/harness/tools/tool-result.ts +15 -0
- package/src/harness/tools/toolbox.ts +36 -0
- package/src/harness/validation/finding-validator.ts +119 -0
- package/src/index.ts +46 -0
- package/src/server/client/App.tsx +26 -9
- package/src/server/client/ArtifactsPanel.tsx +12 -5
- package/src/server/client/AutoRefresh.tsx +1 -1
- package/src/server/client/Filters.tsx +7 -2
- package/src/server/client/FindingCard.tsx +14 -10
- package/src/server/client/FindingsList.tsx +2 -2
- package/src/server/client/MarkdownText.tsx +92 -12
- package/src/server/client/ResumePanel.tsx +368 -0
- package/src/server/client/RunList.tsx +3 -3
- package/src/server/client/SubmitModal.tsx +49 -6
- package/src/server/client/SummaryBar.tsx +1 -1
- package/src/server/client/icons.tsx +17 -0
- package/src/server/client/{constants.ts → utils/constants.ts} +61 -10
- package/src/server/client/utils/markdown.ts +319 -0
- package/src/server/client/{types.ts → utils/types.ts} +64 -0
- package/src/server/index.ts +66 -7
- package/src/server/run-repository.ts +9 -0
- package/src/skill/OUTPUT-FORMAT.md +12 -0
- package/src/skill/SETUP.md +6 -2
- package/src/skill/example-review.md +22 -14
- package/src/skill/hunt.md +45 -19
- package/src/skill/verify.md +3 -2
- package/src/tests/__snapshots__/baseline.test.ts.snap +126 -42
- package/src/tests/ai-core.test.ts +120 -0
- package/src/tests/ai-features.test.ts +183 -0
- package/src/tests/ast.test.ts +335 -0
- package/src/tests/baseline.test.ts +3 -0
- package/src/tests/code-highlight.test.ts +1 -1
- package/src/tests/env.test.ts +69 -0
- package/src/tests/fallback.test.ts +172 -0
- package/src/tests/findings-state.test.ts +50 -2
- package/src/tests/fixtures/fake-agent-tools.ts +69 -0
- package/src/tests/fixtures/fake-investigation.ts +64 -0
- package/src/tests/fixtures/fake-model-provider.ts +48 -0
- package/src/tests/github-review.test.ts +409 -60
- package/src/tests/harness-agent.test.ts +122 -0
- package/src/tests/harness-investigation.test.ts +206 -0
- package/src/tests/harness-tools.test.ts +148 -0
- package/src/tests/hunt-command.test.ts +212 -0
- package/src/tests/logger.test.ts +83 -0
- package/src/tests/markdown.test.ts +61 -1
- package/src/tests/review-resume.test.ts +101 -0
- package/src/tests/review-scope.test.ts +302 -0
- package/src/tests/review-scripts.test.ts +73 -0
- package/src/tests/rule-analyzer.test.ts +61 -0
- package/src/tests/run-status-view.test.ts +94 -0
- package/src/tests/run-status.test.ts +53 -0
- package/src/tests/server.test.ts +76 -21
- package/src/tests/storage.test.ts +63 -0
- package/src/tests/tool-contracts.test.ts +82 -0
- package/src/tests/verify.test.ts +1 -1
- package/src/server/client/markdown.ts +0 -153
- /package/src/server/client/{api.ts → utils/api.ts} +0 -0
- /package/src/server/client/{code-highlight.ts → utils/code-highlight.ts} +0 -0
- /package/src/server/client/{format.ts → utils/format.ts} +0 -0
- /package/src/server/client/{json-highlight.ts → utils/json-highlight.ts} +0 -0
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { readFileSync } from "node:fs";
|
|
9
|
+
import type { AstFacts } from "./ast/types";
|
|
9
10
|
import type { HoundsmanConfig } from "./config";
|
|
10
11
|
import { churnToRecord, collectChurn, type DiffSource } from "./diff-source";
|
|
11
12
|
import { matchesClassifyRule } from "./domain/watchdog";
|
|
@@ -69,12 +70,13 @@ export function matchWatchdogs<TId extends string>(
|
|
|
69
70
|
watchdogs: Record<TId, WatchdogDefinition>,
|
|
70
71
|
watchdogIds: readonly TId[],
|
|
71
72
|
content?: string,
|
|
73
|
+
facts?: AstFacts,
|
|
72
74
|
): TId[] {
|
|
73
75
|
const ids: TId[] = [];
|
|
74
76
|
for (const id of watchdogIds) {
|
|
75
77
|
if (
|
|
76
78
|
watchdogs[id]?.classify?.some((rule) =>
|
|
77
|
-
matchesClassifyRule(filePath, rule, content),
|
|
79
|
+
matchesClassifyRule(filePath, rule, content, facts),
|
|
78
80
|
)
|
|
79
81
|
) {
|
|
80
82
|
ids.push(id);
|
|
@@ -88,6 +90,13 @@ export function isExcludedPath(filePath: string, patterns: readonly RegExp[]): b
|
|
|
88
90
|
return patterns.some((pattern) => pattern.test(filePath));
|
|
89
91
|
}
|
|
90
92
|
|
|
93
|
+
/** Id do watchdog de último recurso (primeiro declarado), se houver. */
|
|
94
|
+
export function fallbackWatchdogId<TId extends string>(
|
|
95
|
+
config: HoundsmanConfig<TId>,
|
|
96
|
+
): TId | undefined {
|
|
97
|
+
return config.watchdogIds.find((id) => config.watchdogs[id]?.fallback === true);
|
|
98
|
+
}
|
|
99
|
+
|
|
91
100
|
// ---------------------------------------------------------------------------
|
|
92
101
|
// Parsing de `git diff --name-status`
|
|
93
102
|
// ---------------------------------------------------------------------------
|
|
@@ -142,12 +151,15 @@ export function classifyEntries<TId extends string>(
|
|
|
142
151
|
entries: FileEntry[],
|
|
143
152
|
config: HoundsmanConfig<TId>,
|
|
144
153
|
churn: ChurnMap = {},
|
|
154
|
+
astFacts?: ReadonlyMap<string, AstFacts>,
|
|
145
155
|
): ClassificationResult {
|
|
146
156
|
const watchdogFiles: Record<string, string[]> = {};
|
|
147
157
|
const files: ClassificationResult["files"] = {};
|
|
148
158
|
const unclassified: string[] = [];
|
|
149
159
|
const excluded: string[] = [];
|
|
150
160
|
const deleted: string[] = [];
|
|
161
|
+
// Watchdog de último recurso: cobre apenas arquivos sem outro dono.
|
|
162
|
+
const fallbackId = fallbackWatchdogId(config);
|
|
151
163
|
// Leitura de conteúdo só é habilitada se algum watchdog declarar regra `content`.
|
|
152
164
|
const needsContent = hasContentRules(config.watchdogs, config.watchdogIds);
|
|
153
165
|
|
|
@@ -167,15 +179,23 @@ export function classifyEntries<TId extends string>(
|
|
|
167
179
|
}
|
|
168
180
|
|
|
169
181
|
const content = needsContent ? readFileContent(path) : undefined;
|
|
170
|
-
const
|
|
182
|
+
const facts = astFacts?.get(path);
|
|
183
|
+
const matched = matchWatchdogs(
|
|
171
184
|
path,
|
|
172
185
|
config.watchdogs,
|
|
173
186
|
config.watchdogIds,
|
|
174
187
|
content,
|
|
188
|
+
facts,
|
|
175
189
|
);
|
|
190
|
+
const ids = fallbackId ? matched.filter((id) => id !== fallbackId) : matched;
|
|
176
191
|
|
|
177
192
|
if (ids.length === 0) {
|
|
178
|
-
|
|
193
|
+
if (fallbackId) {
|
|
194
|
+
watchdogFiles[fallbackId] ??= [];
|
|
195
|
+
watchdogFiles[fallbackId].push(path);
|
|
196
|
+
} else {
|
|
197
|
+
unclassified.push(path);
|
|
198
|
+
}
|
|
179
199
|
continue;
|
|
180
200
|
}
|
|
181
201
|
|
|
@@ -218,10 +238,11 @@ export function classifyRange<TId extends string>(
|
|
|
218
238
|
head: string,
|
|
219
239
|
config: HoundsmanConfig<TId>,
|
|
220
240
|
diff?: DiffSource,
|
|
241
|
+
astFacts?: ReadonlyMap<string, AstFacts>,
|
|
221
242
|
): ClassificationResult {
|
|
222
243
|
const entries = parseEntries(runGit(["diff", `${base}...${head}`, "--name-status"]));
|
|
223
244
|
const churn = diff?.churn ?? collectChurn(base, head);
|
|
224
|
-
const result = classifyEntries(entries, config, churnToRecord(churn));
|
|
245
|
+
const result = classifyEntries(entries, config, churnToRecord(churn), astFacts);
|
|
225
246
|
result.base = base;
|
|
226
247
|
result.head = head;
|
|
227
248
|
return result;
|
|
@@ -76,6 +76,10 @@ export type GitHubLink = {
|
|
|
76
76
|
pr: number;
|
|
77
77
|
/** Quando foi enviado (ISO). */
|
|
78
78
|
at: string;
|
|
79
|
+
/** Node ID da thread de revisão (GraphQL) — base para resolver a conversa. */
|
|
80
|
+
threadId?: string;
|
|
81
|
+
/** Quando a thread foi marcada como resolvida no GitHub (ISO). */
|
|
82
|
+
resolvedAt?: string;
|
|
79
83
|
};
|
|
80
84
|
|
|
81
85
|
/** Marco da revisão que originou o estado: commit revisado + quando. */
|
|
@@ -283,6 +287,12 @@ export type BuildStateOptions = {
|
|
|
283
287
|
reviewed?: FindingsReviewed;
|
|
284
288
|
/** SHA usado para carimbar `foundAtSha` de findings novos/re-reportados. */
|
|
285
289
|
headSha?: string;
|
|
290
|
+
/**
|
|
291
|
+
* Arquivos efetivamente revisados neste ciclo (união de `reviewedFiles`).
|
|
292
|
+
* Quando presente, só findings ausentes desses arquivos viram `done` — o que
|
|
293
|
+
* ficou fora do orçamento/skipped não pode ser dado como resolvido.
|
|
294
|
+
*/
|
|
295
|
+
reviewedPaths?: ReadonlySet<string>;
|
|
286
296
|
now?: string;
|
|
287
297
|
};
|
|
288
298
|
|
|
@@ -303,14 +313,21 @@ export function buildStateFromFindings(
|
|
|
303
313
|
|
|
304
314
|
const result: Record<string, FindingState> = {};
|
|
305
315
|
// 1. Preserva o estado anterior (marca como ausente até provar o contrário).
|
|
316
|
+
const reviewedPaths = options.reviewedPaths;
|
|
306
317
|
for (const prev of Object.values(previous?.findings ?? {})) {
|
|
318
|
+
// Ausente do novo relatório ⇒ corrigido manualmente entre revisões (ou
|
|
319
|
+
// some junto com o trecho): vira `done`. `ignore` é decisão explícita de
|
|
320
|
+
// não corrigir — preserva o estado original. Arquivo fora da revisão
|
|
321
|
+
// (orçamento/skipped) também preserva: ausência não prova resolução.
|
|
322
|
+
const wasReviewed = !reviewedPaths || reviewedPaths.has(prev.file);
|
|
323
|
+
const resolvedByReview =
|
|
324
|
+
wasReviewed && prev.present && prev.decision !== "ignore";
|
|
325
|
+
const queuedAndGone =
|
|
326
|
+
wasReviewed && prev.decision === "execute" && prev.execState === "pending";
|
|
307
327
|
result[prev.id] = {
|
|
308
328
|
...prev,
|
|
309
329
|
present: false,
|
|
310
|
-
execState:
|
|
311
|
-
prev.execState === "pending" && prev.decision === "execute"
|
|
312
|
-
? "done"
|
|
313
|
-
: prev.execState,
|
|
330
|
+
execState: resolvedByReview || queuedAndGone ? "done" : prev.execState,
|
|
314
331
|
updatedAt: now,
|
|
315
332
|
};
|
|
316
333
|
}
|