Compare commits
1 Commits
17835ea243
...
13fd461a1e
| Author | SHA1 | Date |
|---|---|---|
|
|
13fd461a1e |
|
|
@ -36,8 +36,6 @@ const {
|
||||||
SHARD_DOC_SIDECAR_ERROR_CODES,
|
SHARD_DOC_SIDECAR_ERROR_CODES,
|
||||||
INDEX_DOCS_SIDECAR_REQUIRED_FIELDS,
|
INDEX_DOCS_SIDECAR_REQUIRED_FIELDS,
|
||||||
INDEX_DOCS_SIDECAR_ERROR_CODES,
|
INDEX_DOCS_SIDECAR_ERROR_CODES,
|
||||||
SKILL_METADATA_RESOLUTION_ERROR_CODES,
|
|
||||||
resolveSkillMetadataAuthority,
|
|
||||||
validateHelpSidecarContractFile,
|
validateHelpSidecarContractFile,
|
||||||
validateShardDocSidecarContractFile,
|
validateShardDocSidecarContractFile,
|
||||||
validateIndexDocsSidecarContractFile,
|
validateIndexDocsSidecarContractFile,
|
||||||
|
|
@ -257,7 +255,7 @@ async function runTests() {
|
||||||
|
|
||||||
const tempSidecarRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-help-sidecar-'));
|
const tempSidecarRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-help-sidecar-'));
|
||||||
const tempSidecarPath = path.join(tempSidecarRoot, 'help.artifact.yaml');
|
const tempSidecarPath = path.join(tempSidecarRoot, 'help.artifact.yaml');
|
||||||
const deterministicSourcePath = 'bmad-fork/src/core/tasks/help/skill-manifest.yaml';
|
const deterministicSourcePath = 'bmad-fork/src/core/tasks/help.artifact.yaml';
|
||||||
const expectedUnsupportedMajorDetail = 'sidecar schema major version is unsupported';
|
const expectedUnsupportedMajorDetail = 'sidecar schema major version is unsupported';
|
||||||
const expectedBasenameMismatchDetail = 'sidecar basename does not match sourcePath basename';
|
const expectedBasenameMismatchDetail = 'sidecar basename does not match sourcePath basename';
|
||||||
|
|
||||||
|
|
@ -436,7 +434,7 @@ async function runTests() {
|
||||||
|
|
||||||
const tempShardDocRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-shard-doc-sidecar-'));
|
const tempShardDocRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-shard-doc-sidecar-'));
|
||||||
const tempShardDocSidecarPath = path.join(tempShardDocRoot, 'shard-doc.artifact.yaml');
|
const tempShardDocSidecarPath = path.join(tempShardDocRoot, 'shard-doc.artifact.yaml');
|
||||||
const deterministicShardDocSourcePath = 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml';
|
const deterministicShardDocSourcePath = 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml';
|
||||||
|
|
||||||
const writeTempShardDocSidecar = async (data) => {
|
const writeTempShardDocSidecar = async (data) => {
|
||||||
await fs.writeFile(tempShardDocSidecarPath, yaml.stringify(data), 'utf8');
|
await fs.writeFile(tempShardDocSidecarPath, yaml.stringify(data), 'utf8');
|
||||||
|
|
@ -633,7 +631,7 @@ async function runTests() {
|
||||||
|
|
||||||
const tempIndexDocsRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-index-docs-sidecar-'));
|
const tempIndexDocsRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-index-docs-sidecar-'));
|
||||||
const tempIndexDocsSidecarPath = path.join(tempIndexDocsRoot, 'index-docs.artifact.yaml');
|
const tempIndexDocsSidecarPath = path.join(tempIndexDocsRoot, 'index-docs.artifact.yaml');
|
||||||
const deterministicIndexDocsSourcePath = 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml';
|
const deterministicIndexDocsSourcePath = 'bmad-fork/src/core/tasks/index-docs.artifact.yaml';
|
||||||
|
|
||||||
const writeTempIndexDocsSidecar = async (data) => {
|
const writeTempIndexDocsSidecar = async (data) => {
|
||||||
await fs.writeFile(tempIndexDocsSidecarPath, yaml.stringify(data), 'utf8');
|
await fs.writeFile(tempIndexDocsSidecarPath, yaml.stringify(data), 'utf8');
|
||||||
|
|
@ -805,140 +803,6 @@ async function runTests() {
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Test 4d: Skill Metadata Filename Authority Resolution
|
|
||||||
// ============================================================
|
|
||||||
console.log(`${colors.yellow}Test Suite 4d: Skill Metadata Filename Authority Resolution${colors.reset}\n`);
|
|
||||||
try {
|
|
||||||
const convertedCapabilitySources = [
|
|
||||||
{ label: 'help', sourceFilename: 'help.md', artifactFilename: 'help.artifact.yaml' },
|
|
||||||
{ label: 'shard-doc', sourceFilename: 'shard-doc.xml', artifactFilename: 'shard-doc.artifact.yaml' },
|
|
||||||
{ label: 'index-docs', sourceFilename: 'index-docs.xml', artifactFilename: 'index-docs.artifact.yaml' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const withResolverWorkspace = async (sourceFilename, callback) => {
|
|
||||||
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), `bmad-metadata-authority-${sourceFilename.replaceAll(/\W+/g, '-')}-`));
|
|
||||||
try {
|
|
||||||
const tasksDir = path.join(tempRoot, 'src', 'core', 'tasks');
|
|
||||||
await fs.ensureDir(tasksDir);
|
|
||||||
|
|
||||||
const sourcePath = path.join(tasksDir, sourceFilename);
|
|
||||||
await fs.writeFile(sourcePath, '# source\n', 'utf8');
|
|
||||||
|
|
||||||
const sourceStem = path.basename(sourceFilename, path.extname(sourceFilename));
|
|
||||||
const skillDir = path.join(tasksDir, sourceStem);
|
|
||||||
await fs.ensureDir(skillDir);
|
|
||||||
|
|
||||||
await callback({
|
|
||||||
tempRoot,
|
|
||||||
tasksDir,
|
|
||||||
sourcePath,
|
|
||||||
skillDir,
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
await fs.remove(tempRoot);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const sourceConfig of convertedCapabilitySources) {
|
|
||||||
const { label, sourceFilename, artifactFilename } = sourceConfig;
|
|
||||||
|
|
||||||
await withResolverWorkspace(sourceFilename, async ({ tempRoot, tasksDir, sourcePath, skillDir }) => {
|
|
||||||
await fs.writeFile(path.join(skillDir, 'skill-manifest.yaml'), 'canonicalId: canonical\n', 'utf8');
|
|
||||||
await fs.writeFile(path.join(skillDir, 'bmad-config.yaml'), 'canonicalId: bmad-config\n', 'utf8');
|
|
||||||
await fs.writeFile(path.join(skillDir, 'manifest.yaml'), 'canonicalId: manifest\n', 'utf8');
|
|
||||||
await fs.writeFile(path.join(tasksDir, artifactFilename), 'canonicalId: artifact\n', 'utf8');
|
|
||||||
|
|
||||||
const resolution = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourcePath,
|
|
||||||
projectRoot: tempRoot,
|
|
||||||
});
|
|
||||||
assert(
|
|
||||||
resolution.resolvedFilename === 'skill-manifest.yaml' && resolution.derivationMode === 'canonical',
|
|
||||||
`${label} resolver prioritizes per-skill canonical skill-manifest.yaml over legacy metadata files`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
await withResolverWorkspace(sourceFilename, async ({ tempRoot, tasksDir, sourcePath, skillDir }) => {
|
|
||||||
await fs.writeFile(path.join(skillDir, 'bmad-config.yaml'), 'canonicalId: bmad-config\n', 'utf8');
|
|
||||||
await fs.writeFile(path.join(skillDir, 'manifest.yaml'), 'canonicalId: manifest\n', 'utf8');
|
|
||||||
await fs.writeFile(path.join(tasksDir, artifactFilename), 'canonicalId: artifact\n', 'utf8');
|
|
||||||
|
|
||||||
const resolution = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourcePath,
|
|
||||||
projectRoot: tempRoot,
|
|
||||||
});
|
|
||||||
assert(
|
|
||||||
resolution.resolvedFilename === 'bmad-config.yaml' && resolution.derivationMode === 'legacy-fallback',
|
|
||||||
`${label} resolver falls back to bmad-config.yaml before manifest.yaml and *.artifact.yaml`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
await withResolverWorkspace(sourceFilename, async ({ tempRoot, tasksDir, sourcePath, skillDir }) => {
|
|
||||||
await fs.writeFile(path.join(skillDir, 'manifest.yaml'), 'canonicalId: manifest\n', 'utf8');
|
|
||||||
await fs.writeFile(path.join(tasksDir, artifactFilename), 'canonicalId: artifact\n', 'utf8');
|
|
||||||
|
|
||||||
const resolution = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourcePath,
|
|
||||||
projectRoot: tempRoot,
|
|
||||||
});
|
|
||||||
assert(
|
|
||||||
resolution.resolvedFilename === 'manifest.yaml' && resolution.derivationMode === 'legacy-fallback',
|
|
||||||
`${label} resolver falls back to manifest.yaml before *.artifact.yaml`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
await withResolverWorkspace(sourceFilename, async ({ tempRoot, tasksDir, sourcePath }) => {
|
|
||||||
await fs.writeFile(path.join(tasksDir, artifactFilename), 'canonicalId: artifact\n', 'utf8');
|
|
||||||
|
|
||||||
const resolution = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourcePath,
|
|
||||||
projectRoot: tempRoot,
|
|
||||||
});
|
|
||||||
assert(
|
|
||||||
resolution.resolvedFilename === artifactFilename && resolution.derivationMode === 'legacy-fallback',
|
|
||||||
`${label} resolver supports capability-scoped *.artifact.yaml fallback`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
await withResolverWorkspace(sourceFilename, async ({ tempRoot, tasksDir, sourcePath }) => {
|
|
||||||
await fs.writeFile(path.join(tasksDir, 'skill-manifest.yaml'), 'canonicalId: root-canonical\n', 'utf8');
|
|
||||||
await fs.writeFile(path.join(tasksDir, artifactFilename), 'canonicalId: artifact\n', 'utf8');
|
|
||||||
|
|
||||||
const resolution = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourcePath,
|
|
||||||
projectRoot: tempRoot,
|
|
||||||
});
|
|
||||||
assert(
|
|
||||||
resolution.resolvedFilename === artifactFilename,
|
|
||||||
`${label} resolver does not treat root task-folder skill-manifest.yaml as per-skill canonical authority`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
await withResolverWorkspace(sourceFilename, async ({ tempRoot, tasksDir, sourcePath, skillDir }) => {
|
|
||||||
await fs.writeFile(path.join(tasksDir, 'bmad-config.yaml'), 'canonicalId: root-bmad-config\n', 'utf8');
|
|
||||||
await fs.writeFile(path.join(skillDir, 'bmad-config.yaml'), 'canonicalId: skill-bmad-config\n', 'utf8');
|
|
||||||
|
|
||||||
try {
|
|
||||||
await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourcePath,
|
|
||||||
projectRoot: tempRoot,
|
|
||||||
});
|
|
||||||
assert(false, `${label} resolver rejects ambiguous bmad-config.yaml coexistence across legacy locations`);
|
|
||||||
} catch (error) {
|
|
||||||
assert(
|
|
||||||
error.code === SKILL_METADATA_RESOLUTION_ERROR_CODES.AMBIGUOUS_MATCH,
|
|
||||||
`${label} resolver emits deterministic ambiguity code for bmad-config.yaml coexistence`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
assert(false, 'Skill metadata filename authority resolver suite setup', error.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('');
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Test 5: Authority Split and Frontmatter Precedence
|
// Test 5: Authority Split and Frontmatter Precedence
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
@ -950,7 +814,7 @@ async function runTests() {
|
||||||
const tempAuthorityRuntimePath = path.join(tempAuthorityRoot, 'help-runtime.md');
|
const tempAuthorityRuntimePath = path.join(tempAuthorityRoot, 'help-runtime.md');
|
||||||
|
|
||||||
const deterministicAuthorityPaths = {
|
const deterministicAuthorityPaths = {
|
||||||
sidecar: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
sidecar: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
source: 'bmad-fork/src/core/tasks/help.md',
|
source: 'bmad-fork/src/core/tasks/help.md',
|
||||||
runtime: '_bmad/core/tasks/help.md',
|
runtime: '_bmad/core/tasks/help.md',
|
||||||
};
|
};
|
||||||
|
|
@ -1136,7 +1000,7 @@ async function runTests() {
|
||||||
const tempShardDocModuleHelpPath = path.join(tempAuthorityRoot, 'module-help.csv');
|
const tempShardDocModuleHelpPath = path.join(tempAuthorityRoot, 'module-help.csv');
|
||||||
|
|
||||||
const deterministicShardDocAuthorityPaths = {
|
const deterministicShardDocAuthorityPaths = {
|
||||||
sidecar: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
sidecar: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
source: 'bmad-fork/src/core/tasks/shard-doc.xml',
|
source: 'bmad-fork/src/core/tasks/shard-doc.xml',
|
||||||
compatibility: 'bmad-fork/src/core/module-help.csv',
|
compatibility: 'bmad-fork/src/core/module-help.csv',
|
||||||
workflowFile: '_bmad/core/tasks/shard-doc.xml',
|
workflowFile: '_bmad/core/tasks/shard-doc.xml',
|
||||||
|
|
@ -1347,7 +1211,7 @@ async function runTests() {
|
||||||
const tempIndexDocsModuleHelpPath = path.join(tempAuthorityRoot, 'index-docs-module-help.csv');
|
const tempIndexDocsModuleHelpPath = path.join(tempAuthorityRoot, 'index-docs-module-help.csv');
|
||||||
|
|
||||||
const deterministicIndexDocsAuthorityPaths = {
|
const deterministicIndexDocsAuthorityPaths = {
|
||||||
sidecar: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
sidecar: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
source: 'bmad-fork/src/core/tasks/index-docs.xml',
|
source: 'bmad-fork/src/core/tasks/index-docs.xml',
|
||||||
compatibility: 'bmad-fork/src/core/module-help.csv',
|
compatibility: 'bmad-fork/src/core/module-help.csv',
|
||||||
workflowFile: '_bmad/core/tasks/index-docs.xml',
|
workflowFile: '_bmad/core/tasks/index-docs.xml',
|
||||||
|
|
@ -1682,7 +1546,7 @@ async function runTests() {
|
||||||
|
|
||||||
// 6b: Shard-doc fail-fast covers Shard-doc negative matrix classes.
|
// 6b: Shard-doc fail-fast covers Shard-doc negative matrix classes.
|
||||||
{
|
{
|
||||||
const deterministicShardDocFailFastSourcePath = 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml';
|
const deterministicShardDocFailFastSourcePath = 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml';
|
||||||
const shardDocFailureScenarios = [
|
const shardDocFailureScenarios = [
|
||||||
{
|
{
|
||||||
label: 'missing shard-doc sidecar file',
|
label: 'missing shard-doc sidecar file',
|
||||||
|
|
@ -1929,7 +1793,7 @@ async function runTests() {
|
||||||
const error = new Error('Converted shard-doc sidecar canonicalId must remain locked to bmad-shard-doc');
|
const error = new Error('Converted shard-doc sidecar canonicalId must remain locked to bmad-shard-doc');
|
||||||
error.code = SHARD_DOC_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_CANONICAL_ID_MISMATCH;
|
error.code = SHARD_DOC_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_CANONICAL_ID_MISMATCH;
|
||||||
error.fieldPath = 'canonicalId';
|
error.fieldPath = 'canonicalId';
|
||||||
error.sourcePath = 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml';
|
error.sourcePath = 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml';
|
||||||
throw error;
|
throw error;
|
||||||
};
|
};
|
||||||
installer.validateIndexDocsAuthoritySplitAndPrecedence = async () => {
|
installer.validateIndexDocsAuthoritySplitAndPrecedence = async () => {
|
||||||
|
|
@ -1983,7 +1847,7 @@ async function runTests() {
|
||||||
);
|
);
|
||||||
assert(error.fieldPath === 'canonicalId', 'Installer shard-doc canonical drift returns deterministic field path');
|
assert(error.fieldPath === 'canonicalId', 'Installer shard-doc canonical drift returns deterministic field path');
|
||||||
assert(
|
assert(
|
||||||
error.sourcePath === 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
error.sourcePath === 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
'Installer shard-doc canonical drift returns deterministic source path',
|
'Installer shard-doc canonical drift returns deterministic source path',
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
|
|
@ -2200,7 +2064,7 @@ async function runTests() {
|
||||||
const tempAliasConfigDir = path.join(tempAliasAuthorityRoot, '_config');
|
const tempAliasConfigDir = path.join(tempAliasAuthorityRoot, '_config');
|
||||||
const tempAuthorityAliasTablePath = path.join(tempAliasConfigDir, 'canonical-aliases.csv');
|
const tempAuthorityAliasTablePath = path.join(tempAliasConfigDir, 'canonical-aliases.csv');
|
||||||
const aliasAuthorityPaths = {
|
const aliasAuthorityPaths = {
|
||||||
sidecar: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
sidecar: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
source: 'bmad-fork/src/core/tasks/help.md',
|
source: 'bmad-fork/src/core/tasks/help.md',
|
||||||
runtime: '_bmad/core/tasks/help.md',
|
runtime: '_bmad/core/tasks/help.md',
|
||||||
};
|
};
|
||||||
|
|
@ -2579,7 +2443,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-help',
|
canonicalId: 'bmad-help',
|
||||||
authoritativePresenceKey: 'capability:bmad-help',
|
authoritativePresenceKey: 'capability:bmad-help',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
sourcePath: 'bmad-fork/src/core/tasks/help.md',
|
sourcePath: 'bmad-fork/src/core/tasks/help.md',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -2590,7 +2454,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-shard-doc',
|
canonicalId: 'bmad-shard-doc',
|
||||||
authoritativePresenceKey: 'capability:bmad-shard-doc',
|
authoritativePresenceKey: 'capability:bmad-shard-doc',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
sourcePath: 'bmad-fork/src/core/tasks/shard-doc.xml',
|
sourcePath: 'bmad-fork/src/core/tasks/shard-doc.xml',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -2598,7 +2462,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-index-docs',
|
canonicalId: 'bmad-index-docs',
|
||||||
authoritativePresenceKey: 'capability:bmad-index-docs',
|
authoritativePresenceKey: 'capability:bmad-index-docs',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
sourcePath: 'bmad-fork/src/core/tasks/index-docs.xml',
|
sourcePath: 'bmad-fork/src/core/tasks/index-docs.xml',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -2631,7 +2495,7 @@ async function runTests() {
|
||||||
assert(helpTaskRow && helpTaskRow.canonicalId === 'bmad-help', 'Task manifest help row sets canonicalId=bmad-help');
|
assert(helpTaskRow && helpTaskRow.canonicalId === 'bmad-help', 'Task manifest help row sets canonicalId=bmad-help');
|
||||||
assert(helpTaskRow && helpTaskRow.authoritySourceType === 'sidecar', 'Task manifest help row sets authoritySourceType=sidecar');
|
assert(helpTaskRow && helpTaskRow.authoritySourceType === 'sidecar', 'Task manifest help row sets authoritySourceType=sidecar');
|
||||||
assert(
|
assert(
|
||||||
helpTaskRow && helpTaskRow.authoritySourcePath === 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
helpTaskRow && helpTaskRow.authoritySourcePath === 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
'Task manifest help row sets authoritySourcePath to sidecar source path',
|
'Task manifest help row sets authoritySourcePath to sidecar source path',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -2651,7 +2515,7 @@ async function runTests() {
|
||||||
'Task manifest shard-doc row sets authoritySourceType=sidecar',
|
'Task manifest shard-doc row sets authoritySourceType=sidecar',
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
shardDocTaskRow && shardDocTaskRow.authoritySourcePath === 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
shardDocTaskRow && shardDocTaskRow.authoritySourcePath === 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
'Task manifest shard-doc row sets authoritySourcePath to shard-doc sidecar source path',
|
'Task manifest shard-doc row sets authoritySourcePath to shard-doc sidecar source path',
|
||||||
);
|
);
|
||||||
assert(!!indexDocsTaskRow, 'Task manifest includes converted index-docs row');
|
assert(!!indexDocsTaskRow, 'Task manifest includes converted index-docs row');
|
||||||
|
|
@ -2665,7 +2529,7 @@ async function runTests() {
|
||||||
'Task manifest index-docs row sets authoritySourceType=sidecar',
|
'Task manifest index-docs row sets authoritySourceType=sidecar',
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
indexDocsTaskRow && indexDocsTaskRow.authoritySourcePath === 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
indexDocsTaskRow && indexDocsTaskRow.authoritySourcePath === 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
'Task manifest index-docs row sets authoritySourcePath to index-docs sidecar source path',
|
'Task manifest index-docs row sets authoritySourcePath to index-docs sidecar source path',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -2778,7 +2642,7 @@ async function runTests() {
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
capturedAuthorityValidationOptions &&
|
capturedAuthorityValidationOptions &&
|
||||||
capturedAuthorityValidationOptions.sidecarSourcePath === 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
capturedAuthorityValidationOptions.sidecarSourcePath === 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
'Installer passes locked sidecar source path to authority validation',
|
'Installer passes locked sidecar source path to authority validation',
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
|
|
@ -2792,7 +2656,7 @@ async function runTests() {
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
capturedShardDocAuthorityValidationOptions &&
|
capturedShardDocAuthorityValidationOptions &&
|
||||||
capturedShardDocAuthorityValidationOptions.sidecarSourcePath === 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
capturedShardDocAuthorityValidationOptions.sidecarSourcePath === 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
'Installer passes locked shard-doc sidecar source path to shard-doc authority validation',
|
'Installer passes locked shard-doc sidecar source path to shard-doc authority validation',
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
|
|
@ -2807,7 +2671,7 @@ async function runTests() {
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
capturedIndexDocsAuthorityValidationOptions &&
|
capturedIndexDocsAuthorityValidationOptions &&
|
||||||
capturedIndexDocsAuthorityValidationOptions.sidecarSourcePath === 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
capturedIndexDocsAuthorityValidationOptions.sidecarSourcePath === 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
'Installer passes locked index-docs sidecar source path to index-docs authority validation',
|
'Installer passes locked index-docs sidecar source path to index-docs authority validation',
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
|
|
@ -2823,7 +2687,7 @@ async function runTests() {
|
||||||
assert(
|
assert(
|
||||||
Array.isArray(capturedManifestHelpAuthorityRecords) &&
|
Array.isArray(capturedManifestHelpAuthorityRecords) &&
|
||||||
capturedManifestHelpAuthorityRecords[0] &&
|
capturedManifestHelpAuthorityRecords[0] &&
|
||||||
capturedManifestHelpAuthorityRecords[0].authoritySourcePath === 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
capturedManifestHelpAuthorityRecords[0].authoritySourcePath === 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
'Installer passes sidecar authority path into manifest generation options',
|
'Installer passes sidecar authority path into manifest generation options',
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
|
|
@ -2833,7 +2697,7 @@ async function runTests() {
|
||||||
record &&
|
record &&
|
||||||
record.canonicalId === 'bmad-shard-doc' &&
|
record.canonicalId === 'bmad-shard-doc' &&
|
||||||
record.authoritySourceType === 'sidecar' &&
|
record.authoritySourceType === 'sidecar' &&
|
||||||
record.authoritySourcePath === 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
record.authoritySourcePath === 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
),
|
),
|
||||||
'Installer passes shard-doc sidecar authority records into task-manifest projection options',
|
'Installer passes shard-doc sidecar authority records into task-manifest projection options',
|
||||||
);
|
);
|
||||||
|
|
@ -2844,7 +2708,7 @@ async function runTests() {
|
||||||
record &&
|
record &&
|
||||||
record.canonicalId === 'bmad-index-docs' &&
|
record.canonicalId === 'bmad-index-docs' &&
|
||||||
record.authoritySourceType === 'sidecar' &&
|
record.authoritySourceType === 'sidecar' &&
|
||||||
record.authoritySourcePath === 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
record.authoritySourcePath === 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
),
|
),
|
||||||
'Installer passes index-docs sidecar authority records into task-manifest projection options',
|
'Installer passes index-docs sidecar authority records into task-manifest projection options',
|
||||||
);
|
);
|
||||||
|
|
@ -2877,7 +2741,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-help',
|
canonicalId: 'bmad-help',
|
||||||
authoritativePresenceKey: 'capability:bmad-help',
|
authoritativePresenceKey: 'capability:bmad-help',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
sourcePath: 'bmad-fork/src/core/tasks/help.md',
|
sourcePath: 'bmad-fork/src/core/tasks/help.md',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -2888,7 +2752,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-shard-doc',
|
canonicalId: 'bmad-shard-doc',
|
||||||
authoritativePresenceKey: 'capability:bmad-shard-doc',
|
authoritativePresenceKey: 'capability:bmad-shard-doc',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
sourcePath: 'bmad-fork/src/core/tasks/shard-doc.xml',
|
sourcePath: 'bmad-fork/src/core/tasks/shard-doc.xml',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -2896,7 +2760,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-index-docs',
|
canonicalId: 'bmad-index-docs',
|
||||||
authoritativePresenceKey: 'capability:bmad-index-docs',
|
authoritativePresenceKey: 'capability:bmad-index-docs',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
sourcePath: 'bmad-fork/src/core/tasks/index-docs.xml',
|
sourcePath: 'bmad-fork/src/core/tasks/index-docs.xml',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -2933,7 +2797,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-help',
|
canonicalId: 'bmad-help',
|
||||||
alias: 'bmad-help',
|
alias: 'bmad-help',
|
||||||
aliasType: 'canonical-id',
|
aliasType: 'canonical-id',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
normalizedAliasValue: 'bmad-help',
|
normalizedAliasValue: 'bmad-help',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
resolutionEligibility: 'canonical-id-only',
|
resolutionEligibility: 'canonical-id-only',
|
||||||
|
|
@ -2945,7 +2809,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-help',
|
canonicalId: 'bmad-help',
|
||||||
alias: 'help',
|
alias: 'help',
|
||||||
aliasType: 'legacy-name',
|
aliasType: 'legacy-name',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
normalizedAliasValue: 'help',
|
normalizedAliasValue: 'help',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
resolutionEligibility: 'legacy-name-only',
|
resolutionEligibility: 'legacy-name-only',
|
||||||
|
|
@ -2957,7 +2821,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-help',
|
canonicalId: 'bmad-help',
|
||||||
alias: '/bmad-help',
|
alias: '/bmad-help',
|
||||||
aliasType: 'slash-command',
|
aliasType: 'slash-command',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
normalizedAliasValue: 'bmad-help',
|
normalizedAliasValue: 'bmad-help',
|
||||||
rawIdentityHasLeadingSlash: 'true',
|
rawIdentityHasLeadingSlash: 'true',
|
||||||
resolutionEligibility: 'slash-command-only',
|
resolutionEligibility: 'slash-command-only',
|
||||||
|
|
@ -2969,7 +2833,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-shard-doc',
|
canonicalId: 'bmad-shard-doc',
|
||||||
alias: 'bmad-shard-doc',
|
alias: 'bmad-shard-doc',
|
||||||
aliasType: 'canonical-id',
|
aliasType: 'canonical-id',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
normalizedAliasValue: 'bmad-shard-doc',
|
normalizedAliasValue: 'bmad-shard-doc',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
resolutionEligibility: 'canonical-id-only',
|
resolutionEligibility: 'canonical-id-only',
|
||||||
|
|
@ -2981,7 +2845,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-shard-doc',
|
canonicalId: 'bmad-shard-doc',
|
||||||
alias: 'shard-doc',
|
alias: 'shard-doc',
|
||||||
aliasType: 'legacy-name',
|
aliasType: 'legacy-name',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
normalizedAliasValue: 'shard-doc',
|
normalizedAliasValue: 'shard-doc',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
resolutionEligibility: 'legacy-name-only',
|
resolutionEligibility: 'legacy-name-only',
|
||||||
|
|
@ -2993,7 +2857,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-shard-doc',
|
canonicalId: 'bmad-shard-doc',
|
||||||
alias: '/bmad-shard-doc',
|
alias: '/bmad-shard-doc',
|
||||||
aliasType: 'slash-command',
|
aliasType: 'slash-command',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
normalizedAliasValue: 'bmad-shard-doc',
|
normalizedAliasValue: 'bmad-shard-doc',
|
||||||
rawIdentityHasLeadingSlash: 'true',
|
rawIdentityHasLeadingSlash: 'true',
|
||||||
resolutionEligibility: 'slash-command-only',
|
resolutionEligibility: 'slash-command-only',
|
||||||
|
|
@ -3005,7 +2869,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-index-docs',
|
canonicalId: 'bmad-index-docs',
|
||||||
alias: 'bmad-index-docs',
|
alias: 'bmad-index-docs',
|
||||||
aliasType: 'canonical-id',
|
aliasType: 'canonical-id',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
normalizedAliasValue: 'bmad-index-docs',
|
normalizedAliasValue: 'bmad-index-docs',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
resolutionEligibility: 'canonical-id-only',
|
resolutionEligibility: 'canonical-id-only',
|
||||||
|
|
@ -3017,7 +2881,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-index-docs',
|
canonicalId: 'bmad-index-docs',
|
||||||
alias: 'index-docs',
|
alias: 'index-docs',
|
||||||
aliasType: 'legacy-name',
|
aliasType: 'legacy-name',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
normalizedAliasValue: 'index-docs',
|
normalizedAliasValue: 'index-docs',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
resolutionEligibility: 'legacy-name-only',
|
resolutionEligibility: 'legacy-name-only',
|
||||||
|
|
@ -3029,7 +2893,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-index-docs',
|
canonicalId: 'bmad-index-docs',
|
||||||
alias: '/bmad-index-docs',
|
alias: '/bmad-index-docs',
|
||||||
aliasType: 'slash-command',
|
aliasType: 'slash-command',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
normalizedAliasValue: 'bmad-index-docs',
|
normalizedAliasValue: 'bmad-index-docs',
|
||||||
rawIdentityHasLeadingSlash: 'true',
|
rawIdentityHasLeadingSlash: 'true',
|
||||||
resolutionEligibility: 'slash-command-only',
|
resolutionEligibility: 'slash-command-only',
|
||||||
|
|
@ -3142,10 +3006,10 @@ async function runTests() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (row.canonicalId === 'bmad-help') {
|
if (row.canonicalId === 'bmad-help') {
|
||||||
return row.authoritySourcePath === 'bmad-fork/src/core/tasks/help/skill-manifest.yaml';
|
return row.authoritySourcePath === 'bmad-fork/src/core/tasks/help.artifact.yaml';
|
||||||
}
|
}
|
||||||
if (row.canonicalId === 'bmad-shard-doc') {
|
if (row.canonicalId === 'bmad-shard-doc') {
|
||||||
return row.authoritySourcePath === 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml';
|
return row.authoritySourcePath === 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml';
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}),
|
}),
|
||||||
|
|
@ -3199,7 +3063,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-help',
|
canonicalId: 'bmad-help',
|
||||||
authoritativePresenceKey: 'capability:bmad-help',
|
authoritativePresenceKey: 'capability:bmad-help',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
sourcePath: 'bmad-fork/src/core/tasks/help.md',
|
sourcePath: 'bmad-fork/src/core/tasks/help.md',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -3301,7 +3165,7 @@ async function runTests() {
|
||||||
assert(
|
assert(
|
||||||
helpCommandLabelRow &&
|
helpCommandLabelRow &&
|
||||||
helpCommandLabelRow.authoritySourceType === 'sidecar' &&
|
helpCommandLabelRow.authoritySourceType === 'sidecar' &&
|
||||||
helpCommandLabelRow.authoritySourcePath === 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
helpCommandLabelRow.authoritySourcePath === 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
'Command-label report includes sidecar provenance linkage',
|
'Command-label report includes sidecar provenance linkage',
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
|
|
@ -3313,7 +3177,7 @@ async function runTests() {
|
||||||
assert(
|
assert(
|
||||||
shardDocCommandLabelRow &&
|
shardDocCommandLabelRow &&
|
||||||
shardDocCommandLabelRow.authoritySourceType === 'sidecar' &&
|
shardDocCommandLabelRow.authoritySourceType === 'sidecar' &&
|
||||||
shardDocCommandLabelRow.authoritySourcePath === 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
shardDocCommandLabelRow.authoritySourcePath === 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
'Command-label report includes shard-doc sidecar provenance linkage',
|
'Command-label report includes shard-doc sidecar provenance linkage',
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
|
|
@ -3325,7 +3189,7 @@ async function runTests() {
|
||||||
assert(
|
assert(
|
||||||
indexDocsCommandLabelRow &&
|
indexDocsCommandLabelRow &&
|
||||||
indexDocsCommandLabelRow.authoritySourceType === 'sidecar' &&
|
indexDocsCommandLabelRow.authoritySourceType === 'sidecar' &&
|
||||||
indexDocsCommandLabelRow.authoritySourcePath === 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
indexDocsCommandLabelRow.authoritySourcePath === 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
'Command-label report includes index-docs sidecar provenance linkage',
|
'Command-label report includes index-docs sidecar provenance linkage',
|
||||||
);
|
);
|
||||||
const generatedCommandLabelReportRaw = await fs.readFile(generatedCommandLabelReportPath, 'utf8');
|
const generatedCommandLabelReportRaw = await fs.readFile(generatedCommandLabelReportPath, 'utf8');
|
||||||
|
|
@ -3360,7 +3224,7 @@ async function runTests() {
|
||||||
const baselineShardDocLabelContract = evaluateExemplarCommandLabelReportRows(commandLabelRows, {
|
const baselineShardDocLabelContract = evaluateExemplarCommandLabelReportRows(commandLabelRows, {
|
||||||
canonicalId: 'bmad-shard-doc',
|
canonicalId: 'bmad-shard-doc',
|
||||||
displayedCommandLabel: '/bmad-shard-doc',
|
displayedCommandLabel: '/bmad-shard-doc',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
});
|
});
|
||||||
assert(
|
assert(
|
||||||
baselineShardDocLabelContract.valid,
|
baselineShardDocLabelContract.valid,
|
||||||
|
|
@ -3370,7 +3234,7 @@ async function runTests() {
|
||||||
const baselineIndexDocsLabelContract = evaluateExemplarCommandLabelReportRows(commandLabelRows, {
|
const baselineIndexDocsLabelContract = evaluateExemplarCommandLabelReportRows(commandLabelRows, {
|
||||||
canonicalId: 'bmad-index-docs',
|
canonicalId: 'bmad-index-docs',
|
||||||
displayedCommandLabel: '/bmad-index-docs',
|
displayedCommandLabel: '/bmad-index-docs',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
});
|
});
|
||||||
assert(
|
assert(
|
||||||
baselineIndexDocsLabelContract.valid,
|
baselineIndexDocsLabelContract.valid,
|
||||||
|
|
@ -3491,7 +3355,7 @@ async function runTests() {
|
||||||
{
|
{
|
||||||
canonicalId: 'bmad-shard-doc',
|
canonicalId: 'bmad-shard-doc',
|
||||||
displayedCommandLabel: '/bmad-shard-doc',
|
displayedCommandLabel: '/bmad-shard-doc',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
|
|
@ -3508,14 +3372,14 @@ async function runTests() {
|
||||||
installedStageRow &&
|
installedStageRow &&
|
||||||
installedStageRow.issuingComponent === EXEMPLAR_HELP_CATALOG_ISSUING_COMPONENT &&
|
installedStageRow.issuingComponent === EXEMPLAR_HELP_CATALOG_ISSUING_COMPONENT &&
|
||||||
installedStageRow.commandAuthoritySourceType === 'sidecar' &&
|
installedStageRow.commandAuthoritySourceType === 'sidecar' &&
|
||||||
installedStageRow.commandAuthoritySourcePath === 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
installedStageRow.commandAuthoritySourcePath === 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
'Installed compatibility stage row preserves sidecar command provenance and issuing component linkage',
|
'Installed compatibility stage row preserves sidecar command provenance and issuing component linkage',
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
mergedStageRow &&
|
mergedStageRow &&
|
||||||
mergedStageRow.issuingComponent === INSTALLER_HELP_CATALOG_MERGE_COMPONENT &&
|
mergedStageRow.issuingComponent === INSTALLER_HELP_CATALOG_MERGE_COMPONENT &&
|
||||||
mergedStageRow.commandAuthoritySourceType === 'sidecar' &&
|
mergedStageRow.commandAuthoritySourceType === 'sidecar' &&
|
||||||
mergedStageRow.commandAuthoritySourcePath === 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
mergedStageRow.commandAuthoritySourcePath === 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
'Merged config stage row preserves sidecar command provenance and merge issuing component linkage',
|
'Merged config stage row preserves sidecar command provenance and merge issuing component linkage',
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
|
|
@ -3533,7 +3397,7 @@ async function runTests() {
|
||||||
generatedPipelineReportRows.every(
|
generatedPipelineReportRows.every(
|
||||||
(row) =>
|
(row) =>
|
||||||
row.commandAuthoritySourceType === 'sidecar' &&
|
row.commandAuthoritySourceType === 'sidecar' &&
|
||||||
row.commandAuthoritySourcePath === 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
row.commandAuthoritySourcePath === 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
),
|
),
|
||||||
'Installer persists pipeline stage artifact with sidecar command provenance linkage for both stages',
|
'Installer persists pipeline stage artifact with sidecar command provenance linkage for both stages',
|
||||||
);
|
);
|
||||||
|
|
@ -3682,7 +3546,7 @@ async function runTests() {
|
||||||
assert(
|
assert(
|
||||||
exportDerivationRecord &&
|
exportDerivationRecord &&
|
||||||
exportDerivationRecord.exportIdDerivationSourceType === EXEMPLAR_HELP_EXPORT_DERIVATION_SOURCE_TYPE &&
|
exportDerivationRecord.exportIdDerivationSourceType === EXEMPLAR_HELP_EXPORT_DERIVATION_SOURCE_TYPE &&
|
||||||
exportDerivationRecord.exportIdDerivationSourcePath === 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
exportDerivationRecord.exportIdDerivationSourcePath === 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
'Codex export records exemplar derivation source metadata from sidecar canonical-id',
|
'Codex export records exemplar derivation source metadata from sidecar canonical-id',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -3708,7 +3572,7 @@ async function runTests() {
|
||||||
assert(
|
assert(
|
||||||
shardDocExportDerivationRecord &&
|
shardDocExportDerivationRecord &&
|
||||||
shardDocExportDerivationRecord.exportIdDerivationSourceType === EXEMPLAR_HELP_EXPORT_DERIVATION_SOURCE_TYPE &&
|
shardDocExportDerivationRecord.exportIdDerivationSourceType === EXEMPLAR_HELP_EXPORT_DERIVATION_SOURCE_TYPE &&
|
||||||
shardDocExportDerivationRecord.exportIdDerivationSourcePath === 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml' &&
|
shardDocExportDerivationRecord.exportIdDerivationSourcePath === 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml' &&
|
||||||
shardDocExportDerivationRecord.sourcePath === 'bmad-fork/src/core/tasks/shard-doc.xml',
|
shardDocExportDerivationRecord.sourcePath === 'bmad-fork/src/core/tasks/shard-doc.xml',
|
||||||
'Codex export records shard-doc sidecar-canonical derivation metadata and source path',
|
'Codex export records shard-doc sidecar-canonical derivation metadata and source path',
|
||||||
);
|
);
|
||||||
|
|
@ -3735,7 +3599,7 @@ async function runTests() {
|
||||||
assert(
|
assert(
|
||||||
indexDocsExportDerivationRecord &&
|
indexDocsExportDerivationRecord &&
|
||||||
indexDocsExportDerivationRecord.exportIdDerivationSourceType === EXEMPLAR_HELP_EXPORT_DERIVATION_SOURCE_TYPE &&
|
indexDocsExportDerivationRecord.exportIdDerivationSourceType === EXEMPLAR_HELP_EXPORT_DERIVATION_SOURCE_TYPE &&
|
||||||
indexDocsExportDerivationRecord.exportIdDerivationSourcePath === 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml' &&
|
indexDocsExportDerivationRecord.exportIdDerivationSourcePath === 'bmad-fork/src/core/tasks/index-docs.artifact.yaml' &&
|
||||||
indexDocsExportDerivationRecord.sourcePath === 'bmad-fork/src/core/tasks/index-docs.xml',
|
indexDocsExportDerivationRecord.sourcePath === 'bmad-fork/src/core/tasks/index-docs.xml',
|
||||||
'Codex export records index-docs sidecar-canonical derivation metadata and source path',
|
'Codex export records index-docs sidecar-canonical derivation metadata and source path',
|
||||||
);
|
);
|
||||||
|
|
@ -3801,7 +3665,7 @@ async function runTests() {
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
submoduleExportDerivationRecord &&
|
submoduleExportDerivationRecord &&
|
||||||
submoduleExportDerivationRecord.exportIdDerivationSourcePath === 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
submoduleExportDerivationRecord.exportIdDerivationSourcePath === 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
'Codex export locks exemplar derivation source-path contract when running from submodule root',
|
'Codex export locks exemplar derivation source-path contract when running from submodule root',
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -4043,7 +3907,7 @@ async function runTests() {
|
||||||
legacyName: 'help',
|
legacyName: 'help',
|
||||||
canonicalId: 'bmad-help',
|
canonicalId: 'bmad-help',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
futureAdditiveField: 'canonical-additive',
|
futureAdditiveField: 'canonical-additive',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -4440,7 +4304,7 @@ async function runTests() {
|
||||||
legacyName: 'help',
|
legacyName: 'help',
|
||||||
canonicalId: 'bmad-help',
|
canonicalId: 'bmad-help',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
@ -4463,7 +4327,7 @@ async function runTests() {
|
||||||
alias: 'bmad-help',
|
alias: 'bmad-help',
|
||||||
aliasType: 'canonical-id',
|
aliasType: 'canonical-id',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
rowIdentity: 'alias-row:bmad-help:canonical-id',
|
rowIdentity: 'alias-row:bmad-help:canonical-id',
|
||||||
normalizedAliasValue: 'bmad-help',
|
normalizedAliasValue: 'bmad-help',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
|
|
@ -4474,7 +4338,7 @@ async function runTests() {
|
||||||
alias: 'help',
|
alias: 'help',
|
||||||
aliasType: 'legacy-name',
|
aliasType: 'legacy-name',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
rowIdentity: 'alias-row:bmad-help:legacy-name',
|
rowIdentity: 'alias-row:bmad-help:legacy-name',
|
||||||
normalizedAliasValue: 'help',
|
normalizedAliasValue: 'help',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
|
|
@ -4485,7 +4349,7 @@ async function runTests() {
|
||||||
alias: '/bmad-help',
|
alias: '/bmad-help',
|
||||||
aliasType: 'slash-command',
|
aliasType: 'slash-command',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
rowIdentity: 'alias-row:bmad-help:slash-command',
|
rowIdentity: 'alias-row:bmad-help:slash-command',
|
||||||
normalizedAliasValue: 'bmad-help',
|
normalizedAliasValue: 'bmad-help',
|
||||||
rawIdentityHasLeadingSlash: 'true',
|
rawIdentityHasLeadingSlash: 'true',
|
||||||
|
|
@ -4656,9 +4520,9 @@ async function runTests() {
|
||||||
descriptionValue: 'Help command',
|
descriptionValue: 'Help command',
|
||||||
expectedDescriptionValue: 'Help command',
|
expectedDescriptionValue: 'Help command',
|
||||||
descriptionAuthoritySourceType: 'sidecar',
|
descriptionAuthoritySourceType: 'sidecar',
|
||||||
descriptionAuthoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
descriptionAuthoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
commandAuthoritySourceType: 'sidecar',
|
commandAuthoritySourceType: 'sidecar',
|
||||||
commandAuthoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
commandAuthoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
issuerOwnerClass: 'installer',
|
issuerOwnerClass: 'installer',
|
||||||
issuingComponent: 'bmad-fork/tools/cli/installers/lib/core/help-catalog-generator.js::buildSidecarAwareExemplarHelpRow()',
|
issuingComponent: 'bmad-fork/tools/cli/installers/lib/core/help-catalog-generator.js::buildSidecarAwareExemplarHelpRow()',
|
||||||
issuingComponentBindingEvidence: 'deterministic',
|
issuingComponentBindingEvidence: 'deterministic',
|
||||||
|
|
@ -4677,9 +4541,9 @@ async function runTests() {
|
||||||
descriptionValue: 'Help command',
|
descriptionValue: 'Help command',
|
||||||
expectedDescriptionValue: 'Help command',
|
expectedDescriptionValue: 'Help command',
|
||||||
descriptionAuthoritySourceType: 'sidecar',
|
descriptionAuthoritySourceType: 'sidecar',
|
||||||
descriptionAuthoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
descriptionAuthoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
commandAuthoritySourceType: 'sidecar',
|
commandAuthoritySourceType: 'sidecar',
|
||||||
commandAuthoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
commandAuthoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
issuerOwnerClass: 'installer',
|
issuerOwnerClass: 'installer',
|
||||||
issuingComponent: 'bmad-fork/tools/cli/installers/lib/core/installer.js::mergeModuleHelpCatalogs()',
|
issuingComponent: 'bmad-fork/tools/cli/installers/lib/core/installer.js::mergeModuleHelpCatalogs()',
|
||||||
issuingComponentBindingEvidence: 'deterministic',
|
issuingComponentBindingEvidence: 'deterministic',
|
||||||
|
|
@ -4711,7 +4575,7 @@ async function runTests() {
|
||||||
normalizedDisplayedLabel: '/bmad-help',
|
normalizedDisplayedLabel: '/bmad-help',
|
||||||
rowCountForCanonicalId: '1',
|
rowCountForCanonicalId: '1',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
status: 'PASS',
|
status: 'PASS',
|
||||||
failureReason: '',
|
failureReason: '',
|
||||||
},
|
},
|
||||||
|
|
@ -4870,7 +4734,7 @@ async function runTests() {
|
||||||
legacyName: 'help',
|
legacyName: 'help',
|
||||||
canonicalId: 'bmad-help',
|
canonicalId: 'bmad-help',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/help/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/help.artifact.yaml',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
@ -5112,24 +4976,6 @@ async function runTests() {
|
||||||
'Help validation harness emits deterministic replay-evidence validation error code',
|
'Help validation harness emits deterministic replay-evidence validation error code',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.writeFile(path.join(tempSourceTasksDir, 'bmad-config.yaml'), 'canonicalId: root-bmad-config\n', 'utf8');
|
|
||||||
await fs.ensureDir(path.join(tempSourceTasksDir, 'help'));
|
|
||||||
await fs.writeFile(path.join(tempSourceTasksDir, 'help', 'bmad-config.yaml'), 'canonicalId: help-bmad-config\n', 'utf8');
|
|
||||||
try {
|
|
||||||
await harness.generateValidationArtifacts({
|
|
||||||
projectDir: tempProjectRoot,
|
|
||||||
bmadDir: tempBmadDir,
|
|
||||||
bmadFolderName: '_bmad',
|
|
||||||
sourceMarkdownPath: path.join(tempSourceTasksDir, 'help.md'),
|
|
||||||
});
|
|
||||||
assert(false, 'Help validation harness normalizes metadata-resolution ambiguity into harness-native deterministic error');
|
|
||||||
} catch (error) {
|
|
||||||
assert(
|
|
||||||
error.code === HELP_VALIDATION_ERROR_CODES.METADATA_RESOLUTION_FAILED,
|
|
||||||
'Help validation harness emits deterministic metadata-resolution error code',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert(false, 'Deterministic validation artifact suite setup', error.message);
|
assert(false, 'Deterministic validation artifact suite setup', error.message);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -5187,7 +5033,7 @@ async function runTests() {
|
||||||
normalizedDisplayedLabel: '/bmad-shard-doc',
|
normalizedDisplayedLabel: '/bmad-shard-doc',
|
||||||
rowCountForCanonicalId: '1',
|
rowCountForCanonicalId: '1',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
status: 'PASS',
|
status: 'PASS',
|
||||||
failureReason: '',
|
failureReason: '',
|
||||||
},
|
},
|
||||||
|
|
@ -5229,7 +5075,7 @@ async function runTests() {
|
||||||
legacyName: 'shard-doc',
|
legacyName: 'shard-doc',
|
||||||
canonicalId: 'bmad-shard-doc',
|
canonicalId: 'bmad-shard-doc',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
@ -5313,7 +5159,7 @@ async function runTests() {
|
||||||
alias: 'bmad-shard-doc',
|
alias: 'bmad-shard-doc',
|
||||||
aliasType: 'canonical-id',
|
aliasType: 'canonical-id',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
rowIdentity: 'alias-row:bmad-shard-doc:canonical-id',
|
rowIdentity: 'alias-row:bmad-shard-doc:canonical-id',
|
||||||
normalizedAliasValue: 'bmad-shard-doc',
|
normalizedAliasValue: 'bmad-shard-doc',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
|
|
@ -5324,7 +5170,7 @@ async function runTests() {
|
||||||
alias: 'shard-doc',
|
alias: 'shard-doc',
|
||||||
aliasType: 'legacy-name',
|
aliasType: 'legacy-name',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
rowIdentity: 'alias-row:bmad-shard-doc:legacy-name',
|
rowIdentity: 'alias-row:bmad-shard-doc:legacy-name',
|
||||||
normalizedAliasValue: 'shard-doc',
|
normalizedAliasValue: 'shard-doc',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
|
|
@ -5335,7 +5181,7 @@ async function runTests() {
|
||||||
alias: '/bmad-shard-doc',
|
alias: '/bmad-shard-doc',
|
||||||
aliasType: 'slash-command',
|
aliasType: 'slash-command',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
rowIdentity: 'alias-row:bmad-shard-doc:slash-command',
|
rowIdentity: 'alias-row:bmad-shard-doc:slash-command',
|
||||||
normalizedAliasValue: 'bmad-shard-doc',
|
normalizedAliasValue: 'bmad-shard-doc',
|
||||||
rawIdentityHasLeadingSlash: 'true',
|
rawIdentityHasLeadingSlash: 'true',
|
||||||
|
|
@ -5351,7 +5197,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-shard-doc',
|
canonicalId: 'bmad-shard-doc',
|
||||||
authoritativePresenceKey: 'capability:bmad-shard-doc',
|
authoritativePresenceKey: 'capability:bmad-shard-doc',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
recordType: 'source-body-authority',
|
recordType: 'source-body-authority',
|
||||||
|
|
@ -5566,24 +5412,6 @@ async function runTests() {
|
||||||
'Shard-doc validation harness emits deterministic missing-row error code',
|
'Shard-doc validation harness emits deterministic missing-row error code',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.writeFile(path.join(tempSourceTasksDir, 'bmad-config.yaml'), 'canonicalId: root-bmad-config\n', 'utf8');
|
|
||||||
await fs.ensureDir(path.join(tempSourceTasksDir, 'shard-doc'));
|
|
||||||
await fs.writeFile(path.join(tempSourceTasksDir, 'shard-doc', 'bmad-config.yaml'), 'canonicalId: shard-doc-bmad-config\n', 'utf8');
|
|
||||||
try {
|
|
||||||
await harness.generateValidationArtifacts({
|
|
||||||
projectDir: tempProjectRoot,
|
|
||||||
bmadDir: tempBmadDir,
|
|
||||||
bmadFolderName: '_bmad',
|
|
||||||
sourceXmlPath: path.join(tempSourceTasksDir, 'shard-doc.xml'),
|
|
||||||
});
|
|
||||||
assert(false, 'Shard-doc validation harness normalizes metadata-resolution ambiguity into harness-native deterministic error');
|
|
||||||
} catch (error) {
|
|
||||||
assert(
|
|
||||||
error.code === SHARD_DOC_VALIDATION_ERROR_CODES.METADATA_RESOLUTION_FAILED,
|
|
||||||
'Shard-doc validation harness emits deterministic metadata-resolution error code',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert(false, 'Shard-doc validation artifact suite setup', error.message);
|
assert(false, 'Shard-doc validation artifact suite setup', error.message);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -5640,7 +5468,7 @@ async function runTests() {
|
||||||
normalizedDisplayedLabel: '/bmad-index-docs',
|
normalizedDisplayedLabel: '/bmad-index-docs',
|
||||||
rowCountForCanonicalId: '1',
|
rowCountForCanonicalId: '1',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
status: 'PASS',
|
status: 'PASS',
|
||||||
failureReason: '',
|
failureReason: '',
|
||||||
},
|
},
|
||||||
|
|
@ -5684,7 +5512,7 @@ async function runTests() {
|
||||||
legacyName: 'index-docs',
|
legacyName: 'index-docs',
|
||||||
canonicalId: 'bmad-index-docs',
|
canonicalId: 'bmad-index-docs',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
@ -5768,7 +5596,7 @@ async function runTests() {
|
||||||
alias: 'bmad-index-docs',
|
alias: 'bmad-index-docs',
|
||||||
aliasType: 'canonical-id',
|
aliasType: 'canonical-id',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
rowIdentity: 'alias-row:bmad-index-docs:canonical-id',
|
rowIdentity: 'alias-row:bmad-index-docs:canonical-id',
|
||||||
normalizedAliasValue: 'bmad-index-docs',
|
normalizedAliasValue: 'bmad-index-docs',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
|
|
@ -5779,7 +5607,7 @@ async function runTests() {
|
||||||
alias: 'index-docs',
|
alias: 'index-docs',
|
||||||
aliasType: 'legacy-name',
|
aliasType: 'legacy-name',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
rowIdentity: 'alias-row:bmad-index-docs:legacy-name',
|
rowIdentity: 'alias-row:bmad-index-docs:legacy-name',
|
||||||
normalizedAliasValue: 'index-docs',
|
normalizedAliasValue: 'index-docs',
|
||||||
rawIdentityHasLeadingSlash: 'false',
|
rawIdentityHasLeadingSlash: 'false',
|
||||||
|
|
@ -5790,7 +5618,7 @@ async function runTests() {
|
||||||
alias: '/bmad-index-docs',
|
alias: '/bmad-index-docs',
|
||||||
aliasType: 'slash-command',
|
aliasType: 'slash-command',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
rowIdentity: 'alias-row:bmad-index-docs:slash-command',
|
rowIdentity: 'alias-row:bmad-index-docs:slash-command',
|
||||||
normalizedAliasValue: 'bmad-index-docs',
|
normalizedAliasValue: 'bmad-index-docs',
|
||||||
rawIdentityHasLeadingSlash: 'true',
|
rawIdentityHasLeadingSlash: 'true',
|
||||||
|
|
@ -5806,7 +5634,7 @@ async function runTests() {
|
||||||
canonicalId: 'bmad-index-docs',
|
canonicalId: 'bmad-index-docs',
|
||||||
authoritativePresenceKey: 'capability:bmad-index-docs',
|
authoritativePresenceKey: 'capability:bmad-index-docs',
|
||||||
authoritySourceType: 'sidecar',
|
authoritySourceType: 'sidecar',
|
||||||
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml',
|
authoritySourcePath: 'bmad-fork/src/core/tasks/index-docs.artifact.yaml',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
recordType: 'source-body-authority',
|
recordType: 'source-body-authority',
|
||||||
|
|
@ -6021,24 +5849,6 @@ async function runTests() {
|
||||||
'Index-docs validation harness emits deterministic missing-row error code',
|
'Index-docs validation harness emits deterministic missing-row error code',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.writeFile(path.join(tempSourceTasksDir, 'bmad-config.yaml'), 'canonicalId: root-bmad-config\n', 'utf8');
|
|
||||||
await fs.ensureDir(path.join(tempSourceTasksDir, 'index-docs'));
|
|
||||||
await fs.writeFile(path.join(tempSourceTasksDir, 'index-docs', 'bmad-config.yaml'), 'canonicalId: index-docs-bmad-config\n', 'utf8');
|
|
||||||
try {
|
|
||||||
await harness.generateValidationArtifacts({
|
|
||||||
projectDir: tempProjectRoot,
|
|
||||||
bmadDir: tempBmadDir,
|
|
||||||
bmadFolderName: '_bmad',
|
|
||||||
sourceXmlPath: path.join(tempSourceTasksDir, 'index-docs.xml'),
|
|
||||||
});
|
|
||||||
assert(false, 'Index-docs validation harness normalizes metadata-resolution ambiguity into harness-native deterministic error');
|
|
||||||
} catch (error) {
|
|
||||||
assert(
|
|
||||||
error.code === INDEX_DOCS_VALIDATION_ERROR_CODES.METADATA_RESOLUTION_FAILED,
|
|
||||||
'Index-docs validation harness emits deterministic metadata-resolution error code',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert(false, 'Index-docs validation artifact suite setup', error.message);
|
assert(false, 'Index-docs validation artifact suite setup', error.message);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@ const fs = require('fs-extra');
|
||||||
const yaml = require('yaml');
|
const yaml = require('yaml');
|
||||||
const { getProjectRoot, getSourcePath } = require('../../../lib/project-root');
|
const { getProjectRoot, getSourcePath } = require('../../../lib/project-root');
|
||||||
const { normalizeAndResolveExemplarAlias } = require('./help-alias-normalizer');
|
const { normalizeAndResolveExemplarAlias } = require('./help-alias-normalizer');
|
||||||
const { resolveSkillMetadataAuthority } = require('./sidecar-contract-validator');
|
|
||||||
|
|
||||||
const HELP_AUTHORITY_VALIDATION_ERROR_CODES = Object.freeze({
|
const HELP_AUTHORITY_VALIDATION_ERROR_CODES = Object.freeze({
|
||||||
SIDECAR_FILE_NOT_FOUND: 'ERR_HELP_AUTHORITY_SIDECAR_FILE_NOT_FOUND',
|
SIDECAR_FILE_NOT_FOUND: 'ERR_HELP_AUTHORITY_SIDECAR_FILE_NOT_FOUND',
|
||||||
SIDECAR_FILENAME_AMBIGUOUS: 'ERR_HELP_AUTHORITY_SIDECAR_FILENAME_AMBIGUOUS',
|
|
||||||
SIDECAR_PARSE_FAILED: 'ERR_HELP_AUTHORITY_SIDECAR_PARSE_FAILED',
|
SIDECAR_PARSE_FAILED: 'ERR_HELP_AUTHORITY_SIDECAR_PARSE_FAILED',
|
||||||
SIDECAR_INVALID_METADATA: 'ERR_HELP_AUTHORITY_SIDECAR_INVALID_METADATA',
|
SIDECAR_INVALID_METADATA: 'ERR_HELP_AUTHORITY_SIDECAR_INVALID_METADATA',
|
||||||
MARKDOWN_FILE_NOT_FOUND: 'ERR_HELP_AUTHORITY_MARKDOWN_FILE_NOT_FOUND',
|
MARKDOWN_FILE_NOT_FOUND: 'ERR_HELP_AUTHORITY_MARKDOWN_FILE_NOT_FOUND',
|
||||||
|
|
@ -279,37 +277,17 @@ function buildHelpAuthorityRecords({ canonicalId, sidecarSourcePath, sourceMarkd
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validateHelpAuthoritySplitAndPrecedence(options = {}) {
|
async function validateHelpAuthoritySplitAndPrecedence(options = {}) {
|
||||||
|
const sidecarPath = options.sidecarPath || getSourcePath('core', 'tasks', 'help.artifact.yaml');
|
||||||
const sourceMarkdownPath = options.sourceMarkdownPath || getSourcePath('core', 'tasks', 'help.md');
|
const sourceMarkdownPath = options.sourceMarkdownPath || getSourcePath('core', 'tasks', 'help.md');
|
||||||
const runtimeMarkdownPath = options.runtimeMarkdownPath || '';
|
const runtimeMarkdownPath = options.runtimeMarkdownPath || '';
|
||||||
|
|
||||||
let resolvedMetadataAuthority;
|
const sidecarSourcePath = normalizeSourcePath(options.sidecarSourcePath || toProjectRelativePath(sidecarPath));
|
||||||
try {
|
|
||||||
resolvedMetadataAuthority = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourceMarkdownPath,
|
|
||||||
metadataPath: options.sidecarPath || '',
|
|
||||||
metadataSourcePath: options.sidecarSourcePath || '',
|
|
||||||
ambiguousErrorCode: HELP_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILENAME_AMBIGUOUS,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw new HelpAuthorityValidationError({
|
|
||||||
code: error.code || HELP_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILENAME_AMBIGUOUS,
|
|
||||||
detail: error.detail || error.message,
|
|
||||||
fieldPath: error.fieldPath || '<file>',
|
|
||||||
sourcePath: normalizeSourcePath(error.sourcePath || toProjectRelativePath(sourceMarkdownPath)),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const sidecarPath = resolvedMetadataAuthority.resolvedAbsolutePath;
|
|
||||||
|
|
||||||
const sidecarSourcePath = normalizeSourcePath(
|
|
||||||
options.sidecarSourcePath || resolvedMetadataAuthority.canonicalTargetSourcePath || resolvedMetadataAuthority.resolvedSourcePath,
|
|
||||||
);
|
|
||||||
const sourceMarkdownSourcePath = normalizeSourcePath(options.sourceMarkdownSourcePath || toProjectRelativePath(sourceMarkdownPath));
|
const sourceMarkdownSourcePath = normalizeSourcePath(options.sourceMarkdownSourcePath || toProjectRelativePath(sourceMarkdownPath));
|
||||||
const runtimeMarkdownSourcePath = normalizeSourcePath(
|
const runtimeMarkdownSourcePath = normalizeSourcePath(
|
||||||
options.runtimeMarkdownSourcePath || (runtimeMarkdownPath ? toProjectRelativePath(runtimeMarkdownPath) : ''),
|
options.runtimeMarkdownSourcePath || (runtimeMarkdownPath ? toProjectRelativePath(runtimeMarkdownPath) : ''),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!sidecarPath || !(await fs.pathExists(sidecarPath))) {
|
if (!(await fs.pathExists(sidecarPath))) {
|
||||||
throw new HelpAuthorityValidationError({
|
throw new HelpAuthorityValidationError({
|
||||||
code: HELP_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILE_NOT_FOUND,
|
code: HELP_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILE_NOT_FOUND,
|
||||||
detail: 'Expected sidecar metadata file was not found',
|
detail: 'Expected sidecar metadata file was not found',
|
||||||
|
|
@ -381,13 +359,6 @@ async function validateHelpAuthoritySplitAndPrecedence(options = {}) {
|
||||||
authoritativePresenceKey: `capability:${canonicalId}`,
|
authoritativePresenceKey: `capability:${canonicalId}`,
|
||||||
authoritativeRecords,
|
authoritativeRecords,
|
||||||
checkedSurfaces,
|
checkedSurfaces,
|
||||||
metadataAuthority: {
|
|
||||||
resolvedPath: normalizeSourcePath(resolvedMetadataAuthority.resolvedSourcePath || sidecarSourcePath),
|
|
||||||
resolvedFilename: normalizeSourcePath(resolvedMetadataAuthority.resolvedFilename || ''),
|
|
||||||
canonicalTargetFilename: normalizeSourcePath(resolvedMetadataAuthority.canonicalTargetFilename || 'skill-manifest.yaml'),
|
|
||||||
canonicalTargetPath: normalizeSourcePath(resolvedMetadataAuthority.canonicalTargetSourcePath || sidecarSourcePath),
|
|
||||||
derivationMode: normalizeSourcePath(resolvedMetadataAuthority.derivationMode || ''),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,9 @@ const path = require('node:path');
|
||||||
const yaml = require('yaml');
|
const yaml = require('yaml');
|
||||||
const { getSourcePath, getProjectRoot } = require('../../../lib/project-root');
|
const { getSourcePath, getProjectRoot } = require('../../../lib/project-root');
|
||||||
const { normalizeAndResolveExemplarAlias } = require('./help-alias-normalizer');
|
const { normalizeAndResolveExemplarAlias } = require('./help-alias-normalizer');
|
||||||
const { resolveSkillMetadataAuthority } = require('./sidecar-contract-validator');
|
|
||||||
|
|
||||||
const EXEMPLAR_HELP_CATALOG_CANONICAL_ID = 'bmad-help';
|
const EXEMPLAR_HELP_CATALOG_CANONICAL_ID = 'bmad-help';
|
||||||
const EXEMPLAR_HELP_CATALOG_AUTHORITY_SOURCE_PATH = 'bmad-fork/src/core/tasks/help/skill-manifest.yaml';
|
const EXEMPLAR_HELP_CATALOG_AUTHORITY_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.artifact.yaml';
|
||||||
const EXEMPLAR_HELP_CATALOG_SOURCE_MARKDOWN_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.md';
|
const EXEMPLAR_HELP_CATALOG_SOURCE_MARKDOWN_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.md';
|
||||||
const EXEMPLAR_HELP_CATALOG_ISSUING_COMPONENT =
|
const EXEMPLAR_HELP_CATALOG_ISSUING_COMPONENT =
|
||||||
'bmad-fork/tools/cli/installers/lib/core/help-catalog-generator.js::buildSidecarAwareExemplarHelpRow()';
|
'bmad-fork/tools/cli/installers/lib/core/help-catalog-generator.js::buildSidecarAwareExemplarHelpRow()';
|
||||||
|
|
@ -14,7 +13,6 @@ const INSTALLER_HELP_CATALOG_MERGE_COMPONENT = 'bmad-fork/tools/cli/installers/l
|
||||||
|
|
||||||
const HELP_CATALOG_GENERATION_ERROR_CODES = Object.freeze({
|
const HELP_CATALOG_GENERATION_ERROR_CODES = Object.freeze({
|
||||||
SIDECAR_FILE_NOT_FOUND: 'ERR_HELP_CATALOG_SIDECAR_FILE_NOT_FOUND',
|
SIDECAR_FILE_NOT_FOUND: 'ERR_HELP_CATALOG_SIDECAR_FILE_NOT_FOUND',
|
||||||
SIDECAR_FILENAME_AMBIGUOUS: 'ERR_HELP_CATALOG_SIDECAR_FILENAME_AMBIGUOUS',
|
|
||||||
SIDECAR_PARSE_FAILED: 'ERR_HELP_CATALOG_SIDECAR_PARSE_FAILED',
|
SIDECAR_PARSE_FAILED: 'ERR_HELP_CATALOG_SIDECAR_PARSE_FAILED',
|
||||||
SIDECAR_INVALID_METADATA: 'ERR_HELP_CATALOG_SIDECAR_INVALID_METADATA',
|
SIDECAR_INVALID_METADATA: 'ERR_HELP_CATALOG_SIDECAR_INVALID_METADATA',
|
||||||
CANONICAL_ID_MISMATCH: 'ERR_HELP_CATALOG_CANONICAL_ID_MISMATCH',
|
CANONICAL_ID_MISMATCH: 'ERR_HELP_CATALOG_CANONICAL_ID_MISMATCH',
|
||||||
|
|
@ -73,29 +71,9 @@ function createGenerationError(code, fieldPath, sourcePath, detail, observedValu
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadExemplarHelpSidecar(sidecarPath = '') {
|
async function loadExemplarHelpSidecar(sidecarPath = getSourcePath('core', 'tasks', 'help.artifact.yaml')) {
|
||||||
const sourceMarkdownPath = getSourcePath('core', 'tasks', 'help.md');
|
const sourcePath = normalizeSourcePath(toProjectRelativePath(sidecarPath));
|
||||||
let resolvedMetadataAuthority;
|
if (!(await fs.pathExists(sidecarPath))) {
|
||||||
try {
|
|
||||||
resolvedMetadataAuthority = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourceMarkdownPath,
|
|
||||||
metadataPath: sidecarPath,
|
|
||||||
ambiguousErrorCode: HELP_CATALOG_GENERATION_ERROR_CODES.SIDECAR_FILENAME_AMBIGUOUS,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
createGenerationError(
|
|
||||||
error.code || HELP_CATALOG_GENERATION_ERROR_CODES.SIDECAR_FILENAME_AMBIGUOUS,
|
|
||||||
error.fieldPath || '<file>',
|
|
||||||
normalizeSourcePath(error.sourcePath || toProjectRelativePath(sourceMarkdownPath)),
|
|
||||||
error.detail || error.message,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolvedMetadataPath = resolvedMetadataAuthority.resolvedAbsolutePath;
|
|
||||||
const sourcePath = normalizeSourcePath(
|
|
||||||
resolvedMetadataAuthority.canonicalTargetSourcePath || resolvedMetadataAuthority.resolvedSourcePath,
|
|
||||||
);
|
|
||||||
if (!resolvedMetadataPath || !(await fs.pathExists(resolvedMetadataPath))) {
|
|
||||||
createGenerationError(
|
createGenerationError(
|
||||||
HELP_CATALOG_GENERATION_ERROR_CODES.SIDECAR_FILE_NOT_FOUND,
|
HELP_CATALOG_GENERATION_ERROR_CODES.SIDECAR_FILE_NOT_FOUND,
|
||||||
'<file>',
|
'<file>',
|
||||||
|
|
@ -106,7 +84,7 @@ async function loadExemplarHelpSidecar(sidecarPath = '') {
|
||||||
|
|
||||||
let sidecarData;
|
let sidecarData;
|
||||||
try {
|
try {
|
||||||
sidecarData = yaml.parse(await fs.readFile(resolvedMetadataPath, 'utf8'));
|
sidecarData = yaml.parse(await fs.readFile(sidecarPath, 'utf8'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
createGenerationError(
|
createGenerationError(
|
||||||
HELP_CATALOG_GENERATION_ERROR_CODES.SIDECAR_PARSE_FAILED,
|
HELP_CATALOG_GENERATION_ERROR_CODES.SIDECAR_PARSE_FAILED,
|
||||||
|
|
@ -150,9 +128,6 @@ async function loadExemplarHelpSidecar(sidecarPath = '') {
|
||||||
displayName,
|
displayName,
|
||||||
description,
|
description,
|
||||||
sourcePath,
|
sourcePath,
|
||||||
resolvedFilename: normalizeSourcePath(resolvedMetadataAuthority.resolvedFilename || ''),
|
|
||||||
canonicalTargetFilename: normalizeSourcePath(resolvedMetadataAuthority.canonicalTargetFilename || 'skill-manifest.yaml'),
|
|
||||||
derivationMode: normalizeSourcePath(resolvedMetadataAuthority.derivationMode || ''),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,7 @@ const fs = require('fs-extra');
|
||||||
const yaml = require('yaml');
|
const yaml = require('yaml');
|
||||||
const csv = require('csv-parse/sync');
|
const csv = require('csv-parse/sync');
|
||||||
const { getSourcePath } = require('../../../lib/project-root');
|
const { getSourcePath } = require('../../../lib/project-root');
|
||||||
const {
|
const { validateHelpSidecarContractFile, HELP_SIDECAR_ERROR_CODES } = require('./sidecar-contract-validator');
|
||||||
validateHelpSidecarContractFile,
|
|
||||||
HELP_SIDECAR_ERROR_CODES,
|
|
||||||
resolveSkillMetadataAuthority,
|
|
||||||
} = require('./sidecar-contract-validator');
|
|
||||||
const { validateHelpAuthoritySplitAndPrecedence, HELP_FRONTMATTER_MISMATCH_ERROR_CODES } = require('./help-authority-validator');
|
const { validateHelpAuthoritySplitAndPrecedence, HELP_FRONTMATTER_MISMATCH_ERROR_CODES } = require('./help-authority-validator');
|
||||||
const { ManifestGenerator } = require('./manifest-generator');
|
const { ManifestGenerator } = require('./manifest-generator');
|
||||||
const { buildSidecarAwareExemplarHelpRow } = require('./help-catalog-generator');
|
const { buildSidecarAwareExemplarHelpRow } = require('./help-catalog-generator');
|
||||||
|
|
@ -17,7 +13,6 @@ const { CodexSetup } = require('../ide/codex');
|
||||||
|
|
||||||
const HELP_VALIDATION_ERROR_CODES = Object.freeze({
|
const HELP_VALIDATION_ERROR_CODES = Object.freeze({
|
||||||
REQUIRED_ARTIFACT_MISSING: 'ERR_HELP_VALIDATION_REQUIRED_ARTIFACT_MISSING',
|
REQUIRED_ARTIFACT_MISSING: 'ERR_HELP_VALIDATION_REQUIRED_ARTIFACT_MISSING',
|
||||||
METADATA_RESOLUTION_FAILED: 'ERR_HELP_VALIDATION_METADATA_RESOLUTION_FAILED',
|
|
||||||
CSV_SCHEMA_MISMATCH: 'ERR_HELP_VALIDATION_CSV_SCHEMA_MISMATCH',
|
CSV_SCHEMA_MISMATCH: 'ERR_HELP_VALIDATION_CSV_SCHEMA_MISMATCH',
|
||||||
REQUIRED_ROW_IDENTITY_MISSING: 'ERR_HELP_VALIDATION_REQUIRED_ROW_IDENTITY_MISSING',
|
REQUIRED_ROW_IDENTITY_MISSING: 'ERR_HELP_VALIDATION_REQUIRED_ROW_IDENTITY_MISSING',
|
||||||
REQUIRED_EVIDENCE_LINK_MISSING: 'ERR_HELP_VALIDATION_REQUIRED_EVIDENCE_LINK_MISSING',
|
REQUIRED_EVIDENCE_LINK_MISSING: 'ERR_HELP_VALIDATION_REQUIRED_EVIDENCE_LINK_MISSING',
|
||||||
|
|
@ -30,7 +25,7 @@ const HELP_VALIDATION_ERROR_CODES = Object.freeze({
|
||||||
DECISION_RECORD_PARSE_FAILED: 'ERR_HELP_VALIDATION_DECISION_RECORD_PARSE_FAILED',
|
DECISION_RECORD_PARSE_FAILED: 'ERR_HELP_VALIDATION_DECISION_RECORD_PARSE_FAILED',
|
||||||
});
|
});
|
||||||
|
|
||||||
const SIDEcar_AUTHORITY_SOURCE_PATH = 'bmad-fork/src/core/tasks/help/skill-manifest.yaml';
|
const SIDEcar_AUTHORITY_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.artifact.yaml';
|
||||||
const SOURCE_MARKDOWN_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.md';
|
const SOURCE_MARKDOWN_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.md';
|
||||||
const EVIDENCE_ISSUER_COMPONENT = 'bmad-fork/tools/cli/installers/lib/core/help-validation-harness.js';
|
const EVIDENCE_ISSUER_COMPONENT = 'bmad-fork/tools/cli/installers/lib/core/help-validation-harness.js';
|
||||||
|
|
||||||
|
|
@ -541,9 +536,16 @@ class HelpValidationHarness {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async resolveSourceArtifactPaths(options = {}) {
|
resolveSourceArtifactPaths(options = {}) {
|
||||||
const projectDir = path.resolve(options.projectDir || process.cwd());
|
const projectDir = path.resolve(options.projectDir || process.cwd());
|
||||||
|
|
||||||
|
const sidecarCandidates = [
|
||||||
|
options.sidecarPath,
|
||||||
|
path.join(projectDir, 'bmad-fork', 'src', 'core', 'tasks', 'help.artifact.yaml'),
|
||||||
|
path.join(projectDir, 'src', 'core', 'tasks', 'help.artifact.yaml'),
|
||||||
|
getSourcePath('core', 'tasks', 'help.artifact.yaml'),
|
||||||
|
].filter(Boolean);
|
||||||
|
|
||||||
const sourceMarkdownCandidates = [
|
const sourceMarkdownCandidates = [
|
||||||
options.sourceMarkdownPath,
|
options.sourceMarkdownPath,
|
||||||
path.join(projectDir, 'bmad-fork', 'src', 'core', 'tasks', 'help.md'),
|
path.join(projectDir, 'bmad-fork', 'src', 'core', 'tasks', 'help.md'),
|
||||||
|
|
@ -560,33 +562,12 @@ class HelpValidationHarness {
|
||||||
return candidates[0];
|
return candidates[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
const sourceMarkdownPath = await resolveExistingPath(sourceMarkdownCandidates);
|
return Promise.all([resolveExistingPath(sidecarCandidates), resolveExistingPath(sourceMarkdownCandidates)]).then(
|
||||||
|
([sidecarPath, sourceMarkdownPath]) => ({
|
||||||
let resolvedMetadataAuthority;
|
sidecarPath,
|
||||||
try {
|
|
||||||
resolvedMetadataAuthority = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourceMarkdownPath,
|
|
||||||
metadataPath: options.sidecarPath || '',
|
|
||||||
projectRoot: projectDir,
|
|
||||||
ambiguousErrorCode: HELP_VALIDATION_ERROR_CODES.METADATA_RESOLUTION_FAILED,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw new HelpValidationHarnessError({
|
|
||||||
code: HELP_VALIDATION_ERROR_CODES.METADATA_RESOLUTION_FAILED,
|
|
||||||
detail: error.detail || error.message || 'metadata authority resolution failed',
|
|
||||||
artifactId: 1,
|
|
||||||
fieldPath: normalizeValue(error.fieldPath || '<file>'),
|
|
||||||
sourcePath: normalizePath(error.sourcePath || SIDEcar_AUTHORITY_SOURCE_PATH),
|
|
||||||
observedValue: normalizeValue(error.code || '<resolution-error>'),
|
|
||||||
expectedValue: 'unambiguous metadata authority candidate',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
sidecarPath: resolvedMetadataAuthority.resolvedAbsolutePath || options.sidecarPath || '',
|
|
||||||
sourceMarkdownPath,
|
sourceMarkdownPath,
|
||||||
metadataAuthority: resolvedMetadataAuthority,
|
}),
|
||||||
};
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async readSidecarMetadata(sidecarPath) {
|
async readSidecarMetadata(sidecarPath) {
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@ const fs = require('fs-extra');
|
||||||
const yaml = require('yaml');
|
const yaml = require('yaml');
|
||||||
const csv = require('csv-parse/sync');
|
const csv = require('csv-parse/sync');
|
||||||
const { getProjectRoot, getSourcePath } = require('../../../lib/project-root');
|
const { getProjectRoot, getSourcePath } = require('../../../lib/project-root');
|
||||||
const { resolveSkillMetadataAuthority } = require('./sidecar-contract-validator');
|
|
||||||
|
|
||||||
const INDEX_DOCS_AUTHORITY_VALIDATION_ERROR_CODES = Object.freeze({
|
const INDEX_DOCS_AUTHORITY_VALIDATION_ERROR_CODES = Object.freeze({
|
||||||
SIDECAR_FILE_NOT_FOUND: 'ERR_INDEX_DOCS_AUTHORITY_SIDECAR_FILE_NOT_FOUND',
|
SIDECAR_FILE_NOT_FOUND: 'ERR_INDEX_DOCS_AUTHORITY_SIDECAR_FILE_NOT_FOUND',
|
||||||
SIDECAR_FILENAME_AMBIGUOUS: 'ERR_INDEX_DOCS_AUTHORITY_SIDECAR_FILENAME_AMBIGUOUS',
|
|
||||||
SIDECAR_PARSE_FAILED: 'ERR_INDEX_DOCS_AUTHORITY_SIDECAR_PARSE_FAILED',
|
SIDECAR_PARSE_FAILED: 'ERR_INDEX_DOCS_AUTHORITY_SIDECAR_PARSE_FAILED',
|
||||||
SIDECAR_INVALID_METADATA: 'ERR_INDEX_DOCS_AUTHORITY_SIDECAR_INVALID_METADATA',
|
SIDECAR_INVALID_METADATA: 'ERR_INDEX_DOCS_AUTHORITY_SIDECAR_INVALID_METADATA',
|
||||||
SIDECAR_CANONICAL_ID_MISMATCH: 'ERR_INDEX_DOCS_AUTHORITY_SIDECAR_CANONICAL_ID_MISMATCH',
|
SIDECAR_CANONICAL_ID_MISMATCH: 'ERR_INDEX_DOCS_AUTHORITY_SIDECAR_CANONICAL_ID_MISMATCH',
|
||||||
|
|
@ -251,38 +249,18 @@ function buildIndexDocsAuthorityRecords({ canonicalId, sidecarSourcePath, source
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validateIndexDocsAuthoritySplitAndPrecedence(options = {}) {
|
async function validateIndexDocsAuthoritySplitAndPrecedence(options = {}) {
|
||||||
|
const sidecarPath = options.sidecarPath || getSourcePath('core', 'tasks', 'index-docs.artifact.yaml');
|
||||||
const sourceXmlPath = options.sourceXmlPath || getSourcePath('core', 'tasks', 'index-docs.xml');
|
const sourceXmlPath = options.sourceXmlPath || getSourcePath('core', 'tasks', 'index-docs.xml');
|
||||||
const compatibilityCatalogPath = options.compatibilityCatalogPath || getSourcePath('core', 'module-help.csv');
|
const compatibilityCatalogPath = options.compatibilityCatalogPath || getSourcePath('core', 'module-help.csv');
|
||||||
const compatibilityWorkflowFilePath = options.compatibilityWorkflowFilePath || '_bmad/core/tasks/index-docs.xml';
|
const compatibilityWorkflowFilePath = options.compatibilityWorkflowFilePath || '_bmad/core/tasks/index-docs.xml';
|
||||||
|
|
||||||
let resolvedMetadataAuthority;
|
const sidecarSourcePath = normalizeSourcePath(options.sidecarSourcePath || toProjectRelativePath(sidecarPath));
|
||||||
try {
|
|
||||||
resolvedMetadataAuthority = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourceXmlPath,
|
|
||||||
metadataPath: options.sidecarPath || '',
|
|
||||||
metadataSourcePath: options.sidecarSourcePath || '',
|
|
||||||
ambiguousErrorCode: INDEX_DOCS_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILENAME_AMBIGUOUS,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
createValidationError(
|
|
||||||
error.code || INDEX_DOCS_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILENAME_AMBIGUOUS,
|
|
||||||
error.detail || error.message,
|
|
||||||
error.fieldPath || '<file>',
|
|
||||||
normalizeSourcePath(error.sourcePath || toProjectRelativePath(sourceXmlPath)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const sidecarPath = resolvedMetadataAuthority.resolvedAbsolutePath;
|
|
||||||
|
|
||||||
const sidecarSourcePath = normalizeSourcePath(
|
|
||||||
options.sidecarSourcePath || resolvedMetadataAuthority.canonicalTargetSourcePath || resolvedMetadataAuthority.resolvedSourcePath,
|
|
||||||
);
|
|
||||||
const sourceXmlSourcePath = normalizeSourcePath(options.sourceXmlSourcePath || toProjectRelativePath(sourceXmlPath));
|
const sourceXmlSourcePath = normalizeSourcePath(options.sourceXmlSourcePath || toProjectRelativePath(sourceXmlPath));
|
||||||
const compatibilityCatalogSourcePath = normalizeSourcePath(
|
const compatibilityCatalogSourcePath = normalizeSourcePath(
|
||||||
options.compatibilityCatalogSourcePath || toProjectRelativePath(compatibilityCatalogPath),
|
options.compatibilityCatalogSourcePath || toProjectRelativePath(compatibilityCatalogPath),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!sidecarPath || !(await fs.pathExists(sidecarPath))) {
|
if (!(await fs.pathExists(sidecarPath))) {
|
||||||
createValidationError(
|
createValidationError(
|
||||||
INDEX_DOCS_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILE_NOT_FOUND,
|
INDEX_DOCS_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILE_NOT_FOUND,
|
||||||
'Expected index-docs sidecar metadata file was not found',
|
'Expected index-docs sidecar metadata file was not found',
|
||||||
|
|
@ -342,13 +320,6 @@ async function validateIndexDocsAuthoritySplitAndPrecedence(options = {}) {
|
||||||
canonicalId,
|
canonicalId,
|
||||||
authoritativePresenceKey: INDEX_DOCS_LOCKED_AUTHORITATIVE_PRESENCE_KEY,
|
authoritativePresenceKey: INDEX_DOCS_LOCKED_AUTHORITATIVE_PRESENCE_KEY,
|
||||||
authoritativeRecords,
|
authoritativeRecords,
|
||||||
metadataAuthority: {
|
|
||||||
resolvedPath: normalizeSourcePath(resolvedMetadataAuthority.resolvedSourcePath || sidecarSourcePath),
|
|
||||||
resolvedFilename: normalizeSourcePath(resolvedMetadataAuthority.resolvedFilename || ''),
|
|
||||||
canonicalTargetFilename: normalizeSourcePath(resolvedMetadataAuthority.canonicalTargetFilename || 'skill-manifest.yaml'),
|
|
||||||
canonicalTargetPath: normalizeSourcePath(resolvedMetadataAuthority.canonicalTargetSourcePath || sidecarSourcePath),
|
|
||||||
derivationMode: normalizeSourcePath(resolvedMetadataAuthority.derivationMode || ''),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ const fs = require('fs-extra');
|
||||||
const yaml = require('yaml');
|
const yaml = require('yaml');
|
||||||
const csv = require('csv-parse/sync');
|
const csv = require('csv-parse/sync');
|
||||||
const { getSourcePath } = require('../../../lib/project-root');
|
const { getSourcePath } = require('../../../lib/project-root');
|
||||||
const { resolveSkillMetadataAuthority } = require('./sidecar-contract-validator');
|
|
||||||
const { normalizeDisplayedCommandLabel } = require('./help-catalog-generator');
|
const { normalizeDisplayedCommandLabel } = require('./help-catalog-generator');
|
||||||
const { ManifestGenerator } = require('./manifest-generator');
|
const { ManifestGenerator } = require('./manifest-generator');
|
||||||
const {
|
const {
|
||||||
|
|
@ -15,13 +14,12 @@ const {
|
||||||
validateGithubCopilotHelpLoaderEntries,
|
validateGithubCopilotHelpLoaderEntries,
|
||||||
} = require('./projection-compatibility-validator');
|
} = require('./projection-compatibility-validator');
|
||||||
|
|
||||||
const INDEX_DOCS_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml';
|
const INDEX_DOCS_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.artifact.yaml';
|
||||||
const INDEX_DOCS_SOURCE_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.xml';
|
const INDEX_DOCS_SOURCE_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.xml';
|
||||||
const INDEX_DOCS_EVIDENCE_ISSUER_COMPONENT = 'bmad-fork/tools/cli/installers/lib/core/index-docs-validation-harness.js';
|
const INDEX_DOCS_EVIDENCE_ISSUER_COMPONENT = 'bmad-fork/tools/cli/installers/lib/core/index-docs-validation-harness.js';
|
||||||
|
|
||||||
const INDEX_DOCS_VALIDATION_ERROR_CODES = Object.freeze({
|
const INDEX_DOCS_VALIDATION_ERROR_CODES = Object.freeze({
|
||||||
REQUIRED_ARTIFACT_MISSING: 'ERR_INDEX_DOCS_VALIDATION_REQUIRED_ARTIFACT_MISSING',
|
REQUIRED_ARTIFACT_MISSING: 'ERR_INDEX_DOCS_VALIDATION_REQUIRED_ARTIFACT_MISSING',
|
||||||
METADATA_RESOLUTION_FAILED: 'ERR_INDEX_DOCS_VALIDATION_METADATA_RESOLUTION_FAILED',
|
|
||||||
CSV_SCHEMA_MISMATCH: 'ERR_INDEX_DOCS_VALIDATION_CSV_SCHEMA_MISMATCH',
|
CSV_SCHEMA_MISMATCH: 'ERR_INDEX_DOCS_VALIDATION_CSV_SCHEMA_MISMATCH',
|
||||||
REQUIRED_ROW_MISSING: 'ERR_INDEX_DOCS_VALIDATION_REQUIRED_ROW_MISSING',
|
REQUIRED_ROW_MISSING: 'ERR_INDEX_DOCS_VALIDATION_REQUIRED_ROW_MISSING',
|
||||||
YAML_SCHEMA_MISMATCH: 'ERR_INDEX_DOCS_VALIDATION_YAML_SCHEMA_MISMATCH',
|
YAML_SCHEMA_MISMATCH: 'ERR_INDEX_DOCS_VALIDATION_YAML_SCHEMA_MISMATCH',
|
||||||
|
|
@ -891,34 +889,16 @@ class IndexDocsValidationHarness {
|
||||||
const runtimeFolder = normalizeValue(options.bmadFolderName || '_bmad');
|
const runtimeFolder = normalizeValue(options.bmadFolderName || '_bmad');
|
||||||
const bmadDir = path.resolve(options.bmadDir || path.join(outputPaths.projectDir, runtimeFolder));
|
const bmadDir = path.resolve(options.bmadDir || path.join(outputPaths.projectDir, runtimeFolder));
|
||||||
const artifactPaths = this.buildArtifactPathsMap(outputPaths);
|
const artifactPaths = this.buildArtifactPathsMap(outputPaths);
|
||||||
|
const sidecarPath =
|
||||||
|
options.sidecarPath ||
|
||||||
|
((await fs.pathExists(path.join(outputPaths.projectDir, INDEX_DOCS_SIDECAR_SOURCE_PATH)))
|
||||||
|
? path.join(outputPaths.projectDir, INDEX_DOCS_SIDECAR_SOURCE_PATH)
|
||||||
|
: getSourcePath('core', 'tasks', 'index-docs.artifact.yaml'));
|
||||||
const sourceXmlPath =
|
const sourceXmlPath =
|
||||||
options.sourceXmlPath ||
|
options.sourceXmlPath ||
|
||||||
((await fs.pathExists(path.join(outputPaths.projectDir, INDEX_DOCS_SOURCE_XML_SOURCE_PATH)))
|
((await fs.pathExists(path.join(outputPaths.projectDir, INDEX_DOCS_SOURCE_XML_SOURCE_PATH)))
|
||||||
? path.join(outputPaths.projectDir, INDEX_DOCS_SOURCE_XML_SOURCE_PATH)
|
? path.join(outputPaths.projectDir, INDEX_DOCS_SOURCE_XML_SOURCE_PATH)
|
||||||
: getSourcePath('core', 'tasks', 'index-docs.xml'));
|
: getSourcePath('core', 'tasks', 'index-docs.xml'));
|
||||||
let resolvedMetadataAuthority;
|
|
||||||
try {
|
|
||||||
resolvedMetadataAuthority = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourceXmlPath,
|
|
||||||
metadataPath: options.sidecarPath || '',
|
|
||||||
projectRoot: outputPaths.projectDir,
|
|
||||||
ambiguousErrorCode: INDEX_DOCS_VALIDATION_ERROR_CODES.METADATA_RESOLUTION_FAILED,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw new IndexDocsValidationHarnessError({
|
|
||||||
code: INDEX_DOCS_VALIDATION_ERROR_CODES.METADATA_RESOLUTION_FAILED,
|
|
||||||
detail: error.detail || error.message || 'metadata authority resolution failed',
|
|
||||||
artifactId: 1,
|
|
||||||
fieldPath: normalizeValue(error.fieldPath || '<file>'),
|
|
||||||
sourcePath: normalizePath(error.sourcePath || INDEX_DOCS_SIDECAR_SOURCE_PATH),
|
|
||||||
observedValue: normalizeValue(error.code || '<resolution-error>'),
|
|
||||||
expectedValue: 'unambiguous metadata authority candidate',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const sidecarPath =
|
|
||||||
resolvedMetadataAuthority.resolvedAbsolutePath ||
|
|
||||||
options.sidecarPath ||
|
|
||||||
path.join(path.dirname(sourceXmlPath), path.basename(sourceXmlPath, path.extname(sourceXmlPath)), 'skill-manifest.yaml');
|
|
||||||
|
|
||||||
await fs.ensureDir(outputPaths.validationRoot);
|
await fs.ensureDir(outputPaths.validationRoot);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,13 @@ const { CustomHandler } = require('../custom/handler');
|
||||||
const prompts = require('../../../lib/prompts');
|
const prompts = require('../../../lib/prompts');
|
||||||
const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils');
|
const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils');
|
||||||
|
|
||||||
const EXEMPLAR_HELP_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/help/skill-manifest.yaml';
|
const EXEMPLAR_HELP_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.artifact.yaml';
|
||||||
const EXEMPLAR_HELP_SOURCE_MARKDOWN_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.md';
|
const EXEMPLAR_HELP_SOURCE_MARKDOWN_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.md';
|
||||||
const EXEMPLAR_SHARD_DOC_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml';
|
const EXEMPLAR_SHARD_DOC_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml';
|
||||||
const EXEMPLAR_SHARD_DOC_SOURCE_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.xml';
|
const EXEMPLAR_SHARD_DOC_SOURCE_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.xml';
|
||||||
const EXEMPLAR_SHARD_DOC_COMPATIBILITY_CATALOG_SOURCE_PATH = 'bmad-fork/src/core/module-help.csv';
|
const EXEMPLAR_SHARD_DOC_COMPATIBILITY_CATALOG_SOURCE_PATH = 'bmad-fork/src/core/module-help.csv';
|
||||||
const EXEMPLAR_SHARD_DOC_WORKFLOW_FILE_PATH = '_bmad/core/tasks/shard-doc.xml';
|
const EXEMPLAR_SHARD_DOC_WORKFLOW_FILE_PATH = '_bmad/core/tasks/shard-doc.xml';
|
||||||
const EXEMPLAR_INDEX_DOCS_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml';
|
const EXEMPLAR_INDEX_DOCS_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.artifact.yaml';
|
||||||
const EXEMPLAR_INDEX_DOCS_SOURCE_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.xml';
|
const EXEMPLAR_INDEX_DOCS_SOURCE_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.xml';
|
||||||
const EXEMPLAR_INDEX_DOCS_COMPATIBILITY_CATALOG_SOURCE_PATH = 'bmad-fork/src/core/module-help.csv';
|
const EXEMPLAR_INDEX_DOCS_COMPATIBILITY_CATALOG_SOURCE_PATH = 'bmad-fork/src/core/module-help.csv';
|
||||||
const EXEMPLAR_INDEX_DOCS_WORKFLOW_FILE_PATH = '_bmad/core/tasks/index-docs.xml';
|
const EXEMPLAR_INDEX_DOCS_WORKFLOW_FILE_PATH = '_bmad/core/tasks/index-docs.xml';
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ const { validateTaskManifestCompatibilitySurface } = require('./projection-compa
|
||||||
|
|
||||||
// Load package.json for version info
|
// Load package.json for version info
|
||||||
const packageJson = require('../../../../../package.json');
|
const packageJson = require('../../../../../package.json');
|
||||||
const DEFAULT_EXEMPLAR_HELP_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/help/skill-manifest.yaml';
|
const DEFAULT_EXEMPLAR_HELP_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.artifact.yaml';
|
||||||
const DEFAULT_EXEMPLAR_SHARD_DOC_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml';
|
const DEFAULT_EXEMPLAR_SHARD_DOC_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml';
|
||||||
const DEFAULT_EXEMPLAR_INDEX_DOCS_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml';
|
const DEFAULT_EXEMPLAR_INDEX_DOCS_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.artifact.yaml';
|
||||||
const CANONICAL_ALIAS_TABLE_COLUMNS = Object.freeze([
|
const CANONICAL_ALIAS_TABLE_COLUMNS = Object.freeze([
|
||||||
'canonicalId',
|
'canonicalId',
|
||||||
'alias',
|
'alias',
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@ const fs = require('fs-extra');
|
||||||
const yaml = require('yaml');
|
const yaml = require('yaml');
|
||||||
const csv = require('csv-parse/sync');
|
const csv = require('csv-parse/sync');
|
||||||
const { getProjectRoot, getSourcePath } = require('../../../lib/project-root');
|
const { getProjectRoot, getSourcePath } = require('../../../lib/project-root');
|
||||||
const { resolveSkillMetadataAuthority } = require('./sidecar-contract-validator');
|
|
||||||
|
|
||||||
const SHARD_DOC_AUTHORITY_VALIDATION_ERROR_CODES = Object.freeze({
|
const SHARD_DOC_AUTHORITY_VALIDATION_ERROR_CODES = Object.freeze({
|
||||||
SIDECAR_FILE_NOT_FOUND: 'ERR_SHARD_DOC_AUTHORITY_SIDECAR_FILE_NOT_FOUND',
|
SIDECAR_FILE_NOT_FOUND: 'ERR_SHARD_DOC_AUTHORITY_SIDECAR_FILE_NOT_FOUND',
|
||||||
SIDECAR_FILENAME_AMBIGUOUS: 'ERR_SHARD_DOC_AUTHORITY_SIDECAR_FILENAME_AMBIGUOUS',
|
|
||||||
SIDECAR_PARSE_FAILED: 'ERR_SHARD_DOC_AUTHORITY_SIDECAR_PARSE_FAILED',
|
SIDECAR_PARSE_FAILED: 'ERR_SHARD_DOC_AUTHORITY_SIDECAR_PARSE_FAILED',
|
||||||
SIDECAR_INVALID_METADATA: 'ERR_SHARD_DOC_AUTHORITY_SIDECAR_INVALID_METADATA',
|
SIDECAR_INVALID_METADATA: 'ERR_SHARD_DOC_AUTHORITY_SIDECAR_INVALID_METADATA',
|
||||||
SIDECAR_CANONICAL_ID_MISMATCH: 'ERR_SHARD_DOC_AUTHORITY_SIDECAR_CANONICAL_ID_MISMATCH',
|
SIDECAR_CANONICAL_ID_MISMATCH: 'ERR_SHARD_DOC_AUTHORITY_SIDECAR_CANONICAL_ID_MISMATCH',
|
||||||
|
|
@ -251,38 +249,18 @@ function buildShardDocAuthorityRecords({ canonicalId, sidecarSourcePath, sourceX
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validateShardDocAuthoritySplitAndPrecedence(options = {}) {
|
async function validateShardDocAuthoritySplitAndPrecedence(options = {}) {
|
||||||
|
const sidecarPath = options.sidecarPath || getSourcePath('core', 'tasks', 'shard-doc.artifact.yaml');
|
||||||
const sourceXmlPath = options.sourceXmlPath || getSourcePath('core', 'tasks', 'shard-doc.xml');
|
const sourceXmlPath = options.sourceXmlPath || getSourcePath('core', 'tasks', 'shard-doc.xml');
|
||||||
const compatibilityCatalogPath = options.compatibilityCatalogPath || getSourcePath('core', 'module-help.csv');
|
const compatibilityCatalogPath = options.compatibilityCatalogPath || getSourcePath('core', 'module-help.csv');
|
||||||
const compatibilityWorkflowFilePath = options.compatibilityWorkflowFilePath || '_bmad/core/tasks/shard-doc.xml';
|
const compatibilityWorkflowFilePath = options.compatibilityWorkflowFilePath || '_bmad/core/tasks/shard-doc.xml';
|
||||||
|
|
||||||
let resolvedMetadataAuthority;
|
const sidecarSourcePath = normalizeSourcePath(options.sidecarSourcePath || toProjectRelativePath(sidecarPath));
|
||||||
try {
|
|
||||||
resolvedMetadataAuthority = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourceXmlPath,
|
|
||||||
metadataPath: options.sidecarPath || '',
|
|
||||||
metadataSourcePath: options.sidecarSourcePath || '',
|
|
||||||
ambiguousErrorCode: SHARD_DOC_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILENAME_AMBIGUOUS,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
createValidationError(
|
|
||||||
error.code || SHARD_DOC_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILENAME_AMBIGUOUS,
|
|
||||||
error.detail || error.message,
|
|
||||||
error.fieldPath || '<file>',
|
|
||||||
normalizeSourcePath(error.sourcePath || toProjectRelativePath(sourceXmlPath)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const sidecarPath = resolvedMetadataAuthority.resolvedAbsolutePath;
|
|
||||||
|
|
||||||
const sidecarSourcePath = normalizeSourcePath(
|
|
||||||
options.sidecarSourcePath || resolvedMetadataAuthority.canonicalTargetSourcePath || resolvedMetadataAuthority.resolvedSourcePath,
|
|
||||||
);
|
|
||||||
const sourceXmlSourcePath = normalizeSourcePath(options.sourceXmlSourcePath || toProjectRelativePath(sourceXmlPath));
|
const sourceXmlSourcePath = normalizeSourcePath(options.sourceXmlSourcePath || toProjectRelativePath(sourceXmlPath));
|
||||||
const compatibilityCatalogSourcePath = normalizeSourcePath(
|
const compatibilityCatalogSourcePath = normalizeSourcePath(
|
||||||
options.compatibilityCatalogSourcePath || toProjectRelativePath(compatibilityCatalogPath),
|
options.compatibilityCatalogSourcePath || toProjectRelativePath(compatibilityCatalogPath),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!sidecarPath || !(await fs.pathExists(sidecarPath))) {
|
if (!(await fs.pathExists(sidecarPath))) {
|
||||||
createValidationError(
|
createValidationError(
|
||||||
SHARD_DOC_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILE_NOT_FOUND,
|
SHARD_DOC_AUTHORITY_VALIDATION_ERROR_CODES.SIDECAR_FILE_NOT_FOUND,
|
||||||
'Expected shard-doc sidecar metadata file was not found',
|
'Expected shard-doc sidecar metadata file was not found',
|
||||||
|
|
@ -344,13 +322,6 @@ async function validateShardDocAuthoritySplitAndPrecedence(options = {}) {
|
||||||
authoritativePresenceKey: SHARD_DOC_LOCKED_AUTHORITATIVE_PRESENCE_KEY,
|
authoritativePresenceKey: SHARD_DOC_LOCKED_AUTHORITATIVE_PRESENCE_KEY,
|
||||||
authoritativeRecords,
|
authoritativeRecords,
|
||||||
checkedSurfaces: [sourceXmlSourcePath, compatibilityCatalogSourcePath],
|
checkedSurfaces: [sourceXmlSourcePath, compatibilityCatalogSourcePath],
|
||||||
metadataAuthority: {
|
|
||||||
resolvedPath: normalizeSourcePath(resolvedMetadataAuthority.resolvedSourcePath || sidecarSourcePath),
|
|
||||||
resolvedFilename: normalizeSourcePath(resolvedMetadataAuthority.resolvedFilename || ''),
|
|
||||||
canonicalTargetFilename: normalizeSourcePath(resolvedMetadataAuthority.canonicalTargetFilename || 'skill-manifest.yaml'),
|
|
||||||
canonicalTargetPath: normalizeSourcePath(resolvedMetadataAuthority.canonicalTargetSourcePath || sidecarSourcePath),
|
|
||||||
derivationMode: normalizeSourcePath(resolvedMetadataAuthority.derivationMode || ''),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ const fs = require('fs-extra');
|
||||||
const yaml = require('yaml');
|
const yaml = require('yaml');
|
||||||
const csv = require('csv-parse/sync');
|
const csv = require('csv-parse/sync');
|
||||||
const { getSourcePath } = require('../../../lib/project-root');
|
const { getSourcePath } = require('../../../lib/project-root');
|
||||||
const { resolveSkillMetadataAuthority } = require('./sidecar-contract-validator');
|
|
||||||
const { normalizeDisplayedCommandLabel } = require('./help-catalog-generator');
|
const { normalizeDisplayedCommandLabel } = require('./help-catalog-generator');
|
||||||
const { ManifestGenerator } = require('./manifest-generator');
|
const { ManifestGenerator } = require('./manifest-generator');
|
||||||
const {
|
const {
|
||||||
|
|
@ -15,13 +14,12 @@ const {
|
||||||
validateGithubCopilotHelpLoaderEntries,
|
validateGithubCopilotHelpLoaderEntries,
|
||||||
} = require('./projection-compatibility-validator');
|
} = require('./projection-compatibility-validator');
|
||||||
|
|
||||||
const SHARD_DOC_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml';
|
const SHARD_DOC_SIDECAR_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml';
|
||||||
const SHARD_DOC_SOURCE_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.xml';
|
const SHARD_DOC_SOURCE_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.xml';
|
||||||
const SHARD_DOC_EVIDENCE_ISSUER_COMPONENT = 'bmad-fork/tools/cli/installers/lib/core/shard-doc-validation-harness.js';
|
const SHARD_DOC_EVIDENCE_ISSUER_COMPONENT = 'bmad-fork/tools/cli/installers/lib/core/shard-doc-validation-harness.js';
|
||||||
|
|
||||||
const SHARD_DOC_VALIDATION_ERROR_CODES = Object.freeze({
|
const SHARD_DOC_VALIDATION_ERROR_CODES = Object.freeze({
|
||||||
REQUIRED_ARTIFACT_MISSING: 'ERR_SHARD_DOC_VALIDATION_REQUIRED_ARTIFACT_MISSING',
|
REQUIRED_ARTIFACT_MISSING: 'ERR_SHARD_DOC_VALIDATION_REQUIRED_ARTIFACT_MISSING',
|
||||||
METADATA_RESOLUTION_FAILED: 'ERR_SHARD_DOC_VALIDATION_METADATA_RESOLUTION_FAILED',
|
|
||||||
CSV_SCHEMA_MISMATCH: 'ERR_SHARD_DOC_VALIDATION_CSV_SCHEMA_MISMATCH',
|
CSV_SCHEMA_MISMATCH: 'ERR_SHARD_DOC_VALIDATION_CSV_SCHEMA_MISMATCH',
|
||||||
REQUIRED_ROW_MISSING: 'ERR_SHARD_DOC_VALIDATION_REQUIRED_ROW_MISSING',
|
REQUIRED_ROW_MISSING: 'ERR_SHARD_DOC_VALIDATION_REQUIRED_ROW_MISSING',
|
||||||
YAML_SCHEMA_MISMATCH: 'ERR_SHARD_DOC_VALIDATION_YAML_SCHEMA_MISMATCH',
|
YAML_SCHEMA_MISMATCH: 'ERR_SHARD_DOC_VALIDATION_YAML_SCHEMA_MISMATCH',
|
||||||
|
|
@ -890,34 +888,16 @@ class ShardDocValidationHarness {
|
||||||
const runtimeFolder = normalizeValue(options.bmadFolderName || '_bmad');
|
const runtimeFolder = normalizeValue(options.bmadFolderName || '_bmad');
|
||||||
const bmadDir = path.resolve(options.bmadDir || path.join(outputPaths.projectDir, runtimeFolder));
|
const bmadDir = path.resolve(options.bmadDir || path.join(outputPaths.projectDir, runtimeFolder));
|
||||||
const artifactPaths = this.buildArtifactPathsMap(outputPaths);
|
const artifactPaths = this.buildArtifactPathsMap(outputPaths);
|
||||||
|
const sidecarPath =
|
||||||
|
options.sidecarPath ||
|
||||||
|
((await fs.pathExists(path.join(outputPaths.projectDir, SHARD_DOC_SIDECAR_SOURCE_PATH)))
|
||||||
|
? path.join(outputPaths.projectDir, SHARD_DOC_SIDECAR_SOURCE_PATH)
|
||||||
|
: getSourcePath('core', 'tasks', 'shard-doc.artifact.yaml'));
|
||||||
const sourceXmlPath =
|
const sourceXmlPath =
|
||||||
options.sourceXmlPath ||
|
options.sourceXmlPath ||
|
||||||
((await fs.pathExists(path.join(outputPaths.projectDir, SHARD_DOC_SOURCE_XML_SOURCE_PATH)))
|
((await fs.pathExists(path.join(outputPaths.projectDir, SHARD_DOC_SOURCE_XML_SOURCE_PATH)))
|
||||||
? path.join(outputPaths.projectDir, SHARD_DOC_SOURCE_XML_SOURCE_PATH)
|
? path.join(outputPaths.projectDir, SHARD_DOC_SOURCE_XML_SOURCE_PATH)
|
||||||
: getSourcePath('core', 'tasks', 'shard-doc.xml'));
|
: getSourcePath('core', 'tasks', 'shard-doc.xml'));
|
||||||
let resolvedMetadataAuthority;
|
|
||||||
try {
|
|
||||||
resolvedMetadataAuthority = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourceXmlPath,
|
|
||||||
metadataPath: options.sidecarPath || '',
|
|
||||||
projectRoot: outputPaths.projectDir,
|
|
||||||
ambiguousErrorCode: SHARD_DOC_VALIDATION_ERROR_CODES.METADATA_RESOLUTION_FAILED,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw new ShardDocValidationHarnessError({
|
|
||||||
code: SHARD_DOC_VALIDATION_ERROR_CODES.METADATA_RESOLUTION_FAILED,
|
|
||||||
detail: error.detail || error.message || 'metadata authority resolution failed',
|
|
||||||
artifactId: 1,
|
|
||||||
fieldPath: normalizeValue(error.fieldPath || '<file>'),
|
|
||||||
sourcePath: normalizePath(error.sourcePath || SHARD_DOC_SIDECAR_SOURCE_PATH),
|
|
||||||
observedValue: normalizeValue(error.code || '<resolution-error>'),
|
|
||||||
expectedValue: 'unambiguous metadata authority candidate',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const sidecarPath =
|
|
||||||
resolvedMetadataAuthority.resolvedAbsolutePath ||
|
|
||||||
options.sidecarPath ||
|
|
||||||
path.join(path.dirname(sourceXmlPath), path.basename(sourceXmlPath, path.extname(sourceXmlPath)), 'skill-manifest.yaml');
|
|
||||||
|
|
||||||
await fs.ensureDir(outputPaths.validationRoot);
|
await fs.ensureDir(outputPaths.validationRoot);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ const HELP_SIDECAR_ERROR_CODES = Object.freeze({
|
||||||
DEPENDENCIES_REQUIRES_NOT_EMPTY: 'ERR_HELP_SIDECAR_DEPENDENCIES_REQUIRES_NOT_EMPTY',
|
DEPENDENCIES_REQUIRES_NOT_EMPTY: 'ERR_HELP_SIDECAR_DEPENDENCIES_REQUIRES_NOT_EMPTY',
|
||||||
MAJOR_VERSION_UNSUPPORTED: 'ERR_SIDECAR_MAJOR_VERSION_UNSUPPORTED',
|
MAJOR_VERSION_UNSUPPORTED: 'ERR_SIDECAR_MAJOR_VERSION_UNSUPPORTED',
|
||||||
SOURCEPATH_BASENAME_MISMATCH: 'ERR_SIDECAR_SOURCEPATH_BASENAME_MISMATCH',
|
SOURCEPATH_BASENAME_MISMATCH: 'ERR_SIDECAR_SOURCEPATH_BASENAME_MISMATCH',
|
||||||
METADATA_FILENAME_AMBIGUOUS: 'ERR_HELP_SIDECAR_METADATA_FILENAME_AMBIGUOUS',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const SHARD_DOC_SIDECAR_ERROR_CODES = Object.freeze({
|
const SHARD_DOC_SIDECAR_ERROR_CODES = Object.freeze({
|
||||||
|
|
@ -46,7 +45,6 @@ const SHARD_DOC_SIDECAR_ERROR_CODES = Object.freeze({
|
||||||
DEPENDENCIES_REQUIRES_NOT_EMPTY: 'ERR_SHARD_DOC_SIDECAR_DEPENDENCIES_REQUIRES_NOT_EMPTY',
|
DEPENDENCIES_REQUIRES_NOT_EMPTY: 'ERR_SHARD_DOC_SIDECAR_DEPENDENCIES_REQUIRES_NOT_EMPTY',
|
||||||
MAJOR_VERSION_UNSUPPORTED: 'ERR_SHARD_DOC_SIDECAR_MAJOR_VERSION_UNSUPPORTED',
|
MAJOR_VERSION_UNSUPPORTED: 'ERR_SHARD_DOC_SIDECAR_MAJOR_VERSION_UNSUPPORTED',
|
||||||
SOURCEPATH_BASENAME_MISMATCH: 'ERR_SHARD_DOC_SIDECAR_SOURCEPATH_BASENAME_MISMATCH',
|
SOURCEPATH_BASENAME_MISMATCH: 'ERR_SHARD_DOC_SIDECAR_SOURCEPATH_BASENAME_MISMATCH',
|
||||||
METADATA_FILENAME_AMBIGUOUS: 'ERR_SHARD_DOC_SIDECAR_METADATA_FILENAME_AMBIGUOUS',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const INDEX_DOCS_SIDECAR_ERROR_CODES = Object.freeze({
|
const INDEX_DOCS_SIDECAR_ERROR_CODES = Object.freeze({
|
||||||
|
|
@ -62,21 +60,11 @@ const INDEX_DOCS_SIDECAR_ERROR_CODES = Object.freeze({
|
||||||
DEPENDENCIES_REQUIRES_NOT_EMPTY: 'ERR_INDEX_DOCS_SIDECAR_DEPENDENCIES_REQUIRES_NOT_EMPTY',
|
DEPENDENCIES_REQUIRES_NOT_EMPTY: 'ERR_INDEX_DOCS_SIDECAR_DEPENDENCIES_REQUIRES_NOT_EMPTY',
|
||||||
MAJOR_VERSION_UNSUPPORTED: 'ERR_INDEX_DOCS_SIDECAR_MAJOR_VERSION_UNSUPPORTED',
|
MAJOR_VERSION_UNSUPPORTED: 'ERR_INDEX_DOCS_SIDECAR_MAJOR_VERSION_UNSUPPORTED',
|
||||||
SOURCEPATH_BASENAME_MISMATCH: 'ERR_INDEX_DOCS_SIDECAR_SOURCEPATH_BASENAME_MISMATCH',
|
SOURCEPATH_BASENAME_MISMATCH: 'ERR_INDEX_DOCS_SIDECAR_SOURCEPATH_BASENAME_MISMATCH',
|
||||||
METADATA_FILENAME_AMBIGUOUS: 'ERR_INDEX_DOCS_SIDECAR_METADATA_FILENAME_AMBIGUOUS',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const HELP_EXEMPLAR_CANONICAL_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.md';
|
const HELP_EXEMPLAR_CANONICAL_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.md';
|
||||||
const SHARD_DOC_CANONICAL_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.xml';
|
const SHARD_DOC_CANONICAL_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.xml';
|
||||||
const INDEX_DOCS_CANONICAL_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.xml';
|
const INDEX_DOCS_CANONICAL_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.xml';
|
||||||
const SKILL_METADATA_CANONICAL_FILENAME = 'skill-manifest.yaml';
|
|
||||||
const SKILL_METADATA_LEGACY_FILENAMES = Object.freeze(['bmad-config.yaml', 'manifest.yaml']);
|
|
||||||
const SKILL_METADATA_DERIVATION_MODES = Object.freeze({
|
|
||||||
CANONICAL: 'canonical',
|
|
||||||
LEGACY_FALLBACK: 'legacy-fallback',
|
|
||||||
});
|
|
||||||
const SKILL_METADATA_RESOLUTION_ERROR_CODES = Object.freeze({
|
|
||||||
AMBIGUOUS_MATCH: 'ERR_SKILL_METADATA_FILENAME_AMBIGUOUS',
|
|
||||||
});
|
|
||||||
const SIDECAR_SUPPORTED_SCHEMA_MAJOR = 1;
|
const SIDECAR_SUPPORTED_SCHEMA_MAJOR = 1;
|
||||||
|
|
||||||
class SidecarContractError extends Error {
|
class SidecarContractError extends Error {
|
||||||
|
|
@ -97,7 +85,8 @@ function normalizeSourcePath(value) {
|
||||||
return String(value).replaceAll('\\', '/');
|
return String(value).replaceAll('\\', '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
function toProjectRelativePath(filePath, projectRoot = getProjectRoot()) {
|
function toProjectRelativePath(filePath) {
|
||||||
|
const projectRoot = getProjectRoot();
|
||||||
const relative = path.relative(projectRoot, filePath);
|
const relative = path.relative(projectRoot, filePath);
|
||||||
|
|
||||||
if (!relative || relative.startsWith('..')) {
|
if (!relative || relative.startsWith('..')) {
|
||||||
|
|
@ -107,17 +96,6 @@ function toProjectRelativePath(filePath, projectRoot = getProjectRoot()) {
|
||||||
return normalizeSourcePath(relative);
|
return normalizeSourcePath(relative);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dedupeAndSort(values) {
|
|
||||||
const normalized = new Set();
|
|
||||||
for (const value of values || []) {
|
|
||||||
const text = normalizeSourcePath(value).trim();
|
|
||||||
if (text.length > 0) {
|
|
||||||
normalized.add(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [...normalized].sort((left, right) => left.localeCompare(right));
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasOwn(obj, key) {
|
function hasOwn(obj, key) {
|
||||||
return Object.prototype.hasOwnProperty.call(obj, key);
|
return Object.prototype.hasOwnProperty.call(obj, key);
|
||||||
}
|
}
|
||||||
|
|
@ -142,169 +120,7 @@ function parseSchemaMajorVersion(value) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function classifyMetadataFilename(filename) {
|
function getExpectedSidecarBasenameFromSourcePath(sourcePathValue) {
|
||||||
const normalizedFilename = String(filename || '')
|
|
||||||
.trim()
|
|
||||||
.toLowerCase();
|
|
||||||
if (normalizedFilename === SKILL_METADATA_CANONICAL_FILENAME) {
|
|
||||||
return SKILL_METADATA_DERIVATION_MODES.CANONICAL;
|
|
||||||
}
|
|
||||||
if (SKILL_METADATA_LEGACY_FILENAMES.includes(normalizedFilename) || normalizedFilename.endsWith('.artifact.yaml')) {
|
|
||||||
return SKILL_METADATA_DERIVATION_MODES.LEGACY_FALLBACK;
|
|
||||||
}
|
|
||||||
return SKILL_METADATA_DERIVATION_MODES.LEGACY_FALLBACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMetadataStemFromSourcePath(sourcePathValue) {
|
|
||||||
const normalizedSourcePath = normalizeSourcePath(sourcePathValue).trim();
|
|
||||||
if (!normalizedSourcePath) return '';
|
|
||||||
|
|
||||||
const sourceBasename = path.posix.basename(normalizedSourcePath);
|
|
||||||
if (!sourceBasename) return '';
|
|
||||||
|
|
||||||
const sourceExt = path.posix.extname(sourceBasename);
|
|
||||||
const baseWithoutExt = sourceExt ? sourceBasename.slice(0, -sourceExt.length) : sourceBasename;
|
|
||||||
return baseWithoutExt.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildSkillMetadataResolutionPlan({ sourceFilePath, projectRoot = getProjectRoot() }) {
|
|
||||||
const absoluteSourceFilePath = path.resolve(sourceFilePath);
|
|
||||||
const sourceDirAbsolutePath = path.dirname(absoluteSourceFilePath);
|
|
||||||
const metadataStem = getMetadataStemFromSourcePath(absoluteSourceFilePath);
|
|
||||||
const skillFolderAbsolutePath = path.join(sourceDirAbsolutePath, metadataStem);
|
|
||||||
const canonicalTargetAbsolutePath = path.join(skillFolderAbsolutePath, SKILL_METADATA_CANONICAL_FILENAME);
|
|
||||||
|
|
||||||
const candidateGroups = [
|
|
||||||
{
|
|
||||||
precedenceToken: SKILL_METADATA_CANONICAL_FILENAME,
|
|
||||||
derivationMode: SKILL_METADATA_DERIVATION_MODES.CANONICAL,
|
|
||||||
// Canonical authority is per-skill only; root task-folder canonical files are not eligible.
|
|
||||||
explicitCandidates: [canonicalTargetAbsolutePath],
|
|
||||||
wildcardDirectories: [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
precedenceToken: 'bmad-config.yaml',
|
|
||||||
derivationMode: SKILL_METADATA_DERIVATION_MODES.LEGACY_FALLBACK,
|
|
||||||
explicitCandidates: [path.join(skillFolderAbsolutePath, 'bmad-config.yaml'), path.join(sourceDirAbsolutePath, 'bmad-config.yaml')],
|
|
||||||
wildcardDirectories: [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
precedenceToken: 'manifest.yaml',
|
|
||||||
derivationMode: SKILL_METADATA_DERIVATION_MODES.LEGACY_FALLBACK,
|
|
||||||
explicitCandidates: [path.join(skillFolderAbsolutePath, 'manifest.yaml'), path.join(sourceDirAbsolutePath, 'manifest.yaml')],
|
|
||||||
wildcardDirectories: [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
precedenceToken: `${metadataStem}.artifact.yaml`,
|
|
||||||
derivationMode: SKILL_METADATA_DERIVATION_MODES.LEGACY_FALLBACK,
|
|
||||||
explicitCandidates: [
|
|
||||||
path.join(sourceDirAbsolutePath, `${metadataStem}.artifact.yaml`),
|
|
||||||
path.join(skillFolderAbsolutePath, `${metadataStem}.artifact.yaml`),
|
|
||||||
],
|
|
||||||
wildcardDirectories: [],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return {
|
|
||||||
metadataStem,
|
|
||||||
canonicalTargetAbsolutePath,
|
|
||||||
canonicalTargetSourcePath: toProjectRelativePath(canonicalTargetAbsolutePath, projectRoot),
|
|
||||||
candidateGroups,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resolveCandidateGroupMatches(group = {}) {
|
|
||||||
const explicitMatches = [];
|
|
||||||
for (const candidatePath of group.explicitCandidates || []) {
|
|
||||||
if (await fs.pathExists(candidatePath)) {
|
|
||||||
explicitMatches.push(path.resolve(candidatePath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const wildcardMatches = [];
|
|
||||||
for (const wildcardDirectory of group.wildcardDirectories || []) {
|
|
||||||
if (!(await fs.pathExists(wildcardDirectory))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const directoryEntries = await fs.readdir(wildcardDirectory, { withFileTypes: true });
|
|
||||||
for (const entry of directoryEntries) {
|
|
||||||
if (!entry.isFile()) continue;
|
|
||||||
const filename = String(entry.name || '').trim();
|
|
||||||
if (!filename.toLowerCase().endsWith('.artifact.yaml')) continue;
|
|
||||||
wildcardMatches.push(path.join(wildcardDirectory, filename));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dedupeAndSort([...explicitMatches, ...wildcardMatches]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath,
|
|
||||||
metadataPath = '',
|
|
||||||
metadataSourcePath = '',
|
|
||||||
projectRoot = getProjectRoot(),
|
|
||||||
ambiguousErrorCode = SKILL_METADATA_RESOLUTION_ERROR_CODES.AMBIGUOUS_MATCH,
|
|
||||||
}) {
|
|
||||||
const resolutionPlan = buildSkillMetadataResolutionPlan({
|
|
||||||
sourceFilePath,
|
|
||||||
projectRoot,
|
|
||||||
});
|
|
||||||
|
|
||||||
const resolvedMetadataPath = String(metadataPath || '').trim();
|
|
||||||
if (resolvedMetadataPath.length > 0) {
|
|
||||||
const resolvedAbsolutePath = path.resolve(resolvedMetadataPath);
|
|
||||||
const resolvedFilename = path.posix.basename(normalizeSourcePath(resolvedAbsolutePath));
|
|
||||||
return {
|
|
||||||
resolvedAbsolutePath,
|
|
||||||
resolvedSourcePath: normalizeSourcePath(metadataSourcePath || toProjectRelativePath(resolvedAbsolutePath, projectRoot)),
|
|
||||||
resolvedFilename,
|
|
||||||
canonicalTargetFilename: SKILL_METADATA_CANONICAL_FILENAME,
|
|
||||||
canonicalTargetSourcePath: resolutionPlan.canonicalTargetSourcePath,
|
|
||||||
derivationMode: classifyMetadataFilename(resolvedFilename),
|
|
||||||
precedenceToken: resolvedFilename,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const group of resolutionPlan.candidateGroups) {
|
|
||||||
const matches = await resolveCandidateGroupMatches(group);
|
|
||||||
if (matches.length === 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matches.length > 1) {
|
|
||||||
throw new SidecarContractError({
|
|
||||||
code: ambiguousErrorCode,
|
|
||||||
detail: `metadata filename resolution is ambiguous for precedence "${group.precedenceToken}": ${matches.join('|')}`,
|
|
||||||
fieldPath: '<file>',
|
|
||||||
sourcePath: resolutionPlan.canonicalTargetSourcePath,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolvedAbsolutePath = matches[0];
|
|
||||||
const resolvedFilename = path.posix.basename(normalizeSourcePath(resolvedAbsolutePath));
|
|
||||||
return {
|
|
||||||
resolvedAbsolutePath,
|
|
||||||
resolvedSourcePath: normalizeSourcePath(toProjectRelativePath(resolvedAbsolutePath, projectRoot)),
|
|
||||||
resolvedFilename,
|
|
||||||
canonicalTargetFilename: SKILL_METADATA_CANONICAL_FILENAME,
|
|
||||||
canonicalTargetSourcePath: resolutionPlan.canonicalTargetSourcePath,
|
|
||||||
derivationMode: group.derivationMode,
|
|
||||||
precedenceToken: group.precedenceToken,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
resolvedAbsolutePath: '',
|
|
||||||
resolvedSourcePath: '',
|
|
||||||
resolvedFilename: '',
|
|
||||||
canonicalTargetFilename: SKILL_METADATA_CANONICAL_FILENAME,
|
|
||||||
canonicalTargetSourcePath: resolutionPlan.canonicalTargetSourcePath,
|
|
||||||
derivationMode: '',
|
|
||||||
precedenceToken: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getExpectedLegacyArtifactBasenameFromSourcePath(sourcePathValue) {
|
|
||||||
const normalized = normalizeSourcePath(sourcePathValue).trim();
|
const normalized = normalizeSourcePath(sourcePathValue).trim();
|
||||||
if (!normalized) return '';
|
if (!normalized) return '';
|
||||||
|
|
||||||
|
|
@ -402,15 +218,11 @@ function validateSidecarContractData(sidecarData, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedDeclaredSourcePath = normalizeSourcePath(sidecarData.sourcePath);
|
const normalizedDeclaredSourcePath = normalizeSourcePath(sidecarData.sourcePath);
|
||||||
const sidecarBasename = path.posix.basename(normalizeSourcePath(sourcePath)).toLowerCase();
|
const sidecarBasename = path.posix.basename(sourcePath);
|
||||||
const expectedLegacyArtifactBasename = getExpectedLegacyArtifactBasenameFromSourcePath(normalizedDeclaredSourcePath).toLowerCase();
|
const expectedSidecarBasename = getExpectedSidecarBasenameFromSourcePath(normalizedDeclaredSourcePath);
|
||||||
const allowedMetadataBasenames = new Set([SKILL_METADATA_CANONICAL_FILENAME, ...SKILL_METADATA_LEGACY_FILENAMES]);
|
|
||||||
if (expectedLegacyArtifactBasename.length > 0) {
|
|
||||||
allowedMetadataBasenames.add(expectedLegacyArtifactBasename);
|
|
||||||
}
|
|
||||||
|
|
||||||
const sourcePathMismatch = normalizedDeclaredSourcePath !== expectedCanonicalSourcePath;
|
const sourcePathMismatch = normalizedDeclaredSourcePath !== expectedCanonicalSourcePath;
|
||||||
const basenameMismatch = !allowedMetadataBasenames.has(sidecarBasename);
|
const basenameMismatch = !expectedSidecarBasename || sidecarBasename !== expectedSidecarBasename;
|
||||||
|
|
||||||
if (sourcePathMismatch || basenameMismatch) {
|
if (sourcePathMismatch || basenameMismatch) {
|
||||||
createValidationError(
|
createValidationError(
|
||||||
|
|
@ -423,7 +235,7 @@ function validateSidecarContractData(sidecarData, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateHelpSidecarContractData(sidecarData, options = {}) {
|
function validateHelpSidecarContractData(sidecarData, options = {}) {
|
||||||
const sourcePath = normalizeSourcePath(options.errorSourcePath || 'src/core/tasks/help/skill-manifest.yaml');
|
const sourcePath = normalizeSourcePath(options.errorSourcePath || 'src/core/tasks/help.artifact.yaml');
|
||||||
validateSidecarContractData(sidecarData, {
|
validateSidecarContractData(sidecarData, {
|
||||||
sourcePath,
|
sourcePath,
|
||||||
requiredFields: HELP_SIDECAR_REQUIRED_FIELDS,
|
requiredFields: HELP_SIDECAR_REQUIRED_FIELDS,
|
||||||
|
|
@ -443,7 +255,7 @@ function validateHelpSidecarContractData(sidecarData, options = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateShardDocSidecarContractData(sidecarData, options = {}) {
|
function validateShardDocSidecarContractData(sidecarData, options = {}) {
|
||||||
const sourcePath = normalizeSourcePath(options.errorSourcePath || 'src/core/tasks/shard-doc/skill-manifest.yaml');
|
const sourcePath = normalizeSourcePath(options.errorSourcePath || 'src/core/tasks/shard-doc.artifact.yaml');
|
||||||
validateSidecarContractData(sidecarData, {
|
validateSidecarContractData(sidecarData, {
|
||||||
sourcePath,
|
sourcePath,
|
||||||
requiredFields: SHARD_DOC_SIDECAR_REQUIRED_FIELDS,
|
requiredFields: SHARD_DOC_SIDECAR_REQUIRED_FIELDS,
|
||||||
|
|
@ -463,7 +275,7 @@ function validateShardDocSidecarContractData(sidecarData, options = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateIndexDocsSidecarContractData(sidecarData, options = {}) {
|
function validateIndexDocsSidecarContractData(sidecarData, options = {}) {
|
||||||
const sourcePath = normalizeSourcePath(options.errorSourcePath || 'src/core/tasks/index-docs/skill-manifest.yaml');
|
const sourcePath = normalizeSourcePath(options.errorSourcePath || 'src/core/tasks/index-docs.artifact.yaml');
|
||||||
validateSidecarContractData(sidecarData, {
|
validateSidecarContractData(sidecarData, {
|
||||||
sourcePath,
|
sourcePath,
|
||||||
requiredFields: INDEX_DOCS_SIDECAR_REQUIRED_FIELDS,
|
requiredFields: INDEX_DOCS_SIDECAR_REQUIRED_FIELDS,
|
||||||
|
|
@ -482,20 +294,10 @@ function validateIndexDocsSidecarContractData(sidecarData, options = {}) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validateHelpSidecarContractFile(sidecarPath = '', options = {}) {
|
async function validateHelpSidecarContractFile(sidecarPath = getSourcePath('core', 'tasks', 'help.artifact.yaml'), options = {}) {
|
||||||
const sourceFilePath = options.sourceFilePath || getSourcePath('core', 'tasks', 'help.md');
|
const normalizedSourcePath = normalizeSourcePath(options.errorSourcePath || toProjectRelativePath(sidecarPath));
|
||||||
const resolvedMetadataAuthority = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath,
|
|
||||||
metadataPath: sidecarPath,
|
|
||||||
metadataSourcePath: options.errorSourcePath,
|
|
||||||
ambiguousErrorCode: HELP_SIDECAR_ERROR_CODES.METADATA_FILENAME_AMBIGUOUS,
|
|
||||||
});
|
|
||||||
const resolvedSidecarPath = resolvedMetadataAuthority.resolvedAbsolutePath;
|
|
||||||
const normalizedSourcePath = normalizeSourcePath(
|
|
||||||
options.errorSourcePath || resolvedMetadataAuthority.resolvedSourcePath || resolvedMetadataAuthority.canonicalTargetSourcePath,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!resolvedSidecarPath || !(await fs.pathExists(resolvedSidecarPath))) {
|
if (!(await fs.pathExists(sidecarPath))) {
|
||||||
createValidationError(
|
createValidationError(
|
||||||
HELP_SIDECAR_ERROR_CODES.FILE_NOT_FOUND,
|
HELP_SIDECAR_ERROR_CODES.FILE_NOT_FOUND,
|
||||||
'<file>',
|
'<file>',
|
||||||
|
|
@ -506,7 +308,7 @@ async function validateHelpSidecarContractFile(sidecarPath = '', options = {}) {
|
||||||
|
|
||||||
let parsedSidecar;
|
let parsedSidecar;
|
||||||
try {
|
try {
|
||||||
const sidecarRaw = await fs.readFile(resolvedSidecarPath, 'utf8');
|
const sidecarRaw = await fs.readFile(sidecarPath, 'utf8');
|
||||||
parsedSidecar = yaml.parse(sidecarRaw);
|
parsedSidecar = yaml.parse(sidecarRaw);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
createValidationError(
|
createValidationError(
|
||||||
|
|
@ -518,23 +320,12 @@ async function validateHelpSidecarContractFile(sidecarPath = '', options = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
validateHelpSidecarContractData(parsedSidecar, { errorSourcePath: normalizedSourcePath });
|
validateHelpSidecarContractData(parsedSidecar, { errorSourcePath: normalizedSourcePath });
|
||||||
return resolvedMetadataAuthority;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validateShardDocSidecarContractFile(sidecarPath = '', options = {}) {
|
async function validateShardDocSidecarContractFile(sidecarPath = getSourcePath('core', 'tasks', 'shard-doc.artifact.yaml'), options = {}) {
|
||||||
const sourceFilePath = options.sourceFilePath || getSourcePath('core', 'tasks', 'shard-doc.xml');
|
const normalizedSourcePath = normalizeSourcePath(options.errorSourcePath || toProjectRelativePath(sidecarPath));
|
||||||
const resolvedMetadataAuthority = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath,
|
|
||||||
metadataPath: sidecarPath,
|
|
||||||
metadataSourcePath: options.errorSourcePath,
|
|
||||||
ambiguousErrorCode: SHARD_DOC_SIDECAR_ERROR_CODES.METADATA_FILENAME_AMBIGUOUS,
|
|
||||||
});
|
|
||||||
const resolvedSidecarPath = resolvedMetadataAuthority.resolvedAbsolutePath;
|
|
||||||
const normalizedSourcePath = normalizeSourcePath(
|
|
||||||
options.errorSourcePath || resolvedMetadataAuthority.resolvedSourcePath || resolvedMetadataAuthority.canonicalTargetSourcePath,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!resolvedSidecarPath || !(await fs.pathExists(resolvedSidecarPath))) {
|
if (!(await fs.pathExists(sidecarPath))) {
|
||||||
createValidationError(
|
createValidationError(
|
||||||
SHARD_DOC_SIDECAR_ERROR_CODES.FILE_NOT_FOUND,
|
SHARD_DOC_SIDECAR_ERROR_CODES.FILE_NOT_FOUND,
|
||||||
'<file>',
|
'<file>',
|
||||||
|
|
@ -545,7 +336,7 @@ async function validateShardDocSidecarContractFile(sidecarPath = '', options = {
|
||||||
|
|
||||||
let parsedSidecar;
|
let parsedSidecar;
|
||||||
try {
|
try {
|
||||||
const sidecarRaw = await fs.readFile(resolvedSidecarPath, 'utf8');
|
const sidecarRaw = await fs.readFile(sidecarPath, 'utf8');
|
||||||
parsedSidecar = yaml.parse(sidecarRaw);
|
parsedSidecar = yaml.parse(sidecarRaw);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
createValidationError(
|
createValidationError(
|
||||||
|
|
@ -557,23 +348,15 @@ async function validateShardDocSidecarContractFile(sidecarPath = '', options = {
|
||||||
}
|
}
|
||||||
|
|
||||||
validateShardDocSidecarContractData(parsedSidecar, { errorSourcePath: normalizedSourcePath });
|
validateShardDocSidecarContractData(parsedSidecar, { errorSourcePath: normalizedSourcePath });
|
||||||
return resolvedMetadataAuthority;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validateIndexDocsSidecarContractFile(sidecarPath = '', options = {}) {
|
async function validateIndexDocsSidecarContractFile(
|
||||||
const sourceFilePath = options.sourceFilePath || getSourcePath('core', 'tasks', 'index-docs.xml');
|
sidecarPath = getSourcePath('core', 'tasks', 'index-docs.artifact.yaml'),
|
||||||
const resolvedMetadataAuthority = await resolveSkillMetadataAuthority({
|
options = {},
|
||||||
sourceFilePath,
|
) {
|
||||||
metadataPath: sidecarPath,
|
const normalizedSourcePath = normalizeSourcePath(options.errorSourcePath || toProjectRelativePath(sidecarPath));
|
||||||
metadataSourcePath: options.errorSourcePath,
|
|
||||||
ambiguousErrorCode: INDEX_DOCS_SIDECAR_ERROR_CODES.METADATA_FILENAME_AMBIGUOUS,
|
|
||||||
});
|
|
||||||
const resolvedSidecarPath = resolvedMetadataAuthority.resolvedAbsolutePath;
|
|
||||||
const normalizedSourcePath = normalizeSourcePath(
|
|
||||||
options.errorSourcePath || resolvedMetadataAuthority.resolvedSourcePath || resolvedMetadataAuthority.canonicalTargetSourcePath,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!resolvedSidecarPath || !(await fs.pathExists(resolvedSidecarPath))) {
|
if (!(await fs.pathExists(sidecarPath))) {
|
||||||
createValidationError(
|
createValidationError(
|
||||||
INDEX_DOCS_SIDECAR_ERROR_CODES.FILE_NOT_FOUND,
|
INDEX_DOCS_SIDECAR_ERROR_CODES.FILE_NOT_FOUND,
|
||||||
'<file>',
|
'<file>',
|
||||||
|
|
@ -584,7 +367,7 @@ async function validateIndexDocsSidecarContractFile(sidecarPath = '', options =
|
||||||
|
|
||||||
let parsedSidecar;
|
let parsedSidecar;
|
||||||
try {
|
try {
|
||||||
const sidecarRaw = await fs.readFile(resolvedSidecarPath, 'utf8');
|
const sidecarRaw = await fs.readFile(sidecarPath, 'utf8');
|
||||||
parsedSidecar = yaml.parse(sidecarRaw);
|
parsedSidecar = yaml.parse(sidecarRaw);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
createValidationError(
|
createValidationError(
|
||||||
|
|
@ -596,7 +379,6 @@ async function validateIndexDocsSidecarContractFile(sidecarPath = '', options =
|
||||||
}
|
}
|
||||||
|
|
||||||
validateIndexDocsSidecarContractData(parsedSidecar, { errorSourcePath: normalizedSourcePath });
|
validateIndexDocsSidecarContractData(parsedSidecar, { errorSourcePath: normalizedSourcePath });
|
||||||
return resolvedMetadataAuthority;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
@ -606,12 +388,7 @@ module.exports = {
|
||||||
HELP_SIDECAR_ERROR_CODES,
|
HELP_SIDECAR_ERROR_CODES,
|
||||||
SHARD_DOC_SIDECAR_ERROR_CODES,
|
SHARD_DOC_SIDECAR_ERROR_CODES,
|
||||||
INDEX_DOCS_SIDECAR_ERROR_CODES,
|
INDEX_DOCS_SIDECAR_ERROR_CODES,
|
||||||
SKILL_METADATA_CANONICAL_FILENAME,
|
|
||||||
SKILL_METADATA_DERIVATION_MODES,
|
|
||||||
SKILL_METADATA_LEGACY_FILENAMES,
|
|
||||||
SKILL_METADATA_RESOLUTION_ERROR_CODES,
|
|
||||||
SidecarContractError,
|
SidecarContractError,
|
||||||
resolveSkillMetadataAuthority,
|
|
||||||
validateHelpSidecarContractData,
|
validateHelpSidecarContractData,
|
||||||
validateHelpSidecarContractFile,
|
validateHelpSidecarContractFile,
|
||||||
validateShardDocSidecarContractData,
|
validateShardDocSidecarContractData,
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,10 @@ const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generat
|
||||||
const { getTasksFromBmad } = require('./shared/bmad-artifacts');
|
const { getTasksFromBmad } = require('./shared/bmad-artifacts');
|
||||||
const { toDashPath, customAgentDashName } = require('./shared/path-utils');
|
const { toDashPath, customAgentDashName } = require('./shared/path-utils');
|
||||||
const { normalizeAndResolveExemplarAlias } = require('../core/help-alias-normalizer');
|
const { normalizeAndResolveExemplarAlias } = require('../core/help-alias-normalizer');
|
||||||
const { resolveSkillMetadataAuthority } = require('../core/sidecar-contract-validator');
|
|
||||||
const prompts = require('../../../lib/prompts');
|
const prompts = require('../../../lib/prompts');
|
||||||
|
|
||||||
const CODEX_EXPORT_DERIVATION_ERROR_CODES = Object.freeze({
|
const CODEX_EXPORT_DERIVATION_ERROR_CODES = Object.freeze({
|
||||||
SIDECAR_FILE_NOT_FOUND: 'ERR_CODEX_EXPORT_SIDECAR_FILE_NOT_FOUND',
|
SIDECAR_FILE_NOT_FOUND: 'ERR_CODEX_EXPORT_SIDECAR_FILE_NOT_FOUND',
|
||||||
SIDECAR_FILENAME_AMBIGUOUS: 'ERR_CODEX_EXPORT_SIDECAR_FILENAME_AMBIGUOUS',
|
|
||||||
SIDECAR_PARSE_FAILED: 'ERR_CODEX_EXPORT_SIDECAR_PARSE_FAILED',
|
SIDECAR_PARSE_FAILED: 'ERR_CODEX_EXPORT_SIDECAR_PARSE_FAILED',
|
||||||
CANONICAL_ID_MISSING: 'ERR_CODEX_EXPORT_CANONICAL_ID_MISSING',
|
CANONICAL_ID_MISSING: 'ERR_CODEX_EXPORT_CANONICAL_ID_MISSING',
|
||||||
CANONICAL_ID_DERIVATION_FAILED: 'ERR_CODEX_EXPORT_CANONICAL_ID_DERIVATION_FAILED',
|
CANONICAL_ID_DERIVATION_FAILED: 'ERR_CODEX_EXPORT_CANONICAL_ID_DERIVATION_FAILED',
|
||||||
|
|
@ -24,9 +22,9 @@ const CODEX_EXPORT_DERIVATION_ERROR_CODES = Object.freeze({
|
||||||
const EXEMPLAR_HELP_TASK_MARKDOWN_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.md';
|
const EXEMPLAR_HELP_TASK_MARKDOWN_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.md';
|
||||||
const EXEMPLAR_SHARD_DOC_TASK_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.xml';
|
const EXEMPLAR_SHARD_DOC_TASK_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.xml';
|
||||||
const EXEMPLAR_INDEX_DOCS_TASK_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.xml';
|
const EXEMPLAR_INDEX_DOCS_TASK_XML_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.xml';
|
||||||
const EXEMPLAR_HELP_SIDECAR_CONTRACT_SOURCE_PATH = 'bmad-fork/src/core/tasks/help/skill-manifest.yaml';
|
const EXEMPLAR_HELP_SIDECAR_CONTRACT_SOURCE_PATH = 'bmad-fork/src/core/tasks/help.artifact.yaml';
|
||||||
const EXEMPLAR_SHARD_DOC_SIDECAR_CONTRACT_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc/skill-manifest.yaml';
|
const EXEMPLAR_SHARD_DOC_SIDECAR_CONTRACT_SOURCE_PATH = 'bmad-fork/src/core/tasks/shard-doc.artifact.yaml';
|
||||||
const EXEMPLAR_INDEX_DOCS_SIDECAR_CONTRACT_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs/skill-manifest.yaml';
|
const EXEMPLAR_INDEX_DOCS_SIDECAR_CONTRACT_SOURCE_PATH = 'bmad-fork/src/core/tasks/index-docs.artifact.yaml';
|
||||||
const EXEMPLAR_HELP_EXPORT_DERIVATION_SOURCE_TYPE = 'sidecar-canonical-id';
|
const EXEMPLAR_HELP_EXPORT_DERIVATION_SOURCE_TYPE = 'sidecar-canonical-id';
|
||||||
const SHARD_DOC_EXPORT_ALIAS_ROWS = Object.freeze([
|
const SHARD_DOC_EXPORT_ALIAS_ROWS = Object.freeze([
|
||||||
Object.freeze({
|
Object.freeze({
|
||||||
|
|
@ -73,12 +71,12 @@ const EXEMPLAR_CONVERTED_TASK_EXPORT_TARGETS = Object.freeze({
|
||||||
taskSourcePath: EXEMPLAR_HELP_TASK_MARKDOWN_SOURCE_PATH,
|
taskSourcePath: EXEMPLAR_HELP_TASK_MARKDOWN_SOURCE_PATH,
|
||||||
sourcePathSuffix: '/core/tasks/help.md',
|
sourcePathSuffix: '/core/tasks/help.md',
|
||||||
sidecarSourcePath: EXEMPLAR_HELP_SIDECAR_CONTRACT_SOURCE_PATH,
|
sidecarSourcePath: EXEMPLAR_HELP_SIDECAR_CONTRACT_SOURCE_PATH,
|
||||||
sourceFileCandidates: Object.freeze([
|
sidecarSourceCandidates: Object.freeze([
|
||||||
Object.freeze({
|
Object.freeze({
|
||||||
segments: ['bmad-fork', 'src', 'core', 'tasks', 'help.md'],
|
segments: ['bmad-fork', 'src', 'core', 'tasks', 'help.artifact.yaml'],
|
||||||
}),
|
}),
|
||||||
Object.freeze({
|
Object.freeze({
|
||||||
segments: ['src', 'core', 'tasks', 'help.md'],
|
segments: ['src', 'core', 'tasks', 'help.artifact.yaml'],
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
|
|
@ -87,12 +85,12 @@ const EXEMPLAR_CONVERTED_TASK_EXPORT_TARGETS = Object.freeze({
|
||||||
sourcePathSuffix: '/core/tasks/shard-doc.xml',
|
sourcePathSuffix: '/core/tasks/shard-doc.xml',
|
||||||
sidecarSourcePath: EXEMPLAR_SHARD_DOC_SIDECAR_CONTRACT_SOURCE_PATH,
|
sidecarSourcePath: EXEMPLAR_SHARD_DOC_SIDECAR_CONTRACT_SOURCE_PATH,
|
||||||
aliasRows: SHARD_DOC_EXPORT_ALIAS_ROWS,
|
aliasRows: SHARD_DOC_EXPORT_ALIAS_ROWS,
|
||||||
sourceFileCandidates: Object.freeze([
|
sidecarSourceCandidates: Object.freeze([
|
||||||
Object.freeze({
|
Object.freeze({
|
||||||
segments: ['bmad-fork', 'src', 'core', 'tasks', 'shard-doc.xml'],
|
segments: ['bmad-fork', 'src', 'core', 'tasks', 'shard-doc.artifact.yaml'],
|
||||||
}),
|
}),
|
||||||
Object.freeze({
|
Object.freeze({
|
||||||
segments: ['src', 'core', 'tasks', 'shard-doc.xml'],
|
segments: ['src', 'core', 'tasks', 'shard-doc.artifact.yaml'],
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
|
|
@ -101,12 +99,12 @@ const EXEMPLAR_CONVERTED_TASK_EXPORT_TARGETS = Object.freeze({
|
||||||
sourcePathSuffix: '/core/tasks/index-docs.xml',
|
sourcePathSuffix: '/core/tasks/index-docs.xml',
|
||||||
sidecarSourcePath: EXEMPLAR_INDEX_DOCS_SIDECAR_CONTRACT_SOURCE_PATH,
|
sidecarSourcePath: EXEMPLAR_INDEX_DOCS_SIDECAR_CONTRACT_SOURCE_PATH,
|
||||||
aliasRows: INDEX_DOCS_EXPORT_ALIAS_ROWS,
|
aliasRows: INDEX_DOCS_EXPORT_ALIAS_ROWS,
|
||||||
sourceFileCandidates: Object.freeze([
|
sidecarSourceCandidates: Object.freeze([
|
||||||
Object.freeze({
|
Object.freeze({
|
||||||
segments: ['bmad-fork', 'src', 'core', 'tasks', 'index-docs.xml'],
|
segments: ['bmad-fork', 'src', 'core', 'tasks', 'index-docs.artifact.yaml'],
|
||||||
}),
|
}),
|
||||||
Object.freeze({
|
Object.freeze({
|
||||||
segments: ['src', 'core', 'tasks', 'index-docs.xml'],
|
segments: ['src', 'core', 'tasks', 'index-docs.artifact.yaml'],
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
|
|
@ -377,55 +375,9 @@ class CodexSetup extends BaseIdeSetup {
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadConvertedTaskSidecar(projectDir, exportTarget) {
|
async loadConvertedTaskSidecar(projectDir, exportTarget) {
|
||||||
const sourceCandidates = (exportTarget.sourceFileCandidates || []).map((candidate) => path.join(projectDir, ...candidate.segments));
|
for (const candidate of exportTarget.sidecarSourceCandidates) {
|
||||||
if (sourceCandidates.length === 0) {
|
const sidecarPath = path.join(projectDir, ...candidate.segments);
|
||||||
this.throwExportDerivationError({
|
if (await fs.pathExists(sidecarPath)) {
|
||||||
code: CODEX_EXPORT_DERIVATION_ERROR_CODES.SIDECAR_FILE_NOT_FOUND,
|
|
||||||
detail: 'expected exemplar metadata source candidates are missing',
|
|
||||||
fieldPath: '<file>',
|
|
||||||
sourcePath: exportTarget.sidecarSourcePath,
|
|
||||||
observedValue: projectDir,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let resolvedMetadataAuthority = null;
|
|
||||||
for (const sourceCandidate of sourceCandidates) {
|
|
||||||
try {
|
|
||||||
const resolution = await resolveSkillMetadataAuthority({
|
|
||||||
sourceFilePath: sourceCandidate,
|
|
||||||
projectRoot: projectDir,
|
|
||||||
ambiguousErrorCode: CODEX_EXPORT_DERIVATION_ERROR_CODES.SIDECAR_FILENAME_AMBIGUOUS,
|
|
||||||
});
|
|
||||||
if (!resolvedMetadataAuthority) {
|
|
||||||
resolvedMetadataAuthority = resolution;
|
|
||||||
}
|
|
||||||
if (resolution.resolvedAbsolutePath && (await fs.pathExists(resolution.resolvedAbsolutePath))) {
|
|
||||||
resolvedMetadataAuthority = resolution;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.throwExportDerivationError({
|
|
||||||
code: error.code || CODEX_EXPORT_DERIVATION_ERROR_CODES.SIDECAR_FILENAME_AMBIGUOUS,
|
|
||||||
detail: error.detail || error.message,
|
|
||||||
fieldPath: error.fieldPath || '<file>',
|
|
||||||
sourcePath: exportTarget.sidecarSourcePath,
|
|
||||||
observedValue: error.sourcePath || projectDir,
|
|
||||||
cause: error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const sidecarPath = resolvedMetadataAuthority.resolvedAbsolutePath;
|
|
||||||
if (!sidecarPath || !(await fs.pathExists(sidecarPath))) {
|
|
||||||
this.throwExportDerivationError({
|
|
||||||
code: CODEX_EXPORT_DERIVATION_ERROR_CODES.SIDECAR_FILE_NOT_FOUND,
|
|
||||||
detail: 'expected exemplar sidecar metadata file was not found',
|
|
||||||
fieldPath: '<file>',
|
|
||||||
sourcePath: exportTarget.sidecarSourcePath,
|
|
||||||
observedValue: projectDir,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let sidecarData;
|
let sidecarData;
|
||||||
try {
|
try {
|
||||||
sidecarData = yaml.parse(await fs.readFile(sidecarPath, 'utf8'));
|
sidecarData = yaml.parse(await fs.readFile(sidecarPath, 'utf8'));
|
||||||
|
|
@ -464,10 +416,18 @@ class CodexSetup extends BaseIdeSetup {
|
||||||
return {
|
return {
|
||||||
canonicalId,
|
canonicalId,
|
||||||
sourcePath: exportTarget.sidecarSourcePath,
|
sourcePath: exportTarget.sidecarSourcePath,
|
||||||
resolvedFilename: String(resolvedMetadataAuthority.resolvedFilename || ''),
|
|
||||||
derivationMode: String(resolvedMetadataAuthority.derivationMode || ''),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.throwExportDerivationError({
|
||||||
|
code: CODEX_EXPORT_DERIVATION_ERROR_CODES.SIDECAR_FILE_NOT_FOUND,
|
||||||
|
detail: 'expected exemplar sidecar metadata file was not found',
|
||||||
|
fieldPath: '<file>',
|
||||||
|
sourcePath: exportTarget.sidecarSourcePath,
|
||||||
|
observedValue: projectDir,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async resolveSkillIdentityFromArtifact(artifact, projectDir) {
|
async resolveSkillIdentityFromArtifact(artifact, projectDir) {
|
||||||
const inferredSkillName = toDashPath(artifact.relativePath).replace(/\.md$/, '');
|
const inferredSkillName = toDashPath(artifact.relativePath).replace(/\.md$/, '');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue