@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.
Files changed (196) hide show
  1. package/README.md +35 -41
  2. package/assets/grammars/tree-sitter-javascript.wasm +0 -0
  3. package/assets/grammars/tree-sitter-tsx.wasm +0 -0
  4. package/assets/grammars/tree-sitter-typescript.wasm +0 -0
  5. package/assets/grammars/web-tree-sitter.wasm +0 -0
  6. package/package.json +11 -3
  7. package/src/cli/commands/command.ts +5 -0
  8. package/src/cli/commands/doctor-command.ts +116 -24
  9. package/src/cli/commands/hunt-command.ts +25 -0
  10. package/src/cli/commands/status-command.ts +46 -0
  11. package/src/cli/help.ts +18 -1
  12. package/src/cli/index.ts +13 -6
  13. package/src/core/ai/ai-client.ts +221 -0
  14. package/src/core/ai/ai-sdk-model-provider.ts +101 -0
  15. package/src/core/ai/errors.ts +36 -0
  16. package/src/core/ai/features/brief-enricher.ts +62 -0
  17. package/src/core/ai/features/classifier.ts +50 -0
  18. package/src/core/ai/features/context-summarizer.ts +31 -0
  19. package/src/core/ai/features/pre-analyzer.ts +51 -0
  20. package/src/core/ai/features/verifier.ts +45 -0
  21. package/src/core/ai/index.ts +56 -0
  22. package/src/core/ai/model-factory.ts +137 -0
  23. package/src/core/ai/prompts/base.ts +36 -0
  24. package/src/core/ai/prompts/brief.ts +87 -0
  25. package/src/core/ai/prompts/classification.ts +36 -0
  26. package/src/core/ai/prompts/context.ts +29 -0
  27. package/src/core/ai/prompts/pre-analysis.ts +49 -0
  28. package/src/core/ai/prompts/verify.ts +40 -0
  29. package/src/core/ai/schemas.ts +110 -0
  30. package/src/core/ai/types.ts +76 -0
  31. package/src/core/ai/usage-budget.ts +75 -0
  32. package/src/core/ai/usage-recorder.ts +79 -0
  33. package/src/core/assets.ts +16 -0
  34. package/src/core/ast/diff.ts +220 -0
  35. package/src/core/ast/impact.ts +127 -0
  36. package/src/core/ast/parser.ts +167 -0
  37. package/src/core/ast/service.ts +233 -0
  38. package/src/core/ast/symbols.ts +294 -0
  39. package/src/core/ast/types.ts +125 -0
  40. package/src/core/brief.ts +138 -0
  41. package/src/core/commands/findings.ts +120 -6
  42. package/src/core/commands/review.ts +2 -0
  43. package/src/core/commands/scaffold.ts +159 -10
  44. package/src/core/commands/status.ts +63 -0
  45. package/src/core/commands/update.ts +5 -3
  46. package/src/core/config.ts +85 -0
  47. package/src/core/defaults.ts +27 -0
  48. package/src/core/domain/watchdog.ts +43 -5
  49. package/src/core/engine/houndsman-engine.ts +16 -1
  50. package/src/core/engine/review-scope.ts +77 -13
  51. package/src/core/engine/review-session.ts +27 -2
  52. package/src/core/env.ts +101 -0
  53. package/src/core/file-classifier.ts +25 -4
  54. package/src/core/findings-state.ts +21 -4
  55. package/src/core/github-review.ts +620 -57
  56. package/src/core/jev/jev-client.ts +8 -7
  57. package/src/core/jev/jev-verify.ts +2 -1
  58. package/src/core/logging/index.ts +17 -0
  59. package/src/core/logging/logger.ts +187 -0
  60. package/src/core/orchestrator.ts +454 -16
  61. package/src/core/paths.ts +3 -0
  62. package/src/core/project-config.ts +123 -1
  63. package/src/core/registry-check.ts +148 -6
  64. package/src/core/renderers/manifest-writer.ts +33 -0
  65. package/src/core/renderers/resume-renderer.ts +151 -0
  66. package/src/core/report-builder.ts +7 -4
  67. package/src/core/rule-text.ts +97 -0
  68. package/src/core/run-status.ts +39 -5
  69. package/src/core/services/file-classifier.ts +10 -3
  70. package/src/core/services/verifier.ts +14 -3
  71. package/src/core/storage/file/file-storage.ts +2 -0
  72. package/src/core/storage/paths.ts +6 -5
  73. package/src/core/storage/sqlite/mappers.ts +2 -0
  74. package/src/core/storage/sqlite/schema.ts +9 -1
  75. package/src/core/storage/sqlite/sqlite-storage.ts +5 -1
  76. package/src/core/storage/types.ts +15 -0
  77. package/src/core/storage/work-area.ts +12 -0
  78. package/src/core/types.ts +37 -1
  79. package/src/core/verify.ts +17 -5
  80. package/src/harness/README.md +15 -0
  81. package/src/harness/agent/agent-context.ts +33 -0
  82. package/src/harness/agent/agent-errors.ts +30 -0
  83. package/src/harness/agent/agent-factory.ts +45 -0
  84. package/src/harness/agent/agent-reporter.ts +34 -0
  85. package/src/harness/agent/agent-result.ts +16 -0
  86. package/src/harness/agent/agent-runner.ts +32 -0
  87. package/src/harness/agent/agent-scheduler.ts +37 -0
  88. package/src/harness/agent/review-agent.ts +391 -0
  89. package/src/harness/config/harness-config.ts +84 -0
  90. package/src/harness/hunt/hunt-harness.ts +83 -0
  91. package/src/harness/hunt/hunt-options.ts +75 -0
  92. package/src/harness/hunt/hunt-result.ts +17 -0
  93. package/src/harness/hunt/hunt-session.ts +372 -0
  94. package/src/harness/hunt/review-planner.ts +98 -0
  95. package/src/harness/index.ts +36 -0
  96. package/src/harness/investigation/agent-state.ts +134 -0
  97. package/src/harness/investigation/evidence-verifier.ts +129 -0
  98. package/src/harness/investigation/evidence.ts +110 -0
  99. package/src/harness/investigation/finding-critic.ts +96 -0
  100. package/src/harness/investigation/investigation-planner.ts +118 -0
  101. package/src/harness/investigation/investigation-task.ts +10 -0
  102. package/src/harness/investigation/review-journal.ts +87 -0
  103. package/src/harness/investigation/rule-analyzer.ts +178 -0
  104. package/src/harness/investigation/rule-signals.ts +110 -0
  105. package/src/harness/prompts/agent-schemas.ts +57 -0
  106. package/src/harness/prompts/reviewer-prompt-builder.ts +101 -0
  107. package/src/harness/prompts/states/conclude-prompt.ts +16 -0
  108. package/src/harness/prompts/states/investigate-prompt.ts +37 -0
  109. package/src/harness/prompts/states/orient-prompt.ts +15 -0
  110. package/src/harness/prompts/states/verify-prompt.ts +22 -0
  111. package/src/harness/tools/agent-tool.ts +102 -0
  112. package/src/harness/tools/builtin/changed-symbols-tool.ts +48 -0
  113. package/src/harness/tools/builtin/doc-context-tool.ts +74 -0
  114. package/src/harness/tools/builtin/file-outline-tool.ts +66 -0
  115. package/src/harness/tools/builtin/find-references-tool.ts +66 -0
  116. package/src/harness/tools/builtin/find-symbol-tool.ts +91 -0
  117. package/src/harness/tools/builtin/helpers.ts +115 -0
  118. package/src/harness/tools/builtin/impact-tool.ts +48 -0
  119. package/src/harness/tools/builtin/imports-exports-tool.ts +53 -0
  120. package/src/harness/tools/builtin/index.ts +59 -0
  121. package/src/harness/tools/builtin/list-files-tool.ts +85 -0
  122. package/src/harness/tools/builtin/pr-context-tool.ts +41 -0
  123. package/src/harness/tools/builtin/read-file-range-tool.ts +73 -0
  124. package/src/harness/tools/builtin/rule-signals-tool.ts +36 -0
  125. package/src/harness/tools/builtin/search-code-tool.ts +65 -0
  126. package/src/harness/tools/builtin/symbol-context-tool.ts +106 -0
  127. package/src/harness/tools/builtin/tests-for-symbol-tool.ts +61 -0
  128. package/src/harness/tools/path-guard.ts +90 -0
  129. package/src/harness/tools/result-limiter.ts +49 -0
  130. package/src/harness/tools/secret-redactor.ts +54 -0
  131. package/src/harness/tools/tool-cache.ts +50 -0
  132. package/src/harness/tools/tool-call-budget.ts +60 -0
  133. package/src/harness/tools/tool-context.ts +5 -0
  134. package/src/harness/tools/tool-middleware.ts +105 -0
  135. package/src/harness/tools/tool-policy.ts +51 -0
  136. package/src/harness/tools/tool-registry.ts +112 -0
  137. package/src/harness/tools/tool-result.ts +15 -0
  138. package/src/harness/tools/toolbox.ts +36 -0
  139. package/src/harness/validation/finding-validator.ts +119 -0
  140. package/src/index.ts +46 -0
  141. package/src/server/client/App.tsx +26 -9
  142. package/src/server/client/ArtifactsPanel.tsx +12 -5
  143. package/src/server/client/AutoRefresh.tsx +1 -1
  144. package/src/server/client/Filters.tsx +7 -2
  145. package/src/server/client/FindingCard.tsx +14 -10
  146. package/src/server/client/FindingsList.tsx +2 -2
  147. package/src/server/client/MarkdownText.tsx +92 -12
  148. package/src/server/client/ResumePanel.tsx +368 -0
  149. package/src/server/client/RunList.tsx +3 -3
  150. package/src/server/client/SubmitModal.tsx +49 -6
  151. package/src/server/client/SummaryBar.tsx +1 -1
  152. package/src/server/client/icons.tsx +17 -0
  153. package/src/server/client/{constants.ts → utils/constants.ts} +61 -10
  154. package/src/server/client/utils/markdown.ts +319 -0
  155. package/src/server/client/{types.ts → utils/types.ts} +64 -0
  156. package/src/server/index.ts +66 -7
  157. package/src/server/run-repository.ts +9 -0
  158. package/src/skill/OUTPUT-FORMAT.md +12 -0
  159. package/src/skill/SETUP.md +6 -2
  160. package/src/skill/example-review.md +22 -14
  161. package/src/skill/hunt.md +45 -19
  162. package/src/skill/verify.md +3 -2
  163. package/src/tests/__snapshots__/baseline.test.ts.snap +126 -42
  164. package/src/tests/ai-core.test.ts +120 -0
  165. package/src/tests/ai-features.test.ts +183 -0
  166. package/src/tests/ast.test.ts +335 -0
  167. package/src/tests/baseline.test.ts +3 -0
  168. package/src/tests/code-highlight.test.ts +1 -1
  169. package/src/tests/env.test.ts +69 -0
  170. package/src/tests/fallback.test.ts +172 -0
  171. package/src/tests/findings-state.test.ts +50 -2
  172. package/src/tests/fixtures/fake-agent-tools.ts +69 -0
  173. package/src/tests/fixtures/fake-investigation.ts +64 -0
  174. package/src/tests/fixtures/fake-model-provider.ts +48 -0
  175. package/src/tests/github-review.test.ts +409 -60
  176. package/src/tests/harness-agent.test.ts +122 -0
  177. package/src/tests/harness-investigation.test.ts +206 -0
  178. package/src/tests/harness-tools.test.ts +148 -0
  179. package/src/tests/hunt-command.test.ts +212 -0
  180. package/src/tests/logger.test.ts +83 -0
  181. package/src/tests/markdown.test.ts +61 -1
  182. package/src/tests/review-resume.test.ts +101 -0
  183. package/src/tests/review-scope.test.ts +302 -0
  184. package/src/tests/review-scripts.test.ts +73 -0
  185. package/src/tests/rule-analyzer.test.ts +61 -0
  186. package/src/tests/run-status-view.test.ts +94 -0
  187. package/src/tests/run-status.test.ts +53 -0
  188. package/src/tests/server.test.ts +76 -21
  189. package/src/tests/storage.test.ts +63 -0
  190. package/src/tests/tool-contracts.test.ts +82 -0
  191. package/src/tests/verify.test.ts +1 -1
  192. package/src/server/client/markdown.ts +0 -153
  193. /package/src/server/client/{api.ts → utils/api.ts} +0 -0
  194. /package/src/server/client/{code-highlight.ts → utils/code-highlight.ts} +0 -0
  195. /package/src/server/client/{format.ts → utils/format.ts} +0 -0
  196. /package/src/server/client/{json-highlight.ts → utils/json-highlight.ts} +0 -0
@@ -14,6 +14,7 @@ import {
14
14
  type GhRunner,
15
15
  type SubmitSelection,
16
16
  } from "../core/github-review";
17
+ import { logger } from "../core/logging";
17
18
  import { createStorage } from "../core/storage/factory";
18
19
  import { resolveRepoIdentity } from "../core/storage/repo-identity";
19
20
  import type { RepoIdentity, StorageProvider } from "../core/storage/types";
@@ -190,8 +191,8 @@ export class HoundsmanServer {
190
191
  try {
191
192
  this.runs.maintain();
192
193
  } catch (error) {
193
- console.warn(
194
- `[houndsman] VACUUM falhou (seguindo sem compactar): ${
194
+ logger.warn(
195
+ `VACUUM falhou (seguindo sem compactar): ${
195
196
  error instanceof Error ? error.message : String(error)
196
197
  }`,
197
198
  );
@@ -315,7 +316,7 @@ code, pre, .mono { font-family:var(--font-mono); tab-size:4; }
315
316
  .btn:disabled { opacity:.55; cursor:not-allowed; }
316
317
  .icon.spin { animation:spin .8s linear infinite; }
317
318
  .content { width:100%; max-width:1180px; margin:0 auto; padding:22px 24px 64px; }
318
- .page-header { display:flex; align-items:flex-start; justify-content:space-between; gap:18px; }
319
+ .page-header { display:flex; align-items:flex-start; justify-content:space-between; gap:18px; margin-bottom:16px; }
319
320
  .page-header-text { min-width:0; }
320
321
  .page-header-actions { display:flex; align-items:center; gap:10px; flex:none; }
321
322
  .btn.submit-review { color:#1b1305; background:linear-gradient(180deg, var(--accent-strong), var(--accent)); border-color:transparent; box-shadow:0 4px 14px rgba(240,165,44,.22); }
@@ -412,12 +413,25 @@ code, pre, .mono { font-family:var(--font-mono); tab-size:4; }
412
413
  .action-text p:last-child { margin-bottom:0; }
413
414
  .md-list { margin:0 0 6px; padding-left:20px; font-size:13px; line-height:1.65; color:#f0ece6; }
414
415
  .md-list li { margin:0 0 2px; }
415
- .md-quote { margin:0 0 6px; padding:2px 0 2px 10px; border-left:2px solid var(--accent-line); color:var(--muted); font-size:13px; line-height:1.65; }
416
+ .md-quote { margin:0 0 6px; padding:2px 0 2px 10px; border-left:2px solid var(--accent-line); color:var(--muted); font-size:13px; line-height:1.65; white-space:pre-wrap; }
416
417
  .action-text code, .md-code { font-family:var(--font-mono); font-size:11.5px; padding:1px 5px; color:#f0ece6; background:rgba(255,255,255,.06); border:1px solid var(--border); border-radius:5px; }
417
- .action-text a { color:var(--accent-strong); text-decoration:underline; text-underline-offset:2px; }
418
- .action-text strong { color:#fff; font-weight:600; }
419
- .action-text em { color:#e9e4dc; }
418
+ code.md-path { color:#8fc7ff; background:rgba(90,164,240,.1); border-color:rgba(90,164,240,.24); }
419
+ .action-text a, .md-p a, .md-list a, .md-quote a, .md-table a, .md-h a { color:var(--accent-strong); text-decoration:underline; text-underline-offset:2px; }
420
+ .action-text strong, .md-p strong, .md-list strong, .md-quote strong, .md-table strong, .md-h strong { color:#fff; font-weight:600; }
421
+ .action-text em, .md-p em, .md-list em, .md-quote em, .md-table em, .md-h em { color:#e9e4dc; }
420
422
  .md-code-block { margin:6px 0; padding:10px 12px; max-height:320px; overflow:auto; white-space:pre; font-size:11.5px; line-height:1.6; color:#cdc7bf; background:#0b0b0e; border-radius:10px; }
423
+ .md-h { margin:16px 0 8px; font-size:14px; font-weight:700; line-height:1.35; letter-spacing:-.01em; color:#eee9e2; }
424
+ .md-h:first-child { margin-top:0; }
425
+ .md-h1 { font-size:19px; }
426
+ .md-h2 { font-size:16px; }
427
+ .md-h3 { font-size:14px; }
428
+ .md-h4, .md-h5, .md-h6 { font-size:13px; color:#e4dfd7; font-weight:600; }
429
+ .md-hr { margin:14px 0; border:0; border-top:1px solid var(--border); }
430
+ .md-table-wrap { margin:8px 0 12px; padding:4px; overflow-x:auto; border:1px solid rgba(255,255,255,.07); border-radius:10px; background:rgba(255,255,255,.012); }
431
+ .md-table { width:100%; border-collapse:separate; border-spacing:3px; font-size:12px; line-height:1.5; }
432
+ .md-table th, .md-table td { padding:6px 9px; text-align:left; vertical-align:top; border:1px solid rgba(255,255,255,.035); border-radius:6px; }
433
+ .md-table th { color:var(--muted); font-weight:600; background:rgba(255,255,255,.03); }
434
+ .md-table td { color:#d8d3cc; }
421
435
  .decision-tags-block { display:flex; align-items:center; gap:8px; }
422
436
  .evidence { margin:0; padding: 16px; white-space:break-spaces; font-size:12px; line-height:1.6; color:#cdc7bf;
423
437
  background:#0b0b0e; border:1px solid var(--border); border-radius:var(--radius); }
@@ -476,6 +490,10 @@ code, pre, .mono { font-family:var(--font-mono); tab-size:4; }
476
490
  border:1px solid var(--accent-line); border-radius:999px; }
477
491
  .artifact-view { margin:0; padding:14px 16px; max-height:70vh; overflow:auto; font-size:12px; line-height:1.6; color:#cdc7bf;
478
492
  background:#0b0b0e; border:1px solid var(--border); border-radius:var(--radius); }
493
+ .artifact-markdown { white-space:normal; }
494
+ .artifact-markdown .md-p, .artifact-markdown .md-list, .artifact-markdown .md-quote { font-size:12.5px; }
495
+ .artifact-markdown .md-p, .artifact-markdown .md-list { color:#d8d3cc; }
496
+ .artifact-markdown .md-code-block { border:1px solid var(--border); }
479
497
  .json-view { white-space:pre; }
480
498
  .json-key { color:var(--accent-strong); }
481
499
  .json-string { color:#9ddc8a; }
@@ -486,6 +504,47 @@ code, pre, .mono { font-family:var(--font-mono); tab-size:4; }
486
504
  .sent-tag { display:inline-flex; align-items:center; gap:5px; padding:2px 8px; font-size:10px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
487
505
  color:var(--success); background:rgba(69,192,122,.12); border:1px solid rgba(69,192,122,.32); border-radius:999px; text-decoration:none; }
488
506
  .sent-tag:hover { color:#fff; }
507
+ .sent-tag.gh { color:#b9c7d6; background:rgba(139,164,191,.12); border-color:rgba(139,164,191,.35); }
508
+ .sent-tag.gh:hover { color:#fff; background:rgba(139,164,191,.2); }
509
+ .resume { display:flex; flex-direction:column; }
510
+ .resume-hero { display:flex; align-items:flex-start; justify-content:space-between; gap:16px; padding:18px 20px;
511
+ background:linear-gradient(135deg, rgba(240,165,44,.08), rgba(255,255,255,.015) 55%);
512
+ border:1px solid var(--border); border-radius:var(--radius-lg); }
513
+ .resume-kicker { display:block; font-size:10px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:var(--accent); }
514
+ .resume-title { margin:5px 0 7px; font-size:22px; font-weight:700; letter-spacing:-.02em; word-break:break-word; }
515
+ .resume-meta { display:flex; flex-wrap:wrap; align-items:center; gap:12px; margin:0; font-size:12px; color:var(--muted); }
516
+ .resume-pr { display:inline-flex; align-items:center; gap:5px; color:var(--accent-strong); text-decoration:none; }
517
+ .resume-pr:hover { text-decoration:underline; }
518
+ .resume-hero-side { display:flex; flex:none; flex-direction:column; align-items:flex-end; gap:10px; }
519
+ .resume-status { display:inline-flex; align-items:center; padding:5px 12px; font-size:11px; font-weight:700; letter-spacing:.04em; border-radius:999px; }
520
+ .resume-status.blocking { color:var(--blocking); background:rgba(242,89,94,.12); border:1px solid rgba(242,89,94,.35); }
521
+ .resume-status.attention { color:var(--attention); background:rgba(237,161,58,.12); border:1px solid rgba(237,161,58,.35); }
522
+ .resume-status.clean { color:var(--success); background:rgba(69,192,122,.12); border:1px solid rgba(69,192,122,.35); }
523
+ .resume-kpis { margin:14px 0 18px; }
524
+ .resume-kpis .kpi-value { font-size:24px; }
525
+ .churn-add { color:var(--success); }
526
+ .churn-del { color:var(--blocking); }
527
+ .churn-sep { margin:0 3px; color:var(--muted-2); font-weight:400; }
528
+ .kpi-blocking .kpi-value { color:var(--blocking); }
529
+ .kpi-attention .kpi-value { color:var(--attention); }
530
+ .kpi-total .kpi-value { color:var(--fg); }
531
+ .resume-grid { display:grid; grid-template-columns:minmax(0,1.35fr) minmax(0,1fr); gap:16px; align-items:start; }
532
+ .resume-card { min-width:0; padding:16px 18px; background:var(--card); border:1px solid var(--border); border-radius:var(--radius-lg); }
533
+ .resume-card-head { display:flex; align-items:center; justify-content:space-between; gap:10px; }
534
+ .resume-card-title { margin:0 0 10px; font-size:12px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
535
+ .resume-card-count { display:inline-flex; align-items:center; justify-content:center; min-width:22px; height:22px; margin-bottom:10px; padding:0 7px;
536
+ font-family:var(--font-mono); font-size:11px; color:var(--accent); background:var(--accent-soft); border:1px solid var(--accent-line); border-radius:999px; }
537
+ .resume-narrative .md-p:last-child { margin-bottom:0; }
538
+ .resume-domains { display:flex; flex-direction:column; gap:8px; margin:0; padding:0; list-style:none; }
539
+ .resume-domain { display:flex; flex-direction:column; gap:7px; padding:10px 12px; background:var(--surface-2);
540
+ border:1px solid var(--border); border-radius:10px; }
541
+ .resume-domain-head { display:flex; align-items:baseline; justify-content:space-between; gap:10px; }
542
+ .resume-domain-name { font-size:12.5px; font-weight:600; color:var(--fg); }
543
+ .resume-domain-files { flex:none; font-family:var(--font-mono); font-size:10.5px; color:var(--muted-2); }
544
+ .resume-domain-sev { display:flex; flex-wrap:wrap; gap:6px; }
545
+ .resume-domain-sev .sev-badge { padding:2px 7px; font-size:9.5px; }
546
+ .resume-domain-ok { font-size:11.5px; color:var(--success); }
547
+ @media (max-width:900px) { .resume-grid { grid-template-columns:1fr; } .resume-hero { flex-direction:column; } .resume-hero-side { flex-direction:row; align-items:flex-start; } }
489
548
  .modal-layer { position:fixed; inset:0; z-index:50; display:grid; place-items:center; padding:24px; }
490
549
  .modal-backdrop { position:absolute; inset:0; width:100%; padding:0; background:rgba(5,5,7,.66); border:0; cursor:default; backdrop-filter:blur(5px); -webkit-backdrop-filter:blur(5px); }
491
550
  .modal { position:relative; width:min(640px, 100%); max-height:min(78vh, 780px); display:flex; flex-direction:column; overflow:hidden;
@@ -30,6 +30,7 @@ import {
30
30
  resolvePrTarget,
31
31
  type SubmitSelection,
32
32
  submitFindings,
33
+ syncResolvedThreads,
33
34
  } from "../core/github-review";
34
35
  import { pingFindingsStatus } from "../core/run-status";
35
36
  import { systemClock } from "../core/services/clock";
@@ -42,6 +43,8 @@ export type RunListItem = {
42
43
  slug: string;
43
44
  branch: string;
44
45
  updatedAt?: string;
46
+ startedAt?: string;
47
+ heartbeatAt?: string;
45
48
  status: ReviewRecord["status"];
46
49
  summary: FindingsSummary;
47
50
  };
@@ -94,6 +97,8 @@ export class RunRepository {
94
97
  slug: review.slug,
95
98
  branch: review.branch,
96
99
  updatedAt: review.updatedAt,
100
+ startedAt: review.startedAt,
101
+ heartbeatAt: review.heartbeatAt,
97
102
  status: review.status,
98
103
  summary: summarize(state ?? emptyState(review.branch)),
99
104
  };
@@ -211,6 +216,10 @@ export class RunRepository {
211
216
  if (resolution.status !== "found") return null;
212
217
  const finding = state.findings[resolution.id];
213
218
  applyFindingUpdate(finding, body);
219
+ // "Done" na UI é resolução local: resolve a conversa no PR (fail-open).
220
+ if (body.execState === "done") {
221
+ syncResolvedThreads({ state, ids: [finding.id] });
222
+ }
214
223
  reorder(state);
215
224
  state.updatedAt = systemClock();
216
225
  this.storage.writeFindings(review.id, state);
@@ -70,3 +70,15 @@ staging global da review:
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
72
  - Não inventar achados — se não houver violação, o array fica vazio.
73
+
74
+ ## Findings emergentes (opt-in)
75
+
76
+ Quando o watchdog declara `allowEmergentFindings: true`, você pode reportar falhas de
77
+ **lógica** ou **domínio** que não correspondem a uma regra explícita usando os prefixos
78
+ reservados:
79
+
80
+ - `Lógica: <descrição>` — nome/contrato vs comportamento, fluxos, estados, bordas.
81
+ - `Domínio: <descrição>` — transições, idempotência, invariantes, arredondamento, timezone.
82
+
83
+ Esses findings continuam exigindo `evidence` e têm severidade máxima `attention`. Sem o
84
+ opt-in, todo finding precisa citar uma regra existente.
@@ -7,8 +7,11 @@ no seu projeto é **autocontida** — não exige nenhuma dependência local do p
7
7
 
8
8
  - **Bun** — o CLI e o motor usam a runtime Bun (execução de TS, `Bun.spawnSync`).
9
9
  - **git** — o diff usa `git diff <base>...<head> --name-status`.
10
- - Opcional: **`gh`** (contexto da PR) e **`TYPESAFE_API_KEY`** (pré-análise Jev). O pipeline
11
- segue normalmente sem eles.
10
+ - **gh** (Opcional) — Obtém contexto da PR e dispara comentários para o GitHub
11
+ - **`HOUNDSMAN_TYPE_SAFE_API_KEY`** (opcional) — pré-análise Jev.
12
+ - **`HOUNDSMAN_DEEP_SEEK_API_KEY`** (opcional) — IA própria do `hunt` nativo e das features de IA.
13
+ - **`HOUNDSMAN_OPENAI_API_KEY`** / **`HOUNDSMAN_ANTHROPIC_API_KEY`** (opcional) — apenas se
14
+ `ai.provider` for `openai`/`anthropic`.
12
15
 
13
16
  ## Instalação (global)
14
17
 
@@ -87,6 +90,7 @@ Definido em `src/core/config.ts` (pacote) e espelhado em `.houndsman/core/types.
87
90
  | `alwaysIncludeDocs` | Docs sempre presentes nos briefs (default `["AGENTS.md"]`). |
88
91
  | `budgets` | **Opcional** — teto de arquivos por brief (`maxFilesPerBrief`, default `40`); o excedente vira "fora do orçamento" (registrar em `skipped`). |
89
92
  | `concurrency` | **Opcional** — chamadas Jev simultâneas (`jev`, default `5`). |
93
+ | `ast` | **Opcional** — AST determinístico para TS/JS (`enabled`, `maxFileBytes`, `maxImpactFiles`, `languages`, `aliases`). Default: ligado; falhas são fail-open. |
90
94
 
91
95
  > O motor **não contém** ids, paths ou regras do projeto — tudo chega por `HoundsmanConfig`,
92
96
  > carregado em runtime a partir de `houndsman.config.ts` (ou `--config <path>`).
@@ -14,6 +14,28 @@
14
14
  - Novo endpoint interno para reprocessar eventos manualmente.
15
15
  - Registro de tentativas no handler de envio.
16
16
 
17
+ ## Relatórios por domínio
18
+
19
+ | Watchdog | Achados | Revisados | Relatório |
20
+ |---|---|---|---|
21
+ | Arquitetura Backend | 2 | 3/3 | [`review.backend-architecture.md`](review.backend-architecture.md) |
22
+ | Pagamentos & Integrações | 1 | 4/4 | [`review.payments-integrations.md`](review.payments-integrations.md) |
23
+ | Acquirer Integrations | 2 | 3/4 | [`review.acquirer-integrations.md`](review.acquirer-integrations.md) |
24
+
25
+ ## Cobertura
26
+
27
+ | Watchdog | Arquivos revisados | Findings |
28
+ |---|---|---|
29
+ | API & Contratos | 2 | 0 |
30
+ | Arquitetura Backend | 3 | 2 |
31
+ | Pagamentos & Integrações | 4 | 1 |
32
+ | Acquirer Integrations | 3/4 (faltam 1) | 2 |
33
+
34
+ ## Conclusão
35
+
36
+ **Status:** ❌ Mudanças Necessárias
37
+ **Resumo:** 2 violações bloqueantes, 1 ponto de atenção, 1 sugestão e 1 nit.
38
+
17
39
  ## ❌ blocking
18
40
 
19
41
  - **Webhook handler sem verifySignature** — `server/src/services/integrations/acquirer/webhook/handle-charge-event.ts:15` · _Acquirer Integrations, Pagamentos & Integrações_
@@ -42,17 +64,3 @@
42
64
  - **Ordem de membros** — `server/src/services/webhook/webhook-retry-service.ts:12` · _Arquitetura Backend_
43
65
  Campo privado declarado antes do construtor público.
44
66
  **Ação:** Reordenar membros (públicos primeiro).
45
-
46
- ## Cobertura
47
-
48
- | Watchdog | Arquivos revisados | Findings |
49
- |---|---|---|
50
- | API & Contratos | 2 | 0 |
51
- | Arquitetura Backend | 3 | 1 |
52
- | Pagamentos & Integrações | 4 | 2 |
53
- | Acquirer Integrations | 3/4 (faltam 1) | 2 |
54
-
55
- ## Conclusão
56
-
57
- **Status:** ❌ Mudanças Necessárias
58
- **Resumo:** 2 violações bloqueantes, 1 ponto de atenção, 1 sugestão.
package/src/skill/hunt.md CHANGED
@@ -10,6 +10,11 @@ as regras do projeto ficam em `houndsman.config.ts` + `.houndsman/`.
10
10
  **Quando usar:** revisar PR antes de merge · code review de feature branch · validar
11
11
  mudanças antes de push.
12
12
 
13
+ > **Harness nativo (opcional):** além deste skill, o CLI tem `houndsman hunt` — o mesmo
14
+ > fluxo executado pelo próprio houndsman, com tools read-only, investigação por evidência
15
+ > e `VERIFY` obrigatório. Use `houndsman hunt --dry-run` para inspecionar sem IA. Detalhes
16
+ > em `docs/HARNESS.md`.
17
+
13
18
  ## Quem executa o quê
14
19
 
15
20
  - **Você** só invoca o skill: `/houndsman [hunt]`. Não precisa rodar nenhum script à mão.
@@ -76,6 +81,8 @@ staging dos subagentes em `<HOUNDSMAN_HOME>/work/<reviewId>/`:
76
81
  | Artefato | Conteúdo |
77
82
  |---|---|
78
83
  | `classification.json` | Watchdogs ativados por arquivo + status (A/M/D/R) + churn (storage) |
84
+ | `ast-summary.json` | Fatos estruturais + delta por arquivo (AST TS/JS) (storage) |
85
+ | `ast-impact.json` | Importadores reversos e exports públicos alterados (storage) |
79
86
  | `candidates.json` | Indícios da pré-análise Jev (regra + arquivo + confiança) (storage) |
80
87
  | `briefs/<watchdog>.md` | Instruções prontas para cada subagente (staging + storage, para auditoria) |
81
88
  | `manifest.json` | Resumo: watchdogs, arquivos, deletados, status, contexto, Jev, orçamento (storage) |
@@ -83,6 +90,11 @@ staging dos subagentes em `<HOUNDSMAN_HOME>/work/<reviewId>/`:
83
90
  > O prepare imprime o caminho absoluto do diretório de briefs e cada brief traz o
84
91
  > `outputPath` do JSON que o subagente deve gravar. Briefs e contexto também ficam
85
92
  > persistidos no storage para auditoria; o staging é limpo após o `--finalize`.
93
+ >
94
+ > **AST (TS/JS, ligado por padrão):** cada brief ganha a seção `Estrutura (AST)` com
95
+ > símbolos adicionados/removidos/alterados, assinaturas e imports; o impacto reverso
96
+ > (quem importa os arquivos alterados) aparece como mapa de leitura. É fail-open:
97
+ > sem grammar/ABI, a revisão segue só com regex. Desative com `--no-ast`.
86
98
 
87
99
  **Excluídos automaticamente:** lock files, `dist/`, `build/`, `.env*`, imagens, source
88
100
  maps (padrões do projeto em `.houndsman/exclusions.ts`).
@@ -106,7 +118,7 @@ arquivos da PR. Cada brief recebe no máximo `budgets.maxFilesPerBrief` arquivos
106
118
 
107
119
  ### Pré-análise Jev (Passo 1.5, opcional)
108
120
 
109
- Se `TYPESAFE_API_KEY` estiver definida, cada arquivo é avaliado pelo modelo **Jev** contra
121
+ Se `HOUNDSMAN_TYPE_SAFE_API_KEY` estiver definida, cada arquivo é avaliado pelo modelo **Jev** contra
110
122
  as regras atômicas dos watchdogs. Respostas acima do limiar viram **candidatos** em
111
123
  `candidates.json` e entram no brief como *warm start* — o subagente **confirma ou refuta**.
112
124
 
@@ -122,11 +134,14 @@ arquivos alterados desde a última revisão — e **carrega** os findings dos ar
122
134
  (carry-over), sem re-revisá-los. O `manifest.json` traz o bloco `incremental` (`from`,
123
135
  `changedFiles`, `carried`) e o `review.md` abre com um aviso.
124
136
 
125
- - Sem mudanças desde a última revisão → **no-op** (nada a revisar; o estado é preservado).
137
+ - Sem mudanças desde a última revisão → **no-op**: o prepare não gera briefs nem reescreve
138
+ artefatos (classification, manifest, review.md), e o `--finalize` também vira no-op — pare o
139
+ fluxo aí (nenhum subagente é despachado).
126
140
  - Rebase/force-push (histórico reescrito) → cai automaticamente no **review completo**.
127
141
  - Forçar completo: `houndsman --full` (ou `--clean`, que também descarta a triagem anterior).
128
142
 
129
143
  > Custo: o LLM só é gasto nos arquivos que mudaram desde a última revisão — não na PR inteira.
144
+ > Re-rodar `/houndsman` no mesmo commit **não** re-revisa a PR; use `--full` para isso.
130
145
 
131
146
  ---
132
147
 
@@ -135,6 +150,10 @@ arquivos alterados desde a última revisão — e **carrega** os findings dos ar
135
150
  Um subagente por brief. Despache em **ondas** (ex.: até 8 subagentes por bloco de tool
136
151
  calls) — evita estourar limites de taxa quando há muitos watchdogs. O prompt é o próprio brief:
137
152
 
153
+ > **Heartbeat:** antes de despachar cada onda, rode `houndsman status ping`. A UI usa esse
154
+ > sinal (e não `updatedAt`) para saber que a execução está viva; sem ping por 10 min ela
155
+ > mostra "Timeout na revisão".
156
+
138
157
  ```
139
158
  Leia e execute o brief: <caminho absoluto impresso pelo prepare>/briefs/<watchdog-id>.md
140
159
  Você é o watchdog <watchdog-id> do {{projectName}}.
@@ -158,15 +177,18 @@ houndsman --finalize
158
177
  Falha com mensagem clara se faltar algum `findings/<watchdog>.json` no staging. Quando todos existem:
159
178
  1. Valida o schema de cada JSON
160
179
  2. Deduplica achados por `(file, line, rule)` mesclando watchdogs sobrepostos
161
- 3. Agrupa por severidade: ❌ blocking > ⚠️ attention > 💡 suggestion > 🔎 nit
162
- 4. Grava o artefato `review.md` no storage + tabela de cobertura
163
- 5. Anexa os candidatos Jev não confirmados em `🔎 Candidatos não verificados` (não bloqueiam)
164
- 6. Agrupa os achados **por arquivo** dentro de cada severidade (navegabilidade em PRs grandes)
165
- 7. Grava um `review.<watchdog>.md` por watchdog com achados e indexa no `review.md`
180
+ 3. Grava um `review.<watchdog>.md` por watchdog com achados e indexa no `review.md`
166
181
  (**Relatórios por domínio**) — mantém o relatório consolidado enxuto
167
- 8. Persiste a **triagem** no storage — um `id` curto e um `fingerprint` de conteúdo por
168
- finding, preservados entre execuções
169
-
182
+ 4. Grava o `review.md` abrindo pelo **sumário**: contexto, relatórios por domínio, cobertura e
183
+ conclusão — antes dos achados
184
+ 5. Agrupa os achados por severidade (❌ blocking > ⚠️ attention > 💡 suggestion > 🔎 nit) e
185
+ **por arquivo** dentro de cada severidade (navegabilidade em PRs grandes)
186
+ 6. Anexa os candidatos Jev não confirmados em `🔎 Candidatos não verificados` ao final
187
+ (não bloqueiam)
188
+ 7. Persiste a **triagem** no storage — um `id` curto e um `fingerprint` de conteúdo por
189
+ finding, preservados entre execuções9. Marca como **`done`** os findings que sumiram do relatório (corrigidos manualmente entre
190
+ revisões) e **resolve as conversas correspondentes no GitHub** — só as ainda abertas, e
191
+ falha-aberto (sem `gh`/PR o relatório segue igual)
170
192
  Após finalizar, corrija os achados com a capability **`fix`** (`fix.md`): a UI ou os
171
193
  comandos `findings` levam do achado à correção.
172
194
 
@@ -188,14 +210,6 @@ comandos `findings` levam do achado à correção.
188
210
  **Resumo das alterações:**
189
211
  - ...
190
212
 
191
- ## ❌ blocking
192
- ### `src/routes/order-route.ts`
193
- - **<regra>** — `src/routes/order-route.ts:5` · _<watchdogs>_
194
- <mensagem>
195
- **Ação:** <ação>
196
-
197
- ## 🔎 Candidatos não verificados (Jev) ← se houver
198
-
199
213
  ## Relatórios por domínio
200
214
  | Watchdog | Achados | Revisados | Relatório |
201
215
  |---|---|---|---|
@@ -206,8 +220,19 @@ comandos `findings` levam do achado à correção.
206
220
 
207
221
  ## Conclusão
208
222
  **Status:** ✅ Aprovado / ⚠️ Aprovado com Ressalvas / ❌ Mudanças Necessárias
223
+
224
+ ## ❌ blocking
225
+ ### `src/routes/order-route.ts`
226
+ - **<regra>** — `src/routes/order-route.ts:5` · _<watchdogs>_
227
+ <mensagem>
228
+ **Ação:** <ação>
229
+
230
+ ## 🔎 Candidatos não verificados (Jev) ← se houver, sempre ao final
209
231
  ```
210
232
 
233
+ > O **sumário** (relatórios por domínio, cobertura e conclusão) vem **antes** dos achados;
234
+ > os pontos específicos ficam no fim.
235
+
211
236
  ---
212
237
 
213
238
  ## Fluxo Completo
@@ -246,11 +271,12 @@ Se a branch não for informada, detecta com `git branch --show-current`. Base do
246
271
  |---|---|
247
272
  | `houndsman context` | Passo 0 — contexto da PR via `gh` |
248
273
  | `houndsman` | Passo 1 — preparar (briefs + manifesto; incremental quando possível) |
274
+ | `houndsman status ping` | Passo 2 — heartbeat da execução (antes de cada onda) |
249
275
  | `houndsman --finalize` | Passo 3 — gerar o relatório |
250
276
  | `houndsman watchdog <id>` | Contexto de um watchdog (`--json`, `--rules`) |
251
277
 
252
278
  Flags do review: `--base` · `--head` · `--branch` · `--clean` · `--full` (força
253
- completo) · `--no-jev` · `--fail-on-blocking` (com `--finalize`).
279
+ completo) · `--no-jev` · `--no-ast` · `--fail-on-blocking` (com `--finalize`).
254
280
 
255
281
  > Persistência: SQLite global em `<HOUNDSMAN_HOME>/houndsman.db`. O staging dos subagentes
256
282
  > (`briefs/`, `findings/`, contexto) vive em `<HOUNDSMAN_HOME>/work/<reviewId>/` e é limpo
@@ -24,7 +24,7 @@ altera regras.
24
24
  - **âncora sumida** (`stale`) → provável **resolvido** — mas o trecho pode ter sido reescrito;
25
25
  - **arquivo ausente** → fora da verificação (deletado/movido).
26
26
 
27
- 2. **Tier Jev (opcional, só nos ambíguos).** Com `TYPESAFE_API_KEY`, os casos `stale` / sem
27
+ 2. **Tier Jev (opcional, só nos ambíguos).** Com `HOUNDSMAN_TYPE_SAFE_API_KEY`, os casos `stale` / sem
28
28
  âncora são confirmados pelo LLM sobre um **diff focado** do arquivo (`foundAtSha..HEAD`), uma
29
29
  pergunta `noul` por finding. Falha-aberto: sem chave/erro → vale o resultado local.
30
30
 
@@ -43,7 +43,8 @@ bun run houndsman findings verify --apply # marca os resolvidos como done (pi
43
43
 
44
44
  - Sem `--apply`: **só relatório** (grava o artefato `verify.md` no storage). Nada muda na triagem.
45
45
  - Com `--apply`: os findings com status **`resolved`** viram `execState: done` (histórico
46
- `by: "verify"`). `persisting` e `uncertain` **não** são tocados.
46
+ `by: "verify"`) e a **thread correspondente é resolvida no GitHub** (quando há comentário e a
47
+ conversa ainda está aberta; fail-open). `persisting` e `uncertain` **não** são tocados.
47
48
 
48
49
  Filtros (como no `findings list`): `--severity`, `--watchdog`, `--file`, `--decision`. `--all`
49
50
  inclui ausentes. `--no-jev` desliga o tier LLM. `--fail-on-persisting` sai com código 1 se algum