diff --git a/src/utility/agent-components/handler-workflow.txt b/src/utility/agent-components/handler-workflow.txt index 09b7d0825..82ce16f94 100644 --- a/src/utility/agent-components/handler-workflow.txt +++ b/src/utility/agent-components/handler-workflow.txt @@ -1,10 +1,19 @@ When menu item has: workflow="path/to/workflow.md": - 1. CRITICAL: Always LOAD {project-root}/_bmad/core/tasks/workflow.md - 2. Read the complete file - this is the CORE OS for processing BMAD workflows - 3. Pass the workflow definition path as 'workflow-config' parameter to those instructions - 4. Follow workflow.md instructions precisely following all steps - 5. Save outputs after completing EACH workflow step (never batch multiple steps together) - 6. If workflow.md path is "todo", inform user the workflow hasn't been implemented yet + 1. Resolve loader paths safely: + - Primary: {project-root}/_bmad/core/tasks/workflow.md + - Fallback: {project-root}/src/core/tasks/workflow.md + 2. Verify the primary loader exists and is readable before loading it + 3. If primary is missing/unreadable: + - Log a warning with the primary path and underlying error + - Attempt the fallback loader path + 4. If fallback is also missing/unreadable: + - Log an error including both attempted paths and underlying errors + - Fail fast with a descriptive message and HALT + 5. LOAD the resolved workflow loader file and read it completely + 6. Pass the workflow definition path as 'workflow-config' parameter to those instructions + 7. Follow workflow.md instructions precisely following all steps + 8. Save outputs after completing EACH workflow step (never batch multiple steps together) + 9. If workflow.md path is "todo", inform user the workflow hasn't been implemented yet diff --git a/test/test-installation-components.js b/test/test-installation-components.js index 47410e9b4..6503807cf 100644 --- a/test/test-installation-components.js +++ b/test/test-installation-components.js @@ -221,6 +221,18 @@ async function runTests() { 'Workflow generator default BMAD folder matches shared constant', `Expected "${BMAD_FOLDER_NAME}", got "${workflowGenerator.bmadFolderName}"`, ); + + const launcherContent = workflowGenerator.buildLauncherContent('bmm', [ + { + name: 'create-story', + displayPath: '{project-root}/_bmad/bmm/workflows/4-implementation/create-story/workflow.md', + description: 'Create and validate the next story', + }, + ]); + assert( + launcherContent.includes('{project-root}/src/core/tasks/workflow.md'), + 'Workflow launcher includes fallback loader path for workflow task', + ); } catch (error) { assert(false, 'Workflow generator default path is valid', error.message); } @@ -383,6 +395,27 @@ async function runTests() { console.log(''); + // ============================================================ + // Test 10: Workflow Handler Fallback Guard + // ============================================================ + console.log(`${colors.yellow}Test Suite 10: Workflow Handler Fallback Guard${colors.reset}\n`); + + try { + const workflowHandlerPath = path.join(projectRoot, 'src', 'utility', 'agent-components', 'handler-workflow.txt'); + const content = await fs.readFile(workflowHandlerPath, 'utf8'); + + assert(content.includes('{project-root}/src/core/tasks/workflow.md'), 'Workflow handler documents fallback loader path'); + assert(content.includes('Log an error including both attempted paths'), 'Workflow handler requires explicit dual-path error logging'); + assert( + content.includes('Fail fast with a descriptive message and HALT'), + 'Workflow handler mandates fail-fast behavior when loader is unavailable', + ); + } catch (error) { + assert(false, 'Workflow handler fallback guard runs', error.message); + } + + console.log(''); + // ============================================================ // Summary // ============================================================ diff --git a/tools/cli/installers/lib/ide/shared/workflow-command-generator.js b/tools/cli/installers/lib/ide/shared/workflow-command-generator.js index d368ac7f5..3f0d2a437 100644 --- a/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +++ b/tools/cli/installers/lib/ide/shared/workflow-command-generator.js @@ -204,10 +204,16 @@ class WorkflowCommandGenerator { ## Execution When running any workflow: -1. LOAD {project-root}/${this.bmadFolderName}/core/tasks/workflow.md -2. Pass the workflow path as 'workflow-config' parameter -3. Follow workflow.md instructions EXACTLY -4. Save outputs after EACH section +1. Resolve loader paths: + - Primary: {project-root}/${this.bmadFolderName}/core/tasks/workflow.md + - Fallback: {project-root}/src/core/tasks/workflow.md +2. Check the primary path exists and is readable before loading +3. If primary is missing/unreadable, log a warning with the path and error, then try fallback +4. If fallback is also missing/unreadable, log an error with both attempted paths and stop +5. LOAD the resolved workflow loader file +6. Pass the workflow path as 'workflow-config' parameter +7. Follow workflow.md instructions EXACTLY +8. Save outputs after EACH section ## Modes - Normal: Full interaction