agileflow 3.3.0 → 3.4.1
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/CHANGELOG.md +10 -0
- package/README.md +6 -6
- package/lib/skill-loader.js +0 -1
- package/package.json +1 -1
- package/scripts/agileflow-statusline.sh +81 -0
- package/scripts/agileflow-welcome.js +79 -0
- package/scripts/claude-tmux.sh +90 -23
- package/scripts/claude-watchdog.sh +225 -0
- package/scripts/generators/agent-registry.js +14 -1
- package/scripts/generators/inject-babysit.js +22 -9
- package/scripts/generators/inject-help.js +19 -9
- package/scripts/lib/ac-test-matcher.js +452 -0
- package/scripts/lib/audit-cleanup.js +250 -0
- package/scripts/lib/audit-registry.js +304 -0
- package/scripts/lib/configure-features.js +35 -0
- package/scripts/lib/feature-catalog.js +3 -3
- package/scripts/lib/gate-enforcer.js +295 -0
- package/scripts/lib/model-profiles.js +118 -0
- package/scripts/lib/quality-gates.js +163 -0
- package/scripts/lib/signal-detectors.js +44 -1
- package/scripts/lib/skill-catalog.js +557 -0
- package/scripts/lib/skill-recommender.js +311 -0
- package/scripts/lib/status-writer.js +255 -0
- package/scripts/lib/story-claiming.js +128 -45
- package/scripts/lib/task-sync.js +32 -38
- package/scripts/lib/tdd-phase-manager.js +455 -0
- package/scripts/lib/team-events.js +34 -3
- package/scripts/lib/tmux-audit-monitor.js +611 -0
- package/scripts/lib/tmux-group-colors.js +113 -0
- package/scripts/lib/tool-registry.yaml +241 -0
- package/scripts/lib/tool-shed.js +441 -0
- package/scripts/messaging-bridge.js +209 -1
- package/scripts/native-team-observer.js +219 -0
- package/scripts/obtain-context.js +14 -0
- package/scripts/ralph-loop.js +30 -5
- package/scripts/smart-detect.js +21 -0
- package/scripts/spawn-audit-sessions.js +877 -0
- package/scripts/team-manager.js +56 -16
- package/scripts/tmux-close-windows.sh +180 -0
- package/src/core/agents/a11y-analyzer-aria.md +155 -0
- package/src/core/agents/a11y-analyzer-forms.md +162 -0
- package/src/core/agents/a11y-analyzer-keyboard.md +175 -0
- package/src/core/agents/a11y-analyzer-semantic.md +153 -0
- package/src/core/agents/a11y-analyzer-visual.md +158 -0
- package/src/core/agents/a11y-consensus.md +248 -0
- package/src/core/agents/ads-audit-budget.md +181 -0
- package/src/core/agents/ads-audit-compliance.md +169 -0
- package/src/core/agents/ads-audit-creative.md +164 -0
- package/src/core/agents/ads-audit-google.md +226 -0
- package/src/core/agents/ads-audit-meta.md +183 -0
- package/src/core/agents/ads-audit-tracking.md +197 -0
- package/src/core/agents/ads-consensus.md +396 -0
- package/src/core/agents/ads-generate.md +145 -0
- package/src/core/agents/ads-performance-tracker.md +197 -0
- package/src/core/agents/api-quality-analyzer-conventions.md +148 -0
- package/src/core/agents/api-quality-analyzer-docs.md +176 -0
- package/src/core/agents/api-quality-analyzer-errors.md +183 -0
- package/src/core/agents/api-quality-analyzer-pagination.md +171 -0
- package/src/core/agents/api-quality-analyzer-versioning.md +143 -0
- package/src/core/agents/api-quality-consensus.md +214 -0
- package/src/core/agents/arch-analyzer-circular.md +148 -0
- package/src/core/agents/arch-analyzer-complexity.md +171 -0
- package/src/core/agents/arch-analyzer-coupling.md +146 -0
- package/src/core/agents/arch-analyzer-layering.md +151 -0
- package/src/core/agents/arch-analyzer-patterns.md +162 -0
- package/src/core/agents/arch-consensus.md +227 -0
- package/src/core/agents/brainstorm-analyzer-features.md +169 -0
- package/src/core/agents/brainstorm-analyzer-growth.md +161 -0
- package/src/core/agents/brainstorm-analyzer-integration.md +172 -0
- package/src/core/agents/brainstorm-analyzer-market.md +147 -0
- package/src/core/agents/brainstorm-analyzer-ux.md +167 -0
- package/src/core/agents/brainstorm-consensus.md +237 -0
- package/src/core/agents/completeness-consensus.md +5 -5
- package/src/core/agents/perf-consensus.md +2 -2
- package/src/core/agents/security-consensus.md +2 -2
- package/src/core/agents/seo-analyzer-content.md +167 -0
- package/src/core/agents/seo-analyzer-images.md +187 -0
- package/src/core/agents/seo-analyzer-performance.md +206 -0
- package/src/core/agents/seo-analyzer-schema.md +176 -0
- package/src/core/agents/seo-analyzer-sitemap.md +172 -0
- package/src/core/agents/seo-analyzer-technical.md +144 -0
- package/src/core/agents/seo-consensus.md +289 -0
- package/src/core/agents/test-consensus.md +2 -2
- package/src/core/commands/adr.md +1 -0
- package/src/core/commands/ads/audit.md +375 -0
- package/src/core/commands/ads/budget.md +97 -0
- package/src/core/commands/ads/competitor.md +112 -0
- package/src/core/commands/ads/creative.md +85 -0
- package/src/core/commands/ads/generate.md +238 -0
- package/src/core/commands/ads/google.md +112 -0
- package/src/core/commands/ads/health.md +327 -0
- package/src/core/commands/ads/landing.md +119 -0
- package/src/core/commands/ads/linkedin.md +112 -0
- package/src/core/commands/ads/meta.md +91 -0
- package/src/core/commands/ads/microsoft.md +115 -0
- package/src/core/commands/ads/plan.md +321 -0
- package/src/core/commands/ads/test-plan.md +317 -0
- package/src/core/commands/ads/tiktok.md +129 -0
- package/src/core/commands/ads/track.md +288 -0
- package/src/core/commands/ads/youtube.md +124 -0
- package/src/core/commands/ads.md +140 -0
- package/src/core/commands/assign.md +1 -0
- package/src/core/commands/audit.md +43 -6
- package/src/core/commands/babysit.md +315 -1266
- package/src/core/commands/baseline.md +1 -0
- package/src/core/commands/blockers.md +1 -0
- package/src/core/commands/board.md +1 -0
- package/src/core/commands/changelog.md +1 -0
- package/src/core/commands/choose.md +1 -0
- package/src/core/commands/ci.md +1 -0
- package/src/core/commands/code/accessibility.md +347 -0
- package/src/core/commands/code/api.md +297 -0
- package/src/core/commands/code/architecture.md +297 -0
- package/src/core/commands/{audit → code}/completeness.md +72 -25
- package/src/core/commands/{audit → code}/legal.md +63 -16
- package/src/core/commands/{audit → code}/logic.md +64 -16
- package/src/core/commands/{audit → code}/performance.md +67 -20
- package/src/core/commands/{audit → code}/security.md +69 -19
- package/src/core/commands/{audit → code}/test.md +67 -20
- package/src/core/commands/configure.md +1 -0
- package/src/core/commands/council.md +1 -0
- package/src/core/commands/deploy.md +1 -0
- package/src/core/commands/diagnose.md +1 -0
- package/src/core/commands/docs.md +1 -0
- package/src/core/commands/epic/edit.md +213 -0
- package/src/core/commands/epic.md +1 -0
- package/src/core/commands/export.md +238 -0
- package/src/core/commands/help.md +16 -1
- package/src/core/commands/{discovery → ideate}/brief.md +12 -12
- package/src/core/commands/{discovery/new.md → ideate/discover.md} +20 -16
- package/src/core/commands/ideate/features.md +496 -0
- package/src/core/commands/ideate/new.md +158 -124
- package/src/core/commands/impact.md +1 -0
- package/src/core/commands/learn/explain.md +118 -0
- package/src/core/commands/learn/glossary.md +135 -0
- package/src/core/commands/learn/patterns.md +138 -0
- package/src/core/commands/learn/tour.md +126 -0
- package/src/core/commands/migrate/codemods.md +151 -0
- package/src/core/commands/migrate/plan.md +131 -0
- package/src/core/commands/migrate/scan.md +114 -0
- package/src/core/commands/migrate/validate.md +119 -0
- package/src/core/commands/multi-expert.md +1 -0
- package/src/core/commands/pr.md +1 -0
- package/src/core/commands/review.md +1 -0
- package/src/core/commands/seo/audit.md +373 -0
- package/src/core/commands/seo/competitor.md +174 -0
- package/src/core/commands/seo/content.md +107 -0
- package/src/core/commands/seo/geo.md +229 -0
- package/src/core/commands/seo/hreflang.md +140 -0
- package/src/core/commands/seo/images.md +96 -0
- package/src/core/commands/seo/page.md +198 -0
- package/src/core/commands/seo/plan.md +163 -0
- package/src/core/commands/seo/programmatic.md +131 -0
- package/src/core/commands/seo/references/cwv-thresholds.md +64 -0
- package/src/core/commands/seo/references/eeat-framework.md +110 -0
- package/src/core/commands/seo/references/quality-gates.md +91 -0
- package/src/core/commands/seo/references/schema-types.md +102 -0
- package/src/core/commands/seo/schema.md +183 -0
- package/src/core/commands/seo/sitemap.md +97 -0
- package/src/core/commands/seo/technical.md +100 -0
- package/src/core/commands/seo.md +107 -0
- package/src/core/commands/skill/list.md +68 -212
- package/src/core/commands/skill/recommend.md +216 -0
- package/src/core/commands/sprint.md +1 -0
- package/src/core/commands/status/undo.md +191 -0
- package/src/core/commands/status.md +1 -0
- package/src/core/commands/story/edit.md +204 -0
- package/src/core/commands/story/view.md +29 -7
- package/src/core/commands/story-validate.md +1 -0
- package/src/core/commands/story.md +1 -0
- package/src/core/commands/tdd-next.md +238 -0
- package/src/core/commands/tdd.md +211 -0
- package/src/core/commands/team/start.md +10 -6
- package/src/core/commands/tests.md +1 -0
- package/src/core/commands/verify.md +27 -1
- package/src/core/commands/workflow.md +2 -0
- package/src/core/experts/_core-expertise.yaml +105 -0
- package/src/core/experts/analytics/expertise.yaml +5 -99
- package/src/core/experts/codebase-query/expertise.yaml +3 -72
- package/src/core/experts/compliance/expertise.yaml +6 -72
- package/src/core/experts/database/expertise.yaml +9 -52
- package/src/core/experts/documentation/expertise.yaml +7 -140
- package/src/core/experts/integrations/expertise.yaml +7 -127
- package/src/core/experts/mentor/expertise.yaml +8 -35
- package/src/core/experts/monitoring/expertise.yaml +7 -49
- package/src/core/experts/performance/expertise.yaml +1 -26
- package/src/core/experts/security/expertise.yaml +9 -34
- package/src/core/experts/ui/expertise.yaml +6 -36
- package/src/core/knowledge/ads/ad-audit-checklist-scoring.md +424 -0
- package/src/core/knowledge/ads/ad-optimization-logic.md +590 -0
- package/src/core/knowledge/ads/ad-technical-specifications.md +385 -0
- package/src/core/knowledge/ads/definitive-advertising-reference-2026.md +506 -0
- package/src/core/knowledge/ads/paid-advertising-research-2026.md +445 -0
- package/src/core/teams/backend.json +41 -0
- package/src/core/teams/frontend.json +41 -0
- package/src/core/teams/qa.json +41 -0
- package/src/core/teams/solo.json +35 -0
- package/src/core/templates/agileflow-metadata.json +20 -1
- package/tools/cli/commands/setup.js +85 -3
- package/tools/cli/commands/update.js +42 -0
- package/tools/cli/installers/ide/_base-ide.js +42 -5
- package/tools/cli/installers/ide/claude-code.js +71 -3
- package/tools/cli/lib/content-injector.js +160 -12
- package/tools/cli/lib/docs-setup.js +1 -1
- package/src/core/commands/skill/create.md +0 -698
- package/src/core/commands/skill/delete.md +0 -316
- package/src/core/commands/skill/edit.md +0 -359
- package/src/core/commands/skill/test.md +0 -394
- package/src/core/commands/skill/upgrade.md +0 -552
- package/src/core/templates/skill-template.md +0 -117
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* audit-registry.js - Static registry mapping audit types to analyzers
|
|
3
|
+
*
|
|
4
|
+
* Centralizes the mapping of 6 audit commands to their analyzer agents,
|
|
5
|
+
* consensus coordinators, and depth configurations. Previously this info
|
|
6
|
+
* was duplicated across 6 .md command files.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* const { getAuditType, getAnalyzersForAudit } = require('./audit-registry');
|
|
10
|
+
* const security = getAuditType('security');
|
|
11
|
+
* const focused = getAnalyzersForAudit('security', 'deep', ['injection', 'auth']);
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Complete audit type registry.
|
|
16
|
+
* Each entry defines: name, short prefix for tmux, color for tab groups,
|
|
17
|
+
* all analyzers with their subagent_type, which are quick vs deep,
|
|
18
|
+
* and the consensus coordinator.
|
|
19
|
+
*/
|
|
20
|
+
const AUDIT_TYPES = {
|
|
21
|
+
logic: {
|
|
22
|
+
name: 'Logic Analysis',
|
|
23
|
+
prefix: 'Logic',
|
|
24
|
+
color: '#7aa2f7', // sky
|
|
25
|
+
command: 'code/logic',
|
|
26
|
+
analyzers: {
|
|
27
|
+
edge: { subagent_type: 'logic-analyzer-edge', label: 'Edge Cases' },
|
|
28
|
+
invariant: { subagent_type: 'logic-analyzer-invariant', label: 'Invariants' },
|
|
29
|
+
flow: { subagent_type: 'logic-analyzer-flow', label: 'Control Flow' },
|
|
30
|
+
type: { subagent_type: 'logic-analyzer-type', label: 'Type Safety' },
|
|
31
|
+
race: { subagent_type: 'logic-analyzer-race', label: 'Race Conditions' },
|
|
32
|
+
},
|
|
33
|
+
consensus: { subagent_type: 'logic-consensus', label: 'Logic Consensus' },
|
|
34
|
+
quick_analyzers: ['edge', 'invariant', 'flow', 'type', 'race'],
|
|
35
|
+
deep_analyzers: ['edge', 'invariant', 'flow', 'type', 'race'],
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
security: {
|
|
39
|
+
name: 'Security Vulnerability',
|
|
40
|
+
prefix: 'Sec',
|
|
41
|
+
color: '#f7768e', // coral
|
|
42
|
+
command: 'code/security',
|
|
43
|
+
analyzers: {
|
|
44
|
+
injection: { subagent_type: 'security-analyzer-injection', label: 'Injection' },
|
|
45
|
+
auth: { subagent_type: 'security-analyzer-auth', label: 'Authentication' },
|
|
46
|
+
authz: { subagent_type: 'security-analyzer-authz', label: 'Authorization' },
|
|
47
|
+
secrets: { subagent_type: 'security-analyzer-secrets', label: 'Secrets' },
|
|
48
|
+
input: { subagent_type: 'security-analyzer-input', label: 'Input Validation' },
|
|
49
|
+
deps: { subagent_type: 'security-analyzer-deps', label: 'Dependencies' },
|
|
50
|
+
infra: { subagent_type: 'security-analyzer-infra', label: 'Infrastructure' },
|
|
51
|
+
api: { subagent_type: 'security-analyzer-api', label: 'API Security' },
|
|
52
|
+
},
|
|
53
|
+
consensus: { subagent_type: 'security-consensus', label: 'Security Consensus' },
|
|
54
|
+
quick_analyzers: ['injection', 'auth', 'authz', 'secrets', 'input'],
|
|
55
|
+
deep_analyzers: ['injection', 'auth', 'authz', 'secrets', 'input', 'deps', 'infra', 'api'],
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
performance: {
|
|
59
|
+
name: 'Performance Bottleneck',
|
|
60
|
+
prefix: 'Perf',
|
|
61
|
+
color: '#73daca', // mint
|
|
62
|
+
command: 'code/performance',
|
|
63
|
+
analyzers: {
|
|
64
|
+
queries: { subagent_type: 'perf-analyzer-queries', label: 'Queries' },
|
|
65
|
+
rendering: { subagent_type: 'perf-analyzer-rendering', label: 'Rendering' },
|
|
66
|
+
memory: { subagent_type: 'perf-analyzer-memory', label: 'Memory' },
|
|
67
|
+
bundle: { subagent_type: 'perf-analyzer-bundle', label: 'Bundle Size' },
|
|
68
|
+
compute: { subagent_type: 'perf-analyzer-compute', label: 'Compute' },
|
|
69
|
+
network: { subagent_type: 'perf-analyzer-network', label: 'Network' },
|
|
70
|
+
caching: { subagent_type: 'perf-analyzer-caching', label: 'Caching' },
|
|
71
|
+
assets: { subagent_type: 'perf-analyzer-assets', label: 'Assets' },
|
|
72
|
+
},
|
|
73
|
+
consensus: { subagent_type: 'perf-consensus', label: 'Performance Consensus' },
|
|
74
|
+
quick_analyzers: ['queries', 'rendering', 'memory', 'bundle', 'compute'],
|
|
75
|
+
deep_analyzers: [
|
|
76
|
+
'queries',
|
|
77
|
+
'rendering',
|
|
78
|
+
'memory',
|
|
79
|
+
'bundle',
|
|
80
|
+
'compute',
|
|
81
|
+
'network',
|
|
82
|
+
'caching',
|
|
83
|
+
'assets',
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
test: {
|
|
88
|
+
name: 'Test Quality',
|
|
89
|
+
prefix: 'Test',
|
|
90
|
+
color: '#e0af68', // amber
|
|
91
|
+
command: 'code/test',
|
|
92
|
+
analyzers: {
|
|
93
|
+
coverage: { subagent_type: 'test-analyzer-coverage', label: 'Coverage' },
|
|
94
|
+
fragility: { subagent_type: 'test-analyzer-fragility', label: 'Fragility' },
|
|
95
|
+
mocking: { subagent_type: 'test-analyzer-mocking', label: 'Mocking' },
|
|
96
|
+
assertions: { subagent_type: 'test-analyzer-assertions', label: 'Assertions' },
|
|
97
|
+
structure: { subagent_type: 'test-analyzer-structure', label: 'Structure' },
|
|
98
|
+
integration: { subagent_type: 'test-analyzer-integration', label: 'Integration' },
|
|
99
|
+
maintenance: { subagent_type: 'test-analyzer-maintenance', label: 'Maintenance' },
|
|
100
|
+
patterns: { subagent_type: 'test-analyzer-patterns', label: 'Anti-Patterns' },
|
|
101
|
+
},
|
|
102
|
+
consensus: { subagent_type: 'test-consensus', label: 'Test Consensus' },
|
|
103
|
+
quick_analyzers: ['coverage', 'fragility', 'mocking', 'assertions', 'structure'],
|
|
104
|
+
deep_analyzers: [
|
|
105
|
+
'coverage',
|
|
106
|
+
'fragility',
|
|
107
|
+
'mocking',
|
|
108
|
+
'assertions',
|
|
109
|
+
'structure',
|
|
110
|
+
'integration',
|
|
111
|
+
'maintenance',
|
|
112
|
+
'patterns',
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
completeness: {
|
|
117
|
+
name: 'Completeness',
|
|
118
|
+
prefix: 'Comp',
|
|
119
|
+
color: '#bb9af7', // violet
|
|
120
|
+
command: 'code/completeness',
|
|
121
|
+
analyzers: {
|
|
122
|
+
handlers: { subagent_type: 'completeness-analyzer-handlers', label: 'Handlers' },
|
|
123
|
+
routes: { subagent_type: 'completeness-analyzer-routes', label: 'Routes' },
|
|
124
|
+
api: { subagent_type: 'completeness-analyzer-api', label: 'API Endpoints' },
|
|
125
|
+
stubs: { subagent_type: 'completeness-analyzer-stubs', label: 'Stubs' },
|
|
126
|
+
state: { subagent_type: 'completeness-analyzer-state', label: 'State' },
|
|
127
|
+
imports: { subagent_type: 'completeness-analyzer-imports', label: 'Imports' },
|
|
128
|
+
conditional: { subagent_type: 'completeness-analyzer-conditional', label: 'Conditionals' },
|
|
129
|
+
},
|
|
130
|
+
consensus: { subagent_type: 'completeness-consensus', label: 'Completeness Consensus' },
|
|
131
|
+
quick_analyzers: ['handlers', 'routes', 'api', 'stubs', 'state'],
|
|
132
|
+
deep_analyzers: ['handlers', 'routes', 'api', 'stubs', 'state', 'imports', 'conditional'],
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
brainstorm: {
|
|
136
|
+
name: 'Feature Brainstorm',
|
|
137
|
+
prefix: 'Brain',
|
|
138
|
+
color: '#c0caf5', // lavender
|
|
139
|
+
command: 'ideate/features',
|
|
140
|
+
analyzers: {
|
|
141
|
+
features: { subagent_type: 'brainstorm-analyzer-features', label: 'Feature Gaps' },
|
|
142
|
+
ux: { subagent_type: 'brainstorm-analyzer-ux', label: 'UX Improvements' },
|
|
143
|
+
market: { subagent_type: 'brainstorm-analyzer-market', label: 'Market Features' },
|
|
144
|
+
growth: { subagent_type: 'brainstorm-analyzer-growth', label: 'Growth & Engagement' },
|
|
145
|
+
integration: { subagent_type: 'brainstorm-analyzer-integration', label: 'Integrations' },
|
|
146
|
+
},
|
|
147
|
+
consensus: { subagent_type: 'brainstorm-consensus', label: 'Brainstorm Consensus' },
|
|
148
|
+
quick_analyzers: ['features', 'ux', 'market'],
|
|
149
|
+
deep_analyzers: ['features', 'ux', 'market', 'growth', 'integration'],
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
ideate: {
|
|
153
|
+
name: 'Ideation',
|
|
154
|
+
prefix: 'Idea',
|
|
155
|
+
color: '#ff9e64', // orange
|
|
156
|
+
command: 'ideate/new',
|
|
157
|
+
analyzers: {
|
|
158
|
+
security: { subagent_type: 'agileflow-security', label: 'Security' },
|
|
159
|
+
performance: { subagent_type: 'agileflow-performance', label: 'Performance' },
|
|
160
|
+
refactor: { subagent_type: 'agileflow-refactor', label: 'Code Quality' },
|
|
161
|
+
ui: { subagent_type: 'agileflow-ui', label: 'UX/Design' },
|
|
162
|
+
testing: { subagent_type: 'agileflow-testing', label: 'Testing' },
|
|
163
|
+
api: { subagent_type: 'agileflow-api', label: 'API/Architecture' },
|
|
164
|
+
accessibility: { subagent_type: 'agileflow-accessibility', label: 'Accessibility' },
|
|
165
|
+
compliance: { subagent_type: 'agileflow-compliance', label: 'Compliance' },
|
|
166
|
+
database: { subagent_type: 'agileflow-database', label: 'Database' },
|
|
167
|
+
monitoring: { subagent_type: 'agileflow-monitoring', label: 'Monitoring' },
|
|
168
|
+
qa: { subagent_type: 'agileflow-qa', label: 'QA' },
|
|
169
|
+
analytics: { subagent_type: 'agileflow-analytics', label: 'Analytics' },
|
|
170
|
+
documentation: { subagent_type: 'agileflow-documentation', label: 'Documentation' },
|
|
171
|
+
},
|
|
172
|
+
consensus: null, // ideation does its own synthesis (no consensus coordinator)
|
|
173
|
+
quick_analyzers: ['security', 'performance', 'refactor', 'ui', 'testing', 'api'],
|
|
174
|
+
deep_analyzers: [
|
|
175
|
+
'security',
|
|
176
|
+
'performance',
|
|
177
|
+
'refactor',
|
|
178
|
+
'ui',
|
|
179
|
+
'testing',
|
|
180
|
+
'api',
|
|
181
|
+
'accessibility',
|
|
182
|
+
'compliance',
|
|
183
|
+
'database',
|
|
184
|
+
'monitoring',
|
|
185
|
+
'qa',
|
|
186
|
+
'analytics',
|
|
187
|
+
'documentation',
|
|
188
|
+
],
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
legal: {
|
|
192
|
+
name: 'Legal Risk',
|
|
193
|
+
prefix: 'Legal',
|
|
194
|
+
color: '#9ece6a', // lime
|
|
195
|
+
command: 'code/legal',
|
|
196
|
+
analyzers: {
|
|
197
|
+
privacy: { subagent_type: 'legal-analyzer-privacy', label: 'Privacy' },
|
|
198
|
+
terms: { subagent_type: 'legal-analyzer-terms', label: 'Terms' },
|
|
199
|
+
a11y: { subagent_type: 'legal-analyzer-a11y', label: 'Accessibility' },
|
|
200
|
+
licensing: { subagent_type: 'legal-analyzer-licensing', label: 'Licensing' },
|
|
201
|
+
consumer: { subagent_type: 'legal-analyzer-consumer', label: 'Consumer' },
|
|
202
|
+
security: { subagent_type: 'legal-analyzer-security', label: 'Security' },
|
|
203
|
+
ai: { subagent_type: 'legal-analyzer-ai', label: 'AI Compliance' },
|
|
204
|
+
content: { subagent_type: 'legal-analyzer-content', label: 'Content' },
|
|
205
|
+
international: { subagent_type: 'legal-analyzer-international', label: 'International' },
|
|
206
|
+
},
|
|
207
|
+
consensus: { subagent_type: 'legal-consensus', label: 'Legal Consensus' },
|
|
208
|
+
quick_analyzers: ['privacy', 'terms', 'a11y', 'licensing', 'consumer'],
|
|
209
|
+
deep_analyzers: [
|
|
210
|
+
'privacy',
|
|
211
|
+
'terms',
|
|
212
|
+
'a11y',
|
|
213
|
+
'licensing',
|
|
214
|
+
'consumer',
|
|
215
|
+
'security',
|
|
216
|
+
'ai',
|
|
217
|
+
'content',
|
|
218
|
+
'international',
|
|
219
|
+
],
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Get audit type configuration.
|
|
225
|
+
*
|
|
226
|
+
* @param {string} type - Audit type key (logic, security, performance, test, completeness, legal, ideate)
|
|
227
|
+
* @returns {object|null} Audit type config or null if invalid
|
|
228
|
+
*/
|
|
229
|
+
function getAuditType(type) {
|
|
230
|
+
return AUDIT_TYPES[type] || null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get all valid audit type keys.
|
|
235
|
+
*
|
|
236
|
+
* @returns {string[]} Array of audit type keys
|
|
237
|
+
*/
|
|
238
|
+
function getAuditTypeKeys() {
|
|
239
|
+
return Object.keys(AUDIT_TYPES);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get analyzers for a given audit type, depth, and focus.
|
|
244
|
+
*
|
|
245
|
+
* @param {string} type - Audit type key
|
|
246
|
+
* @param {string} [depth='quick'] - 'quick', 'deep', or 'ultradeep'
|
|
247
|
+
* @param {string[]} [focus] - Array of focus areas, or null/['all'] for all
|
|
248
|
+
* @returns {{ analyzers: Array<{ key: string, subagent_type: string, label: string }>, consensus: object }|null}
|
|
249
|
+
*/
|
|
250
|
+
function getAnalyzersForAudit(type, depth, focus) {
|
|
251
|
+
const audit = AUDIT_TYPES[type];
|
|
252
|
+
if (!audit) return null;
|
|
253
|
+
|
|
254
|
+
const effectiveDepth = depth === 'ultradeep' || depth === 'extreme' ? 'deep' : depth || 'quick';
|
|
255
|
+
const analyzerKeys = effectiveDepth === 'deep' ? audit.deep_analyzers : audit.quick_analyzers;
|
|
256
|
+
|
|
257
|
+
// Filter by focus if specified
|
|
258
|
+
let selectedKeys = analyzerKeys;
|
|
259
|
+
if (focus && focus.length > 0 && !focus.includes('all')) {
|
|
260
|
+
selectedKeys = analyzerKeys.filter(key => focus.includes(key));
|
|
261
|
+
// If focus specifies keys not in current depth, include them anyway
|
|
262
|
+
for (const f of focus) {
|
|
263
|
+
if (audit.analyzers[f] && !selectedKeys.includes(f)) {
|
|
264
|
+
selectedKeys.push(f);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const analyzers = selectedKeys.map(key => ({
|
|
270
|
+
key,
|
|
271
|
+
subagent_type: audit.analyzers[key].subagent_type,
|
|
272
|
+
label: audit.analyzers[key].label,
|
|
273
|
+
}));
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
analyzers,
|
|
277
|
+
consensus: audit.consensus,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Get analyzer count for a given audit type at each depth.
|
|
283
|
+
*
|
|
284
|
+
* @param {string} type - Audit type key
|
|
285
|
+
* @returns {{ quick: number, deep: number, total: number }|null}
|
|
286
|
+
*/
|
|
287
|
+
function getAnalyzerCounts(type) {
|
|
288
|
+
const audit = AUDIT_TYPES[type];
|
|
289
|
+
if (!audit) return null;
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
quick: audit.quick_analyzers.length,
|
|
293
|
+
deep: audit.deep_analyzers.length,
|
|
294
|
+
total: Object.keys(audit.analyzers).length,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
module.exports = {
|
|
299
|
+
AUDIT_TYPES,
|
|
300
|
+
getAuditType,
|
|
301
|
+
getAuditTypeKeys,
|
|
302
|
+
getAnalyzersForAudit,
|
|
303
|
+
getAnalyzerCounts,
|
|
304
|
+
};
|
|
@@ -393,6 +393,25 @@ function enableFeature(feature, options = {}, version) {
|
|
|
393
393
|
if (feature === 'agentteams') {
|
|
394
394
|
settings.env = settings.env || {};
|
|
395
395
|
settings.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = '1';
|
|
396
|
+
|
|
397
|
+
// Register PostToolUse hooks for native team observability
|
|
398
|
+
if (!settings.hooks) settings.hooks = {};
|
|
399
|
+
if (!settings.hooks.PostToolUse) settings.hooks.PostToolUse = [];
|
|
400
|
+
const observerCmd = 'node $CLAUDE_PROJECT_DIR/.agileflow/scripts/native-team-observer.js';
|
|
401
|
+
for (const matcher of ['TeamCreate', 'SendMessage', 'ListTeams']) {
|
|
402
|
+
const exists = settings.hooks.PostToolUse.some(
|
|
403
|
+
h =>
|
|
404
|
+
h.matcher === matcher &&
|
|
405
|
+
h.hooks?.some(hk => hk.command && hk.command.includes('native-team-observer'))
|
|
406
|
+
);
|
|
407
|
+
if (!exists) {
|
|
408
|
+
settings.hooks.PostToolUse.push({
|
|
409
|
+
matcher,
|
|
410
|
+
hooks: [{ type: 'command', command: observerCmd, timeout: 5000 }],
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
396
415
|
writeJSON('.claude/settings.json', settings);
|
|
397
416
|
updateMetadata(
|
|
398
417
|
{
|
|
@@ -408,6 +427,7 @@ function enableFeature(feature, options = {}, version) {
|
|
|
408
427
|
);
|
|
409
428
|
success('Native Agent Teams enabled');
|
|
410
429
|
info('Set CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 in .claude/settings.json');
|
|
430
|
+
info('Registered PostToolUse hooks for native team observability');
|
|
411
431
|
info('Claude Code will use native TeamCreate/SendMessage tools');
|
|
412
432
|
info('Fallback: subagent mode (Task/TaskOutput) when native is unavailable');
|
|
413
433
|
return true;
|
|
@@ -954,6 +974,20 @@ function disableFeature(feature, version) {
|
|
|
954
974
|
delete settings.env;
|
|
955
975
|
}
|
|
956
976
|
}
|
|
977
|
+
|
|
978
|
+
// Remove PostToolUse hooks for native team observer
|
|
979
|
+
if (settings.hooks?.PostToolUse) {
|
|
980
|
+
settings.hooks.PostToolUse = settings.hooks.PostToolUse.filter(
|
|
981
|
+
h => !h.hooks?.some(hk => hk.command && hk.command.includes('native-team-observer'))
|
|
982
|
+
);
|
|
983
|
+
if (settings.hooks.PostToolUse.length === 0) {
|
|
984
|
+
delete settings.hooks.PostToolUse;
|
|
985
|
+
}
|
|
986
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
987
|
+
delete settings.hooks;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
|
|
957
991
|
writeJSON('.claude/settings.json', settings);
|
|
958
992
|
updateMetadata(
|
|
959
993
|
{
|
|
@@ -969,6 +1003,7 @@ function disableFeature(feature, version) {
|
|
|
969
1003
|
);
|
|
970
1004
|
success('Native Agent Teams disabled');
|
|
971
1005
|
info('Removed CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS from .claude/settings.json');
|
|
1006
|
+
info('Removed PostToolUse hooks for native team observer');
|
|
972
1007
|
info('AgileFlow will use subagent mode (Task/TaskOutput) for multi-agent orchestration');
|
|
973
1008
|
return true;
|
|
974
1009
|
}
|
|
@@ -116,7 +116,7 @@ const FEATURE_CATALOG = [
|
|
|
116
116
|
feature: 'discovery',
|
|
117
117
|
name: 'Discovery',
|
|
118
118
|
description: 'Brainstorm, research, and synthesize findings into a Product Brief',
|
|
119
|
-
how_to_use: '/agileflow:
|
|
119
|
+
how_to_use: '/agileflow:ideate:discover "<topic>"',
|
|
120
120
|
category: 'workflow',
|
|
121
121
|
detector: null,
|
|
122
122
|
auto_mode: null,
|
|
@@ -168,7 +168,7 @@ const FEATURE_CATALOG = [
|
|
|
168
168
|
feature: 'logic-audit',
|
|
169
169
|
name: 'Logic Audit',
|
|
170
170
|
description: 'Multi-agent analysis for edge cases, race conditions, type bugs, and dead code',
|
|
171
|
-
how_to_use: '/agileflow:
|
|
171
|
+
how_to_use: '/agileflow:code:logic',
|
|
172
172
|
category: 'analysis',
|
|
173
173
|
detector: null,
|
|
174
174
|
auto_mode: null,
|
|
@@ -179,7 +179,7 @@ const FEATURE_CATALOG = [
|
|
|
179
179
|
name: 'Completeness Audit',
|
|
180
180
|
description:
|
|
181
181
|
'Multi-agent analysis for forgotten features, dead handlers, stub code, and incomplete implementations',
|
|
182
|
-
how_to_use: '/agileflow:
|
|
182
|
+
how_to_use: '/agileflow:code:completeness',
|
|
183
183
|
category: 'analysis',
|
|
184
184
|
detector: null,
|
|
185
185
|
auto_mode: null,
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gate-enforcer.js - Workflow Gate Enforcement for Babysit Strict Mode
|
|
3
|
+
*
|
|
4
|
+
* Filters AskUserQuestion options based on workflow gate status.
|
|
5
|
+
* When STRICT=true in babysit, certain options are removed or blocked
|
|
6
|
+
* based on whether gates have been satisfied (tests passed, review done, etc.).
|
|
7
|
+
*
|
|
8
|
+
* Gates:
|
|
9
|
+
* - tests_passed: Must run and pass tests before commit
|
|
10
|
+
* - review_done: Must run code review for 5+ source files before commit
|
|
11
|
+
* - logic_audit_done: Must run logic audit before commit (advisory in non-strict)
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* const { filterOptions, getGateStatus, updateGate } = require('./gate-enforcer');
|
|
15
|
+
* const filtered = filterOptions(options, gateState, { strict: true });
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Constants
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Gate types that can block workflow progression
|
|
26
|
+
*/
|
|
27
|
+
const GATES = {
|
|
28
|
+
TESTS_PASSED: 'tests_passed',
|
|
29
|
+
REVIEW_DONE: 'review_done',
|
|
30
|
+
LOGIC_AUDIT_DONE: 'logic_audit_done',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Actions that require specific gates to be satisfied
|
|
35
|
+
*/
|
|
36
|
+
const GATE_REQUIREMENTS = {
|
|
37
|
+
commit: {
|
|
38
|
+
strict: [GATES.TESTS_PASSED],
|
|
39
|
+
strict_5plus: [GATES.TESTS_PASSED, GATES.REVIEW_DONE],
|
|
40
|
+
},
|
|
41
|
+
next_story: {
|
|
42
|
+
strict: [GATES.TESTS_PASSED],
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Patterns that identify commit-related options
|
|
48
|
+
*/
|
|
49
|
+
const COMMIT_PATTERNS = [/^commit/i, /^git commit/i, /commit.*changes/i, /commit:?\s/i];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Patterns that identify "skip" options
|
|
53
|
+
*/
|
|
54
|
+
const SKIP_PATTERNS = [/skip.*test/i, /skip.*review/i, /skip.*audit/i, /skip.*verif/i];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Patterns that identify "next story" options
|
|
58
|
+
*/
|
|
59
|
+
const NEXT_STORY_PATTERNS = [/continue to/i, /next story/i, /move to.*US-/i];
|
|
60
|
+
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// Gate State Management
|
|
63
|
+
// ============================================================================
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create initial gate state for a workflow session
|
|
67
|
+
* @param {Object} options
|
|
68
|
+
* @param {number} options.filesChanged - Number of source files modified
|
|
69
|
+
* @param {boolean} options.strict - Whether strict mode is enabled
|
|
70
|
+
* @returns {Object} Initial gate state
|
|
71
|
+
*/
|
|
72
|
+
function createGateState(options = {}) {
|
|
73
|
+
const { filesChanged = 0, strict = false } = options;
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
strict,
|
|
77
|
+
files_changed: filesChanged,
|
|
78
|
+
gates: {
|
|
79
|
+
[GATES.TESTS_PASSED]: false,
|
|
80
|
+
[GATES.REVIEW_DONE]: false,
|
|
81
|
+
[GATES.LOGIC_AUDIT_DONE]: false,
|
|
82
|
+
},
|
|
83
|
+
history: [],
|
|
84
|
+
created_at: new Date().toISOString(),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Update a gate's status
|
|
90
|
+
* @param {Object} gateState - Current gate state
|
|
91
|
+
* @param {string} gate - Gate name from GATES
|
|
92
|
+
* @param {boolean} passed - Whether the gate passed
|
|
93
|
+
* @param {Object} metadata - Additional info (e.g., test count, review findings)
|
|
94
|
+
* @returns {Object} Updated gate state
|
|
95
|
+
*/
|
|
96
|
+
function updateGate(gateState, gate, passed, metadata = {}) {
|
|
97
|
+
if (!Object.values(GATES).includes(gate)) {
|
|
98
|
+
throw new Error(`Unknown gate: ${gate}. Valid: ${Object.values(GATES).join(', ')}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const updated = {
|
|
102
|
+
...gateState,
|
|
103
|
+
gates: {
|
|
104
|
+
...gateState.gates,
|
|
105
|
+
[gate]: passed,
|
|
106
|
+
},
|
|
107
|
+
history: [
|
|
108
|
+
...gateState.history,
|
|
109
|
+
{
|
|
110
|
+
gate,
|
|
111
|
+
passed,
|
|
112
|
+
at: new Date().toISOString(),
|
|
113
|
+
...metadata,
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
return updated;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Check if all required gates for an action are satisfied
|
|
123
|
+
* @param {Object} gateState - Current gate state
|
|
124
|
+
* @param {string} action - Action to check ('commit', 'next_story')
|
|
125
|
+
* @returns {{ allowed: boolean, missing: string[] }}
|
|
126
|
+
*/
|
|
127
|
+
function checkGates(gateState, action) {
|
|
128
|
+
if (!gateState.strict) {
|
|
129
|
+
return { allowed: true, missing: [] };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let requirements;
|
|
133
|
+
if (action === 'commit' && gateState.files_changed >= 5) {
|
|
134
|
+
requirements = GATE_REQUIREMENTS.commit.strict_5plus || [];
|
|
135
|
+
} else {
|
|
136
|
+
requirements = (GATE_REQUIREMENTS[action] && GATE_REQUIREMENTS[action].strict) || [];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const missing = requirements.filter(gate => !gateState.gates[gate]);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
allowed: missing.length === 0,
|
|
143
|
+
missing,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ============================================================================
|
|
148
|
+
// Option Filtering
|
|
149
|
+
// ============================================================================
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Check if an option label matches any pattern in a list
|
|
153
|
+
* @param {string} label - Option label text
|
|
154
|
+
* @param {RegExp[]} patterns - Patterns to match against
|
|
155
|
+
* @returns {boolean}
|
|
156
|
+
*/
|
|
157
|
+
function matchesPattern(label, patterns) {
|
|
158
|
+
if (typeof label !== 'string') return false;
|
|
159
|
+
return patterns.some(p => p.test(label));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Filter AskUserQuestion options based on gate state
|
|
164
|
+
*
|
|
165
|
+
* In strict mode:
|
|
166
|
+
* - Remove "commit" options if tests haven't passed
|
|
167
|
+
* - Remove "commit" options if review not done (5+ files)
|
|
168
|
+
* - Remove "skip tests/review/audit" options
|
|
169
|
+
* - Add gate status hints to option descriptions
|
|
170
|
+
*
|
|
171
|
+
* In non-strict mode:
|
|
172
|
+
* - Options are returned unchanged (soft guidance only)
|
|
173
|
+
*
|
|
174
|
+
* @param {Object[]} options - AskUserQuestion options array
|
|
175
|
+
* @param {Object} gateState - Current gate state
|
|
176
|
+
* @returns {Object[]} Filtered options
|
|
177
|
+
*/
|
|
178
|
+
function filterOptions(options, gateState) {
|
|
179
|
+
if (!Array.isArray(options)) return [];
|
|
180
|
+
if (!gateState || !gateState.strict) {
|
|
181
|
+
return options;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return options
|
|
185
|
+
.filter(opt => {
|
|
186
|
+
const label = opt.label || '';
|
|
187
|
+
|
|
188
|
+
// In strict mode, remove skip options entirely
|
|
189
|
+
if (matchesPattern(label, SKIP_PATTERNS)) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Check commit gates
|
|
194
|
+
if (matchesPattern(label, COMMIT_PATTERNS)) {
|
|
195
|
+
const { allowed } = checkGates(gateState, 'commit');
|
|
196
|
+
if (!allowed) {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Check next story gates
|
|
202
|
+
if (matchesPattern(label, NEXT_STORY_PATTERNS)) {
|
|
203
|
+
const { allowed } = checkGates(gateState, 'next_story');
|
|
204
|
+
if (!allowed) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return true;
|
|
210
|
+
})
|
|
211
|
+
.map(opt => {
|
|
212
|
+
// Add gate status hints to descriptions
|
|
213
|
+
const label = opt.label || '';
|
|
214
|
+
|
|
215
|
+
if (matchesPattern(label, COMMIT_PATTERNS) && gateState.strict) {
|
|
216
|
+
const checks = [];
|
|
217
|
+
if (gateState.gates[GATES.TESTS_PASSED]) checks.push('tests passed');
|
|
218
|
+
if (gateState.gates[GATES.REVIEW_DONE]) checks.push('review done');
|
|
219
|
+
if (gateState.gates[GATES.LOGIC_AUDIT_DONE]) checks.push('audit done');
|
|
220
|
+
|
|
221
|
+
if (checks.length > 0) {
|
|
222
|
+
return {
|
|
223
|
+
...opt,
|
|
224
|
+
description: `${opt.description || ''} [Gates: ${checks.join(', ')}]`.trim(),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return opt;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get a human-readable gate status summary
|
|
235
|
+
* @param {Object} gateState - Current gate state
|
|
236
|
+
* @returns {string} Status summary
|
|
237
|
+
*/
|
|
238
|
+
function getGateStatusSummary(gateState) {
|
|
239
|
+
if (!gateState || !gateState.strict) {
|
|
240
|
+
return 'Strict mode: OFF (soft guidance)';
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const lines = [`Strict mode: ON | ${gateState.files_changed} files changed`];
|
|
244
|
+
|
|
245
|
+
for (const [gate, passed] of Object.entries(gateState.gates)) {
|
|
246
|
+
const icon = passed ? '✅' : '⬜';
|
|
247
|
+
const name = gate.replace(/_/g, ' ');
|
|
248
|
+
lines.push(` ${icon} ${name}`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return lines.join('\n');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Get blocking message for a failed gate check
|
|
256
|
+
* @param {string[]} missingGates - List of unsatisfied gates
|
|
257
|
+
* @returns {string} Human-readable blocking message
|
|
258
|
+
*/
|
|
259
|
+
function getBlockingMessage(missingGates) {
|
|
260
|
+
const messages = {
|
|
261
|
+
[GATES.TESTS_PASSED]: 'Run tests first (tests must pass before committing)',
|
|
262
|
+
[GATES.REVIEW_DONE]: 'Run code review first (required for 5+ modified files)',
|
|
263
|
+
[GATES.LOGIC_AUDIT_DONE]: 'Run logic audit first',
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
return missingGates.map(gate => `🚫 ${messages[gate] || gate}`).join('\n');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ============================================================================
|
|
270
|
+
// Exports
|
|
271
|
+
// ============================================================================
|
|
272
|
+
|
|
273
|
+
module.exports = {
|
|
274
|
+
// Constants
|
|
275
|
+
GATES,
|
|
276
|
+
GATE_REQUIREMENTS,
|
|
277
|
+
|
|
278
|
+
// State management
|
|
279
|
+
createGateState,
|
|
280
|
+
updateGate,
|
|
281
|
+
checkGates,
|
|
282
|
+
|
|
283
|
+
// Option filtering
|
|
284
|
+
filterOptions,
|
|
285
|
+
matchesPattern,
|
|
286
|
+
|
|
287
|
+
// Reporting
|
|
288
|
+
getGateStatusSummary,
|
|
289
|
+
getBlockingMessage,
|
|
290
|
+
|
|
291
|
+
// Patterns (for testing)
|
|
292
|
+
COMMIT_PATTERNS,
|
|
293
|
+
SKIP_PATTERNS,
|
|
294
|
+
NEXT_STORY_PATTERNS,
|
|
295
|
+
};
|