agileflow 2.90.6 → 2.91.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +6 -6
  3. package/lib/codebase-indexer.js +810 -0
  4. package/lib/validate-names.js +3 -3
  5. package/package.json +4 -1
  6. package/scripts/obtain-context.js +238 -0
  7. package/scripts/precompact-context.sh +13 -1
  8. package/scripts/query-codebase.js +430 -0
  9. package/scripts/tui/blessed/data/watcher.js +175 -0
  10. package/scripts/tui/blessed/index.js +244 -0
  11. package/scripts/tui/blessed/panels/output.js +95 -0
  12. package/scripts/tui/blessed/panels/sessions.js +143 -0
  13. package/scripts/tui/blessed/panels/trace.js +91 -0
  14. package/scripts/tui/blessed/ui/help.js +77 -0
  15. package/scripts/tui/blessed/ui/screen.js +52 -0
  16. package/scripts/tui/blessed/ui/statusbar.js +51 -0
  17. package/scripts/tui/blessed/ui/tabbar.js +99 -0
  18. package/scripts/tui/index.js +38 -32
  19. package/scripts/tui/simple-tui.js +8 -5
  20. package/scripts/validators/README.md +143 -0
  21. package/scripts/validators/component-validator.js +212 -0
  22. package/scripts/validators/json-schema-validator.js +179 -0
  23. package/scripts/validators/markdown-validator.js +153 -0
  24. package/scripts/validators/migration-validator.js +117 -0
  25. package/scripts/validators/security-validator.js +276 -0
  26. package/scripts/validators/story-format-validator.js +176 -0
  27. package/scripts/validators/test-result-validator.js +99 -0
  28. package/scripts/validators/workflow-validator.js +240 -0
  29. package/src/core/agents/accessibility.md +6 -0
  30. package/src/core/agents/adr-writer.md +6 -0
  31. package/src/core/agents/analytics.md +6 -0
  32. package/src/core/agents/api.md +6 -0
  33. package/src/core/agents/ci.md +6 -0
  34. package/src/core/agents/codebase-query.md +237 -0
  35. package/src/core/agents/compliance.md +6 -0
  36. package/src/core/agents/configuration-damage-control.md +6 -0
  37. package/src/core/agents/configuration-visual-e2e.md +6 -0
  38. package/src/core/agents/database.md +10 -0
  39. package/src/core/agents/datamigration.md +6 -0
  40. package/src/core/agents/design.md +6 -0
  41. package/src/core/agents/devops.md +6 -0
  42. package/src/core/agents/documentation.md +6 -0
  43. package/src/core/agents/epic-planner.md +6 -0
  44. package/src/core/agents/integrations.md +6 -0
  45. package/src/core/agents/mentor.md +6 -0
  46. package/src/core/agents/mobile.md +6 -0
  47. package/src/core/agents/monitoring.md +6 -0
  48. package/src/core/agents/multi-expert.md +6 -0
  49. package/src/core/agents/performance.md +6 -0
  50. package/src/core/agents/product.md +6 -0
  51. package/src/core/agents/qa.md +6 -0
  52. package/src/core/agents/readme-updater.md +6 -0
  53. package/src/core/agents/refactor.md +6 -0
  54. package/src/core/agents/research.md +6 -0
  55. package/src/core/agents/security.md +6 -0
  56. package/src/core/agents/testing.md +10 -0
  57. package/src/core/agents/ui.md +6 -0
  58. package/src/core/commands/audit.md +401 -0
  59. package/src/core/commands/board.md +1 -0
  60. package/src/core/commands/epic.md +92 -1
  61. package/src/core/commands/help.md +1 -0
  62. package/src/core/commands/metrics.md +1 -0
  63. package/src/core/commands/research/analyze.md +1 -0
  64. package/src/core/commands/research/ask.md +2 -0
  65. package/src/core/commands/research/import.md +1 -0
  66. package/src/core/commands/research/list.md +2 -0
  67. package/src/core/commands/research/synthesize.md +584 -0
  68. package/src/core/commands/research/view.md +2 -0
  69. package/src/core/commands/status.md +126 -1
  70. package/src/core/commands/story/list.md +9 -9
  71. package/src/core/commands/story/view.md +1 -0
  72. package/src/core/experts/codebase-query/expertise.yaml +190 -0
  73. package/src/core/experts/codebase-query/question.md +73 -0
  74. package/src/core/experts/codebase-query/self-improve.md +105 -0
  75. package/tools/cli/commands/tui.js +40 -271
@@ -1,287 +1,56 @@
1
- #!/usr/bin/env node
2
-
3
1
  /**
4
- * AgileFlow TUI Dashboard
5
- *
6
- * Static dashboard view - prints once and exits.
7
- * No continuous refresh, no screen clearing, scrollable output.
2
+ * AgileFlow CLI - TUI Command
8
3
  *
9
- * Usage: npx agileflow tui
4
+ * Launches the Terminal User Interface for real-time session monitoring.
5
+ * Uses React/Ink for a proper live-updating terminal UI.
10
6
  */
11
7
 
12
- const path = require('path');
8
+ const path = require('node:path');
9
+ const { spawn } = require('node:child_process');
13
10
  const fs = require('fs');
14
- const { c: colors } = require('../../../lib/colors');
15
-
16
- function showHeader(version) {
17
- console.log('');
18
- console.log(
19
- `${colors.orange}${colors.bold} ╔═══════════════════════════════════════════╗${colors.reset}`
20
- );
21
- console.log(
22
- `${colors.orange}${colors.bold} ║ AgileFlow Dashboard ║${colors.reset}`
23
- );
24
- console.log(
25
- `${colors.orange}${colors.bold} ╚═══════════════════════════════════════════╝${colors.reset}`
26
- );
27
- if (version) {
28
- console.log(`${colors.dim} v${version}${colors.reset}`);
29
- }
30
- console.log('');
31
- }
32
-
33
- async function loadStatus() {
34
- const statusPath = path.join(process.cwd(), 'docs', '09-agents', 'status.json');
35
-
36
- if (!fs.existsSync(statusPath)) {
37
- return null;
38
- }
39
-
40
- try {
41
- const content = fs.readFileSync(statusPath, 'utf8');
42
- return JSON.parse(content);
43
- } catch (err) {
44
- return null;
45
- }
46
- }
47
-
48
- function loadLoopStatus() {
49
- const loopPath = path.join(process.cwd(), 'docs', '09-agents', 'loop-status.json');
50
-
51
- if (!fs.existsSync(loopPath)) {
52
- return null;
53
- }
54
-
55
- try {
56
- const content = fs.readFileSync(loopPath, 'utf8');
57
- return JSON.parse(content);
58
- } catch (err) {
59
- return null;
60
- }
61
- }
62
-
63
- function getStatusColor(status) {
64
- switch (status) {
65
- case 'completed':
66
- case 'done':
67
- return colors.green;
68
- case 'in_progress':
69
- case 'in-progress':
70
- return colors.yellow;
71
- case 'blocked':
72
- return colors.red;
73
- case 'ready':
74
- return colors.cyan;
75
- default:
76
- return colors.dim;
77
- }
78
- }
79
-
80
- function getStatusSymbol(status) {
81
- switch (status) {
82
- case 'completed':
83
- case 'done':
84
- return '✓';
85
- case 'in_progress':
86
- case 'in-progress':
87
- return '▶';
88
- case 'blocked':
89
- return '✗';
90
- case 'ready':
91
- return '○';
92
- default:
93
- return '·';
94
- }
95
- }
96
-
97
- function formatStory(story, compact = false) {
98
- const statusColor = getStatusColor(story.status);
99
- const symbol = getStatusSymbol(story.status);
100
- const id = story.id || story.story_id || 'Unknown';
101
- const title = story.title || story.summary || 'Untitled';
102
- const status = (story.status || 'unknown').replace(/_/g, ' ');
103
- const owner = story.owner || '-';
104
-
105
- if (compact) {
106
- const truncTitle = title.length > 35 ? title.substring(0, 32) + '...' : title;
107
- return ` ${statusColor}${symbol}${colors.reset} ${colors.bold}${id}${colors.reset} ${truncTitle}`;
108
- }
109
-
110
- return ` ${statusColor}${symbol}${colors.reset} ${colors.bold}${id}${colors.reset} ${title.substring(0, 50)}${title.length > 50 ? '...' : ''}
111
- ${statusColor}${status}${colors.reset} ${colors.dim}│ Owner: ${owner}${colors.reset}`;
112
- }
113
-
114
- function drawProgressBar(percent, width = 20) {
115
- const filled = Math.round((percent / 100) * width);
116
- const empty = width - filled;
117
- const bar = '█'.repeat(filled) + '░'.repeat(empty);
118
-
119
- let color = colors.red;
120
- if (percent >= 80) color = colors.green;
121
- else if (percent >= 50) color = colors.yellow;
122
- else if (percent >= 20) color = colors.cyan;
123
-
124
- return `${color}${bar}${colors.reset} ${percent}%`;
125
- }
126
-
127
- async function showDashboard(options = {}) {
128
- const version = options.version;
129
- const compact = options.compact || false;
130
-
131
- showHeader(version);
132
11
 
133
- const status = await loadStatus();
134
- const loopStatus = loadLoopStatus();
135
-
136
- if (!status) {
137
- console.log(
138
- `${colors.dim} No status.json found. Run /agileflow:story to create stories.${colors.reset}`
139
- );
140
- console.log('');
141
- return;
142
- }
143
-
144
- // Count stories by status
145
- const stories = Object.values(status).filter(
146
- s => s && typeof s === 'object' && (s.id || s.story_id)
147
- );
148
- const counts = {
149
- in_progress: stories.filter(s => ['in_progress', 'in-progress'].includes(s.status)).length,
150
- blocked: stories.filter(s => s.status === 'blocked').length,
151
- ready: stories.filter(s => s.status === 'ready').length,
152
- completed: stories.filter(s => ['completed', 'done'].includes(s.status)).length,
153
- };
154
-
155
- const total = stories.length;
156
- const completionPct = total > 0 ? Math.round((counts.completed / total) * 100) : 0;
12
+ module.exports = {
13
+ name: 'tui',
14
+ description: 'Launch Terminal User Interface for session monitoring',
15
+ options: [['-d, --directory <path>', 'Project directory (default: current directory)']],
16
+ action: async options => {
17
+ const directory = path.resolve(options.directory || '.');
18
+
19
+ // Check if AgileFlow is installed
20
+ const agileflowDir = path.join(directory, '.agileflow');
21
+ if (!fs.existsSync(agileflowDir)) {
22
+ console.error('Error: AgileFlow is not installed in this directory');
23
+ console.log("Run 'npx agileflow setup' first\n");
24
+ process.exit(1);
25
+ }
157
26
 
158
- // Summary Section
159
- console.log(`${colors.bold} SUMMARY${colors.reset}`);
160
- console.log(` ${''.repeat(45)}`);
161
- console.log(
162
- ` ${colors.yellow}● In Progress:${colors.reset} ${counts.in_progress} ${colors.red}● Blocked:${colors.reset} ${counts.blocked} ${colors.cyan}● Ready:${colors.reset} ${counts.ready} ${colors.green}● Done:${colors.reset} ${counts.completed}`
163
- );
164
- console.log(` Progress: ${drawProgressBar(completionPct)}`);
165
- console.log('');
27
+ // Find the TUI script - relative to this file in packages/cli
28
+ const cliRoot = path.join(__dirname, '..', '..', '..');
29
+ const tuiScript = path.join(cliRoot, 'scripts', 'tui', 'index.js');
166
30
 
167
- // Loop Status (if active)
168
- if (loopStatus && loopStatus.state && loopStatus.state !== 'idle') {
169
- const stateColor =
170
- loopStatus.state === 'running'
171
- ? colors.green
172
- : loopStatus.state === 'paused'
173
- ? colors.yellow
174
- : colors.dim;
175
- console.log(`${colors.bold} ACTIVE LOOP${colors.reset}`);
176
- console.log(` ${'─'.repeat(45)}`);
177
- console.log(
178
- ` ${stateColor}●${colors.reset} ${loopStatus.epic || '-'} / ${loopStatus.story || '-'}`
179
- );
180
- if (loopStatus.progress !== undefined) {
181
- console.log(` Progress: ${drawProgressBar(loopStatus.progress)}`);
31
+ if (!fs.existsSync(tuiScript)) {
32
+ console.error('Error: TUI script not found at', tuiScript);
33
+ process.exit(1);
182
34
  }
183
- console.log('');
184
- }
185
-
186
- // In Progress Stories
187
- const inProgressStories = stories.filter(s => ['in_progress', 'in-progress'].includes(s.status));
188
- if (inProgressStories.length > 0) {
189
- console.log(`${colors.bold} ${colors.yellow}IN PROGRESS${colors.reset}`);
190
- console.log(` ${'─'.repeat(45)}`);
191
- inProgressStories.forEach(story => {
192
- console.log(formatStory(story, compact));
193
- });
194
- console.log('');
195
- }
196
35
 
197
- // Blocked Stories
198
- const blockedStories = stories.filter(s => s.status === 'blocked');
199
- if (blockedStories.length > 0) {
200
- console.log(`${colors.bold} ${colors.red}BLOCKED${colors.reset}`);
201
- console.log(` ${'─'.repeat(45)}`);
202
- blockedStories.forEach(story => {
203
- console.log(formatStory(story, compact));
36
+ // Spawn the TUI process from packages/cli directory to use correct deps
37
+ const child = spawn('node', [tuiScript], {
38
+ cwd: cliRoot, // Run from packages/cli to use its node_modules
39
+ stdio: 'inherit',
40
+ env: {
41
+ ...process.env,
42
+ FORCE_COLOR: '1',
43
+ AGILEFLOW_PROJECT_DIR: directory, // Pass project dir as env var
44
+ },
204
45
  });
205
- console.log('');
206
- }
207
46
 
208
- // Ready Stories (up to 5)
209
- const readyStories = stories.filter(s => s.status === 'ready').slice(0, 5);
210
- if (readyStories.length > 0) {
211
- const moreReady =
212
- counts.ready > 5 ? ` ${colors.dim}(+${counts.ready - 5} more)${colors.reset}` : '';
213
- console.log(`${colors.bold} ${colors.cyan}READY${colors.reset}${moreReady}`);
214
- console.log(` ${'─'.repeat(45)}`);
215
- readyStories.forEach(story => {
216
- console.log(formatStory(story, compact));
47
+ child.on('error', err => {
48
+ console.error('Error launching TUI:', err.message);
49
+ process.exit(1);
217
50
  });
218
- console.log('');
219
- }
220
51
 
221
- // Completed Stories (last 3)
222
- const completedStories = stories
223
- .filter(s => ['completed', 'done'].includes(s.status))
224
- .slice(-3)
225
- .reverse();
226
- if (completedStories.length > 0) {
227
- const moreCompleted =
228
- counts.completed > 3 ? ` ${colors.dim}(+${counts.completed - 3} more)${colors.reset}` : '';
229
- console.log(`${colors.bold} ${colors.green}RECENTLY COMPLETED${colors.reset}${moreCompleted}`);
230
- console.log(` ${'─'.repeat(45)}`);
231
- completedStories.forEach(story => {
232
- console.log(formatStory(story, compact));
52
+ child.on('exit', code => {
53
+ process.exit(code || 0);
233
54
  });
234
- console.log('');
235
- }
236
-
237
- // Footer
238
- console.log(`${colors.dim} ─────────────────────────────────────────────${colors.reset}`);
239
- console.log(`${colors.dim} /agileflow:board Interactive kanban view${colors.reset}`);
240
- console.log(`${colors.dim} /agileflow:story:list Full story listing${colors.reset}`);
241
- console.log('');
242
- }
243
-
244
- async function main(options = {}) {
245
- const args = process.argv.slice(2);
246
-
247
- // Check for help flag
248
- if (args.includes('--help') || args.includes('-h')) {
249
- console.log('');
250
- console.log(`${colors.bold}AgileFlow TUI Dashboard${colors.reset}`);
251
- console.log('');
252
- console.log(`${colors.bold}Usage:${colors.reset}`);
253
- console.log(' npx agileflow tui Show dashboard');
254
- console.log(' npx agileflow tui --compact Compact view');
255
- console.log(' npx agileflow tui --help Show this help');
256
- console.log('');
257
- return;
258
- }
259
-
260
- const compact = args.includes('--compact') || args.includes('-c');
261
-
262
- // Get version from package.json
263
- let version;
264
- try {
265
- const pkgPath = path.join(__dirname, '..', '..', '..', 'package.json');
266
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
267
- version = pkg.version;
268
- } catch (e) {
269
- version = null;
270
- }
271
-
272
- await showDashboard({ version, compact, ...options });
273
- }
274
-
275
- // Run directly if executed as script
276
- if (require.main === module) {
277
- main().catch(err => {
278
- console.error(`${colors.red}Error:${colors.reset}`, err.message);
279
- process.exit(1);
280
- });
281
- }
282
-
283
- module.exports = {
284
- name: 'tui',
285
- description: 'Show project dashboard',
286
- action: main,
55
+ },
287
56
  };