Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD across contents and paths, upstream package/repo coordinates -> @golem15/msd-core and golem15com/msd-core. Deep links into upstream history, sibling upstream packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is. Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line, package/plugin identity, regenerated lockfile, install-tree fixtures, derived registries and benchmark baseline; migration checksum baseline re-locked (MSD keeps its own install state, so no install had applied the old sums); sort-order and regex-escaped expectations in tests adjusted.
71 lines
3.4 KiB
JavaScript
71 lines
3.4 KiB
JavaScript
// allow-test-rule: source-text-is-the-product
|
|
// The agent_skills injection for the review-family workflows lives as text in
|
|
// the workflow .md files — that text IS what the orchestrating runtime loads
|
|
// and executes. There is no intermediate runtime that parses these workflows
|
|
// into a prompt we could assert on structurally, so the deployed contract is
|
|
// the workflow text itself.
|
|
//
|
|
// Regression guard for #991: code-review.md / code-review-fix.md /
|
|
// eval-review.md were the lone outliers among ~20 workflows that never
|
|
// injected the project-configured agent_skills into the subagents they spawn.
|
|
// Subagents do not inherit the orchestrator's auto-loaded context, so this
|
|
// injection is the ONLY channel for reviewer/fixer/auditor rule context.
|
|
|
|
const { test, describe } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const { escapeRegex: escapeRe } = require('../msd-core/bin/lib/pattern.cjs');
|
|
|
|
const WORKFLOWS_DIR = path.join(__dirname, '..', 'msd-core', 'workflows');
|
|
|
|
// Workflow file -> EVERY subagent type it spawns and must inject skills for.
|
|
// A workflow can spawn more than one agent type: code-review-fix.md spawns the
|
|
// fixer (twice) AND re-spawns the reviewer in its --auto loop, so it must
|
|
// inject skills for BOTH. Listing every spawned type here is what catches a
|
|
// partially-fixed workflow (the gap Codex flagged on the first pass at #991).
|
|
const REVIEW_FAMILY = [
|
|
{ file: 'code-review.md', agentTypes: ['msd-code-reviewer'] },
|
|
{ file: 'code-review-fix.md', agentTypes: ['msd-code-fixer', 'msd-code-reviewer'] },
|
|
{ file: 'eval-review.md', agentTypes: ['msd-eval-auditor'] },
|
|
];
|
|
|
|
const cases = REVIEW_FAMILY.flatMap(({ file, agentTypes }) =>
|
|
agentTypes.map((agentType) => ({ file, agentType })),
|
|
);
|
|
|
|
describe('agent_skills injection — review-family workflows (#991)', () => {
|
|
for (const { file, agentType } of cases) {
|
|
test(`${file} queries + injects agent_skills for every ${agentType} spawn`, () => {
|
|
const content = fs.readFileSync(path.join(WORKFLOWS_DIR, file), 'utf8');
|
|
|
|
// 1. Must query the project-configured skills for this agent type, using
|
|
// the same `msd_run query agent-skills <type>` idiom as the ~20
|
|
// sibling workflows (plan-phase, execute-phase, secure-phase, ...).
|
|
const assignRe = new RegExp(
|
|
'([A-Z][A-Z0-9_]*)=\\$\\(\\s*msd_run query agent-skills ' + escapeRe(agentType) + '\\s*\\)',
|
|
);
|
|
const m = content.match(assignRe);
|
|
assert.ok(
|
|
m,
|
|
`${file}: missing \`VAR=$(msd_run query agent-skills ${agentType})\` — configured agent_skills are never queried (#991)`,
|
|
);
|
|
const varName = m[1];
|
|
|
|
// 2. The queried block must be interpolated into the spawn prompt for
|
|
// EVERY spawn of this agent type. code-review-fix.md spawns the fixer
|
|
// twice (initial + auto-iteration re-spawn); both must inject, or a
|
|
// spawn runs under-equipped.
|
|
const interpolations = content.split('${' + varName + '}').length - 1;
|
|
const spawnCount = (
|
|
content.match(new RegExp('subagent_type=["\']' + escapeRe(agentType) + '["\']', 'g')) || []
|
|
).length;
|
|
assert.ok(
|
|
interpolations >= Math.max(1, spawnCount),
|
|
`${file}: \${${varName}} is interpolated ${interpolations}x but ${agentType} is spawned ${spawnCount}x — every spawn must inject the skills block (#991)`,
|
|
);
|
|
});
|
|
}
|
|
});
|