run method

  1. @override
Future<void> run()
override

Runs this command.

The return value is wrapped in a Future if necessary and returned by CommandRunner.runCommand.

Implementation

@override
Future<void> run() async {
  final argResults = this.argResults;
  if (argResults == null || argResults.rest.isEmpty) {
    logger.err(
        'Please specify a phase to plan (e.g., spectra plan "Phase 1").');
    return;
  }

  final phase = argResults.rest.first;

  final projectFile = File('.spectra/PROJECT.md');
  final roadmapFile = File('.spectra/ROADMAP.md');

  if (!projectFile.existsSync() || !roadmapFile.existsSync()) {
    logger.err('Project context not found. Run `spectra new` first.');
    return;
  }

  final projectContext = projectFile.readAsStringSync();
  final roadmapContext = roadmapFile.readAsStringSync();

  final provider = await _llmService.getPreferredProvider();
  if (provider == null) {
    logger.err(
        'No LLM provider configured. Run `spectra config` to set up a provider.');
    return;
  }

  logger.info('Planning tasks for $phase using ${provider.name}...');

  final prompt = '''
You are a software architect. Break the following phase into atomic, implementable tasks.
Each task must be wrapped in a <task> XML tag following this structure:
<task id="1" type="implement">
<n>Task Name</n>
<files><file action="create">path/to/file.dart</file></files>
<objective>Specific goal of this task</objective>
<verification>How to verify this task works</verification>
<acceptance>Git commit message for this task</acceptance>
</task>

PROJECT CONTEXT:
$projectContext

ROADMAP:
$roadmapContext

TARGET PHASE:
$phase

Return ONLY the XML tasks, one per line.
''';

  try {
    final response = await provider.generateResponse(prompt);
    final tasks = _parseTasksFromResponse(response);

    if (tasks.isEmpty) {
      logger.err('Failed to generate any valid tasks from LLM response.');
      logger.detail('Response was: $response');
      return;
    }

    final planContent = '''
# PLAN: $phase

${tasks.map((t) => t.toXml()).join('\n\n')}
''';

    final planFile = File('.spectra/PLAN.md');
    planFile.writeAsStringSync(planContent);

    logger.success('PLAN.md generated with ${tasks.length} tasks.');
  } catch (e) {
    logger.err('Error generating plan: $e');
  }
}