* refactor(#1679): ADR-1239 Phase B — collapse program + command chains [AC2 slice 4] Phase 2 AC2 slice 4. Collapses two more duplicated runtime->string chains in bin/install.js's post-install next-step message: - program (14 branches): an EXACT duplicate of runtimeLabel -> getRuntimeLabel. - command (14 branches): the per-runtime /gsd-new-project invocation syntax (gemini '/gsd:', codex '$', cursor skill-mention, kimi '/skill:', default '/gsd-new-project') -> new getRuntimeNewProjectCommand(runtime) helper. - src/runtime-name-policy.cts: RUNTIME_NEW_PROJECT_COMMANDS table + getRuntimeNewProjectCommand(runtime) (sibling to runtimeFlags/getRuntimeLabel). - bin/install.js: import getRuntimeNewProjectCommand; replace the program + command chains with single lookups. - tests/runtime-label-policy.test.cjs: 2 new tests for getRuntimeNewProjectCommand (4 overrides + default for the other 12). runtime === count: 53 -> 25 (-28). Cumulative Phase 2 this session: 129 -> 25 (-104). golden-install-parity 16/16 (program/command are stdout-only so not parity-covered, but program matches RUNTIME_LABELS exactly and command values are preserved verbatim in the table). AC2 data-collapse now essentially exhausted; remaining 25 branches are the ADR-1235 agent-loop tail + per-runtime semantic behavior. * chore(changeset): add Changed fragment for program+command collapse (#1679)
This commit is contained in:
7
.changeset/agile-newts-roar.md
Normal file
7
.changeset/agile-newts-roar.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
type: Changed
|
||||||
|
pr: 1813
|
||||||
|
---
|
||||||
|
**Internal: the installer's `program` (display-name) + `command` (slash-invocation) chains are now single-source lookups** — the 14-line `program` chain (an exact duplicate of `runtimeLabel`) → `getRuntimeLabel`, and the 14-line `command` chain (the per-runtime `/gsd-new-project` syntax: gemini `/gsd:`, codex `$`, cursor skill-mention, kimi `/skill:`, default `/gsd-new-project`) → new `getRuntimeNewProjectCommand(runtime)` helper (ADR-1239 Phase B / #1679 AC2 slice 4). `runtime ===` count in `bin/install.js`: 53 → 25 (cumulative this session: 129 → 25). Stdout strings preserved byte-for-byte; no install-output change (golden-parity 16/16). No user-facing change.
|
||||||
|
|
||||||
|
<!-- docs-exempt: internal refactor; no user-facing doc surface -->
|
||||||
@@ -37,7 +37,7 @@ const {
|
|||||||
// installer to the runtime-name-policy leaf (ADR-1508 / #1510 Phase 1) so the
|
// installer to the runtime-name-policy leaf (ADR-1508 / #1510 Phase 1) so the
|
||||||
// conversion module's rewrite engine can consume it without importing
|
// conversion module's rewrite engine can consume it without importing
|
||||||
// bin/install.js. Re-exported below for back-compat consumers/tests.
|
// bin/install.js. Re-exported below for back-compat consumers/tests.
|
||||||
const { getDirName, getRuntimeLabel, getGlobalConfigHomeFragment, runtimeFlags } = require('../gsd-core/bin/lib/runtime-name-policy.cjs');
|
const { getDirName, getRuntimeLabel, getGlobalConfigHomeFragment, runtimeFlags, getRuntimeNewProjectCommand } = require('../gsd-core/bin/lib/runtime-name-policy.cjs');
|
||||||
const {
|
const {
|
||||||
applyWorktreeBaseRef,
|
applyWorktreeBaseRef,
|
||||||
readBaseRefFromSettings,
|
readBaseRefFromSettings,
|
||||||
@@ -10519,37 +10519,11 @@ function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let program = 'Claude Code';
|
// program + command are now single-source lookups (ADR-1239 Phase B / #1679):
|
||||||
if (runtime === 'opencode') program = 'OpenCode';
|
// program is the runtime display label; command is the per-host /gsd-new-project
|
||||||
if (runtime === 'gemini') program = 'Gemini';
|
// invocation syntax.
|
||||||
if (runtime === 'kilo') program = 'Kilo';
|
const program = getRuntimeLabel(runtime);
|
||||||
if (runtime === 'codex') program = 'Codex';
|
const command = getRuntimeNewProjectCommand(runtime);
|
||||||
if (runtime === 'copilot') program = 'Copilot';
|
|
||||||
if (runtime === 'antigravity') program = 'Antigravity';
|
|
||||||
if (runtime === 'cursor') program = 'Cursor';
|
|
||||||
if (runtime === 'windsurf') program = 'Windsurf';
|
|
||||||
if (runtime === 'augment') program = 'Augment';
|
|
||||||
if (runtime === 'trae') program = 'Trae';
|
|
||||||
if (runtime === 'cline') program = 'Cline';
|
|
||||||
if (runtime === 'qwen') program = 'Qwen Code';
|
|
||||||
if (runtime === 'hermes') program = 'Hermes Agent';
|
|
||||||
if (runtime === 'kimi') program = 'Kimi CLI';
|
|
||||||
|
|
||||||
let command = '/gsd-new-project';
|
|
||||||
if (runtime === 'opencode') command = '/gsd-new-project';
|
|
||||||
if (runtime === 'kilo') command = '/gsd-new-project';
|
|
||||||
if (runtime === 'gemini') command = '/gsd:new-project';
|
|
||||||
if (runtime === 'codex') command = '$gsd-new-project';
|
|
||||||
if (runtime === 'copilot') command = '/gsd-new-project';
|
|
||||||
if (runtime === 'antigravity') command = '/gsd-new-project';
|
|
||||||
if (runtime === 'cursor') command = 'gsd-new-project (mention the skill name)';
|
|
||||||
if (runtime === 'windsurf') command = '/gsd-new-project';
|
|
||||||
if (runtime === 'augment') command = '/gsd-new-project';
|
|
||||||
if (runtime === 'trae') command = '/gsd-new-project';
|
|
||||||
if (runtime === 'cline') command = '/gsd-new-project';
|
|
||||||
if (runtime === 'qwen') command = '/gsd-new-project';
|
|
||||||
if (runtime === 'hermes') command = '/gsd-new-project';
|
|
||||||
if (runtime === 'kimi') command = '/skill:gsd-new-project';
|
|
||||||
|
|
||||||
// Claude Code global installs use the skills/ format (CC 2.1.88+).
|
// Claude Code global installs use the skills/ format (CC 2.1.88+).
|
||||||
// Restart is required for CC to pick up newly-installed skills, and the
|
// Restart is required for CC to pick up newly-installed skills, and the
|
||||||
|
|||||||
@@ -284,3 +284,24 @@ export function runtimeFlags(runtime: string): Readonly<Record<string, boolean>>
|
|||||||
}
|
}
|
||||||
return Object.freeze(flags);
|
return Object.freeze(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `/gsd-new-project` invocation syntax per runtime — the post-install
|
||||||
|
* "next step" command string. Most runtimes use the default `/gsd-new-project`;
|
||||||
|
* a few hosts need a different surface syntax. Collapses the 14-line
|
||||||
|
* `if (runtime === 'x') command = ...` chain in bin/install.js's next-step
|
||||||
|
* message (ADR-1239 Phase B / #1679 AC2). Pure: no I/O.
|
||||||
|
*/
|
||||||
|
const DEFAULT_NEW_PROJECT_COMMAND = '/gsd-new-project';
|
||||||
|
const RUNTIME_NEW_PROJECT_COMMANDS: Readonly<Record<string, string>> = {
|
||||||
|
gemini: '/gsd:new-project',
|
||||||
|
codex: '$gsd-new-project',
|
||||||
|
cursor: 'gsd-new-project (mention the skill name)',
|
||||||
|
kimi: '/skill:gsd-new-project',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getRuntimeNewProjectCommand(runtime: string): string {
|
||||||
|
if (!runtime) return DEFAULT_NEW_PROJECT_COMMAND;
|
||||||
|
const c = RUNTIME_NEW_PROJECT_COMMANDS[runtime];
|
||||||
|
return typeof c === 'string' && c.length > 0 ? c : DEFAULT_NEW_PROJECT_COMMAND;
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const assert = require('node:assert/strict');
|
|||||||
const runtimeNamePolicy = require('../gsd-core/bin/lib/runtime-name-policy.cjs');
|
const runtimeNamePolicy = require('../gsd-core/bin/lib/runtime-name-policy.cjs');
|
||||||
const registry = require('../gsd-core/bin/lib/capability-registry.cjs');
|
const registry = require('../gsd-core/bin/lib/capability-registry.cjs');
|
||||||
|
|
||||||
const { getRuntimeLabel } = runtimeNamePolicy;
|
const { getRuntimeLabel, getRuntimeNewProjectCommand } = runtimeNamePolicy;
|
||||||
|
|
||||||
// Golden oracle: hardcoded expected map of all 16 runtime ids to their short
|
// Golden oracle: hardcoded expected map of all 16 runtime ids to their short
|
||||||
// install/uninstall display label. A pinned expected value in a TEST is correct
|
// install/uninstall display label. A pinned expected value in a TEST is correct
|
||||||
@@ -101,3 +101,30 @@ test('getRuntimeLabel fallback: alias is NOT auto-expanded (raw id match only)',
|
|||||||
assert.strictEqual(getRuntimeLabel('claude-code'), 'Claude Code',
|
assert.strictEqual(getRuntimeLabel('claude-code'), 'Claude Code',
|
||||||
'getRuntimeLabel("claude-code") must return the default "Claude Code" (raw-id match only; aliases are not expanded)');
|
'getRuntimeLabel("claude-code") must return the default "Claude Code" (raw-id match only; aliases are not expanded)');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// getRuntimeNewProjectCommand (ADR-1239 Phase B / #1679 AC2) — the per-runtime
|
||||||
|
// /gsd-new-project invocation syntax for the post-install next-step message.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const GOLDEN_COMMAND_MAP = {
|
||||||
|
// 4 real overrides (the rest use the default):
|
||||||
|
gemini: '/gsd:new-project',
|
||||||
|
codex: '$gsd-new-project',
|
||||||
|
cursor: 'gsd-new-project (mention the skill name)',
|
||||||
|
kimi: '/skill:gsd-new-project',
|
||||||
|
};
|
||||||
|
const DEFAULT_CMD = '/gsd-new-project';
|
||||||
|
|
||||||
|
test('getRuntimeNewProjectCommand: the 4 overrides + the default for the other 12 runtimes', () => {
|
||||||
|
for (const [id, expected] of Object.entries(GOLDEN_COMMAND_MAP)) {
|
||||||
|
assert.strictEqual(getRuntimeLabel ? getRuntimeNewProjectCommand(id) : null, expected, `override ${id}`);
|
||||||
|
}
|
||||||
|
// sanity: getRuntimeNewProjectCommand is imported alongside getRuntimeLabel above
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getRuntimeNewProjectCommand: claude/unknown/empty + the 12 non-override runtimes → default', () => {
|
||||||
|
for (const id of ['claude', 'opencode', 'kilo', 'copilot', 'antigravity', 'windsurf', 'augment', 'trae', 'cline', 'qwen', 'hermes', 'codebuddy', 'unknown', '']) {
|
||||||
|
assert.strictEqual(getRuntimeNewProjectCommand(id), DEFAULT_CMD, `runtime '${id}' must return the default command`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user