* fix(#4482): strip Copilot notes from OpenCode artifacts * chore: add changeset for #4532 * fix(#4482): filter runtime notes across emitted surfaces * fix(#4482): make runtime note filtering runtime-neutral * test(#4482): keep ack fixture outside registered provenance --------- Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
|
||||
const { test, describe } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
process.env.GSD_TEST_MODE = '1';
|
||||
const {
|
||||
@@ -73,6 +75,70 @@ const flatRuntimeSuites = [
|
||||
},
|
||||
];
|
||||
|
||||
describe('#4482: OpenCode conversion strips Copilot-only runtime notes', () => {
|
||||
const convert = (body) => liveConversion.convertClaudeToOpencodeFrontmatter(
|
||||
['---', 'name: gsd-test', 'description: test', '---', body].join('\n'),
|
||||
);
|
||||
|
||||
test('removes a Copilot-only note without leaving an empty wrapper', () => {
|
||||
const out = convert([
|
||||
'<runtime_note>',
|
||||
'**Copilot (VS Code):** Use `vscode_askquestions` wherever this workflow calls `AskUserQuestion`.',
|
||||
'</runtime_note>',
|
||||
'',
|
||||
'<objective>Keep me.</objective>',
|
||||
].join('\n'));
|
||||
|
||||
assert.ok(!out.includes('vscode_askquestions'));
|
||||
assert.ok(!out.includes('<runtime_note>'));
|
||||
assert.ok(out.includes('<objective>Keep me.</objective>'));
|
||||
});
|
||||
|
||||
test('preserves runtime-neutral fallback text in a mixed note', () => {
|
||||
const out = convert([
|
||||
'<runtime_note>',
|
||||
'**Copilot (VS Code):** Use `vscode_askquestions` instead of `AskUserQuestion`.',
|
||||
'',
|
||||
'**TEXT_MODE fallback:** Present a numbered list when interactive tools are unavailable.',
|
||||
'</runtime_note>',
|
||||
].join('\n'));
|
||||
|
||||
assert.ok(!out.includes('vscode_askquestions'));
|
||||
assert.match(out, /<runtime_note>\n\*\*TEXT_MODE fallback:\*\*/);
|
||||
assert.ok(out.includes('</runtime_note>'));
|
||||
});
|
||||
|
||||
test('leaves unrelated runtime notes intact', () => {
|
||||
const note = '<runtime_note>\n**OpenCode:** Keep this runtime-specific guidance.\n</runtime_note>';
|
||||
assert.ok(convert(note).includes(note));
|
||||
});
|
||||
|
||||
test('the shared audience filter covers every non-Copilot runtime and preserves Copilot', () => {
|
||||
const note = '<runtime_note>\n**Copilot (VS Code):** Use `vscode_askquestions`.\n\n**TEXT_MODE fallback:** Keep me.\n</runtime_note>';
|
||||
const runtimes = [
|
||||
'antigravity', 'augment', 'claude', 'cline', 'codebuddy', 'codex', 'cursor', 'hermes',
|
||||
'kilo', 'kimi', 'kimi-code', 'opencode', 'pi', 'qwen', 'trae', 'windsurf', 'zcode',
|
||||
];
|
||||
for (const runtime of runtimes) {
|
||||
const out = liveConversion.filterRuntimeNotesForTarget(note, runtime);
|
||||
assert.ok(!out.includes('vscode_askquestions'), `${runtime} must not receive the Copilot note`);
|
||||
assert.ok(out.includes('TEXT_MODE fallback'), `${runtime} must retain neutral fallback guidance`);
|
||||
}
|
||||
assert.strictEqual(liveConversion.filterRuntimeNotesForTarget(note, 'copilot'), note);
|
||||
});
|
||||
|
||||
test('a real OpenCode install filters mvp-phase workflow assets too', (t) => {
|
||||
const { runMinimalInstall } = require('./helpers/install-shared.cjs');
|
||||
const { cleanup } = require('./helpers.cjs');
|
||||
const { configDir, root } = runMinimalInstall({ runtime: 'opencode', scope: 'global' });
|
||||
t.after(() => cleanup(root));
|
||||
const installed = fs.readFileSync(path.join(configDir, 'gsd-core', 'workflows', 'mvp-phase.md'), 'utf8');
|
||||
assert.ok(!installed.includes('vscode_askquestions'));
|
||||
assert.ok(installed.includes('TEXT_MODE fallback'));
|
||||
assert.ok(installed.includes('<runtime_note>'));
|
||||
});
|
||||
});
|
||||
|
||||
for (const { label, convert, configDir } of flatRuntimeSuites) {
|
||||
describe(`${label} agent conversion (isAgent: true)`, () => {
|
||||
test('keeps name: field for agents', () => {
|
||||
@@ -273,6 +339,19 @@ describe('convertClaudeToKiloFrontmatter output parity: bin/install.js vs runtim
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertClaudeToOpencodeFrontmatter output parity: bin/install.js vs runtime-artifact-conversion.cjs (#4482)', () => {
|
||||
const { convertClaudeToOpencodeFrontmatter: convertViaConversionModule } =
|
||||
require('../gsd-core/bin/lib/runtime-artifact-conversion.cjs');
|
||||
const input = `${SAMPLE_COMMAND}\n\n<runtime_note>\n**Copilot (VS Code):** Use vscode_askquestions.\n</runtime_note>`;
|
||||
|
||||
test('published and module converters filter runtime notes identically', () => {
|
||||
assert.equal(
|
||||
convertClaudeToOpencodeFrontmatter(input),
|
||||
convertViaConversionModule(input),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// DEFECT.GENERATIVE-FIX output-parity guard: convertClaudeCommandToTraeSkill is
|
||||
// defined TWICE — once in bin/install.js (dead for the live skills-install
|
||||
|
||||
Reference in New Issue
Block a user