maestro-flow 0.4.19 → 0.4.20
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/.agents/agents/workflow-collab-planner.md +4 -1
- package/.agents/agents/workflow-plan-checker.md +11 -1
- package/.agents/agents/workflow-planner.md +4 -1
- package/.agents/skills/maestro/SKILL.md +8 -5
- package/.agents/skills/maestro-analyze/SKILL.md +1 -1
- package/.agents/skills/maestro-brainstorm/SKILL.md +2 -1
- package/.agents/skills/maestro-companion/SKILL.md +533 -0
- package/.agents/skills/maestro-grill/SKILL.md +116 -0
- package/.agents/skills/maestro-plan/SKILL.md +4 -0
- package/.agents/skills/maestro-ralph/SKILL.md +11 -7
- package/.agents/skills/maestro-swarm-workflow/SKILL.md +258 -0
- package/.agents/skills/manage-codebase-rebuild/SKILL.md +13 -1
- package/.agents/skills/manage-codebase-refresh/SKILL.md +3 -0
- package/.agents/skills/spec-setup/SKILL.md +9 -5
- package/.agy/agents/workflow-collab-planner.md +4 -1
- package/.agy/agents/workflow-plan-checker.md +11 -1
- package/.agy/agents/workflow-planner.md +4 -1
- package/.agy/skills/maestro/SKILL.md +8 -5
- package/.agy/skills/maestro-analyze/SKILL.md +1 -1
- package/.agy/skills/maestro-brainstorm/SKILL.md +2 -1
- package/.agy/skills/maestro-companion/SKILL.md +529 -0
- package/.agy/skills/maestro-grill/SKILL.md +116 -0
- package/.agy/skills/maestro-plan/SKILL.md +4 -0
- package/.agy/skills/maestro-ralph/SKILL.md +11 -7
- package/.agy/skills/maestro-swarm-workflow/SKILL.md +255 -0
- package/.agy/skills/manage-codebase-rebuild/SKILL.md +13 -1
- package/.agy/skills/manage-codebase-refresh/SKILL.md +3 -0
- package/.agy/skills/spec-setup/SKILL.md +9 -5
- package/.claude/agents/workflow-collab-planner.md +4 -1
- package/.claude/agents/workflow-plan-checker.md +11 -1
- package/.claude/agents/workflow-planner.md +4 -1
- package/.claude/commands/maestro-analyze.md +1 -1
- package/.claude/commands/maestro-brainstorm.md +2 -1
- package/.claude/commands/maestro-companion.md +531 -0
- package/.claude/commands/maestro-grill.md +114 -0
- package/.claude/commands/maestro-plan.md +4 -0
- package/.claude/commands/maestro-ralph.md +11 -7
- package/.claude/commands/maestro-swarm-workflow.md +256 -0
- package/.claude/commands/maestro.md +8 -5
- package/.claude/commands/manage-codebase-rebuild.md +13 -1
- package/.claude/commands/manage-codebase-refresh.md +3 -0
- package/.claude/commands/spec-setup.md +9 -5
- package/.codex/skills/maestro/SKILL.md +7 -2
- package/.codex/skills/maestro-companion/SKILL.md +485 -0
- package/.codex/skills/maestro-grill/SKILL.md +111 -0
- package/.codex/skills/maestro-ralph/SKILL.md +11 -7
- package/.codex/skills/manage-codebase-rebuild/SKILL.md +6 -0
- package/.codex/skills/manage-codebase-refresh/SKILL.md +6 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/graph-analysis.d.ts +36 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/graph-analysis.js +138 -2
- package/dashboard/dist-server/dashboard/src/server/wiki/graph-analysis.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/wiki/search.js +13 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/search.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/wiki/virtual-wiki-adapters.d.ts +11 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/virtual-wiki-adapters.js +178 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/virtual-wiki-adapters.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/wiki/wiki-indexer.d.ts +1 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/wiki-indexer.js +39 -23
- package/dashboard/dist-server/dashboard/src/server/wiki/wiki-indexer.js.map +1 -1
- package/dist/src/cli.js +1 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/install-backend.d.ts +7 -0
- package/dist/src/commands/install-backend.d.ts.map +1 -1
- package/dist/src/commands/install-backend.js +14 -0
- package/dist/src/commands/install-backend.js.map +1 -1
- package/dist/src/commands/install.d.ts.map +1 -1
- package/dist/src/commands/install.js +18 -0
- package/dist/src/commands/install.js.map +1 -1
- package/dist/src/commands/kg.d.ts +11 -0
- package/dist/src/commands/kg.d.ts.map +1 -0
- package/dist/src/commands/kg.js +515 -0
- package/dist/src/commands/kg.js.map +1 -0
- package/dist/src/i18n/locales/en.d.ts.map +1 -1
- package/dist/src/i18n/locales/en.js +10 -0
- package/dist/src/i18n/locales/en.js.map +1 -1
- package/dist/src/i18n/locales/zh.d.ts.map +1 -1
- package/dist/src/i18n/locales/zh.js +10 -0
- package/dist/src/i18n/locales/zh.js.map +1 -1
- package/dist/src/i18n/types.d.ts +9 -0
- package/dist/src/i18n/types.d.ts.map +1 -1
- package/dist/src/tui/install-ui/InstallConfirm.d.ts +1 -0
- package/dist/src/tui/install-ui/InstallConfirm.d.ts.map +1 -1
- package/dist/src/tui/install-ui/InstallConfirm.js +1 -1
- package/dist/src/tui/install-ui/InstallConfirm.js.map +1 -1
- package/dist/src/tui/install-ui/InstallExecution.d.ts +1 -0
- package/dist/src/tui/install-ui/InstallExecution.d.ts.map +1 -1
- package/dist/src/tui/install-ui/InstallExecution.js +22 -0
- package/dist/src/tui/install-ui/InstallExecution.js.map +1 -1
- package/dist/src/tui/install-ui/InstallFlow.d.ts +1 -1
- package/dist/src/tui/install-ui/InstallFlow.d.ts.map +1 -1
- package/dist/src/tui/install-ui/InstallFlow.js +23 -5
- package/dist/src/tui/install-ui/InstallFlow.js.map +1 -1
- package/dist/src/tui/install-ui/InstallHub.d.ts +2 -0
- package/dist/src/tui/install-ui/InstallHub.d.ts.map +1 -1
- package/dist/src/tui/install-ui/InstallHub.js +6 -0
- package/dist/src/tui/install-ui/InstallHub.js.map +1 -1
- package/dist/src/tui/install-ui/InstallResult.d.ts.map +1 -1
- package/dist/src/tui/install-ui/InstallResult.js +1 -1
- package/dist/src/tui/install-ui/InstallResult.js.map +1 -1
- package/dist/src/tui/install-ui/KgVendorConfig.d.ts +7 -0
- package/dist/src/tui/install-ui/KgVendorConfig.d.ts.map +1 -0
- package/dist/src/tui/install-ui/KgVendorConfig.js +9 -0
- package/dist/src/tui/install-ui/KgVendorConfig.js.map +1 -0
- package/dist/src/utils/update-notices.js +11 -0
- package/dist/src/utils/update-notices.js.map +1 -1
- package/package.json +1 -1
- package/workflows/analyze.md +2 -1
- package/workflows/brainstorm.md +24 -1
- package/workflows/codebase-rebuild.md +141 -1
- package/workflows/codebase-refresh.md +20 -0
- package/workflows/finish-work.md +7 -2
- package/workflows/grill.md +513 -0
- package/workflows/plan.md +7 -4
- package/workflows/specs-setup.md +99 -3
- package/workflows/swarm/wf-analyze.js +186 -0
- package/workflows/swarm/wf-brainstorm.js +284 -0
- package/workflows/swarm/wf-execute.js +203 -0
- package/workflows/swarm/wf-grill.js +198 -0
- package/workflows/swarm/wf-milestone-audit.js +236 -0
- package/workflows/swarm/wf-plan.js +233 -0
- package/workflows/swarm/wf-review.js +226 -0
- package/workflows/swarm/wf-verify.js +298 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: 'wf-review',
|
|
3
|
+
description: 'Multi-dimension parallel code review via workflow-reviewer with adversarial verification',
|
|
4
|
+
whenToUse: 'Accelerate quality-review with parallel dimension-specific scanning and finding verification',
|
|
5
|
+
phases: [
|
|
6
|
+
{ title: 'Scan', detail: 'Parallel dimension scanning via workflow-reviewer' },
|
|
7
|
+
{ title: 'Verify', detail: 'Adversarial verification of critical findings' },
|
|
8
|
+
{ title: 'Report', detail: 'Consolidated review report with verdict' },
|
|
9
|
+
],
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Aligned with workflow-reviewer.md dimension definitions
|
|
13
|
+
const REVIEW_DIMENSIONS = [
|
|
14
|
+
{ key: 'correctness', prefix: 'COR', prompt: 'Dimension: correctness. Focus: Logic errors, off-by-one, null handling, missing error propagation, type mismatches, unhandled edge cases, broken invariants, incorrect conditions.' },
|
|
15
|
+
{ key: 'security', prefix: 'SEC', prompt: 'Dimension: security. Focus: Injection vectors (SQL/command/XSS), auth bypass, hardcoded secrets, missing input validation, data exposure in logs/errors, SSRF, IDOR, insecure crypto.' },
|
|
16
|
+
{ key: 'performance', prefix: 'PRF', prompt: 'Dimension: performance. Focus: O(n^2+) algorithms, N+1 queries, missing pagination, resource leaks (unclosed handles/streams), synchronous blocking, missing caching, bundle size impact.' },
|
|
17
|
+
{ key: 'architecture', prefix: 'ARC', prompt: 'Dimension: architecture. Focus: Layer violations (UI calling DB directly), circular dependencies, god classes/functions, inconsistent patterns, tight coupling, missing abstractions.' },
|
|
18
|
+
{ key: 'maintainability', prefix: 'MNT', prompt: 'Dimension: maintainability. Focus: Functions >50 lines, cyclomatic complexity >10, duplicated logic, unclear naming, dead code, missing error context, poor separation of concerns.' },
|
|
19
|
+
{ key: 'best-practices', prefix: 'BPR', prompt: 'Dimension: best-practices. Focus: Deprecated API usage, framework anti-patterns, inconsistent style with codebase, missing TypeScript strict checks, raw `any` types, missing documentation for public APIs.' },
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
const FINDING_SCHEMA = {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
dimension: { type: 'string' },
|
|
26
|
+
findings: {
|
|
27
|
+
type: 'array',
|
|
28
|
+
items: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
id: { type: 'string' },
|
|
32
|
+
dimension: { type: 'string' },
|
|
33
|
+
severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },
|
|
34
|
+
title: { type: 'string' },
|
|
35
|
+
file: { type: 'string' },
|
|
36
|
+
line: { type: 'number' },
|
|
37
|
+
description: { type: 'string' },
|
|
38
|
+
suggestion: { type: 'string' },
|
|
39
|
+
evidence: { type: 'string' },
|
|
40
|
+
},
|
|
41
|
+
required: ['id', 'dimension', 'severity', 'title', 'file', 'description'],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
required: ['dimension', 'findings'],
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const VERDICT_SCHEMA = {
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties: {
|
|
51
|
+
finding_id: { type: 'string' },
|
|
52
|
+
is_real: { type: 'boolean' },
|
|
53
|
+
confidence: { type: 'number', minimum: 0, maximum: 100 },
|
|
54
|
+
reasoning: { type: 'string' },
|
|
55
|
+
adjusted_severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low', 'false-positive'] },
|
|
56
|
+
},
|
|
57
|
+
required: ['finding_id', 'is_real', 'confidence', 'reasoning'],
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const REPORT_SCHEMA = {
|
|
61
|
+
type: 'object',
|
|
62
|
+
properties: {
|
|
63
|
+
verdict: { type: 'string', enum: ['APPROVE', 'REQUEST_CHANGES', 'BLOCK'] },
|
|
64
|
+
overall_quality: { type: 'number', minimum: 1, maximum: 5 },
|
|
65
|
+
dimension_summary: {
|
|
66
|
+
type: 'array',
|
|
67
|
+
items: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
properties: {
|
|
70
|
+
dimension: { type: 'string' },
|
|
71
|
+
finding_count: { type: 'number' },
|
|
72
|
+
max_severity: { type: 'string' },
|
|
73
|
+
assessment: { type: 'string' },
|
|
74
|
+
},
|
|
75
|
+
required: ['dimension', 'finding_count'],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
blocking_issues: { type: 'array', items: { type: 'object', properties: { id: { type: 'string' }, title: { type: 'string' }, file: { type: 'string' }, severity: { type: 'string' }, suggestion: { type: 'string' } }, required: ['id', 'title', 'file', 'severity'] } },
|
|
79
|
+
summary: { type: 'string' },
|
|
80
|
+
},
|
|
81
|
+
required: ['verdict', 'overall_quality', 'dimension_summary', 'blocking_issues', 'summary'],
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const target = args?.target || 'changed files on current branch'
|
|
85
|
+
const scope = args?.scope || ''
|
|
86
|
+
const specs = args?.specs || ''
|
|
87
|
+
const tier = args?.tier || 'standard'
|
|
88
|
+
const dimensions = args?.dimensions
|
|
89
|
+
? REVIEW_DIMENSIONS.filter(d => args.dimensions.includes(d.key))
|
|
90
|
+
: (tier === 'quick' ? REVIEW_DIMENSIONS.slice(0, 3) : REVIEW_DIMENSIONS)
|
|
91
|
+
|
|
92
|
+
// Phase 1: Parallel dimension scanning via workflow-reviewer
|
|
93
|
+
phase('Scan')
|
|
94
|
+
log(`Scanning ${dimensions.length} dimensions in parallel via workflow-reviewer...`)
|
|
95
|
+
|
|
96
|
+
const scans = await parallel(
|
|
97
|
+
dimensions.map(dim => () =>
|
|
98
|
+
agent(
|
|
99
|
+
`${dim.prompt}
|
|
100
|
+
|
|
101
|
+
Review target: ${target}
|
|
102
|
+
${scope ? 'Files to review: ' + scope : 'Find changed files via git diff and review them.'}
|
|
103
|
+
${specs ? 'Project specs/conventions: ' + specs : ''}
|
|
104
|
+
|
|
105
|
+
Process:
|
|
106
|
+
1. Read the target files (use git diff if no explicit file list)
|
|
107
|
+
2. Perform structural scan — imports, exports, function signatures, complexity indicators
|
|
108
|
+
3. Apply dimension-specific analysis rules
|
|
109
|
+
4. Classify severity: Critical (security vuln, data corruption, crash) / High (logic bug, resource leak) / Medium (code smell, maintainability) / Low (style, minor optimization)
|
|
110
|
+
5. Return only real, actionable findings with specific file paths, line numbers, and evidence
|
|
111
|
+
|
|
112
|
+
Finding IDs use format: ${dim.prefix}-{NNN}`,
|
|
113
|
+
{ label: `scan:${dim.key}`, phase: 'Scan', schema: FINDING_SCHEMA, agentType: 'workflow-reviewer' }
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
const validScans = scans.filter(Boolean)
|
|
119
|
+
const allFindings = validScans.flatMap(s => s.findings)
|
|
120
|
+
const criticalHigh = allFindings.filter(f => f.severity === 'critical' || f.severity === 'high')
|
|
121
|
+
|
|
122
|
+
log(`Found ${allFindings.length} total (${criticalHigh.length} critical/high across ${validScans.length} dimensions)`)
|
|
123
|
+
|
|
124
|
+
// Phase 2: Adversarial verification of critical/high findings
|
|
125
|
+
phase('Verify')
|
|
126
|
+
|
|
127
|
+
if (criticalHigh.length > 0) {
|
|
128
|
+
log(`Adversarially verifying ${criticalHigh.length} critical/high findings...`)
|
|
129
|
+
|
|
130
|
+
const verified = await pipeline(
|
|
131
|
+
criticalHigh,
|
|
132
|
+
(finding) => agent(
|
|
133
|
+
`Adversarially verify this code review finding. Your job is to REFUTE it — find reasons it might be:
|
|
134
|
+
- A false positive (the code is actually correct)
|
|
135
|
+
- Less severe than claimed (downgrade severity)
|
|
136
|
+
- Not applicable in this context
|
|
137
|
+
|
|
138
|
+
Finding: [${finding.severity}] ${finding.id}: ${finding.title}
|
|
139
|
+
File: ${finding.file}${finding.line ? ':' + finding.line : ''}
|
|
140
|
+
Description: ${finding.description}
|
|
141
|
+
Evidence: ${finding.evidence || 'none provided'}
|
|
142
|
+
|
|
143
|
+
Read the actual source code at the specified location. Check:
|
|
144
|
+
1. Is the code actually doing what the finding claims?
|
|
145
|
+
2. Is there handling elsewhere that mitigates this?
|
|
146
|
+
3. Is the severity justified?
|
|
147
|
+
|
|
148
|
+
Default to is_real=false and adjusted_severity=false-positive if uncertain.
|
|
149
|
+
Only confirm findings you can verify in the actual code with high confidence.`,
|
|
150
|
+
{ label: `verify:${finding.id}`, phase: 'Verify', schema: VERDICT_SCHEMA }
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
const confirmedFindings = []
|
|
155
|
+
const falsePositives = []
|
|
156
|
+
|
|
157
|
+
verified.filter(Boolean).forEach((verdict, i) => {
|
|
158
|
+
const finding = criticalHigh[i]
|
|
159
|
+
if (verdict.is_real && verdict.confidence >= 60) {
|
|
160
|
+
confirmedFindings.push({ ...finding, verdict: verdict, adjusted_severity: verdict.adjusted_severity || finding.severity })
|
|
161
|
+
} else {
|
|
162
|
+
falsePositives.push({ ...finding, verdict: verdict })
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
const lowMedFindings = allFindings.filter(f => f.severity === 'medium' || f.severity === 'low')
|
|
167
|
+
|
|
168
|
+
// Phase 3: Consolidated report
|
|
169
|
+
phase('Report')
|
|
170
|
+
|
|
171
|
+
const report = await agent(
|
|
172
|
+
`Generate a consolidated code review report.
|
|
173
|
+
|
|
174
|
+
Confirmed findings (adversarially verified, ${confirmedFindings.length}):
|
|
175
|
+
${confirmedFindings.map(f => `- [${f.adjusted_severity}] ${f.id}: ${f.title} @ ${f.file}:${f.line || '?'} (confidence: ${f.verdict.confidence}%)\n ${f.description}`).join('\n') || 'None'}
|
|
176
|
+
|
|
177
|
+
False positives filtered: ${falsePositives.length}
|
|
178
|
+
${falsePositives.map(f => `- ${f.id}: ${f.title} — ${f.verdict.reasoning}`).join('\n') || ''}
|
|
179
|
+
|
|
180
|
+
Low/medium findings (not individually verified, ${lowMedFindings.length}):
|
|
181
|
+
${lowMedFindings.map(f => `- [${f.severity}] ${f.id}: ${f.title} @ ${f.file}`).join('\n') || 'None'}
|
|
182
|
+
|
|
183
|
+
Determine verdict:
|
|
184
|
+
- APPROVE: no confirmed critical/high findings
|
|
185
|
+
- REQUEST_CHANGES: has confirmed high findings but no critical
|
|
186
|
+
- BLOCK: has confirmed critical findings
|
|
187
|
+
|
|
188
|
+
Rate overall quality (1-5) and summarize per dimension.`,
|
|
189
|
+
{ label: 'report', phase: 'Report', schema: REPORT_SCHEMA }
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
report: report,
|
|
194
|
+
confirmed: confirmedFindings,
|
|
195
|
+
false_positives: falsePositives,
|
|
196
|
+
low_findings: lowMedFindings,
|
|
197
|
+
metadata: {
|
|
198
|
+
target: target,
|
|
199
|
+
dimensions_scanned: dimensions.length,
|
|
200
|
+
total_findings: allFindings.length,
|
|
201
|
+
verified_count: criticalHigh.length,
|
|
202
|
+
confirmed_count: confirmedFindings.length,
|
|
203
|
+
false_positive_count: falsePositives.length,
|
|
204
|
+
verdict: report ? report.verdict : 'UNKNOWN',
|
|
205
|
+
},
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
phase('Report')
|
|
209
|
+
log('No critical/high findings — generating clean report')
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
report: { verdict: 'APPROVE', overall_quality: 4, dimension_summary: validScans.map(s => ({ dimension: s.dimension, finding_count: s.findings.length, max_severity: s.findings[0]?.severity || 'none', assessment: 'Clean' })), blocking_issues: [], summary: 'No critical or high severity issues found. Code passes review.' },
|
|
213
|
+
confirmed: [],
|
|
214
|
+
false_positives: [],
|
|
215
|
+
low_findings: allFindings,
|
|
216
|
+
metadata: {
|
|
217
|
+
target: target,
|
|
218
|
+
dimensions_scanned: dimensions.length,
|
|
219
|
+
total_findings: allFindings.length,
|
|
220
|
+
verified_count: 0,
|
|
221
|
+
confirmed_count: 0,
|
|
222
|
+
false_positive_count: 0,
|
|
223
|
+
verdict: 'APPROVE',
|
|
224
|
+
},
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: 'wf-verify',
|
|
3
|
+
description: 'Three-layer goal-backward verification via workflow-verifier + anti-pattern scan',
|
|
4
|
+
whenToUse: 'Accelerate maestro-verify with parallel existence/substance/connection checks and convergence validation',
|
|
5
|
+
phases: [
|
|
6
|
+
{ title: 'Check', detail: 'Parallel 3-layer verification + anti-pattern scan via workflow-verifier' },
|
|
7
|
+
{ title: 'Aggregate', detail: 'Cross-layer aggregation and gap analysis' },
|
|
8
|
+
],
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Aligned with workflow-verifier.md: Layer 1 Existence, Layer 2 Substance, Layer 3 Connection
|
|
12
|
+
const LAYER_SCHEMA = {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
layer: { type: 'string', enum: ['existence', 'substance', 'connection'] },
|
|
16
|
+
passed: { type: 'boolean' },
|
|
17
|
+
checks: {
|
|
18
|
+
type: 'array',
|
|
19
|
+
items: {
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
goal: { type: 'string' },
|
|
23
|
+
status: { type: 'string', enum: ['pass', 'fail', 'partial', 'skip'] },
|
|
24
|
+
evidence: { type: 'string' },
|
|
25
|
+
file: { type: 'string' },
|
|
26
|
+
gap: { type: 'string' },
|
|
27
|
+
},
|
|
28
|
+
required: ['goal', 'status', 'evidence'],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
summary: { type: 'string' },
|
|
32
|
+
},
|
|
33
|
+
required: ['layer', 'passed', 'checks', 'summary'],
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const CONVERGENCE_SCHEMA = {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
task_id: { type: 'string' },
|
|
40
|
+
criteria_results: {
|
|
41
|
+
type: 'array',
|
|
42
|
+
items: {
|
|
43
|
+
type: 'object',
|
|
44
|
+
properties: {
|
|
45
|
+
criterion: { type: 'string' },
|
|
46
|
+
met: { type: 'boolean' },
|
|
47
|
+
evidence: { type: 'string' },
|
|
48
|
+
verification_command: { type: 'string' },
|
|
49
|
+
command_output: { type: 'string' },
|
|
50
|
+
},
|
|
51
|
+
required: ['criterion', 'met', 'evidence'],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
overall_converged: { type: 'boolean' },
|
|
55
|
+
},
|
|
56
|
+
required: ['task_id', 'criteria_results', 'overall_converged'],
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const ANTIPATTERN_SCHEMA = {
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
clean: { type: 'boolean' },
|
|
63
|
+
findings: {
|
|
64
|
+
type: 'array',
|
|
65
|
+
items: {
|
|
66
|
+
type: 'object',
|
|
67
|
+
properties: {
|
|
68
|
+
type: { type: 'string', enum: ['stub', 'placeholder', 'todo', 'fixme', 'empty-return', 'empty-catch', 'ts-ignore', 'skip-test', 'hardcoded-secret', 'not-implemented'] },
|
|
69
|
+
file: { type: 'string' },
|
|
70
|
+
line: { type: 'number' },
|
|
71
|
+
content: { type: 'string' },
|
|
72
|
+
severity: { type: 'string', enum: ['blocker', 'warning'] },
|
|
73
|
+
},
|
|
74
|
+
required: ['type', 'file', 'content', 'severity'],
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
required: ['clean', 'findings'],
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const AGGREGATE_SCHEMA = {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {
|
|
84
|
+
status: { type: 'string', enum: ['pass', 'fail'] },
|
|
85
|
+
confidence: { type: 'number', minimum: 0, maximum: 100 },
|
|
86
|
+
layers: {
|
|
87
|
+
type: 'array',
|
|
88
|
+
items: {
|
|
89
|
+
type: 'object',
|
|
90
|
+
properties: {
|
|
91
|
+
layer: { type: 'string' },
|
|
92
|
+
passed: { type: 'boolean' },
|
|
93
|
+
total_checks: { type: 'number' },
|
|
94
|
+
passed_checks: { type: 'number' },
|
|
95
|
+
failed_checks: { type: 'number' },
|
|
96
|
+
},
|
|
97
|
+
required: ['layer', 'passed', 'total_checks', 'passed_checks'],
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
convergence_summary: {
|
|
101
|
+
type: 'object',
|
|
102
|
+
properties: {
|
|
103
|
+
total_tasks: { type: 'number' },
|
|
104
|
+
converged_tasks: { type: 'number' },
|
|
105
|
+
unmet_criteria: { type: 'array', items: { type: 'object', properties: { task: { type: 'string' }, criterion: { type: 'string' } }, required: ['task', 'criterion'] } },
|
|
106
|
+
},
|
|
107
|
+
required: ['total_tasks', 'converged_tasks'],
|
|
108
|
+
},
|
|
109
|
+
gaps: {
|
|
110
|
+
type: 'array',
|
|
111
|
+
items: {
|
|
112
|
+
type: 'object',
|
|
113
|
+
properties: {
|
|
114
|
+
description: { type: 'string' },
|
|
115
|
+
source_layer: { type: 'string' },
|
|
116
|
+
severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },
|
|
117
|
+
remediation: { type: 'string' },
|
|
118
|
+
affected_files: { type: 'array', items: { type: 'string' } },
|
|
119
|
+
},
|
|
120
|
+
required: ['description', 'source_layer', 'severity', 'remediation'],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
antipattern_blockers: { type: 'number' },
|
|
124
|
+
executive_summary: { type: 'string' },
|
|
125
|
+
},
|
|
126
|
+
required: ['status', 'confidence', 'layers', 'gaps', 'executive_summary'],
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const goals = args?.goals || ''
|
|
130
|
+
const planDir = args?.plan_dir || ''
|
|
131
|
+
const scope = args?.scope || ''
|
|
132
|
+
const taskFiles = args?.task_files || []
|
|
133
|
+
const skipTests = args?.skip_tests || false
|
|
134
|
+
const skipAntipattern = args?.skip_antipattern || false
|
|
135
|
+
const mustHaves = args?.must_haves || ''
|
|
136
|
+
|
|
137
|
+
// Phase 1: Parallel 3-layer + anti-pattern + convergence checks
|
|
138
|
+
phase('Check')
|
|
139
|
+
|
|
140
|
+
const checks = [
|
|
141
|
+
// Layer 1: Existence — verify all expected artifacts exist
|
|
142
|
+
() => agent(
|
|
143
|
+
`Layer 1 — EXISTENCE verification.
|
|
144
|
+
Goals: ${goals}
|
|
145
|
+
${planDir ? 'Plan directory: ' + planDir + ' — read task JSONs for expected files[]' : ''}
|
|
146
|
+
${scope ? 'Scope: ' + scope : ''}
|
|
147
|
+
${mustHaves ? 'Must-haves (artifacts): ' + mustHaves : ''}
|
|
148
|
+
|
|
149
|
+
Verify all expected artifacts EXIST:
|
|
150
|
+
1. Read task JSON files in plan directory to find files[].path where action="create"
|
|
151
|
+
2. Check each expected file exists on disk (Glob/Read)
|
|
152
|
+
3. Verify functions/classes/modules are present at files[].target
|
|
153
|
+
4. Check configuration entries are added
|
|
154
|
+
5. Report pass/fail with evidence (actual file paths found or missing)
|
|
155
|
+
|
|
156
|
+
Set layer="existence" in output.`,
|
|
157
|
+
{ label: 'layer:existence', phase: 'Check', schema: LAYER_SCHEMA, agentType: 'workflow-verifier' }
|
|
158
|
+
),
|
|
159
|
+
|
|
160
|
+
// Layer 2: Substance — verify artifacts are non-trivial
|
|
161
|
+
() => agent(
|
|
162
|
+
`Layer 2 — SUBSTANCE verification.
|
|
163
|
+
Goals: ${goals}
|
|
164
|
+
${planDir ? 'Plan directory: ' + planDir : ''}
|
|
165
|
+
${scope ? 'Scope: ' + scope : ''}
|
|
166
|
+
|
|
167
|
+
Verify artifacts contain REAL SUBSTANCE (not stubs):
|
|
168
|
+
1. Read implementation files — check for meaningful logic (not empty bodies, not pass-through)
|
|
169
|
+
2. Verify functions have real implementations (not "throw new Error('not implemented')")
|
|
170
|
+
3. Check tests actually test behavior (not empty test cases or skipped tests)
|
|
171
|
+
4. Verify configuration values are real (not placeholder/TODO values)
|
|
172
|
+
5. Check error handling is substantive (not empty catch blocks)
|
|
173
|
+
|
|
174
|
+
Set layer="substance" in output.`,
|
|
175
|
+
{ label: 'layer:substance', phase: 'Check', schema: LAYER_SCHEMA, agentType: 'workflow-verifier' }
|
|
176
|
+
),
|
|
177
|
+
|
|
178
|
+
// Layer 3: Connection — verify wiring
|
|
179
|
+
() => agent(
|
|
180
|
+
`Layer 3 — CONNECTION verification.
|
|
181
|
+
Goals: ${goals}
|
|
182
|
+
${planDir ? 'Plan directory: ' + planDir : ''}
|
|
183
|
+
${scope ? 'Scope: ' + scope : ''}
|
|
184
|
+
${mustHaves ? 'Must-haves (key_links): ' + mustHaves : ''}
|
|
185
|
+
|
|
186
|
+
Verify artifacts are properly WIRED together:
|
|
187
|
+
1. Check imports resolve correctly (no broken import paths)
|
|
188
|
+
2. Verify new modules are registered/exported from index files
|
|
189
|
+
3. Check routes are mounted, handlers connected
|
|
190
|
+
4. Verify event handlers and callbacks are wired
|
|
191
|
+
5. Check database models are used consistently across layers
|
|
192
|
+
6. Verify dependency injection and configuration loading
|
|
193
|
+
|
|
194
|
+
Set layer="connection" in output.`,
|
|
195
|
+
{ label: 'layer:connection', phase: 'Check', schema: LAYER_SCHEMA, agentType: 'workflow-verifier' }
|
|
196
|
+
),
|
|
197
|
+
]
|
|
198
|
+
|
|
199
|
+
// Anti-pattern scan (unless skipped)
|
|
200
|
+
if (!skipAntipattern) {
|
|
201
|
+
checks.push(() => agent(
|
|
202
|
+
`Anti-pattern scan for modified files.
|
|
203
|
+
${scope ? 'Scope: ' + scope : 'Scan recently modified files (use git diff --name-only).'}
|
|
204
|
+
|
|
205
|
+
Search for code quality anti-patterns using grep:
|
|
206
|
+
- TODO / FIXME comments that indicate incomplete work
|
|
207
|
+
- Empty catch blocks: catch (e) {} or catch { }
|
|
208
|
+
- Empty returns in functions that should return values
|
|
209
|
+
- @ts-ignore / @ts-expect-error without explanatory comment
|
|
210
|
+
- Skipped tests: .skip, xit, xdescribe, test.skip
|
|
211
|
+
- Hardcoded secrets: password=, api_key=, secret= with literal values
|
|
212
|
+
- Placeholder text: "lorem ipsum", "test123", "TODO", "PLACEHOLDER"
|
|
213
|
+
- Not-implemented stubs: throw new Error("not implemented"), pass, ...
|
|
214
|
+
|
|
215
|
+
Use Grep tool to find these patterns. Report each with exact file and line number.
|
|
216
|
+
Severity: "blocker" for stubs/not-implemented/hardcoded-secrets, "warning" for TODO/FIXME.`,
|
|
217
|
+
{ label: 'antipattern', phase: 'Check', schema: ANTIPATTERN_SCHEMA, agentType: 'workflow-verifier' }
|
|
218
|
+
))
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Per-task convergence validation (if task files provided)
|
|
222
|
+
if (taskFiles.length > 0) {
|
|
223
|
+
checks.push(...taskFiles.map((taskFile, idx) => () => agent(
|
|
224
|
+
`Per-task convergence validation for: ${taskFile}
|
|
225
|
+
|
|
226
|
+
1. Read the task JSON file at: ${taskFile}
|
|
227
|
+
2. Find convergence.criteria[] — each item is a condition that must be true
|
|
228
|
+
3. If convergence.verification command exists, run it via Bash
|
|
229
|
+
4. Check each criterion individually (pass/fail with specific evidence)
|
|
230
|
+
5. Cross-reference with task summaries in .summaries/ if they exist
|
|
231
|
+
|
|
232
|
+
Report overall_converged=true only if ALL criteria are met.`,
|
|
233
|
+
{ label: `convergence:task-${idx}`, phase: 'Check', schema: CONVERGENCE_SCHEMA, agentType: 'workflow-verifier' }
|
|
234
|
+
)))
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
log(`Running ${checks.length} parallel verification checks...`)
|
|
238
|
+
const results = await parallel(checks)
|
|
239
|
+
const validResults = results.filter(Boolean)
|
|
240
|
+
|
|
241
|
+
const layers = validResults.filter(r => r.layer)
|
|
242
|
+
const antipatterns = validResults.find(r => r.clean !== undefined) || { clean: true, findings: [] }
|
|
243
|
+
const convergenceResults = validResults.filter(r => r.task_id)
|
|
244
|
+
|
|
245
|
+
// Phase 2: Aggregate
|
|
246
|
+
phase('Aggregate')
|
|
247
|
+
|
|
248
|
+
const layerDigest = layers.map(l => {
|
|
249
|
+
const passCount = l.checks.filter(c => c.status === 'pass').length
|
|
250
|
+
const failCount = l.checks.filter(c => c.status === 'fail').length
|
|
251
|
+
return `Layer: ${l.layer} — ${l.passed ? 'PASS' : 'FAIL'} (${passCount} pass, ${failCount} fail)\n${l.summary}\nFailed checks:\n${l.checks.filter(c => c.status === 'fail').map(c => ` - ${c.goal}: ${c.gap || c.evidence}`).join('\n') || ' none'}`
|
|
252
|
+
}).join('\n\n')
|
|
253
|
+
|
|
254
|
+
const convergenceDigest = convergenceResults.length > 0
|
|
255
|
+
? `Convergence: ${convergenceResults.filter(c => c.overall_converged).length}/${convergenceResults.length} tasks converged\nUnmet criteria:\n${convergenceResults.filter(c => !c.overall_converged).flatMap(c => c.criteria_results.filter(cr => !cr.met).map(cr => ` - ${c.task_id}: ${cr.criterion}`)).join('\n') || ' none'}`
|
|
256
|
+
: 'No convergence criteria checked (no task files provided).'
|
|
257
|
+
|
|
258
|
+
const antipatternDigest = antipatterns.clean
|
|
259
|
+
? 'Anti-pattern scan: CLEAN'
|
|
260
|
+
: `Anti-pattern scan: ${antipatterns.findings.length} issues (${antipatterns.findings.filter(f => f.severity === 'blocker').length} blockers)\n${antipatterns.findings.map(f => ` [${f.severity}] ${f.type} @ ${f.file}:${f.line || '?'}: ${f.content}`).join('\n')}`
|
|
261
|
+
|
|
262
|
+
const aggregate = await agent(
|
|
263
|
+
`Aggregate all verification results into a final assessment.
|
|
264
|
+
|
|
265
|
+
${layerDigest}
|
|
266
|
+
|
|
267
|
+
${convergenceDigest}
|
|
268
|
+
|
|
269
|
+
${antipatternDigest}
|
|
270
|
+
|
|
271
|
+
Determine:
|
|
272
|
+
1. Overall status: "pass" requires ALL layers pass AND no antipattern blockers AND all convergence met
|
|
273
|
+
2. Confidence score (0-100) — based on evidence strength and coverage
|
|
274
|
+
3. Per-layer summary with check counts
|
|
275
|
+
4. Convergence summary (if tasks checked)
|
|
276
|
+
5. Consolidated gap list: extract every failed check and antipattern blocker, assign severity, suggest remediation
|
|
277
|
+
6. Executive summary (what works, what's broken, what to do next)`,
|
|
278
|
+
{ label: 'aggregate', phase: 'Aggregate', schema: AGGREGATE_SCHEMA }
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
layers: layers,
|
|
283
|
+
convergence: convergenceResults,
|
|
284
|
+
antipatterns: antipatterns,
|
|
285
|
+
aggregate: aggregate,
|
|
286
|
+
metadata: {
|
|
287
|
+
layer_count: layers.length,
|
|
288
|
+
total_checks: layers.reduce((sum, l) => sum + l.checks.length, 0),
|
|
289
|
+
passed_checks: layers.reduce((sum, l) => sum + l.checks.filter(c => c.status === 'pass').length, 0),
|
|
290
|
+
failed_checks: layers.reduce((sum, l) => sum + l.checks.filter(c => c.status === 'fail').length, 0),
|
|
291
|
+
convergence_tasks: convergenceResults.length,
|
|
292
|
+
converged_tasks: convergenceResults.filter(c => c.overall_converged).length,
|
|
293
|
+
antipattern_count: antipatterns.findings.length,
|
|
294
|
+
blocker_count: antipatterns.findings.filter(f => f.severity === 'blocker').length,
|
|
295
|
+
overall_status: aggregate ? aggregate.status : 'unknown',
|
|
296
|
+
confidence: aggregate ? aggregate.confidence : 0,
|
|
297
|
+
},
|
|
298
|
+
}
|