Files
msd-core/tests/runtime-flags.test.cjs
Tom Boucher 8f2ebbe9bf feat(#1928): remove sunset Gemini CLI runtime, redirect to Antigravity (#1996)
* feat(#1928): remove sunset gemini cli runtime, redirect to antigravity

Google sunset Gemini CLI on 2026-06-18; Antigravity CLI is its official successor (already a first-class GSD runtime). Remove the gemini runtime from the enum (16->15), aliases, labels, config-home fragment, install path, converters (convertClaudeToGemini{Markdown,Toml,Agent}, convertSlashCommandsToGeminiMentions), capability descriptor, gemini-extension.json, RULESET.GEMINI.*, and the interactive menu (renumbered, no gap).

--gemini now prints an explicit deprecation notice citing the 2026-06-18 sunset and redirects to --antigravity (no silent alias, per the issue's Hyrum's-Law rejection). Antigravity is preserved throughout: its GEMINI.md contextFileName, .gemini/antigravity config home, the shared convertGeminiToolName/claudeToGeminiTools tool vocabulary, and the 'gemini' hookEvents dialect it declares. GEMINI.md retargeted as Antigravity's context file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(#1928): backfill changeset PR number (#1996)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(#1928): drop Gemini CLI from issue templates (review nit)

Removes the sunset Gemini CLI runtime from the two GitHub issue-template
runtime lists that the removal PR missed, per @davesienkowski's review nit:
- feature_request.yml: 'Applicable runtimes' checkbox (a user could otherwise
  request a feature for a runtime GSD no longer supports)
- bug_report.yml: 'Runtime' dropdown + the stale ~/.gemini/settings.json
  retrieval-help line

Leaves the post-removal templates fully consistent with the Antigravity redirect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 13:32:51 -04:00

55 lines
2.5 KiB
JavaScript

'use strict';
/**
* Tests for runtimeFlags (ADR-1239 Phase B / #1679 AC2). Collapses the four
* duplicated `const isX = runtime === 'x'` declaration blocks in bin/install.js
* into one helper. Pins: all flags present, exactly one true per known runtime,
* claude/unknown/empty → all false, frozen.
*/
const { test } = require('node:test');
const assert = require('node:assert/strict');
const { runtimeFlags } = require('../gsd-core/bin/lib/runtime-name-policy.cjs');
const registry = require('../gsd-core/bin/lib/capability-registry.cjs');
const EXPECTED_FLAGS = [
'isOpencode', 'isKilo', 'isCodex', 'isCopilot', 'isAntigravity',
'isCursor', 'isWindsurf', 'isAugment', 'isTrae', 'isQwen', 'isHermes',
'isCodebuddy', 'isCline', 'isKimi',
];
test('runtimeFlags: every known non-claude runtime sets exactly its own flag true', () => {
const ids = EXPECTED_FLAGS.map((f) => f.slice(2).toLowerCase());
for (const id of ids) {
const flags = runtimeFlags(id);
const trues = EXPECTED_FLAGS.filter((f) => flags[f] === true);
assert.deepStrictEqual(trues, ['is' + id.charAt(0).toUpperCase() + id.slice(1)], `runtime '${id}' must set exactly its own flag`);
}
});
test('runtimeFlags: claude / unknown / empty → all flags false (fail-closed)', () => {
for (const id of ['claude', 'unknown', '', 'claude-code']) {
const flags = runtimeFlags(id);
for (const f of EXPECTED_FLAGS) {
assert.strictEqual(flags[f], false, `runtime '${id}': ${f} must be false`);
}
}
});
test('runtimeFlags: all 14 flags present + boolean + the object is frozen', () => {
const flags = runtimeFlags('opencode');
for (const f of EXPECTED_FLAGS) {
assert.strictEqual(typeof flags[f], 'boolean', `${f} must be boolean`);
}
assert.deepStrictEqual(Object.keys(flags).sort(), [...EXPECTED_FLAGS].sort(), 'exactly the 14 flags');
assert.ok(Object.isFrozen(flags), 'flags object must be frozen');
});
test('runtimeFlags drift guard: covers every registry runtime except claude', () => {
// Adding a registry runtime that is not claude must get a flag or be added to
// RUNTIME_FLAG_IDS — pin the set so a new runtime forces a deliberate update.
const registryNonClaude = Object.keys(registry.runtimes).filter((r) => r !== 'claude').sort();
const flagIds = EXPECTED_FLAGS.map((f) => f.slice(2).toLowerCase()).sort();
const missing = registryNonClaude.filter((r) => !flagIds.includes(r));
assert.deepEqual(missing, [], `registry runtimes missing a runtimeFlags entry: ${missing.join(', ')} — add to RUNTIME_FLAG_IDS`);
});