refactor(#1763): ADR-1235 agent migration — cut over the trivial-converter group to the descriptor path (#1764)
ADR-1235 step 1: route the trivial-converter runtime group (cursor, windsurf, augment, trae, codebuddy) off the inline install() agent loop onto the descriptor-driven installRuntimeArtifacts path. Establishes the converter-context foundation (pre-converter cross-cutting + no agent-stamp). Agent install output is byte-identical for all 16 runtimes (golden-parity, global + verified local). cline deliberately excluded (local rules-only). Closes #1763.
This commit is contained in:
@@ -56,11 +56,11 @@ const RESOLVED_CORE = resolveProfile({ modes: ['core'], manifest: MANIFEST });
|
||||
// ─── Layout contract ─────────────────────────────────────────────────────────
|
||||
|
||||
describe('enh-789 — codebuddy layout has commands + skills kinds', () => {
|
||||
test('resolveRuntimeArtifactLayout codebuddy returns 2 kinds', () => {
|
||||
test('resolveRuntimeArtifactLayout codebuddy returns 3 kinds (ADR-1235 §1 agents cutover)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('codebuddy', '/tmp/fake-codebuddy-dir');
|
||||
assert.strictEqual(layout.kinds.length, 2, 'codebuddy must have exactly 2 artifact kinds');
|
||||
assert.strictEqual(layout.kinds.length, 3, 'codebuddy must have exactly 3 artifact kinds (commands + skills + agents)');
|
||||
const kindNames = layout.kinds.map(k => k.kind).sort();
|
||||
assert.deepStrictEqual(kindNames, ['commands', 'skills']);
|
||||
assert.deepStrictEqual(kindNames, ['agents', 'commands', 'skills']);
|
||||
});
|
||||
|
||||
test('codebuddy commands kind targets commands/ with gsd- prefix', () => {
|
||||
|
||||
@@ -31,12 +31,12 @@ const RESOLVED_CORE = resolveProfile({ modes: ['core'], manifest: MANIFEST });
|
||||
|
||||
// ─── Layout contract ─────────────────────────────────────────────────────────
|
||||
|
||||
describe('enh-790 — augment layout has commands + skills kinds', () => {
|
||||
test('resolveRuntimeArtifactLayout augment returns 2 kinds', () => {
|
||||
describe('enh-790 — augment layout has commands + skills + agents kinds', () => {
|
||||
test('resolveRuntimeArtifactLayout augment returns 3 kinds', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('augment', '/tmp/fake-augment-dir');
|
||||
assert.strictEqual(layout.kinds.length, 2, 'augment must have exactly 2 artifact kinds');
|
||||
assert.strictEqual(layout.kinds.length, 3, 'augment must have exactly 3 artifact kinds');
|
||||
const kindNames = layout.kinds.map(k => k.kind).sort();
|
||||
assert.deepStrictEqual(kindNames, ['commands', 'skills']);
|
||||
assert.deepStrictEqual(kindNames, ['agents', 'commands', 'skills']);
|
||||
});
|
||||
|
||||
test('augment commands kind targets commands/ with gsd- prefix', () => {
|
||||
|
||||
@@ -44,6 +44,8 @@ const FAKE_DIR = '/tmp/fake-config-dir-dd';
|
||||
// ── STEP-0 golden (captured from switch BEFORE edits) ────────────────────────
|
||||
// Format: { kind, destSubpath, prefix } for each entry in kinds[].
|
||||
// 'function' means we assert typeof kind.stage === 'function'.
|
||||
// ADR-1235 step 1 (#1763): cursor, windsurf, augment, trae, codebuddy each gained
|
||||
// an `agents` kind (appended last). Goldens consciously updated post-cutover.
|
||||
|
||||
const GOLDEN = {
|
||||
// ── claude ──────────────────────────────────────────────────────────────────
|
||||
@@ -58,13 +60,16 @@ const GOLDEN = {
|
||||
// ── cursor ───────────────────────────────────────────────────────────────────
|
||||
// Old switch: BOTH scopes returned [skills, commands] (no scope branch).
|
||||
// 5b backfill: local == global.
|
||||
// ADR-1235 step 1 (#1763): agents kind added.
|
||||
'cursor/global': [
|
||||
{ kind: 'skills', destSubpath: 'skills', prefix: 'gsd-' },
|
||||
{ kind: 'commands', destSubpath: 'commands', prefix: 'gsd-' },
|
||||
{ kind: 'agents', destSubpath: 'agents', prefix: 'gsd-' },
|
||||
],
|
||||
'cursor/local': [
|
||||
{ kind: 'skills', destSubpath: 'skills', prefix: 'gsd-' },
|
||||
{ kind: 'commands', destSubpath: 'commands', prefix: 'gsd-' },
|
||||
{ kind: 'agents', destSubpath: 'agents', prefix: 'gsd-' },
|
||||
],
|
||||
|
||||
// ── gemini ───────────────────────────────────────────────────────────────────
|
||||
@@ -104,29 +109,39 @@ const GOLDEN = {
|
||||
],
|
||||
|
||||
// ── windsurf ─────────────────────────────────────────────────────────────────
|
||||
'windsurf/global': [],
|
||||
// ADR-1235 step 1 (#1763): agents kind added to both scopes.
|
||||
'windsurf/global': [
|
||||
{ kind: 'agents', destSubpath: 'agents', prefix: 'gsd-' },
|
||||
],
|
||||
'windsurf/local': [
|
||||
{ kind: 'commands', destSubpath: 'workflows', prefix: 'gsd-' },
|
||||
{ kind: 'agents', destSubpath: 'agents', prefix: 'gsd-' },
|
||||
],
|
||||
|
||||
// ── augment ──────────────────────────────────────────────────────────────────
|
||||
// Old switch: no scope branch → local == global. 5b backfill restores this.
|
||||
// ADR-1235 step 1 (#1763): agents kind added.
|
||||
'augment/global': [
|
||||
{ kind: 'commands', destSubpath: 'commands', prefix: 'gsd-' },
|
||||
{ kind: 'skills', destSubpath: 'skills', prefix: 'gsd-' },
|
||||
{ kind: 'agents', destSubpath: 'agents', prefix: 'gsd-' },
|
||||
],
|
||||
'augment/local': [
|
||||
{ kind: 'commands', destSubpath: 'commands', prefix: 'gsd-' },
|
||||
{ kind: 'skills', destSubpath: 'skills', prefix: 'gsd-' },
|
||||
{ kind: 'agents', destSubpath: 'agents', prefix: 'gsd-' },
|
||||
],
|
||||
|
||||
// ── trae ─────────────────────────────────────────────────────────────────────
|
||||
// Old switch: no scope branch → local == global. 5b backfill restores this.
|
||||
// ADR-1235 step 1 (#1763): agents kind added.
|
||||
'trae/global': [
|
||||
{ kind: 'skills', destSubpath: 'skills', prefix: 'gsd-' },
|
||||
{ kind: 'agents', destSubpath: 'agents', prefix: 'gsd-' },
|
||||
],
|
||||
'trae/local': [
|
||||
{ kind: 'skills', destSubpath: 'skills', prefix: 'gsd-' },
|
||||
{ kind: 'agents', destSubpath: 'agents', prefix: 'gsd-' },
|
||||
],
|
||||
|
||||
// ── qwen ─────────────────────────────────────────────────────────────────────
|
||||
@@ -149,13 +164,16 @@ const GOLDEN = {
|
||||
|
||||
// ── codebuddy ────────────────────────────────────────────────────────────────
|
||||
// Old switch: no scope branch → local == global. 5b backfill restores this.
|
||||
// ADR-1235 step 1 (#1763): agents kind added.
|
||||
'codebuddy/global': [
|
||||
{ kind: 'commands', destSubpath: 'commands', prefix: 'gsd-' },
|
||||
{ kind: 'skills', destSubpath: 'skills', prefix: 'gsd-' },
|
||||
{ kind: 'agents', destSubpath: 'agents', prefix: 'gsd-' },
|
||||
],
|
||||
'codebuddy/local': [
|
||||
{ kind: 'commands', destSubpath: 'commands', prefix: 'gsd-' },
|
||||
{ kind: 'skills', destSubpath: 'skills', prefix: 'gsd-' },
|
||||
{ kind: 'agents', destSubpath: 'agents', prefix: 'gsd-' },
|
||||
],
|
||||
|
||||
// ── cline ────────────────────────────────────────────────────────────────────
|
||||
@@ -360,13 +378,15 @@ describe('resolveRuntimeArtifactLayout — scope defaults to global (descriptor-
|
||||
// ── Non-vacuous check: verify at least one multi-kind runtime ─────────────────
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — multi-kind runtimes non-vacuous (descriptor-driven)', () => {
|
||||
test('augment global returns 2 kinds (commands + skills)', () => {
|
||||
test('augment global returns 3 kinds (commands + skills + agents)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('augment', FAKE_DIR, 'global');
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
assert.strictEqual(layout.kinds.length, 3);
|
||||
assert.strictEqual(layout.kinds[0].kind, 'commands');
|
||||
assert.strictEqual(layout.kinds[1].kind, 'skills');
|
||||
assert.strictEqual(layout.kinds[2].kind, 'agents');
|
||||
assert.strictEqual(typeof layout.kinds[0].stage, 'function');
|
||||
assert.strictEqual(typeof layout.kinds[1].stage, 'function');
|
||||
assert.strictEqual(typeof layout.kinds[2].stage, 'function');
|
||||
});
|
||||
|
||||
test('kimi global returns skills then kimi-agents', () => {
|
||||
@@ -378,10 +398,11 @@ describe('resolveRuntimeArtifactLayout — multi-kind runtimes non-vacuous (desc
|
||||
assert.strictEqual(layout.kinds[1].prefix, 'gsd');
|
||||
});
|
||||
|
||||
test('codebuddy global returns commands then skills', () => {
|
||||
test('codebuddy global returns commands then skills then agents', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('codebuddy', FAKE_DIR, 'global');
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
assert.strictEqual(layout.kinds.length, 3);
|
||||
assert.strictEqual(layout.kinds[0].kind, 'commands');
|
||||
assert.strictEqual(layout.kinds[1].kind, 'skills');
|
||||
assert.strictEqual(layout.kinds[2].kind, 'agents');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -61,11 +61,11 @@ describe('resolveRuntimeArtifactLayout — claude global', () => {
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — cursor', () => {
|
||||
test('returns correct layout for cursor — skills + commands kinds (#785)', () => {
|
||||
test('returns correct layout for cursor — skills + commands + agents kinds (#785, ADR-1235)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('cursor', FAKE_DIR);
|
||||
assert.strictEqual(layout.runtime, 'cursor');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
assert.strictEqual(layout.kinds.length, 3);
|
||||
|
||||
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
|
||||
assert.ok(skillsKind, 'must have a skills kind');
|
||||
@@ -78,6 +78,12 @@ describe('resolveRuntimeArtifactLayout — cursor', () => {
|
||||
assert.strictEqual(commandsKind.destSubpath, 'commands');
|
||||
assert.strictEqual(commandsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof commandsKind.stage, 'function');
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'must have an agents kind (ADR-1235 §1 descriptor cutover)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -134,54 +140,84 @@ describe('resolveRuntimeArtifactLayout — antigravity', () => {
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — windsurf', () => {
|
||||
test('returns local workflow layout for windsurf', () => {
|
||||
test('returns local workflow + agents layout for windsurf (ADR-1235)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('windsurf', FAKE_DIR, 'local');
|
||||
assert.strictEqual(layout.runtime, 'windsurf');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 1);
|
||||
assert.strictEqual(layout.kinds[0].kind, 'commands');
|
||||
assert.strictEqual(layout.kinds[0].destSubpath, 'workflows');
|
||||
assert.strictEqual(layout.kinds[0].prefix, 'gsd-');
|
||||
assert.strictEqual(typeof layout.kinds[0].stage, 'function');
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
|
||||
const commandsKind = layout.kinds.find(k => k.kind === 'commands');
|
||||
assert.ok(commandsKind, 'must have a commands/workflows kind');
|
||||
assert.strictEqual(commandsKind.destSubpath, 'workflows');
|
||||
assert.strictEqual(commandsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof commandsKind.stage, 'function');
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'must have an agents kind (ADR-1235 §1 descriptor cutover)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
|
||||
test('returns empty global layout for windsurf', () => {
|
||||
test('returns agents-only global layout for windsurf (ADR-1235)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('windsurf', FAKE_DIR, 'global');
|
||||
assert.strictEqual(layout.runtime, 'windsurf');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 0);
|
||||
assert.strictEqual(layout.kinds.length, 1);
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'global windsurf must have agents kind (ADR-1235 §1)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — augment', () => {
|
||||
test('returns correct layout for augment (commands + skills)', () => {
|
||||
test('returns correct layout for augment (commands + skills + agents — ADR-1235)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('augment', FAKE_DIR);
|
||||
assert.strictEqual(layout.runtime, 'augment');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
// commands kind first
|
||||
assert.strictEqual(layout.kinds[0].kind, 'commands');
|
||||
assert.strictEqual(layout.kinds[0].destSubpath, 'commands');
|
||||
assert.strictEqual(layout.kinds[0].prefix, 'gsd-');
|
||||
assert.strictEqual(typeof layout.kinds[0].stage, 'function');
|
||||
// skills kind second
|
||||
assert.strictEqual(layout.kinds[1].kind, 'skills');
|
||||
assert.strictEqual(layout.kinds[1].destSubpath, 'skills');
|
||||
assert.strictEqual(layout.kinds[1].prefix, 'gsd-');
|
||||
assert.strictEqual(typeof layout.kinds[1].stage, 'function');
|
||||
assert.strictEqual(layout.kinds.length, 3);
|
||||
|
||||
const commandsKind = layout.kinds.find(k => k.kind === 'commands');
|
||||
assert.ok(commandsKind, 'must have a commands kind');
|
||||
assert.strictEqual(commandsKind.destSubpath, 'commands');
|
||||
assert.strictEqual(commandsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof commandsKind.stage, 'function');
|
||||
|
||||
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
|
||||
assert.ok(skillsKind, 'must have a skills kind');
|
||||
assert.strictEqual(skillsKind.destSubpath, 'skills');
|
||||
assert.strictEqual(skillsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof skillsKind.stage, 'function');
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'must have an agents kind (ADR-1235 §1 descriptor cutover)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — trae', () => {
|
||||
test('returns correct layout for trae', () => {
|
||||
test('returns correct layout for trae (skills + agents — ADR-1235)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('trae', FAKE_DIR);
|
||||
assert.strictEqual(layout.runtime, 'trae');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 1);
|
||||
assert.strictEqual(layout.kinds[0].kind, 'skills');
|
||||
assert.strictEqual(layout.kinds[0].destSubpath, 'skills');
|
||||
assert.strictEqual(layout.kinds[0].prefix, 'gsd-');
|
||||
assert.strictEqual(typeof layout.kinds[0].stage, 'function');
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
|
||||
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
|
||||
assert.ok(skillsKind, 'must have a skills kind');
|
||||
assert.strictEqual(skillsKind.destSubpath, 'skills');
|
||||
assert.strictEqual(skillsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof skillsKind.stage, 'function');
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'must have an agents kind (ADR-1235 §1 descriptor cutover)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -234,21 +270,29 @@ describe('resolveRuntimeArtifactLayout — hermes', () => {
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — codebuddy', () => {
|
||||
test('returns correct layout for codebuddy (commands + skills — #789)', () => {
|
||||
test('returns correct layout for codebuddy (commands + skills + agents — #789, ADR-1235)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('codebuddy', FAKE_DIR);
|
||||
assert.strictEqual(layout.runtime, 'codebuddy');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
// commands kind first
|
||||
assert.strictEqual(layout.kinds[0].kind, 'commands');
|
||||
assert.strictEqual(layout.kinds[0].destSubpath, 'commands');
|
||||
assert.strictEqual(layout.kinds[0].prefix, 'gsd-');
|
||||
assert.strictEqual(typeof layout.kinds[0].stage, 'function');
|
||||
// skills kind second
|
||||
assert.strictEqual(layout.kinds[1].kind, 'skills');
|
||||
assert.strictEqual(layout.kinds[1].destSubpath, 'skills');
|
||||
assert.strictEqual(layout.kinds[1].prefix, 'gsd-');
|
||||
assert.strictEqual(typeof layout.kinds[1].stage, 'function');
|
||||
assert.strictEqual(layout.kinds.length, 3);
|
||||
|
||||
const commandsKind = layout.kinds.find(k => k.kind === 'commands');
|
||||
assert.ok(commandsKind, 'must have a commands kind');
|
||||
assert.strictEqual(commandsKind.destSubpath, 'commands');
|
||||
assert.strictEqual(commandsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof commandsKind.stage, 'function');
|
||||
|
||||
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
|
||||
assert.ok(skillsKind, 'must have a skills kind');
|
||||
assert.strictEqual(skillsKind.destSubpath, 'skills');
|
||||
assert.strictEqual(skillsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof skillsKind.stage, 'function');
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'must have an agents kind (ADR-1235 §1 descriptor cutover)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'gsd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user