fix(start-work): align command routing with exported agent keys

This commit is contained in:
YeonGyu-Kim
2026-04-08 16:00:47 +09:00
parent 4394129667
commit 8925ec3a16
3 changed files with 55 additions and 7 deletions
@@ -5,7 +5,7 @@ import * as skillLoader from "../features/opencode-skill-loader";
import type { OhMyOpenCodeConfig } from "../config";
import type { PluginComponents } from "./plugin-components-loader";
import { applyCommandConfig } from "./command-config-handler";
import { getAgentDisplayName } from "../shared/agent-display-names";
import { getAgentDisplayName, getAgentListDisplayName } from "../shared/agent-display-names";
function createPluginComponents(): PluginComponents {
return {
@@ -97,7 +97,7 @@ describe("applyCommandConfig", () => {
expect(commandConfig["agents-global-skill"]?.description).toContain("Agents global skill");
});
test("normalizes Atlas command agents to the config key OpenCode expects for native routing", async () => {
test("normalizes Atlas command agents to the exported agent key used for native routing", async () => {
// given
loadBuiltinCommandsSpy.mockReturnValue({
"start-work": {
@@ -119,10 +119,10 @@ describe("applyCommandConfig", () => {
// then
const commandConfig = config.command as Record<string, { agent?: string }>;
expect(commandConfig["start-work"]?.agent).toBe("atlas");
expect(commandConfig["start-work"]?.agent).toBe(getAgentListDisplayName("atlas"));
});
test("normalizes legacy display-name command agents back to config keys", async () => {
test("normalizes legacy display-name command agents to the exported agent key", async () => {
// given
loadBuiltinCommandsSpy.mockReturnValue({
"start-work": {
@@ -144,6 +144,6 @@ describe("applyCommandConfig", () => {
// then
const commandConfig = config.command as Record<string, { agent?: string }>;
expect(commandConfig["start-work"]?.agent).toBe("atlas");
expect(commandConfig["start-work"]?.agent).toBe(getAgentListDisplayName("atlas"));
});
});
@@ -1,5 +1,8 @@
import type { OhMyOpenCodeConfig } from "../config";
import { getAgentConfigKey } from "../shared/agent-display-names";
import {
getAgentConfigKey,
getAgentListDisplayName,
} from "../shared/agent-display-names";
import {
loadUserCommands,
loadProjectCommands,
@@ -96,7 +99,7 @@ export async function applyCommandConfig(params: {
function remapCommandAgentFields(commands: Record<string, Record<string, unknown>>): void {
for (const cmd of Object.values(commands)) {
if (cmd?.agent && typeof cmd.agent === "string") {
cmd.agent = getAgentConfigKey(cmd.agent);
cmd.agent = getAgentListDisplayName(getAgentConfigKey(cmd.agent));
}
}
}
@@ -1250,6 +1250,51 @@ describe("config-handler plugin loading error boundary (#1559)", () => {
})
})
describe("command agent routing coherence", () => {
test("keeps start-work aligned with the exported Atlas agent key", async () => {
//#given
const createBuiltinAgentsMock = agents.createBuiltinAgents as unknown as {
mockResolvedValue: (value: Record<string, unknown>) => void
}
createBuiltinAgentsMock.mockResolvedValue({
sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" },
atlas: { name: "atlas", prompt: "test", mode: "primary" },
})
;(builtinCommands.loadBuiltinCommands as unknown as {
mockReturnValue: (value: Record<string, unknown>) => void
}).mockReturnValue({
"start-work": {
name: "start-work",
description: "(builtin) Start work",
template: "template",
agent: "atlas",
},
})
const pluginConfig = createPluginConfig({})
const config: Record<string, unknown> = {
model: "anthropic/claude-opus-4-6",
agent: {},
}
const handler = createConfigHandler({
ctx: { directory: "/tmp" },
pluginConfig,
modelCacheState: {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
},
})
//#when
await handler(config)
//#then
const agentConfig = config.agent as Record<string, unknown>
const commandConfig = config.command as Record<string, { agent?: string }>
expect(Object.keys(agentConfig)).toContain(getAgentListDisplayName("atlas"))
expect(commandConfig["start-work"]?.agent).toBe(getAgentListDisplayName("atlas"))
})
})
describe("per-agent todowrite/todoread deny when task_system enabled", () => {
const AGENTS_WITH_TODO_DENY = new Set([
getAgentListDisplayName("sisyphus"),