Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions src/plugin-handlers/agent-config-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import type { OhMyOpenCodeConfig } from "../config"
import * as agentLoader from "../features/claude-code-agent-loader"
import * as skillLoader from "../features/opencode-skill-loader"
import type { LoadedSkill } from "../features/opencode-skill-loader"
import { getAgentDisplayName, getAgentListDisplayName } from "../shared/agent-display-names"
import { applyAgentConfig } from "./agent-config-handler"
import type { PluginComponents } from "./plugin-components-loader"
import { getAgentDisplayName } from "../shared/agent-display-names"

const BUILTIN_SISYPHUS_DISPLAY_NAME = getAgentListDisplayName("sisyphus")
const BUILTIN_SISYPHUS_DISPLAY_NAME = getAgentDisplayName("sisyphus")
const BUILTIN_SISYPHUS_JUNIOR_DISPLAY_NAME = getAgentDisplayName("sisyphus-junior")
const BUILTIN_MULTIMODAL_LOOKER_DISPLAY_NAME = getAgentDisplayName("multimodal-looker")

Expand Down
5 changes: 2 additions & 3 deletions src/plugin-handlers/agent-config-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
} from "./agent-override-protection";
import { buildPrometheusAgentConfig } from "./prometheus-agent-config-builder";
import { buildPlanDemoteConfig } from "./plan-model-inheritance";
import { getAgentListDisplayName } from "../shared/agent-display-names";

type AgentConfigRecord = Record<string, Record<string, unknown> | undefined> & {
build?: Record<string, unknown>;
Expand Down Expand Up @@ -160,10 +159,10 @@ export async function applyAgentConfig(params: {
if (isSisyphusEnabled && builtinAgents.sisyphus) {
if (configuredDefaultAgent) {
(params.config as { default_agent?: string }).default_agent =
getAgentListDisplayName(configuredDefaultAgent);
getAgentDisplayName(configuredDefaultAgent);
Comment on lines 161 to +162
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Normalize default_agent through config-key parser

default_agent is now canonicalized with getAgentDisplayName(configuredDefaultAgent), which does not strip legacy ZWSP list prefixes. If an existing config still contains an old prefixed value (for example from prior releases), this assignment keeps the prefix while config.agent keys are remapped to unprefixed display names, so the default agent can stop matching any exported agent key after upgrade. Resolve the input with getAgentConfigKey(...) before converting back to a display name.

Useful? React with 👍 / 👎.

} else {
(params.config as { default_agent?: string }).default_agent =
getAgentListDisplayName("sisyphus");
getAgentDisplayName("sisyphus");
}

// Assembly order: Sisyphus -> Hephaestus -> Prometheus -> Atlas
Expand Down
24 changes: 12 additions & 12 deletions src/plugin-handlers/agent-key-remapper.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, it, expect } from "bun:test"
import { remapAgentKeysToDisplayNames } from "./agent-key-remapper"
import { getAgentDisplayName, getAgentListDisplayName } from "../shared/agent-display-names"
import { getAgentDisplayName } from "../shared/agent-display-names"

describe("remapAgentKeysToDisplayNames", () => {
it("remaps known agent keys to display names", () => {
Expand All @@ -14,7 +14,7 @@ describe("remapAgentKeysToDisplayNames", () => {
const result = remapAgentKeysToDisplayNames(agents)

// then known agents get display name keys only
expect(result[getAgentListDisplayName("sisyphus")]).toBeDefined()
expect(result[getAgentDisplayName("sisyphus")]).toBeDefined()
expect(result["oracle"]).toBeDefined()
expect(result["sisyphus"]).toBeUndefined()
})
Expand Down Expand Up @@ -49,13 +49,13 @@ describe("remapAgentKeysToDisplayNames", () => {
const result = remapAgentKeysToDisplayNames(agents)

// then all get display name keys
expect(result[getAgentListDisplayName("sisyphus")]).toBeDefined()
expect(result[getAgentDisplayName("sisyphus")]).toBeDefined()
expect(result["sisyphus"]).toBeUndefined()
expect(result[getAgentListDisplayName("hephaestus")]).toBeDefined()
expect(result[getAgentDisplayName("hephaestus")]).toBeDefined()
expect(result["hephaestus"]).toBeUndefined()
expect(result[getAgentListDisplayName("prometheus")]).toBeDefined()
expect(result[getAgentDisplayName("prometheus")]).toBeDefined()
expect(result["prometheus"]).toBeUndefined()
expect(result[getAgentListDisplayName("atlas")]).toBeDefined()
expect(result[getAgentDisplayName("atlas")]).toBeDefined()
expect(result["atlas"]).toBeUndefined()
expect(result[getAgentDisplayName("athena")]).toBeDefined()
expect(result["athena"]).toBeUndefined()
Expand All @@ -77,8 +77,8 @@ describe("remapAgentKeysToDisplayNames", () => {
const result = remapAgentKeysToDisplayNames(agents)

// then only display key is emitted
expect(Object.keys(result)).toEqual([getAgentListDisplayName("sisyphus")])
expect(result[getAgentListDisplayName("sisyphus")]).toBeDefined()
expect(Object.keys(result)).toEqual([getAgentDisplayName("sisyphus")])
expect(result[getAgentDisplayName("sisyphus")]).toBeDefined()
expect(result["sisyphus"]).toBeUndefined()
})

Expand All @@ -96,10 +96,10 @@ describe("remapAgentKeysToDisplayNames", () => {

// then
expect(sortedNames).toEqual([
getAgentListDisplayName("sisyphus"),
getAgentListDisplayName("hephaestus"),
getAgentListDisplayName("prometheus"),
getAgentListDisplayName("atlas"),
getAgentDisplayName("sisyphus"),
getAgentDisplayName("hephaestus"),
getAgentDisplayName("prometheus"),
getAgentDisplayName("atlas"),
Comment on lines +99 to +102
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Update the expected sorted order to match the clean display names, or this test will fail after removing the ZWSP prefixes.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/plugin-handlers/agent-key-remapper.test.ts, line 99:

<comment>Update the expected sorted order to match the clean display names, or this test will fail after removing the ZWSP prefixes.</comment>

<file context>
@@ -96,10 +96,10 @@ describe("remapAgentKeysToDisplayNames", () => {
-      getAgentListDisplayName("hephaestus"),
-      getAgentListDisplayName("prometheus"),
-      getAgentListDisplayName("atlas"),
+      getAgentDisplayName("sisyphus"),
+      getAgentDisplayName("hephaestus"),
+      getAgentDisplayName("prometheus"),
</file context>
Suggested change
getAgentDisplayName("sisyphus"),
getAgentDisplayName("hephaestus"),
getAgentDisplayName("prometheus"),
getAgentDisplayName("atlas"),
getAgentDisplayName("atlas"),
getAgentDisplayName("hephaestus"),
getAgentDisplayName("prometheus"),
getAgentDisplayName("sisyphus"),
Fix with Cubic

])
})
})
4 changes: 2 additions & 2 deletions src/plugin-handlers/agent-key-remapper.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { getAgentListDisplayName } from "../shared/agent-display-names"
import { getAgentDisplayName } from "../shared/agent-display-names"

export function remapAgentKeysToDisplayNames(
agents: Record<string, unknown>,
): Record<string, unknown> {
const result: Record<string, unknown> = {}

for (const [key, value] of Object.entries(agents)) {
const displayName = getAgentListDisplayName(key)
const displayName = getAgentDisplayName(key)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Normalize legacy prefixed keys before remapping agents

Using getAgentDisplayName(key) directly leaves legacy ZWSP-prefixed keys unchanged, while builtin config keys (for example atlas) are remapped to the new clean display name. In upgraded configs that still contain prefixed keys, this now produces two entries for the same core agent (clean and prefixed), and downstream logic keyed by clean names can skip the legacy entry (ordering/permission updates), causing inconsistent runtime behavior.

Useful? React with 👍 / 👎.

if (displayName && displayName !== key) {
result[displayName] = value
// Regression guard: do not also assign result[key].
Expand Down
14 changes: 7 additions & 7 deletions src/plugin-handlers/agent-priority-order.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { describe, expect, test } from "bun:test"

import { reorderAgentsByPriority } from "./agent-priority-order"
import { getAgentDisplayName, getAgentListDisplayName } from "../shared/agent-display-names"
import { getAgentDisplayName } from "../shared/agent-display-names"

describe("reorderAgentsByPriority", () => {
test("moves core agents to canonical order and injects runtime order fields", () => {
// given
const sisyphus = getAgentListDisplayName("sisyphus")
const hephaestus = getAgentListDisplayName("hephaestus")
const prometheus = getAgentListDisplayName("prometheus")
const atlas = getAgentListDisplayName("atlas")
const sisyphus = getAgentDisplayName("sisyphus")
const hephaestus = getAgentDisplayName("hephaestus")
const prometheus = getAgentDisplayName("prometheus")
const atlas = getAgentDisplayName("atlas")
const oracle = getAgentDisplayName("oracle")

const agents: Record<string, unknown> = {
Expand Down Expand Up @@ -59,8 +59,8 @@ describe("reorderAgentsByPriority", () => {

test("leaves non-object agent configs untouched while still reordering keys", () => {
// given
const sisyphus = getAgentListDisplayName("sisyphus")
const atlas = getAgentListDisplayName("atlas")
const sisyphus = getAgentDisplayName("sisyphus")
const atlas = getAgentDisplayName("atlas")

const agents: Record<string, unknown> = {
[atlas]: "atlas-config",
Expand Down
10 changes: 5 additions & 5 deletions src/plugin-handlers/agent-priority-order.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { getAgentListDisplayName } from "../shared/agent-display-names";
import { getAgentDisplayName } from "../shared/agent-display-names";

const CORE_AGENT_ORDER: ReadonlyArray<{ displayName: string; order: number }> = [
{ displayName: getAgentListDisplayName("sisyphus"), order: 1 },
{ displayName: getAgentListDisplayName("hephaestus"), order: 2 },
{ displayName: getAgentListDisplayName("prometheus"), order: 3 },
{ displayName: getAgentListDisplayName("atlas"), order: 4 },
{ displayName: getAgentDisplayName("sisyphus"), order: 1 },
{ displayName: getAgentDisplayName("hephaestus"), order: 2 },
{ displayName: getAgentDisplayName("prometheus"), order: 3 },
{ displayName: getAgentDisplayName("atlas"), order: 4 },
];

function injectOrderField(
Expand Down
5 changes: 2 additions & 3 deletions src/plugin-handlers/command-config-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import type { PluginComponents } from "./plugin-components-loader";
import { applyCommandConfig } from "./command-config-handler";
import {
getAgentDisplayName,
getAgentListDisplayName,
} from "../shared/agent-display-names";

function createPluginComponents(): PluginComponents {
Expand Down Expand Up @@ -122,7 +121,7 @@ describe("applyCommandConfig", () => {

// then
const commandConfig = config.command as Record<string, { agent?: string }>;
expect(commandConfig["start-work"]?.agent).toBe(getAgentListDisplayName("atlas"));
expect(commandConfig["start-work"]?.agent).toBe(getAgentDisplayName("atlas"));
});

test("normalizes legacy display-name command agents to the exported list key", async () => {
Expand All @@ -147,6 +146,6 @@ describe("applyCommandConfig", () => {

// then
const commandConfig = config.command as Record<string, { agent?: string }>;
expect(commandConfig["start-work"]?.agent).toBe(getAgentListDisplayName("atlas"));
expect(commandConfig["start-work"]?.agent).toBe(getAgentDisplayName("atlas"));
});
});
4 changes: 2 additions & 2 deletions src/plugin-handlers/command-config-handler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { OhMyOpenCodeConfig } from "../config";
import {
getAgentConfigKey,
getAgentListDisplayName,
getAgentDisplayName,
} from "../shared/agent-display-names";
import {
loadUserCommands,
Expand Down Expand Up @@ -99,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 = getAgentListDisplayName(getAgentConfigKey(cmd.agent));
cmd.agent = getAgentDisplayName(getAgentConfigKey(cmd.agent));
}
}
}
Loading
Loading