fix(opencode): trust discovered modes, don't inject hardcoded defaults (#1366)

* fix(opencode): trust discovered modes instead of always injecting defaults

When OpenCode reports its available agents, respect that list exactly
rather than seeding from DEFAULT_MODES first. This means users who have
intentionally disabled modes (e.g. Plan) in their OpenCode config will
no longer see those modes surfaced in Paseo.

DEFAULT_MODES is still used as a fallback when discovery returns nothing
(e.g. OpenCode unreachable or no agents configured).

* test(opencode): update mode discovery expectations

* test(opencode): expect discovered custom modes only
This commit is contained in:
Matt Cowger
2026-06-19 11:20:26 +08:00
committed by GitHub
parent b90baaff71
commit ccb8714a71
3 changed files with 21 additions and 11 deletions
@@ -63,7 +63,7 @@ function questionEvent(questionOverrides: Record<string, unknown> = {}): unknown
}
describe("OpenCode auto_accept feature", () => {
test("lists OpenCode modes without the legacy virtual full-access mode", async () => {
test("lists discovered OpenCode modes without injecting defaults", async () => {
const { runtime } = mockOpenCodeClient({
agents: [
{ name: "build", mode: "primary", hidden: false, description: "Build agent" },
@@ -74,7 +74,16 @@ describe("OpenCode auto_accept feature", () => {
const client = new OpenCodeAgentClient(createTestLogger(), undefined, { runtime });
const modes = await client.listModes({ cwd: "/tmp/project", force: false });
expect(modes.map((mode) => mode.id)).toEqual(["build", "plan", "paseo-custom"]);
expect(modes.map((mode) => mode.id)).toEqual(["build", "paseo-custom"]);
});
test("falls back to default OpenCode modes when discovery returns no modes", async () => {
const { runtime } = mockOpenCodeClient({ agents: [] });
const client = new OpenCodeAgentClient(createTestLogger(), undefined, { runtime });
const modes = await client.listModes({ cwd: "/tmp/project", force: false });
expect(modes.map((mode) => mode.id)).toEqual(["build", "plan"]);
});
test("lists auto accept as a provider feature", async () => {
@@ -404,8 +404,7 @@ describe("OpenCodeAgentClient adapter smoke tests", () => {
const modes = await session.getAvailableModes();
expect(modes.some((mode) => mode.id === "build")).toBe(true);
expect(modes.some((mode) => mode.id === "plan")).toBe(true);
expect(modes.map((mode) => mode.id)).toEqual(["paseo-test-custom"]);
const custom = modes.find((mode) => mode.id === "paseo-test-custom");
expect(custom).toBeDefined();
@@ -591,14 +591,16 @@ function mapOpenCodeAgentToMode(agent: {
}
function mergeOpenCodeModes(discoveredModes: AgentMode[]): AgentMode[] {
const modesById = new Map(DEFAULT_MODES.map((mode) => [mode.id, mode]));
for (const mode of discoveredModes) {
if (mode.id === OPENCODE_LEGACY_FULL_ACCESS_MODE_ID) {
continue;
}
modesById.set(mode.id, mode);
const filtered = discoveredModes.filter(
(mode) => mode.id !== OPENCODE_LEGACY_FULL_ACCESS_MODE_ID,
);
// When discovery returns results, trust them exactly — don't inject hardcoded
// defaults that the user may have intentionally disabled in their OpenCode config.
// Fall back to DEFAULT_MODES only when discovery produced nothing.
if (filtered.length > 0) {
return sortOpenCodeModes(filtered);
}
return sortOpenCodeModes(Array.from(modesById.values()));
return sortOpenCodeModes([...DEFAULT_MODES]);
}
function sortOpenCodeModes(modes: AgentMode[]): AgentMode[] {