chati-dev 4.3.1 → 4.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.
Files changed (158) hide show
  1. package/README.md +18 -13
  2. package/bin/chati.js +28 -4
  3. package/framework/agents/build/dev.md +5 -1
  4. package/framework/agents/discover/greenfield-wu.md +16 -1
  5. package/framework/agents/plan/tasks.md +31 -0
  6. package/framework/agents/plan/ux-brand-architect.md +21 -2
  7. package/framework/agents/plan/ux-component-engineer.md +10 -0
  8. package/framework/agents/quality/qa-implementation.md +1 -1
  9. package/framework/agents/quality/qa-planning.md +1 -1
  10. package/framework/agents/quality/qa-visual.md +24 -21
  11. package/framework/config.yaml +5 -4
  12. package/framework/constitution.md +60 -11
  13. package/framework/context/governance.md +12 -10
  14. package/framework/context/root.md +2 -2
  15. package/framework/data/entity-registry.yaml +12 -4
  16. package/framework/data/qa-rubrics.yaml +335 -0
  17. package/framework/domains/constitution.yaml +3 -3
  18. package/framework/executors/json-validate.js +80 -0
  19. package/framework/executors/npm-script.js +72 -0
  20. package/framework/executors/path-check.js +67 -0
  21. package/framework/executors/registry.yaml +36 -0
  22. package/framework/hooks/advance-trigger.js +47 -3
  23. package/framework/hooks/constitution-guard.js +9 -4
  24. package/framework/hooks/git-push-authority.js +113 -0
  25. package/framework/hooks/license-guard.js +59 -9
  26. package/framework/hooks/model-governance.js +40 -17
  27. package/framework/hooks/prism-engine.js +78 -11
  28. package/framework/hooks/session-digest.js +12 -3
  29. package/framework/hooks/settings.json +7 -3
  30. package/framework/hooks/style-guard.js +52 -3
  31. package/framework/hooks/team-quality-gate.js +43 -5
  32. package/framework/i18n/en.yaml +3 -3
  33. package/framework/i18n/es.yaml +3 -3
  34. package/framework/i18n/fr.yaml +3 -3
  35. package/framework/i18n/pt.yaml +3 -3
  36. package/framework/intelligence/confidence.yaml +85 -6
  37. package/framework/intelligence/context-engine.md +9 -5
  38. package/framework/intelligence/decision-engine.md +1 -1
  39. package/framework/manifest.json +1351 -0
  40. package/framework/manifest.sig +1 -0
  41. package/framework/orchestrator/chati-router.js +1 -1
  42. package/framework/orchestrator/chati-update.md +19 -3
  43. package/framework/orchestrator/chati.md +24 -3
  44. package/framework/quality-gates/planning-gate.md +2 -0
  45. package/framework/scaffold/motion-premium/scaffold.yaml +2 -1
  46. package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
  47. package/framework/scaffold/saas-dashboard/README.md +58 -0
  48. package/framework/scaffold/saas-dashboard/app/dashboard/page.tsx.template +546 -0
  49. package/framework/scaffold/saas-dashboard/app/globals.css.template +746 -0
  50. package/framework/scaffold/saas-dashboard/app/layout.tsx.template +192 -0
  51. package/framework/scaffold/saas-dashboard/app/shell.css.template +1070 -0
  52. package/framework/scaffold/saas-dashboard/components/data/Chart.tsx.template +725 -0
  53. package/framework/scaffold/saas-dashboard/components/data/DataTable.tsx.template +623 -0
  54. package/framework/scaffold/saas-dashboard/components/data/DataTable.types.ts.template +104 -0
  55. package/framework/scaffold/saas-dashboard/components/data/DataTablePagination.tsx.template +234 -0
  56. package/framework/scaffold/saas-dashboard/components/data/SkeletonBlock.tsx.template +111 -0
  57. package/framework/scaffold/saas-dashboard/components/data/StatCard.tsx.template +393 -0
  58. package/framework/scaffold/saas-dashboard/components/data/StatCardGrid.tsx.template +121 -0
  59. package/framework/scaffold/saas-dashboard/components/feedback/EmptyState.tsx.template +281 -0
  60. package/framework/scaffold/saas-dashboard/components/interaction/CommandPalette.tsx.template +767 -0
  61. package/framework/scaffold/saas-dashboard/components/interaction/Field.tsx.template +351 -0
  62. package/framework/scaffold/saas-dashboard/components/interaction/Form.tsx.template +424 -0
  63. package/framework/scaffold/saas-dashboard/components/primitives/Badge.tsx.template +193 -0
  64. package/framework/scaffold/saas-dashboard/components/primitives/Button.tsx.template +261 -0
  65. package/framework/scaffold/saas-dashboard/components/primitives/Card.tsx.template +287 -0
  66. package/framework/scaffold/saas-dashboard/components/primitives/Input.tsx.template +310 -0
  67. package/framework/scaffold/saas-dashboard/components/primitives/Spinner.tsx.template +135 -0
  68. package/framework/scaffold/saas-dashboard/components/primitives/index.ts.template +60 -0
  69. package/framework/scaffold/saas-dashboard/components/shell/AppShell.tsx.template +174 -0
  70. package/framework/scaffold/saas-dashboard/components/shell/Breadcrumb.tsx.template +186 -0
  71. package/framework/scaffold/saas-dashboard/components/shell/Container.tsx.template +86 -0
  72. package/framework/scaffold/saas-dashboard/components/shell/NavItem.tsx.template +147 -0
  73. package/framework/scaffold/saas-dashboard/components/shell/Sidebar.tsx.template +378 -0
  74. package/framework/scaffold/saas-dashboard/components/shell/SidebarContext.tsx.template +169 -0
  75. package/framework/scaffold/saas-dashboard/components/shell/ThemeToggle.tsx.template +128 -0
  76. package/framework/scaffold/saas-dashboard/components/shell/Topbar.tsx.template +301 -0
  77. package/framework/scaffold/saas-dashboard/lib/brand.ts.template +324 -0
  78. package/framework/scaffold/saas-dashboard/scaffold.yaml +225 -0
  79. package/framework/schemas/session.schema.json +5 -0
  80. package/framework/schemas/task.schema.json +9 -0
  81. package/framework/scripts/visual-qa.js +87 -1
  82. package/framework/tasks/orchestrator-health.md +4 -4
  83. package/framework/tasks/qa-impl-verdict.md +11 -5
  84. package/framework/templates/qa-gate-tmpl.yaml +24 -11
  85. package/package.json +4 -4
  86. package/src/config/claude-settings-generator.js +9 -6
  87. package/src/config/context-file-generator.js +0 -6
  88. package/src/dashboard/renderer.js +0 -36
  89. package/src/executors/runner.js +204 -0
  90. package/src/installer/core.js +35 -4
  91. package/src/installer/manifest.js +30 -4
  92. package/src/installer/signing-public-key.pem +1 -1
  93. package/src/installer/templates.js +5 -6
  94. package/src/installer/validator.js +2 -1
  95. package/src/intelligence/registry-manager.js +3 -2
  96. package/src/license/client.js +9 -3
  97. package/src/license/commands.js +12 -2
  98. package/src/license/machine-id.js +42 -1
  99. package/src/memory/gotchas.js +58 -40
  100. package/src/memory/magic-docs.js +7 -2
  101. package/src/memory/session-digest.js +9 -4
  102. package/src/orchestrator/cli.js +195 -23
  103. package/src/orchestrator/deviation-handler.js +5 -3
  104. package/src/orchestrator/doctor.js +98 -16
  105. package/src/orchestrator/pipeline-manager.js +44 -22
  106. package/src/orchestrator/session-manager.js +56 -8
  107. package/src/telemetry/sender.js +7 -19
  108. package/src/terminal/run-parallel.js +14 -14
  109. package/src/terminal/run-team.js +3 -3
  110. package/src/upgrade/backup.js +22 -44
  111. package/src/upgrade/migrator.js +51 -12
  112. package/src/upgrade/tracked-files-detector.js +34 -16
  113. package/src/utils/constitution-meta.js +12 -0
  114. package/src/utils/feature-flags.js +26 -2
  115. package/src/utils/flatten-entities.js +4 -40
  116. package/src/utils/schema-validator.js +0 -14
  117. package/src/wizard/i18n.js +3 -3
  118. package/src/api/index.js +0 -120
  119. package/src/autonomy/autonomous-gate.js +0 -294
  120. package/src/autonomy/build-loop.js +0 -281
  121. package/src/autonomy/build-state.js +0 -286
  122. package/src/autonomy/cause-analyzer.js +0 -177
  123. package/src/autonomy/escalation.js +0 -214
  124. package/src/autonomy/index.js +0 -51
  125. package/src/autonomy/mode-manager.js +0 -225
  126. package/src/autonomy/mode-suggester.js +0 -283
  127. package/src/autonomy/progress-reporter.js +0 -275
  128. package/src/autonomy/safety-net.js +0 -370
  129. package/src/config/agent-customizer.js +0 -231
  130. package/src/decision/analyzer.js +0 -291
  131. package/src/decision/engine.js +0 -250
  132. package/src/decision/index.js +0 -38
  133. package/src/decision/registry-healer.js +0 -468
  134. package/src/decision/registry-updater.js +0 -339
  135. package/src/extensions/loader.js +0 -145
  136. package/src/extensions/registry.js +0 -134
  137. package/src/gates/circuit-breaker.js +0 -151
  138. package/src/gates/g1-planning-complete.js +0 -154
  139. package/src/gates/g2-qa-planning.js +0 -156
  140. package/src/gates/g3-implementation.js +0 -215
  141. package/src/gates/g4-qa-implementation.js +0 -240
  142. package/src/gates/g5-deploy-ready.js +0 -181
  143. package/src/gates/gate-base.js +0 -185
  144. package/src/gates/index.js +0 -46
  145. package/src/health/auto-fix.js +0 -216
  146. package/src/health/engine.js +0 -246
  147. package/src/merger/semantic-merger.js +0 -292
  148. package/src/preview/detector.js +0 -238
  149. package/src/preview/index.js +0 -20
  150. package/src/preview/launcher.js +0 -235
  151. package/src/preview/log-buffer.js +0 -103
  152. package/src/quality/metrics-collector.js +0 -281
  153. package/src/quality/test-runner.js +0 -366
  154. package/src/tasks/executor.js +0 -195
  155. package/src/tasks/index.js +0 -4
  156. package/src/tasks/loader.js +0 -210
  157. package/src/tasks/router.js +0 -182
  158. package/src/utils/event-bus.js +0 -126
@@ -1,283 +0,0 @@
1
- /**
2
- * @fileoverview Suggests optimal execution mode based on project context
3
- * Analyzes risk factors to recommend human-in-the-loop vs autonomous execution
4
- */
5
-
6
- import { EXECUTION_MODES } from './mode-manager.js';
7
-
8
- // Factor weights for mode suggestion
9
- const WEIGHTS = {
10
- GREENFIELD: 30,
11
- HIGH_TASK_COUNT: 20,
12
- RISK_DOMAIN: 25,
13
- HAS_HISTORY: 25,
14
- RECENT_GOTCHA: 15,
15
- };
16
-
17
- // Risk domains that increase score towards human-in-the-loop
18
- const HIGH_RISK_DOMAINS = [
19
- 'security',
20
- 'database',
21
- 'infrastructure',
22
- 'authentication',
23
- 'authorization',
24
- 'payment',
25
- 'data-migration',
26
- 'encryption',
27
- ];
28
-
29
- /**
30
- * Suggest execution mode based on project context.
31
- *
32
- * Factors:
33
- * - Project type: greenfield → human (higher risk), brownfield → autonomous
34
- * - Complexity: high (>10 tasks) → human, low → autonomous
35
- * - Risk: security/infra → human, UI/docs → autonomous
36
- * - History: first time → human, executed before → autonomous
37
- * - Gotchas: recent gotchas in domain → human
38
- *
39
- * @param {object} context
40
- * @param {boolean} context.isGreenfield
41
- * @param {number} [context.taskCount] - Estimated task count
42
- * @param {string[]} [context.riskDomains] - e.g. ['security', 'database', 'infrastructure']
43
- * @param {boolean} [context.hasHistory] - Project was built before
44
- * @param {number} [context.recentGotchas] - Number of recent gotchas
45
- * @returns {{ suggestion: string, confidence: number, factors: object[], reasoning: string }}
46
- */
47
- export function suggestMode(context) {
48
- const factors = [];
49
- let humanScore = 0;
50
-
51
- // Factor 1: Project type
52
- if (context.isGreenfield) {
53
- humanScore += WEIGHTS.GREENFIELD;
54
- factors.push({
55
- name: 'project_type',
56
- value: 'greenfield',
57
- impact: WEIGHTS.GREENFIELD,
58
- direction: 'human',
59
- reason: 'Greenfield projects have higher uncertainty',
60
- });
61
- } else {
62
- humanScore -= WEIGHTS.GREENFIELD;
63
- factors.push({
64
- name: 'project_type',
65
- value: 'brownfield',
66
- impact: -WEIGHTS.GREENFIELD,
67
- direction: 'autonomous',
68
- reason: 'Brownfield projects have established patterns',
69
- });
70
- }
71
-
72
- // Factor 2: Task complexity
73
- const taskCount = context.taskCount || 0;
74
- if (taskCount > 10) {
75
- humanScore += WEIGHTS.HIGH_TASK_COUNT;
76
- factors.push({
77
- name: 'task_count',
78
- value: taskCount,
79
- impact: WEIGHTS.HIGH_TASK_COUNT,
80
- direction: 'human',
81
- reason: `High task count (${taskCount}) increases complexity`,
82
- });
83
- } else if (taskCount > 0) {
84
- factors.push({
85
- name: 'task_count',
86
- value: taskCount,
87
- impact: 0,
88
- direction: 'neutral',
89
- reason: `Moderate task count (${taskCount}) is manageable`,
90
- });
91
- }
92
-
93
- // Factor 3: Risk domains
94
- const riskDomains = context.riskDomains || [];
95
- const highRiskCount = riskDomains.filter(domain =>
96
- HIGH_RISK_DOMAINS.includes(domain.toLowerCase())
97
- ).length;
98
-
99
- if (highRiskCount > 0) {
100
- const riskImpact = Math.min(highRiskCount * WEIGHTS.RISK_DOMAIN, 75); // Cap at 75
101
- humanScore += riskImpact;
102
- factors.push({
103
- name: 'risk_domains',
104
- value: riskDomains,
105
- impact: riskImpact,
106
- direction: 'human',
107
- reason: `High-risk domains detected: ${riskDomains.join(', ')}`,
108
- });
109
- } else if (riskDomains.length > 0) {
110
- factors.push({
111
- name: 'risk_domains',
112
- value: riskDomains,
113
- impact: 0,
114
- direction: 'neutral',
115
- reason: `Low-risk domains: ${riskDomains.join(', ')}`,
116
- });
117
- }
118
-
119
- // Factor 4: Project history
120
- if (context.hasHistory) {
121
- humanScore -= WEIGHTS.HAS_HISTORY;
122
- factors.push({
123
- name: 'history',
124
- value: true,
125
- impact: -WEIGHTS.HAS_HISTORY,
126
- direction: 'autonomous',
127
- reason: 'Project has been built before',
128
- });
129
- } else {
130
- humanScore += WEIGHTS.HAS_HISTORY;
131
- factors.push({
132
- name: 'history',
133
- value: false,
134
- impact: WEIGHTS.HAS_HISTORY,
135
- direction: 'human',
136
- reason: 'First-time project execution',
137
- });
138
- }
139
-
140
- // Factor 5: Recent gotchas
141
- const recentGotchas = context.recentGotchas || 0;
142
- if (recentGotchas > 0) {
143
- const gotchaImpact = Math.min(recentGotchas * WEIGHTS.RECENT_GOTCHA, 45); // Cap at 3 gotchas
144
- humanScore += gotchaImpact;
145
- factors.push({
146
- name: 'gotchas',
147
- value: recentGotchas,
148
- impact: gotchaImpact,
149
- direction: 'human',
150
- reason: `${recentGotchas} recent gotcha(s) detected`,
151
- });
152
- }
153
-
154
- // Calculate confidence based on factor strength
155
- const totalImpact = factors.reduce((sum, f) => sum + Math.abs(f.impact), 0);
156
- const confidence = Math.min(Math.round((totalImpact / 150) * 100), 100);
157
-
158
- // Determine suggestion
159
- const suggestion = humanScore > 50
160
- ? EXECUTION_MODES.HUMAN_IN_THE_LOOP
161
- : EXECUTION_MODES.AUTONOMOUS;
162
-
163
- // Build reasoning
164
- const reasoning = buildReasoning(suggestion, humanScore, factors);
165
-
166
- return {
167
- suggestion,
168
- confidence,
169
- factors,
170
- reasoning,
171
- score: humanScore,
172
- };
173
- }
174
-
175
- /**
176
- * Calculate risk score from project context.
177
- * @param {object} context
178
- * @returns {{ score: number, level: 'low'|'medium'|'high', factors: string[] }}
179
- */
180
- export function calculateRiskScore(context) {
181
- const riskFactors = [];
182
- let score = 0;
183
-
184
- // Greenfield adds base risk
185
- if (context.isGreenfield) {
186
- score += 25;
187
- riskFactors.push('greenfield project');
188
- }
189
-
190
- // High task count adds complexity risk
191
- if (context.taskCount > 10) {
192
- score += 20;
193
- riskFactors.push(`high task count (${context.taskCount})`);
194
- } else if (context.taskCount > 5) {
195
- score += 10;
196
- riskFactors.push(`moderate task count (${context.taskCount})`);
197
- }
198
-
199
- // Risk domains
200
- const riskDomains = context.riskDomains || [];
201
- const highRiskCount = riskDomains.filter(domain =>
202
- HIGH_RISK_DOMAINS.includes(domain.toLowerCase())
203
- ).length;
204
-
205
- score += highRiskCount * 15;
206
- if (highRiskCount > 0) {
207
- riskFactors.push(`${highRiskCount} high-risk domain(s)`);
208
- }
209
-
210
- // No history adds risk
211
- if (!context.hasHistory) {
212
- score += 15;
213
- riskFactors.push('no project history');
214
- }
215
-
216
- // Recent gotchas
217
- if (context.recentGotchas > 0) {
218
- score += Math.min(context.recentGotchas * 10, 30);
219
- riskFactors.push(`${context.recentGotchas} recent gotcha(s)`);
220
- }
221
-
222
- // Determine level
223
- let level;
224
- if (score < 30) {
225
- level = 'low';
226
- } else if (score < 60) {
227
- level = 'medium';
228
- } else {
229
- level = 'high';
230
- }
231
-
232
- return {
233
- score,
234
- level,
235
- factors: riskFactors,
236
- };
237
- }
238
-
239
- /**
240
- * Build human-readable reasoning for mode suggestion.
241
- * @param {string} suggestion
242
- * @param {number} score
243
- * @param {object[]} factors
244
- * @returns {string}
245
- */
246
- function buildReasoning(suggestion, score, factors) {
247
- const lines = [];
248
-
249
- if (suggestion === EXECUTION_MODES.HUMAN_IN_THE_LOOP) {
250
- lines.push(`Recommending human-in-the-loop mode (score: ${Math.round(score)}/100 towards human).`);
251
- } else {
252
- lines.push(`Recommending autonomous mode (score: ${Math.round(score)}/100 towards human, below threshold).`);
253
- }
254
-
255
- const humanFactors = factors.filter(f => f.direction === 'human');
256
- const autoFactors = factors.filter(f => f.direction === 'autonomous');
257
-
258
- if (humanFactors.length > 0) {
259
- lines.push('');
260
- lines.push('Factors favoring human validation:');
261
- humanFactors.forEach(f => {
262
- lines.push(` • ${f.reason} (+${f.impact})`);
263
- });
264
- }
265
-
266
- if (autoFactors.length > 0) {
267
- lines.push('');
268
- lines.push('Factors favoring autonomous execution:');
269
- autoFactors.forEach(f => {
270
- lines.push(` • ${f.reason} (${f.impact})`);
271
- });
272
- }
273
-
274
- return lines.join('\n');
275
- }
276
-
277
- /**
278
- * Get high-risk domain list.
279
- * @returns {string[]}
280
- */
281
- export function getHighRiskDomains() {
282
- return [...HIGH_RISK_DOMAINS];
283
- }
@@ -1,275 +0,0 @@
1
- /**
2
- * @fileoverview Progress reporting for autonomous execution
3
- * Reports progress to user without blocking the pipeline
4
- */
5
-
6
- /**
7
- * Build a progress report for the user.
8
- * @param {object} pipelineState
9
- * @param {object} [options] - { verbose: boolean }
10
- * @returns {{ summary: string, details: object, progress: number }}
11
- */
12
- export function buildProgressReport(pipelineState, options = {}) {
13
- const { verbose = false } = options;
14
-
15
- const progress = calculateCompletion(pipelineState);
16
- const summary = verbose
17
- ? formatDetailedReport(pipelineState)
18
- : formatProgressLine(pipelineState);
19
-
20
- const details = {
21
- currentAgent: pipelineState.current_agent,
22
- currentStage: pipelineState.current_stage,
23
- agentsCompleted: countCompletedAgents(pipelineState),
24
- agentsTotal: countTotalAgents(pipelineState),
25
- lastScore: pipelineState.last_score,
26
- warnings: pipelineState.warnings || [],
27
- };
28
-
29
- return {
30
- summary,
31
- details,
32
- progress,
33
- };
34
- }
35
-
36
- /**
37
- * Format progress as a compact one-line status.
38
- * Example: "[DISCOVER 2/3] brief ✅ → detail 🔄 (score: 92%)" or "[PLAN 3/6] phases 🔄 (score: 92%)"
39
- * @param {object} pipelineState
40
- * @returns {string}
41
- */
42
- export function formatProgressLine(pipelineState) {
43
- const stage = pipelineState.current_stage || 'INIT';
44
- const currentAgent = pipelineState.current_agent || 'none';
45
- const agentStatus = pipelineState.agent_status || {};
46
-
47
- // Count completed vs total in current stage
48
- const stageAgents = getStageAgents(stage);
49
- const completed = stageAgents.filter(a => agentStatus[a] === 'completed').length;
50
- const total = stageAgents.length;
51
-
52
- // Build agent chain
53
- const agentChain = buildAgentChain(stageAgents, agentStatus, currentAgent);
54
-
55
- // Add score if available
56
- const scoreInfo = pipelineState.last_score
57
- ? ` (score: ${pipelineState.last_score}%)`
58
- : '';
59
-
60
- return `[${stage} ${completed}/${total}] ${agentChain}${scoreInfo}`;
61
- }
62
-
63
- /**
64
- * Build a detailed multi-line report.
65
- * @param {object} pipelineState
66
- * @returns {string}
67
- */
68
- export function formatDetailedReport(pipelineState) {
69
- const lines = [];
70
- const progress = calculateCompletion(pipelineState);
71
- const stage = pipelineState.current_stage || 'INIT';
72
- const agentStatus = pipelineState.agent_status || {};
73
-
74
- lines.push(`Progress: ${progress}%`);
75
- lines.push(`Stage: ${stage}`);
76
- lines.push('');
77
-
78
- // DISCOVER agents
79
- lines.push('DISCOVER:');
80
- const discoverAgents = getStageAgents('DISCOVER');
81
- discoverAgents.forEach(agent => {
82
- const status = agentStatus[agent] || 'pending';
83
- const icon = getStatusIcon(status);
84
- const isActive = agent === pipelineState.current_agent;
85
- const prefix = isActive ? '→ ' : ' ';
86
- lines.push(`${prefix}${icon} ${agent}`);
87
- });
88
-
89
- lines.push('');
90
-
91
- // PLAN agents
92
- lines.push('PLAN:');
93
- const planAgents = getStageAgents('PLAN');
94
- planAgents.forEach(agent => {
95
- const status = agentStatus[agent] || 'pending';
96
- const icon = getStatusIcon(status);
97
- const isActive = agent === pipelineState.current_agent;
98
- const prefix = isActive ? '→ ' : ' ';
99
- lines.push(`${prefix}${icon} ${agent}`);
100
- });
101
-
102
- lines.push('');
103
-
104
- // BUILD agents
105
- lines.push('BUILD:');
106
- const buildAgents = getStageAgents('BUILD');
107
- buildAgents.forEach(agent => {
108
- const status = agentStatus[agent] || 'pending';
109
- const icon = getStatusIcon(status);
110
- const isActive = agent === pipelineState.current_agent;
111
- const prefix = isActive ? '→ ' : ' ';
112
- lines.push(`${prefix}${icon} ${agent}`);
113
- });
114
-
115
- lines.push('');
116
-
117
- // DEPLOY agents
118
- lines.push('DEPLOY:');
119
- const deployAgents = getStageAgents('DEPLOY');
120
- deployAgents.forEach(agent => {
121
- const status = agentStatus[agent] || 'pending';
122
- const icon = getStatusIcon(status);
123
- const isActive = agent === pipelineState.current_agent;
124
- const prefix = isActive ? '→ ' : ' ';
125
- lines.push(`${prefix}${icon} ${agent}`);
126
- });
127
-
128
- // Add warnings if any
129
- if (pipelineState.warnings && pipelineState.warnings.length > 0) {
130
- lines.push('');
131
- lines.push('Warnings:');
132
- pipelineState.warnings.forEach(warning => {
133
- lines.push(` ⚠ ${warning}`);
134
- });
135
- }
136
-
137
- return lines.join('\n');
138
- }
139
-
140
- /**
141
- * Calculate overall pipeline completion percentage.
142
- * @param {object} pipelineState
143
- * @returns {number} 0-100
144
- */
145
- export function calculateCompletion(pipelineState) {
146
- const agentStatus = pipelineState.agent_status || {};
147
- const allAgents = getAllAgents();
148
-
149
- const completed = Object.values(agentStatus).filter(s => s === 'completed').length;
150
- const total = allAgents.length;
151
-
152
- return total > 0 ? Math.round((completed / total) * 100) : 0;
153
- }
154
-
155
- /**
156
- * Get agents for a specific stage.
157
- * @param {string} stage
158
- * @returns {string[]}
159
- */
160
- function getStageAgents(stage) {
161
- const stages = {
162
- DISCOVER: ['greenfield-wu', 'brownfield-wu', 'brief'],
163
- PLAN: ['detail', 'architect', 'ux', 'phases', 'tasks'], // qa-planning runs inside Planning Team; score synced via team dissolution
164
- BUILD: ['dev', 'qa-implementation'],
165
- DEPLOY: ['devops'],
166
- };
167
-
168
- return stages[stage] || [];
169
- }
170
-
171
- /**
172
- * Get all agents in order.
173
- * @returns {string[]}
174
- */
175
- function getAllAgents() {
176
- return [
177
- ...getStageAgents('DISCOVER'),
178
- ...getStageAgents('PLAN'),
179
- ...getStageAgents('BUILD'),
180
- ...getStageAgents('DEPLOY'),
181
- ];
182
- }
183
-
184
- /**
185
- * Build agent chain visualization.
186
- * @param {string[]} agents
187
- * @param {object} agentStatus
188
- * @param {string} currentAgent
189
- * @returns {string}
190
- */
191
- function buildAgentChain(agents, agentStatus, currentAgent) {
192
- const parts = [];
193
-
194
- for (let i = 0; i < agents.length; i++) {
195
- const agent = agents[i];
196
- const status = agentStatus[agent] || 'pending';
197
- const isActive = agent === currentAgent;
198
-
199
- if (status === 'completed') {
200
- parts.push(`${agent} ✅`);
201
- } else if (isActive) {
202
- parts.push(`${agent} 🔄`);
203
- } else if (status === 'failed') {
204
- parts.push(`${agent} ❌`);
205
- } else {
206
- // Don't show pending agents in compact view
207
- break;
208
- }
209
-
210
- if (i < agents.length - 1 && (status === 'completed' || isActive)) {
211
- parts.push('→');
212
- }
213
- }
214
-
215
- return parts.join(' ');
216
- }
217
-
218
- /**
219
- * Get status icon for agent.
220
- * @param {string} status
221
- * @returns {string}
222
- */
223
- function getStatusIcon(status) {
224
- const icons = {
225
- completed: '✅',
226
- in_progress: '🔄',
227
- failed: '❌',
228
- pending: '⏸',
229
- skipped: '⏭',
230
- preview: '👁',
231
- };
232
-
233
- return icons[status] || '⏸';
234
- }
235
-
236
- /**
237
- * Count completed agents.
238
- * @param {object} pipelineState
239
- * @returns {number}
240
- */
241
- function countCompletedAgents(pipelineState) {
242
- const agentStatus = pipelineState.agent_status || {};
243
- return Object.values(agentStatus).filter(s => s === 'completed').length;
244
- }
245
-
246
- /**
247
- * Count total agents.
248
- * @param {object} _pipelineState
249
- * @returns {number}
250
- */
251
- function countTotalAgents(_pipelineState) {
252
- return getAllAgents().length;
253
- }
254
-
255
- /**
256
- * Get progress summary by stage.
257
- * @param {object} pipelineState
258
- * @returns {{ discover: number, plan: number, build: number, deploy: number }}
259
- */
260
- export function getStageProgress(pipelineState) {
261
- const agentStatus = pipelineState.agent_status || {};
262
-
263
- const getProgress = (stage) => {
264
- const agents = getStageAgents(stage);
265
- const completed = agents.filter(a => agentStatus[a] === 'completed').length;
266
- return agents.length > 0 ? Math.round((completed / agents.length) * 100) : 0;
267
- };
268
-
269
- return {
270
- discover: getProgress('DISCOVER'),
271
- plan: getProgress('PLAN'),
272
- build: getProgress('BUILD'),
273
- deploy: getProgress('DEPLOY'),
274
- };
275
- }