fix: hide internal workflow task from codex exports

This commit is contained in:
Dicky Moore 2026-02-08 14:05:42 +00:00
parent 40787c5035
commit 129f2d4ac9
2 changed files with 63 additions and 2 deletions

View File

@ -21,6 +21,7 @@ const { ManifestGenerator } = require('../tools/cli/installers/lib/core/manifest
const { WorkflowCommandGenerator } = require('../tools/cli/installers/lib/ide/shared/workflow-command-generator'); const { WorkflowCommandGenerator } = require('../tools/cli/installers/lib/ide/shared/workflow-command-generator');
const { TaskToolCommandGenerator } = require('../tools/cli/installers/lib/ide/shared/task-tool-command-generator'); const { TaskToolCommandGenerator } = require('../tools/cli/installers/lib/ide/shared/task-tool-command-generator');
const { IdeManager } = require('../tools/cli/installers/lib/ide/manager'); const { IdeManager } = require('../tools/cli/installers/lib/ide/manager');
const { CodexSetup } = require('../tools/cli/installers/lib/ide/codex');
const { ModuleManager } = require('../tools/cli/installers/lib/modules/manager'); const { ModuleManager } = require('../tools/cli/installers/lib/modules/manager');
const { BMAD_FOLDER_NAME } = require('../tools/cli/installers/lib/ide/shared/path-utils'); const { BMAD_FOLDER_NAME } = require('../tools/cli/installers/lib/ide/shared/path-utils');
@ -707,6 +708,40 @@ internal: true
console.log(''); console.log('');
// ============================================================
// Test 18: Codex Task Visibility Guard
// ============================================================
console.log(`${colors.yellow}Test Suite 18: Codex Task Visibility Guard${colors.reset}\n`);
try {
const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-codex-visibility-'));
const projectDir = path.join(tmpRoot, 'project');
const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME);
await fs.ensureDir(projectDir);
await fs.copy(path.join(projectRoot, 'src', 'core'), path.join(bmadDir, 'core'));
await fs.copy(path.join(projectRoot, 'src', 'bmm'), path.join(bmadDir, 'bmm'));
const manifestGenerator = new ManifestGenerator();
await manifestGenerator.generateManifests(bmadDir, ['bmm'], [], { ides: ['codex'] });
const codexSetup = new CodexSetup();
await codexSetup.setup(projectDir, bmadDir, {
selectedModules: ['bmm'],
preCollectedConfig: { installLocation: 'project' },
});
const promptsDir = path.join(projectDir, '.codex', 'prompts');
const generated = await fs.readdir(promptsDir);
assert(!generated.includes('bmad-workflow.md'), 'Codex export excludes internal workflow runner task prompt', generated.join(', '));
await fs.remove(tmpRoot);
} catch (error) {
assert(false, 'Codex task visibility guard runs', error.message);
}
console.log('');
// ============================================================ // ============================================================
// Summary // Summary
// ============================================================ // ============================================================

View File

@ -1,5 +1,6 @@
const path = require('node:path'); const path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const yaml = require('yaml');
/** /**
* Helpers for gathering BMAD agents/tasks from the installed tree. * Helpers for gathering BMAD agents/tasks from the installed tree.
@ -149,8 +150,33 @@ async function getTasksFromDir(dirPath, moduleName) {
const filePath = path.join(dirPath, file); const filePath = path.join(dirPath, file);
const content = await fs.readFile(filePath, 'utf8'); const content = await fs.readFile(filePath, 'utf8');
// Skip internal/engine files (not user-facing tasks) let isInternal = false;
if (content.includes('internal="true"')) { let isStandalone = true;
if (file.endsWith('.md')) {
// Parse markdown frontmatter for standalone/internal flags.
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
if (frontmatterMatch) {
try {
const frontmatter = yaml.parse(frontmatterMatch[1]) || {};
isInternal = frontmatter.internal === true || frontmatter.internal === 'true';
if (frontmatter.standalone === false || frontmatter.standalone === 'false') {
isStandalone = false;
}
} catch {
// Keep defaults when frontmatter parsing fails.
}
}
} else {
// XML tasks rely on attributes for standalone/internal visibility.
isInternal = /internal\s*=\s*["']true["']/i.test(content);
if (/standalone\s*=\s*["']false["']/i.test(content)) {
isStandalone = false;
}
}
// Skip internal/engine or explicitly non-standalone tasks.
if (isInternal || !isStandalone) {
continue; continue;
} }