@payconductor/houndsman 0.3.0 → 0.5.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 +25 -39
- package/package.json +1 -1
- package/src/cli/commands/context-command.ts +11 -9
- package/src/cli/commands/doctor-command.ts +5 -0
- package/src/cli/commands/findings-command.ts +13 -3
- package/src/cli/commands/review-command.ts +1 -2
- package/src/cli/commands/status-command.ts +46 -0
- package/src/cli/help.ts +8 -3
- package/src/cli/index.ts +5 -2
- package/src/core/commands/context.ts +29 -13
- package/src/core/commands/findings.ts +216 -125
- package/src/core/commands/review.ts +7 -8
- package/src/core/commands/scaffold.ts +15 -16
- package/src/core/commands/status.ts +63 -0
- package/src/core/config.ts +16 -7
- package/src/core/engine/houndsman-engine.ts +15 -1
- package/src/core/engine/review-scope.ts +26 -8
- package/src/core/engine/review-session.ts +37 -9
- package/src/core/findings-state.ts +53 -75
- package/src/core/github-review.ts +620 -57
- package/src/core/jev/jev-candidates.ts +49 -35
- package/src/core/orchestrator.ts +271 -134
- package/src/core/paths.ts +26 -17
- package/src/core/pr-context.ts +19 -5
- package/src/core/project-config.ts +4 -5
- package/src/core/renderers/manifest-writer.ts +29 -18
- package/src/core/renderers/resume-renderer.ts +151 -0
- package/src/core/report-builder.ts +7 -4
- package/src/core/run-layout.ts +4 -104
- package/src/core/run-status.ts +59 -50
- package/src/core/services/git-repository.ts +16 -0
- package/src/core/services/project-files.ts +13 -1
- package/src/core/storage/factory.ts +24 -0
- package/src/core/storage/file/file-storage.ts +271 -0
- package/src/core/storage/paths.ts +64 -0
- package/src/core/storage/repo-identity.ts +70 -0
- package/src/core/storage/sqlite/mappers.ts +162 -0
- package/src/core/storage/sqlite/schema.ts +116 -0
- package/src/core/storage/sqlite/sqlite-storage.ts +431 -0
- package/src/core/storage/types.ts +152 -0
- package/src/core/storage/work-area.ts +191 -0
- package/src/index.ts +27 -6
- package/src/server/artifacts.ts +8 -61
- package/src/server/client/App.tsx +26 -9
- package/src/server/client/ArtifactsPanel.tsx +144 -23
- package/src/server/client/AutoRefresh.tsx +1 -1
- package/src/server/client/Filters.tsx +7 -2
- package/src/server/client/FindingCard.tsx +50 -15
- package/src/server/client/FindingsList.tsx +2 -2
- package/src/server/client/MarkdownText.tsx +181 -0
- package/src/server/client/ResumePanel.tsx +368 -0
- package/src/server/client/RunList.tsx +3 -3
- package/src/server/client/SubmitModal.tsx +58 -10
- package/src/server/client/SummaryBar.tsx +1 -1
- package/src/server/client/icons.tsx +17 -0
- package/src/server/client/utils/code-highlight.ts +422 -0
- package/src/server/client/utils/constants.ts +226 -0
- package/src/server/client/utils/json-highlight.ts +55 -0
- package/src/server/client/utils/markdown.ts +319 -0
- package/src/server/client/{types.ts → utils/types.ts} +81 -0
- package/src/server/index.ts +154 -16
- package/src/server/run-repository.ts +153 -136
- package/src/skill/OUTPUT-FORMAT.md +6 -4
- package/src/skill/README.md +22 -14
- package/src/skill/SETUP.md +4 -4
- package/src/skill/example-review.md +22 -14
- package/src/skill/fix.md +5 -5
- package/src/skill/hunt.md +55 -32
- package/src/skill/train.md +1 -1
- package/src/skill/verify.md +7 -6
- package/src/tests/__snapshots__/baseline.test.ts.snap +74 -61
- package/src/tests/baseline.test.ts +79 -34
- package/src/tests/cli.test.ts +40 -19
- package/src/tests/code-highlight.test.ts +123 -0
- package/src/tests/domain.test.ts +1 -1
- package/src/tests/findings-commands.test.ts +153 -131
- package/src/tests/findings-state.test.ts +56 -5
- package/src/tests/fixtures/fake-project.ts +0 -1
- package/src/tests/github-review.test.ts +409 -60
- package/src/tests/infrastructure.test.ts +33 -38
- package/src/tests/markdown.test.ts +149 -0
- 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 +81 -5
- package/src/tests/run-status-view.test.ts +94 -0
- package/src/tests/run-status.test.ts +86 -23
- package/src/tests/server.test.ts +184 -96
- package/src/tests/storage.test.ts +449 -0
- package/src/server/client/constants.ts +0 -91
- /package/src/server/client/{api.ts → utils/api.ts} +0 -0
- /package/src/server/client/{format.ts → utils/format.ts} +0 -0
|
@@ -36,6 +36,50 @@ export type JevCandidatesFile = {
|
|
|
36
36
|
|
|
37
37
|
const SEVERITY_SET = new Set<string>(SEVERITY_ORDER);
|
|
38
38
|
|
|
39
|
+
/** Serializa o artefato `candidates.json` (sempre com quebra de linha final). */
|
|
40
|
+
export function serializeCandidates(data: JevCandidatesFile): string {
|
|
41
|
+
return `${JSON.stringify(data, null, 2)}\n`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Valida/parseia o JSON bruto do artefato; null se inválido. */
|
|
45
|
+
export function parseCandidates(
|
|
46
|
+
raw: unknown,
|
|
47
|
+
validIds: readonly string[] = [],
|
|
48
|
+
): JevCandidatesFile | null {
|
|
49
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
50
|
+
const value = raw as Record<string, unknown>;
|
|
51
|
+
const idSet = validIds.length > 0 ? new Set(validIds) : null;
|
|
52
|
+
const isCandidate = (entry: unknown): entry is JevCandidate => {
|
|
53
|
+
if (typeof entry !== "object" || entry === null) return false;
|
|
54
|
+
const c = entry as Record<string, unknown>;
|
|
55
|
+
return (
|
|
56
|
+
typeof c.watchdogId === "string" &&
|
|
57
|
+
(idSet === null || idSet.has(c.watchdogId)) &&
|
|
58
|
+
typeof c.rule === "string" &&
|
|
59
|
+
typeof c.severity === "string" &&
|
|
60
|
+
SEVERITY_SET.has(c.severity) &&
|
|
61
|
+
typeof c.file === "string" &&
|
|
62
|
+
typeof c.confidence === "number" &&
|
|
63
|
+
typeof c.questionKey === "string"
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
const candidates = Array.isArray(value.candidates)
|
|
67
|
+
? value.candidates.filter(isCandidate)
|
|
68
|
+
: [];
|
|
69
|
+
return {
|
|
70
|
+
available: value.available === true,
|
|
71
|
+
reason: typeof value.reason === "string" ? value.reason : undefined,
|
|
72
|
+
model: typeof value.model === "string" ? value.model : undefined,
|
|
73
|
+
threshold: typeof value.threshold === "number" ? value.threshold : undefined,
|
|
74
|
+
analyzedFiles:
|
|
75
|
+
typeof value.analyzedFiles === "number" ? value.analyzedFiles : undefined,
|
|
76
|
+
candidates,
|
|
77
|
+
skipped: Array.isArray(value.skipped)
|
|
78
|
+
? (value.skipped as JevSkippedFile[])
|
|
79
|
+
: undefined,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
39
83
|
/** Persistência do artefato `candidates.json` para um diretório de review. */
|
|
40
84
|
export class JevCandidatesStore {
|
|
41
85
|
/** Limiar padrão de confiança (`noul`) para virar candidato. */
|
|
@@ -57,49 +101,19 @@ export class JevCandidatesStore {
|
|
|
57
101
|
|
|
58
102
|
/** Grava o `candidates.json` (sempre com candidatos válidos apenas). */
|
|
59
103
|
write(data: JevCandidatesFile): void {
|
|
60
|
-
writeFileSync(this.filePath,
|
|
104
|
+
writeFileSync(this.filePath, serializeCandidates(data));
|
|
61
105
|
}
|
|
62
106
|
|
|
63
107
|
/** Lê o `candidates.json`; null se ausente/inválido. */
|
|
64
108
|
read(): JevCandidatesFile | null {
|
|
65
109
|
if (!existsSync(this.filePath)) return null;
|
|
66
110
|
try {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const candidates = Array.isArray(raw.candidates)
|
|
72
|
-
? raw.candidates.filter((c) => this.isCandidate(c))
|
|
73
|
-
: [];
|
|
74
|
-
return {
|
|
75
|
-
available: raw.available === true,
|
|
76
|
-
reason: typeof raw.reason === "string" ? raw.reason : undefined,
|
|
77
|
-
model: typeof raw.model === "string" ? raw.model : undefined,
|
|
78
|
-
threshold: typeof raw.threshold === "number" ? raw.threshold : undefined,
|
|
79
|
-
analyzedFiles:
|
|
80
|
-
typeof raw.analyzedFiles === "number" ? raw.analyzedFiles : undefined,
|
|
81
|
-
candidates,
|
|
82
|
-
skipped: Array.isArray(raw.skipped)
|
|
83
|
-
? (raw.skipped as JevSkippedFile[])
|
|
84
|
-
: undefined,
|
|
85
|
-
};
|
|
111
|
+
return parseCandidates(
|
|
112
|
+
JSON.parse(readFileSync(this.filePath, "utf8")),
|
|
113
|
+
this.watchdogIdSet ? [...this.watchdogIdSet] : [],
|
|
114
|
+
);
|
|
86
115
|
} catch {
|
|
87
116
|
return null;
|
|
88
117
|
}
|
|
89
118
|
}
|
|
90
|
-
|
|
91
|
-
private isCandidate(value: unknown): value is JevCandidate {
|
|
92
|
-
if (typeof value !== "object" || value === null) return false;
|
|
93
|
-
const c = value as Record<string, unknown>;
|
|
94
|
-
return (
|
|
95
|
-
typeof c.watchdogId === "string" &&
|
|
96
|
-
(this.watchdogIdSet === null || this.watchdogIdSet.has(c.watchdogId)) &&
|
|
97
|
-
typeof c.rule === "string" &&
|
|
98
|
-
typeof c.severity === "string" &&
|
|
99
|
-
SEVERITY_SET.has(c.severity) &&
|
|
100
|
-
typeof c.file === "string" &&
|
|
101
|
-
typeof c.confidence === "number" &&
|
|
102
|
-
typeof c.questionKey === "string"
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
119
|
}
|