red64-cli 0.1.0 → 0.3.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 (125) hide show
  1. package/README.md +1 -2
  2. package/dist/cli/parseArgs.d.ts.map +1 -1
  3. package/dist/cli/parseArgs.js +5 -0
  4. package/dist/cli/parseArgs.js.map +1 -1
  5. package/dist/components/init/CompleteStep.d.ts.map +1 -1
  6. package/dist/components/init/CompleteStep.js +2 -2
  7. package/dist/components/init/CompleteStep.js.map +1 -1
  8. package/dist/components/init/TestCheckStep.d.ts +16 -0
  9. package/dist/components/init/TestCheckStep.d.ts.map +1 -0
  10. package/dist/components/init/TestCheckStep.js +120 -0
  11. package/dist/components/init/TestCheckStep.js.map +1 -0
  12. package/dist/components/init/index.d.ts +1 -0
  13. package/dist/components/init/index.d.ts.map +1 -1
  14. package/dist/components/init/index.js +1 -0
  15. package/dist/components/init/index.js.map +1 -1
  16. package/dist/components/init/types.d.ts +9 -0
  17. package/dist/components/init/types.d.ts.map +1 -1
  18. package/dist/components/screens/InitScreen.d.ts.map +1 -1
  19. package/dist/components/screens/InitScreen.js +69 -6
  20. package/dist/components/screens/InitScreen.js.map +1 -1
  21. package/dist/components/screens/ListScreen.d.ts.map +1 -1
  22. package/dist/components/screens/ListScreen.js +28 -3
  23. package/dist/components/screens/ListScreen.js.map +1 -1
  24. package/dist/components/screens/StartScreen.d.ts.map +1 -1
  25. package/dist/components/screens/StartScreen.js +212 -13
  26. package/dist/components/screens/StartScreen.js.map +1 -1
  27. package/dist/components/ui/ArtifactsSidebar.d.ts +19 -0
  28. package/dist/components/ui/ArtifactsSidebar.d.ts.map +1 -0
  29. package/dist/components/ui/ArtifactsSidebar.js +51 -0
  30. package/dist/components/ui/ArtifactsSidebar.js.map +1 -0
  31. package/dist/components/ui/FeatureSidebar.d.ts.map +1 -1
  32. package/dist/components/ui/FeatureSidebar.js +1 -1
  33. package/dist/components/ui/FeatureSidebar.js.map +1 -1
  34. package/dist/components/ui/index.d.ts +1 -0
  35. package/dist/components/ui/index.d.ts.map +1 -1
  36. package/dist/components/ui/index.js +1 -0
  37. package/dist/components/ui/index.js.map +1 -1
  38. package/dist/services/ClaudeErrorDetector.js +3 -3
  39. package/dist/services/ClaudeErrorDetector.js.map +1 -1
  40. package/dist/services/ConfigService.d.ts +1 -0
  41. package/dist/services/ConfigService.d.ts.map +1 -1
  42. package/dist/services/ConfigService.js.map +1 -1
  43. package/dist/services/ProjectDetector.d.ts +28 -0
  44. package/dist/services/ProjectDetector.d.ts.map +1 -0
  45. package/dist/services/ProjectDetector.js +236 -0
  46. package/dist/services/ProjectDetector.js.map +1 -0
  47. package/dist/services/TestRunner.d.ts +46 -0
  48. package/dist/services/TestRunner.d.ts.map +1 -0
  49. package/dist/services/TestRunner.js +85 -0
  50. package/dist/services/TestRunner.js.map +1 -0
  51. package/dist/services/index.d.ts +2 -0
  52. package/dist/services/index.d.ts.map +1 -1
  53. package/dist/services/index.js +2 -0
  54. package/dist/services/index.js.map +1 -1
  55. package/dist/types/index.d.ts +13 -0
  56. package/dist/types/index.d.ts.map +1 -1
  57. package/dist/types/index.js.map +1 -1
  58. package/framework/.red64/settings/templates/specs/gap-analysis.md +163 -0
  59. package/framework/agents/claude/.claude/agents/red64/spec-impl.md +131 -2
  60. package/framework/agents/claude/.claude/agents/red64/validate-gap.md +13 -7
  61. package/framework/agents/claude/.claude/commands/red64/spec-impl.md +24 -0
  62. package/framework/agents/claude/.claude/commands/red64/validate-gap.md +4 -0
  63. package/framework/agents/codex/.codex/agents/red64/spec-impl.md +131 -2
  64. package/framework/agents/codex/.codex/agents/red64/validate-gap.md +13 -7
  65. package/framework/agents/codex/.codex/commands/red64/spec-impl.md +24 -0
  66. package/framework/agents/codex/.codex/commands/red64/validate-gap.md +4 -0
  67. package/framework/stacks/generic/feedback.md +80 -0
  68. package/framework/stacks/nextjs/accessibility.md +437 -0
  69. package/framework/stacks/nextjs/api.md +431 -0
  70. package/framework/stacks/nextjs/coding-style.md +282 -0
  71. package/framework/stacks/nextjs/commenting.md +226 -0
  72. package/framework/stacks/nextjs/components.md +411 -0
  73. package/framework/stacks/nextjs/conventions.md +333 -0
  74. package/framework/stacks/nextjs/css.md +310 -0
  75. package/framework/stacks/nextjs/error-handling.md +442 -0
  76. package/framework/stacks/nextjs/feedback.md +124 -0
  77. package/framework/stacks/nextjs/migrations.md +332 -0
  78. package/framework/stacks/nextjs/models.md +362 -0
  79. package/framework/stacks/nextjs/queries.md +410 -0
  80. package/framework/stacks/nextjs/responsive.md +338 -0
  81. package/framework/stacks/nextjs/tech-stack.md +177 -0
  82. package/framework/stacks/nextjs/test-writing.md +475 -0
  83. package/framework/stacks/nextjs/validation.md +467 -0
  84. package/framework/stacks/python/api.md +468 -0
  85. package/framework/stacks/python/authentication.md +342 -0
  86. package/framework/stacks/python/code-quality.md +283 -0
  87. package/framework/stacks/python/code-refactoring.md +315 -0
  88. package/framework/stacks/python/coding-style.md +462 -0
  89. package/framework/stacks/python/conventions.md +399 -0
  90. package/framework/stacks/python/error-handling.md +512 -0
  91. package/framework/stacks/python/feedback.md +92 -0
  92. package/framework/stacks/python/implement-ai-llm.md +468 -0
  93. package/framework/stacks/python/migrations.md +388 -0
  94. package/framework/stacks/python/models.md +399 -0
  95. package/framework/stacks/python/python.md +232 -0
  96. package/framework/stacks/python/queries.md +451 -0
  97. package/framework/stacks/python/structure.md +245 -58
  98. package/framework/stacks/python/tech.md +92 -35
  99. package/framework/stacks/python/testing.md +380 -0
  100. package/framework/stacks/python/validation.md +471 -0
  101. package/framework/stacks/rails/authentication.md +176 -0
  102. package/framework/stacks/rails/code-quality.md +287 -0
  103. package/framework/stacks/rails/code-refactoring.md +299 -0
  104. package/framework/stacks/rails/feedback.md +130 -0
  105. package/framework/stacks/rails/implement-ai-llm-with-rubyllm.md +342 -0
  106. package/framework/stacks/rails/rails.md +301 -0
  107. package/framework/stacks/rails/rails8-best-practices.md +498 -0
  108. package/framework/stacks/rails/rails8-css.md +573 -0
  109. package/framework/stacks/rails/structure.md +140 -0
  110. package/framework/stacks/rails/tech.md +108 -0
  111. package/framework/stacks/react/code-quality.md +521 -0
  112. package/framework/stacks/react/components.md +625 -0
  113. package/framework/stacks/react/data-fetching.md +586 -0
  114. package/framework/stacks/react/feedback.md +110 -0
  115. package/framework/stacks/react/forms.md +694 -0
  116. package/framework/stacks/react/performance.md +640 -0
  117. package/framework/stacks/react/product.md +22 -9
  118. package/framework/stacks/react/state-management.md +472 -0
  119. package/framework/stacks/react/structure.md +351 -44
  120. package/framework/stacks/react/tech.md +219 -30
  121. package/framework/stacks/react/testing.md +690 -0
  122. package/package.json +1 -1
  123. package/framework/stacks/node/product.md +0 -27
  124. package/framework/stacks/node/structure.md +0 -82
  125. package/framework/stacks/node/tech.md +0 -63
@@ -7,6 +7,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
7
  import { useState, useEffect } from 'react';
8
8
  import { Box, Text } from 'ink';
9
9
  import { createStateStore } from '../../services/StateStore.js';
10
+ import { createWorktreeService } from '../../services/WorktreeService.js';
10
11
  import { Spinner, FlowTable } from '../ui/index.js';
11
12
  /**
12
13
  * Get base directory from environment or default
@@ -22,13 +23,37 @@ function getBaseDir() {
22
23
  export const ListScreen = () => {
23
24
  const [state, setState] = useState({ step: 'loading' });
24
25
  const [stateStore] = useState(() => createStateStore(getBaseDir()));
26
+ const [worktreeService] = useState(() => createWorktreeService());
25
27
  // Load all flows on mount
26
28
  useEffect(() => {
27
29
  const loadFlows = async () => {
28
30
  try {
31
+ const baseDir = getBaseDir();
29
32
  // Requirements 3.1, 3.2 - Scan and load all flow states
30
- const flows = await stateStore.list();
31
- setState({ step: 'loaded', flows });
33
+ // First load from main repo
34
+ const mainFlows = await stateStore.list();
35
+ // Also scan worktrees for flow states
36
+ const worktrees = await worktreeService.list(baseDir);
37
+ const worktreeFlows = [];
38
+ const seenFeatures = new Set(mainFlows.map(f => f.feature));
39
+ for (const worktree of worktrees) {
40
+ // Skip main worktree (already scanned)
41
+ if (worktree.path === baseDir)
42
+ continue;
43
+ if (!worktree.path)
44
+ continue;
45
+ const worktreeStateStore = createStateStore(worktree.path);
46
+ const flows = await worktreeStateStore.list();
47
+ for (const flow of flows) {
48
+ // Avoid duplicates - prefer worktree state as it's more current
49
+ if (!seenFeatures.has(flow.feature)) {
50
+ worktreeFlows.push(flow);
51
+ seenFeatures.add(flow.feature);
52
+ }
53
+ }
54
+ }
55
+ const allFlows = [...mainFlows, ...worktreeFlows];
56
+ setState({ step: 'loaded', flows: allFlows });
32
57
  }
33
58
  catch (error) {
34
59
  setState({
@@ -38,7 +63,7 @@ export const ListScreen = () => {
38
63
  }
39
64
  };
40
65
  loadFlows();
41
- }, [stateStore]);
66
+ }, [stateStore, worktreeService]);
42
67
  // Render based on state
43
68
  switch (state.step) {
44
69
  case 'loading':
@@ -1 +1 @@
1
- {"version":3,"file":"ListScreen.js","sourceRoot":"","sources":["../../../src/components/screens/ListScreen.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ListScreen.js","sourceRoot":"","sources":["../../../src/components/screens/ListScreen.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"StartScreen.d.ts","sourceRoot":"","sources":["../../../src/components/screens/StartScreen.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAGxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AA0HpD;;;;;GAKG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CA2sC7C,CAAC"}
1
+ {"version":3,"file":"StartScreen.d.ts","sourceRoot":"","sources":["../../../src/components/screens/StartScreen.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAGxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AA0IpD;;;;;GAKG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CA26C7C,CAAC"}
@@ -18,10 +18,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
18
  import { useState, useEffect, useCallback, useRef } from 'react';
19
19
  import { Box, Text, useApp } from 'ink';
20
20
  import { Spinner, Select } from '@inkjs/ui';
21
- import { createStateStore, createAgentInvoker, createExtendedFlowMachine, createWorktreeService, createCommitService, createTaskParser, createSpecInitService, createClaudeHealthCheck, createGitStatusChecker, createConfigService, sanitizeFeatureName } from '../../services/index.js';
22
- import { FeatureSidebar } from '../ui/index.js';
21
+ import { createStateStore, createAgentInvoker, createExtendedFlowMachine, createWorktreeService, createCommitService, createTaskParser, createSpecInitService, createClaudeHealthCheck, createGitStatusChecker, createConfigService, createProjectDetector, createTestRunner, sanitizeFeatureName } from '../../services/index.js';
22
+ import { FeatureSidebar, ArtifactsSidebar } from '../ui/index.js';
23
23
  import { join } from 'node:path';
24
- import { appendFile, mkdir } from 'node:fs/promises';
24
+ import { appendFile, mkdir, stat } from 'node:fs/promises';
25
25
  /**
26
26
  * Phase display information
27
27
  */
@@ -47,6 +47,17 @@ const PHASE_LABELS = {
47
47
  'aborted': { label: 'Aborted', description: 'Flow was aborted' },
48
48
  'error': { label: 'Error', description: 'An error occurred' }
49
49
  };
50
+ /**
51
+ * Map approval phases to the specific file(s) to review
52
+ */
53
+ const PHASE_REVIEW_FILES = {
54
+ 'requirements-approval': 'requirements.md',
55
+ 'gap-review': 'gap-analysis.md',
56
+ 'design-approval': 'design.md',
57
+ 'design-validation-review': 'design.md',
58
+ 'tasks-approval': 'tasks.md',
59
+ 'merge-decision': ''
60
+ };
50
61
  /**
51
62
  * Approval options for review phases
52
63
  */
@@ -113,6 +124,8 @@ export const StartScreen = ({ args, flags }) => {
113
124
  const healthCheck = createClaudeHealthCheck();
114
125
  const gitStatusChecker = createGitStatusChecker();
115
126
  const configService = createConfigService();
127
+ const projectDetector = createProjectDetector();
128
+ const testRunner = createTestRunner();
116
129
  servicesRef.current = {
117
130
  stateStore,
118
131
  agentInvoker,
@@ -123,7 +136,9 @@ export const StartScreen = ({ args, flags }) => {
123
136
  specInitService,
124
137
  healthCheck,
125
138
  gitStatusChecker,
126
- configService
139
+ configService,
140
+ projectDetector,
141
+ testRunner
127
142
  };
128
143
  }
129
144
  const services = servicesRef.current;
@@ -165,10 +180,15 @@ export const StartScreen = ({ args, flags }) => {
165
180
  completedTasks: [], // Orchestrator-tracked completed task IDs
166
181
  phaseMetrics: {}, // Phase timing metrics
167
182
  commitCount: 0, // Number of commits for this feature
168
- agent: 'claude' // Default, will be loaded from config
183
+ agent: 'claude', // Default, will be loaded from config
184
+ artifacts: [] // Generated artifacts
169
185
  });
170
186
  // Track if flow has been started
171
187
  const flowStartedRef = useRef(false);
188
+ // Ref to hold existingFlowState for resumeExistingFlow (avoids stale closure)
189
+ const existingFlowStateRef = useRef(null);
190
+ // Keep ref in sync with state
191
+ existingFlowStateRef.current = flowState.existingFlowState;
172
192
  // Add output line (to screen and log file)
173
193
  const addOutput = useCallback((line) => {
174
194
  setFlowState(prev => ({
@@ -178,6 +198,19 @@ export const StartScreen = ({ args, flags }) => {
178
198
  // Also log to file
179
199
  logToFile(line);
180
200
  }, [logToFile]);
201
+ // Add artifact to the list
202
+ const addArtifact = useCallback((artifact) => {
203
+ setFlowState(prev => {
204
+ // Avoid duplicates
205
+ if (prev.artifacts.some(a => a.path === artifact.path)) {
206
+ return prev;
207
+ }
208
+ return {
209
+ ...prev,
210
+ artifacts: [...prev.artifacts, artifact]
211
+ };
212
+ });
213
+ }, []);
181
214
  // Get working directory (worktree or repo)
182
215
  const getWorkingDir = useCallback(() => {
183
216
  return flowState.worktreePath ?? repoPath;
@@ -329,6 +362,10 @@ export const StartScreen = ({ args, flags }) => {
329
362
  const existingState = await stateStore.load(featureName);
330
363
  // Use override if provided, otherwise use current state, otherwise preserve existing
331
364
  const completedTasks = completedTasksOverride ?? flowState.completedTasks;
365
+ // Use dir (resolved workDir) as worktreePath if it's different from repoPath
366
+ // This fixes the race condition where flowState.worktreePath is still null due to async setFlowState
367
+ // Also preserve worktreePath from existing state on resume to prevent losing it
368
+ const effectiveWorktreePath = dir !== repoPath ? dir : (flowState.worktreePath ?? existingState?.metadata.worktreePath ?? undefined);
332
369
  const state = {
333
370
  feature: featureName,
334
371
  phase: convertToFlowPhase(phase),
@@ -339,7 +376,7 @@ export const StartScreen = ({ args, flags }) => {
339
376
  description,
340
377
  mode,
341
378
  tier: flags.tier,
342
- worktreePath: flowState.worktreePath ?? undefined,
379
+ worktreePath: effectiveWorktreePath,
343
380
  resolvedFeatureName: flowState.resolvedFeatureName ?? undefined
344
381
  },
345
382
  // Orchestrator-controlled task progress
@@ -350,10 +387,14 @@ export const StartScreen = ({ args, flags }) => {
350
387
  // Phase timing metrics
351
388
  phaseMetrics: Object.keys(flowState.phaseMetrics).length > 0
352
389
  ? { ...existingState?.phaseMetrics, ...flowState.phaseMetrics }
353
- : existingState?.phaseMetrics
390
+ : existingState?.phaseMetrics,
391
+ // Persist artifacts to disk so they survive resume
392
+ artifacts: flowState.artifacts.length > 0
393
+ ? flowState.artifacts
394
+ : existingState?.artifacts
354
395
  };
355
396
  await stateStore.save(state);
356
- }, [featureName, description, mode, flags.tier, flowState.worktreePath, flowState.resolvedFeatureName, flowState.completedTasks, flowState.totalTasks, flowState.phaseMetrics, getWorkingDir]);
397
+ }, [featureName, description, mode, flags.tier, flowState.worktreePath, flowState.resolvedFeatureName, flowState.completedTasks, flowState.totalTasks, flowState.phaseMetrics, getWorkingDir, repoPath]);
357
398
  // Transition to next phase
358
399
  const transitionPhase = useCallback((event) => {
359
400
  const nextPhase = services.flowMachine.send(event);
@@ -401,6 +442,7 @@ export const StartScreen = ({ args, flags }) => {
401
442
  existingFlowState: existingState,
402
443
  worktreePath: existingState.metadata.worktreePath ?? null,
403
444
  resolvedFeatureName: existingState.metadata.resolvedFeatureName ?? null,
445
+ artifacts: existingState.artifacts ? [...existingState.artifacts] : prev.artifacts,
404
446
  completedTasks: [...completedTasks],
405
447
  totalTasks
406
448
  }));
@@ -418,6 +460,7 @@ export const StartScreen = ({ args, flags }) => {
418
460
  existingFlowState: existingState,
419
461
  worktreePath: existingState.metadata.worktreePath ?? null,
420
462
  resolvedFeatureName: existingState.metadata.resolvedFeatureName ?? null,
463
+ artifacts: existingState.artifacts ? [...existingState.artifacts] : prev.artifacts,
421
464
  completedTasks: [...completedTasks],
422
465
  totalTasks
423
466
  }));
@@ -496,7 +539,8 @@ export const StartScreen = ({ args, flags }) => {
496
539
  }, [flowState.existingFlowState, services.commitService, services.gitStatusChecker, featureName, repoPath, exit, addOutput]);
497
540
  // Resume from existing flow state
498
541
  const resumeExistingFlow = useCallback(async () => {
499
- const existingState = flowState.existingFlowState;
542
+ // Read from ref to avoid stale closure issue
543
+ const existingState = existingFlowStateRef.current;
500
544
  if (!existingState) {
501
545
  addOutput('Error: No existing flow state to resume');
502
546
  return;
@@ -522,6 +566,10 @@ export const StartScreen = ({ args, flags }) => {
522
566
  timeoutMs: 30000
523
567
  });
524
568
  setFlowState(prev => ({ ...prev, isHealthChecking: false }));
569
+ // Guard against undefined result (can happen if component unmounts during check)
570
+ if (!healthResult) {
571
+ return;
572
+ }
525
573
  if (!healthResult.healthy) {
526
574
  const errorMsg = healthResult.error
527
575
  ? `${getClaudeErrorLabel(healthResult.error.code)}: ${healthResult.error.suggestion}`
@@ -535,17 +583,55 @@ export const StartScreen = ({ args, flags }) => {
535
583
  return;
536
584
  }
537
585
  addOutput(`API ready (${healthResult.durationMs}ms)`);
586
+ // Run project tests (unless skipped)
587
+ if (!flags['skip-tests']) {
588
+ addOutput('');
589
+ addOutput('Checking project tests...');
590
+ // Load config to get test command
591
+ const config = await services.configService.load(workDir);
592
+ let testCommand = config?.testCommand;
593
+ // If no stored command, try to detect
594
+ if (!testCommand) {
595
+ const detection = await services.projectDetector.detect(workDir);
596
+ testCommand = detection.testCommand ?? undefined;
597
+ }
598
+ if (testCommand) {
599
+ addOutput(`Running: ${testCommand}`);
600
+ const testResult = await services.testRunner.run({
601
+ testCommand,
602
+ workingDir: workDir,
603
+ timeoutMs: 300000
604
+ });
605
+ if (!testResult.success) {
606
+ const errorMsg = testResult.timedOut
607
+ ? 'Tests timed out'
608
+ : `Tests failed (exit code: ${testResult.exitCode})`;
609
+ await logToFile(`Test check failed: ${errorMsg}`);
610
+ setFlowState(prev => ({
611
+ ...prev,
612
+ error: errorMsg,
613
+ phase: { type: 'error', feature: featureName, error: `${errorMsg}. Use --skip-tests to bypass.` }
614
+ }));
615
+ return;
616
+ }
617
+ addOutput(`Tests passed (${(testResult.durationMs / 1000).toFixed(1)}s)`);
618
+ }
619
+ else {
620
+ addOutput('No test command configured, skipping tests');
621
+ }
622
+ }
538
623
  // Set up flow machine to the current phase
539
624
  const effectiveName = existingState.metadata.resolvedFeatureName ?? sanitizeFeatureName(featureName);
540
- // Update state with existing flow info
625
+ // Update state with existing flow info, restoring persisted artifacts
541
626
  setFlowState(prev => ({
542
627
  ...prev,
543
628
  worktreePath: existingState.metadata.worktreePath ?? null,
544
- resolvedFeatureName: effectiveName
629
+ resolvedFeatureName: effectiveName,
630
+ artifacts: existingState.artifacts ? [...existingState.artifacts] : prev.artifacts
545
631
  }));
546
632
  // Resume based on current phase
547
633
  await resumeFromPhase(existingState.phase.type, workDir, effectiveName);
548
- }, [flowState.existingFlowState, services.healthCheck, flags, featureName, repoPath, initLogFile, addOutput]);
634
+ }, [services.healthCheck, services.configService, services.projectDetector, services.testRunner, services.commitService, flags, featureName, repoPath, initLogFile, addOutput]);
549
635
  // Resume from a specific phase
550
636
  const resumeFromPhase = async (phaseType, workDir, effectiveName) => {
551
637
  addOutput(`Continuing from ${phaseType}...`);
@@ -667,6 +753,10 @@ export const StartScreen = ({ args, flags }) => {
667
753
  timeoutMs: 30000
668
754
  });
669
755
  setFlowState(prev => ({ ...prev, isHealthChecking: false }));
756
+ // Guard against undefined result (can happen if component unmounts during check)
757
+ if (!healthResult) {
758
+ return;
759
+ }
670
760
  if (!healthResult.healthy) {
671
761
  await logToFile(`Health check failed: ${healthResult.message}`);
672
762
  if (healthResult.error) {
@@ -686,6 +776,43 @@ export const StartScreen = ({ args, flags }) => {
686
776
  return;
687
777
  }
688
778
  addOutput(`API ready (${healthResult.durationMs}ms)`);
779
+ // Run project tests (unless skipped)
780
+ if (!flags['skip-tests']) {
781
+ addOutput('');
782
+ addOutput('Checking project tests...');
783
+ // Load config to get test command
784
+ const config = await services.configService.load(repoPath);
785
+ let testCommand = config?.testCommand;
786
+ // If no stored command, try to detect
787
+ if (!testCommand) {
788
+ const detection = await services.projectDetector.detect(repoPath);
789
+ testCommand = detection.testCommand ?? undefined;
790
+ }
791
+ if (testCommand) {
792
+ addOutput(`Running: ${testCommand}`);
793
+ const testResult = await services.testRunner.run({
794
+ testCommand,
795
+ workingDir: repoPath,
796
+ timeoutMs: 300000
797
+ });
798
+ if (!testResult.success) {
799
+ const errorMsg = testResult.timedOut
800
+ ? 'Tests timed out'
801
+ : `Tests failed (exit code: ${testResult.exitCode})`;
802
+ await logToFile(`Test check failed: ${errorMsg}`);
803
+ setFlowState(prev => ({
804
+ ...prev,
805
+ error: errorMsg,
806
+ phase: { type: 'error', feature: featureName, error: `${errorMsg}. Use --skip-tests to bypass.` }
807
+ }));
808
+ return;
809
+ }
810
+ addOutput(`Tests passed (${(testResult.durationMs / 1000).toFixed(1)}s)`);
811
+ }
812
+ else {
813
+ addOutput('No test command configured, skipping tests');
814
+ }
815
+ }
689
816
  addOutput('');
690
817
  addOutput(`Starting flow: ${featureName}`);
691
818
  addOutput(`Mode: ${mode}`);
@@ -739,6 +866,14 @@ export const StartScreen = ({ args, flags }) => {
739
866
  setFlowState(prev => ({ ...prev, resolvedFeatureName: initResult.featureName }));
740
867
  addOutput(`Spec directory: ${initResult.specDir}`);
741
868
  addOutput(`Feature name: ${initResult.featureName}`);
869
+ // Track spec.json artifact
870
+ addArtifact({
871
+ name: 'Spec Config',
872
+ filename: 'spec.json',
873
+ path: `.red64/specs/${initResult.featureName}/spec.json`,
874
+ phase: 'initializing',
875
+ createdAt: new Date().toISOString()
876
+ });
742
877
  // Commit init
743
878
  await commitChanges(`initialize spec directory`, workDir);
744
879
  // Step 3: Generate requirements - pass the resolved feature name
@@ -757,8 +892,30 @@ export const StartScreen = ({ args, flags }) => {
757
892
  transitionPhase({ type: 'ERROR', error: result.error ?? 'Requirements generation failed' });
758
893
  return;
759
894
  }
895
+ // Validate that requirements were actually written (not just template)
896
+ const reqPath = join(workDir, `.red64/specs/${effectiveName}/requirements.md`);
897
+ try {
898
+ const reqStat = await stat(reqPath);
899
+ if (reqStat.size < 500) {
900
+ // Template is ~160 bytes; real requirements are much larger
901
+ transitionPhase({ type: 'ERROR', error: 'Requirements agent did not generate content. Ensure a project description is provided.' });
902
+ return;
903
+ }
904
+ }
905
+ catch {
906
+ transitionPhase({ type: 'ERROR', error: 'Requirements file was not created by agent.' });
907
+ return;
908
+ }
760
909
  // Commit requirements
761
910
  await commitChanges(`generate requirements`, workDir);
911
+ // Track requirements artifact
912
+ addArtifact({
913
+ name: 'Requirements',
914
+ filename: 'requirements.md',
915
+ path: `.red64/specs/${effectiveName}/requirements.md`,
916
+ phase: 'requirements-generating',
917
+ createdAt: new Date().toISOString()
918
+ });
762
919
  // Transition to approval
763
920
  const approvalPhase = transitionPhase({ type: 'PHASE_COMPLETE' });
764
921
  await saveFlowState(approvalPhase, workDir);
@@ -773,8 +930,25 @@ export const StartScreen = ({ args, flags }) => {
773
930
  transitionPhase({ type: 'ERROR', error: result.error ?? 'Design generation failed' });
774
931
  return;
775
932
  }
933
+ // Validate that design.md was actually created
934
+ const designPath = join(workDir, `.red64/specs/${effectiveName}/design.md`);
935
+ try {
936
+ await stat(designPath);
937
+ }
938
+ catch {
939
+ transitionPhase({ type: 'ERROR', error: 'Design file was not created by agent. Check that requirements were properly generated.' });
940
+ return;
941
+ }
776
942
  // Commit design
777
943
  await commitChanges(`generate technical design`, workDir);
944
+ // Track design artifact
945
+ addArtifact({
946
+ name: 'Design',
947
+ filename: 'design.md',
948
+ path: `.red64/specs/${effectiveName}/design.md`,
949
+ phase: 'design-generating',
950
+ createdAt: new Date().toISOString()
951
+ });
778
952
  // Transition to approval
779
953
  const approvalPhase = transitionPhase({ type: 'PHASE_COMPLETE' });
780
954
  await saveFlowState(approvalPhase, workDir);
@@ -789,8 +963,25 @@ export const StartScreen = ({ args, flags }) => {
789
963
  transitionPhase({ type: 'ERROR', error: result.error ?? 'Tasks generation failed' });
790
964
  return;
791
965
  }
966
+ // Validate that tasks.md was actually created
967
+ const tasksPath = join(workDir, `.red64/specs/${effectiveName}/tasks.md`);
968
+ try {
969
+ await stat(tasksPath);
970
+ }
971
+ catch {
972
+ transitionPhase({ type: 'ERROR', error: 'Tasks file was not created by agent. Check that design was properly generated.' });
973
+ return;
974
+ }
792
975
  // Commit tasks
793
976
  await commitChanges(`generate implementation tasks`, workDir);
977
+ // Track tasks artifact
978
+ addArtifact({
979
+ name: 'Tasks',
980
+ filename: 'tasks.md',
981
+ path: `.red64/specs/${effectiveName}/tasks.md`,
982
+ phase: 'tasks-generating',
983
+ createdAt: new Date().toISOString()
984
+ });
794
985
  // Parse tasks for implementation phase - use effective name for spec directory
795
986
  const specDir = join(workDir, '.red64', 'specs', effectiveName);
796
987
  const tasks = await services.taskParser.parse(specDir);
@@ -905,6 +1096,14 @@ export const StartScreen = ({ args, flags }) => {
905
1096
  const gapResult = await executeCommand(`/red64:validate-gap ${effectiveName} -y`, workDir);
906
1097
  if (gapResult.success) {
907
1098
  await commitChanges(`gap analysis`, workDir);
1099
+ // Track gap analysis artifact
1100
+ addArtifact({
1101
+ name: 'Gap Analysis',
1102
+ filename: 'gap-analysis.md',
1103
+ path: `.red64/specs/${effectiveName}/gap-analysis.md`,
1104
+ phase: 'gap-analysis',
1105
+ createdAt: new Date().toISOString()
1106
+ });
908
1107
  }
909
1108
  transitionPhase({ type: 'PHASE_COMPLETE' });
910
1109
  break;
@@ -975,7 +1174,7 @@ export const StartScreen = ({ args, flags }) => {
975
1174
  }
976
1175
  // Should sidebar be shown?
977
1176
  const showSidebar = flowState.worktreePath !== null || flowState.phase.type !== 'idle';
978
- return (_jsxs(Box, { flexDirection: "row", paddingX: 1, children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: "red64 start" }), _jsxs(Text, { dimColor: true, children: [" - ", featureName] })] }), flowState.worktreePath && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["Worktree: ", flowState.worktreePath] }) })), renderPhaseIndicator(), _jsx(Box, { flexDirection: "column", marginBottom: 1, children: flowState.output.slice(-10).map((line, i) => (_jsx(Text, { dimColor: i < flowState.output.length - 1, children: line }, i))) }), flowState.isHealthChecking && (_jsx(Box, { marginBottom: 1, children: _jsx(Spinner, { label: "Checking Claude API status..." }) })), flowState.isExecuting && !flowState.isHealthChecking && (_jsx(Box, { marginBottom: 1, children: _jsx(Spinner, { label: "Processing..." }) })), flowState.error && !flowState.isExecuting && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", children: flowState.error }) })), flowState.preStartStep.type === 'existing-flow-detected' && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", paddingX: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "Existing Flow Detected" }), _jsxs(Text, { dimColor: true, children: ["Phase: ", flowState.preStartStep.existingState.phase.type] }), _jsx(Box, { marginTop: 1, children: _jsx(Select, { options: EXISTING_FLOW_OPTIONS, onChange: handleExistingFlowDecision }) })] })), flowState.preStartStep.type === 'uncommitted-changes' && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", paddingX: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "Uncommitted Changes Detected" }), _jsxs(Text, { dimColor: true, children: [flowState.preStartStep.gitStatus.staged, " staged, ", flowState.preStartStep.gitStatus.unstaged, " unstaged, ", flowState.preStartStep.gitStatus.untracked, " untracked"] }), _jsx(Box, { marginTop: 1, children: _jsx(Select, { options: UNCOMMITTED_CHANGES_OPTIONS, onChange: handleUncommittedChangesDecision }) })] })), isApprovalPhase && !flowState.isExecuting && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [_jsx(Text, { bold: true, children: "Review Required" }), _jsxs(Text, { dimColor: true, children: ["Review output in .red64/specs/", sanitizeFeatureName(featureName), "/"] }), _jsx(Box, { marginTop: 1, children: _jsx(Select, { options: APPROVAL_OPTIONS, onChange: handleApproval }) })] }))] }), showSidebar && (_jsx(FeatureSidebar, { featureName: flowState.resolvedFeatureName ?? sanitizeFeatureName(featureName), sandboxMode: flags.sandbox ?? false, currentPhase: flowState.phase.type, mode: mode, currentTask: flowState.currentTask, totalTasks: flowState.totalTasks, commitCount: flowState.commitCount, agent: flowState.agent, model: flags.model }))] }));
1177
+ return (_jsxs(Box, { flexDirection: "row", paddingX: 1, children: [showSidebar && (_jsx(FeatureSidebar, { featureName: flowState.resolvedFeatureName ?? sanitizeFeatureName(featureName), sandboxMode: flags.sandbox ?? false, currentPhase: flowState.phase.type, mode: mode, currentTask: flowState.currentTask, totalTasks: flowState.totalTasks, commitCount: flowState.commitCount, agent: flowState.agent, model: flags.model })), _jsxs(Box, { flexDirection: "column", flexGrow: 1, marginLeft: showSidebar ? 1 : 0, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: "red64 start" }), _jsxs(Text, { dimColor: true, children: [" - ", featureName] })] }), flowState.worktreePath && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["Worktree: ", flowState.worktreePath] }) })), renderPhaseIndicator(), _jsx(Box, { flexDirection: "column", marginBottom: 1, children: flowState.output.slice(-10).map((line, i) => (_jsx(Text, { dimColor: i < flowState.output.length - 1, children: line }, i))) }), flowState.isHealthChecking && (_jsx(Box, { marginBottom: 1, children: _jsx(Spinner, { label: "Checking Claude API status..." }) })), flowState.isExecuting && !flowState.isHealthChecking && (_jsx(Box, { marginBottom: 1, children: _jsx(Spinner, { label: "Processing..." }) })), flowState.error && !flowState.isExecuting && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", children: flowState.error }) })), flowState.preStartStep.type === 'existing-flow-detected' && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", paddingX: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "Existing Flow Detected" }), _jsxs(Text, { dimColor: true, children: ["Phase: ", flowState.preStartStep.existingState.phase.type] }), _jsx(Box, { marginTop: 1, children: _jsx(Select, { options: EXISTING_FLOW_OPTIONS, onChange: handleExistingFlowDecision }) })] })), flowState.preStartStep.type === 'uncommitted-changes' && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", paddingX: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "Uncommitted Changes Detected" }), _jsxs(Text, { dimColor: true, children: [flowState.preStartStep.gitStatus.staged, " staged, ", flowState.preStartStep.gitStatus.unstaged, " unstaged, ", flowState.preStartStep.gitStatus.untracked, " untracked"] }), _jsx(Box, { marginTop: 1, children: _jsx(Select, { options: UNCOMMITTED_CHANGES_OPTIONS, onChange: handleUncommittedChangesDecision }) })] })), isApprovalPhase && !flowState.isExecuting && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [_jsx(Text, { bold: true, children: "Review Required" }), _jsxs(Text, { dimColor: true, children: ["Review output in .red64/specs/", flowState.resolvedFeatureName ?? sanitizeFeatureName(featureName), "/", PHASE_REVIEW_FILES[flowState.phase.type] ?? ''] }), _jsx(Box, { marginTop: 1, children: _jsx(Select, { options: APPROVAL_OPTIONS, onChange: handleApproval }) })] }))] }), showSidebar && (_jsx(ArtifactsSidebar, { artifacts: flowState.artifacts, worktreePath: flowState.worktreePath }))] }));
979
1178
  };
980
1179
  /**
981
1180
  * Convert ExtendedFlowPhase to FlowPhase for state persistence