feat(#2093): migrate Kilo onto EoS imperative adapter + hook-bus/model/MCP/dispatch upgrades (ADR-1239)
Fold remaining isKilo logic branches into descriptor-driven reads: finishPermissionWriter (uninstall cleanup), skipSharedHooksInstall (hooks copy), and a skills converter-name registry (the artifactLayout.converter field is now load-bearing, not decorative). frontmatterDialect stays the documented dispatch key for frontmatter (no descriptor field for it). Dead isKilo destructure bindings removed. Byte-identical golden parity for all 16 runtimes (opencode, which shares kilo's combined-family path, verified clean). UPGRADE 1 (hook bus): install .kilo/plugins/gsd-core.js native plugin + extensionEvents:"kilo" + EXTENSION_EVENT_SURFACES.kilo (OpenCode-fork bus). UPGRADE 2 (active model): populate runtimeTierDefaults.kilo + thread modelOverride through convertClaudeToKiloFrontmatter — model no longer stripped from agents. UPGRADE 3 (MCP): document the gsd-core MCP companion under kilo's mcp config key. UPGRADE 4 (named dispatch): agents/*.md mode:subagent roster is the Task-tool dispatch surface (tested); subagentToolkit stays 'undocumented' per AC so dispatch degrades to 'degraded' by design. Model-catalog single-source edit ripples the shared model-catalog.json hash into all 16 golden fixtures (expected). Inline defect fixes (no-defer): stale- bake-guard resolveAgentDir 'agent'->'agents' (was a silent no-op for opencode/ codex), hardcoded 'Removed OpenCode plugin' uninstall log -> generic, and the connect-gsd-mcp-server.md OpenCode mcpServers->mcp doc error. Tests: kilo-imperative-reference (adapter/axes/fail-closed/degradation/ hostBehaviors + widened isKilo source-grep across 4 modules) + kilo-upgrades (plugin parity+load, model-override converter, agents dispatch surface, MCP doc). Matrix + how-to + config docs updated; changeset added. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -702,6 +702,36 @@ describe('issue #2612: runtime "opencode" — OpenCode tier resolution', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Issue #2093: kilo runtime tier resolution ───────────────────────────────
|
||||
// Kilo is an OpenCode fork and shares the IDENTICAL built-in tier IDs (UPGRADE 2
|
||||
// / ADR-1239). Kilo moved from Group B (no built-in defaults) to Group A here.
|
||||
describe('issue #2093: runtime "kilo" — Kilo tier resolution', () => {
|
||||
let tmpDir;
|
||||
beforeEach(() => { isolateHome(); tmpDir = createTempProject(); resetRuntimeWarningCaches(); });
|
||||
afterEach(() => { cleanup(tmpDir); restoreHome(); });
|
||||
|
||||
test('opus tier -> anthropic/claude-opus-4-8', () => {
|
||||
writeConfig(tmpDir, { runtime: 'kilo', model_profile: 'quality' });
|
||||
assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-planner'), 'anthropic/claude-opus-4-8');
|
||||
});
|
||||
|
||||
test('sonnet tier -> anthropic/claude-sonnet-5', () => {
|
||||
writeConfig(tmpDir, { runtime: 'kilo', model_profile: 'balanced' });
|
||||
assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-roadmapper'), 'anthropic/claude-sonnet-5');
|
||||
});
|
||||
|
||||
test('haiku tier -> anthropic/claude-haiku-4-5', () => {
|
||||
writeConfig(tmpDir, { runtime: 'kilo', model_profile: 'budget' });
|
||||
assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-codebase-mapper'), 'anthropic/claude-haiku-4-5');
|
||||
});
|
||||
|
||||
test('kilo: effort resolves universally but render param is null (no wire param)', () => {
|
||||
writeConfig(tmpDir, { runtime: 'kilo', model_profile: 'quality' });
|
||||
const eff = resolveEffortInternal(tmpDir, 'gsd-planner');
|
||||
assert.strictEqual(renderEffortForRuntime('kilo', eff).param, null);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Issue #2612: copilot runtime tier resolution ────────────────────────────
|
||||
describe('issue #2612: runtime "copilot" — Copilot tier resolution', () => {
|
||||
let tmpDir;
|
||||
@@ -736,10 +766,6 @@ describe('issue #2612: Group B runtimes — no built-in map, use unknown-runtime
|
||||
assert.strictEqual(RUNTIME_PROFILE_MAP.cursor, undefined);
|
||||
});
|
||||
|
||||
test('kilo is not in RUNTIME_PROFILE_MAP', () => {
|
||||
assert.strictEqual(RUNTIME_PROFILE_MAP.kilo, undefined);
|
||||
});
|
||||
|
||||
test('windsurf is not in RUNTIME_PROFILE_MAP', () => {
|
||||
assert.strictEqual(RUNTIME_PROFILE_MAP.windsurf, undefined);
|
||||
});
|
||||
@@ -830,4 +856,21 @@ describe('issue #2612: partial override merge for new Group A runtimes', () => {
|
||||
// gsd-planner budget -> sonnet -> built-in default
|
||||
assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-planner'), 'claude-sonnet-5');
|
||||
});
|
||||
|
||||
// #2093: kilo just moved into Group A — same partial-merge coverage as opencode.
|
||||
test('kilo.sonnet override wins; opus and haiku still use built-in defaults', () => {
|
||||
writeConfig(tmpDir, {
|
||||
runtime: 'kilo',
|
||||
model_profile: 'balanced',
|
||||
model_profile_overrides: {
|
||||
kilo: { sonnet: 'anthropic/claude-sonnet-4-7' },
|
||||
},
|
||||
});
|
||||
// gsd-planner balanced -> opus -> built-in default
|
||||
assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-planner'), 'anthropic/claude-opus-4-8');
|
||||
// gsd-roadmapper balanced -> sonnet -> overridden
|
||||
assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-roadmapper'), 'anthropic/claude-sonnet-4-7');
|
||||
// gsd-codebase-mapper balanced -> haiku -> built-in default (haiku not overridden)
|
||||
assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-codebase-mapper'), 'anthropic/claude-haiku-4-5');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user