summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIdris Gadi <[email protected]>2026-02-04 02:39:21 +0530
committerGitHub <[email protected]>2026-02-03 15:09:21 -0600
commit95211a8854d2ce4b89c784f0f2393cc921cf0f33 (patch)
tree1c42a590de7ab8a0cd6dcac6bd2b1606cdcc95ce
parent6b5cf936a27a98b84e3e92f8f41723bad1024cde (diff)
downloadopencode-95211a8854d2ce4b89c784f0f2393cc921cf0f33.tar.gz
opencode-95211a8854d2ce4b89c784f0f2393cc921cf0f33.zip
feat(tui): allow theme colors in agent customization (#11444)
-rw-r--r--packages/opencode/src/cli/cmd/tui/context/local.tsx15
-rw-r--r--packages/opencode/src/config/config.ts8
-rw-r--r--packages/opencode/test/config/agent-color.test.ts5
-rw-r--r--packages/web/src/content/docs/agents.mdx7
4 files changed, 26 insertions, 9 deletions
diff --git a/packages/opencode/src/cli/cmd/tui/context/local.tsx b/packages/opencode/src/cli/cmd/tui/context/local.tsx
index d058ce54f..72c72dc5b 100644
--- a/packages/opencode/src/cli/cmd/tui/context/local.tsx
+++ b/packages/opencode/src/cli/cmd/tui/context/local.tsx
@@ -35,6 +35,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
const agent = iife(() => {
const agents = createMemo(() => sync.data.agent.filter((x) => x.mode !== "subagent" && !x.hidden))
+ const visibleAgents = createMemo(() => sync.data.agent.filter((x) => !x.hidden))
const [agentStore, setAgentStore] = createStore<{
current: string
}>({
@@ -48,6 +49,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
theme.warning,
theme.primary,
theme.error,
+ theme.info,
])
return {
list() {
@@ -75,11 +77,16 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
})
},
color(name: string) {
- const all = sync.data.agent
- const agent = all.find((x) => x.name === name)
- if (agent?.color) return RGBA.fromHex(agent.color)
- const index = all.findIndex((x) => x.name === name)
+ const index = visibleAgents().findIndex((x) => x.name === name)
if (index === -1) return colors()[0]
+ const agent = visibleAgents()[index]
+
+ if (agent?.color) {
+ const color = agent.color
+ if (color.startsWith("#")) return RGBA.fromHex(color)
+ // already validated by config, just satisfying TS here
+ return theme[color as keyof typeof theme] as RGBA
+ }
return colors()[index % colors().length]
},
}
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index dae6db6f9..91816a00f 100644
--- a/packages/opencode/src/config/config.ts
+++ b/packages/opencode/src/config/config.ts
@@ -645,10 +645,12 @@ export namespace Config {
.describe("Hide this subagent from the @ autocomplete menu (default: false, only applies to mode: subagent)"),
options: z.record(z.string(), z.any()).optional(),
color: z
- .string()
- .regex(/^#[0-9a-fA-F]{6}$/, "Invalid hex color format")
+ .union([
+ z.string().regex(/^#[0-9a-fA-F]{6}$/, "Invalid hex color format"),
+ z.enum(["primary", "secondary", "accent", "success", "warning", "error", "info"]),
+ ])
.optional()
- .describe("Hex color code for the agent (e.g., #FF5733)"),
+ .describe("Hex color code (e.g., #FF5733) or theme color (e.g., primary)"),
steps: z
.number()
.int()
diff --git a/packages/opencode/test/config/agent-color.test.ts b/packages/opencode/test/config/agent-color.test.ts
index a2c374296..b9c7cccc4 100644
--- a/packages/opencode/test/config/agent-color.test.ts
+++ b/packages/opencode/test/config/agent-color.test.ts
@@ -15,6 +15,7 @@ test("agent color parsed from project config", async () => {
$schema: "https://opencode.ai/config.json",
agent: {
build: { color: "#FFA500" },
+ plan: { color: "primary" },
},
}),
)
@@ -25,6 +26,7 @@ test("agent color parsed from project config", async () => {
fn: async () => {
const cfg = await Config.get()
expect(cfg.agent?.["build"]?.color).toBe("#FFA500")
+ expect(cfg.agent?.["plan"]?.color).toBe("primary")
},
})
})
@@ -38,6 +40,7 @@ test("Agent.get includes color from config", async () => {
$schema: "https://opencode.ai/config.json",
agent: {
plan: { color: "#A855F7" },
+ build: { color: "accent" },
},
}),
)
@@ -48,6 +51,8 @@ test("Agent.get includes color from config", async () => {
fn: async () => {
const plan = await AgentSvc.get("plan")
expect(plan?.color).toBe("#A855F7")
+ const build = await AgentSvc.get("build")
+ expect(build?.color).toBe("accent")
},
})
})
diff --git a/packages/web/src/content/docs/agents.mdx b/packages/web/src/content/docs/agents.mdx
index 62957ad91..755c4ba25 100644
--- a/packages/web/src/content/docs/agents.mdx
+++ b/packages/web/src/content/docs/agents.mdx
@@ -576,18 +576,21 @@ Users can always invoke any subagent directly via the `@` autocomplete menu, eve
Customize the agent's visual appearance in the UI with the `color` option. This affects how the agent appears in the interface.
+Use a valid hex color (e.g., `#FF5733`) or theme color: `primary`, `secondary`, `accent`, `success`, `warning`, `error`, `info`.
+
```json title="opencode.json"
{
"agent": {
"creative": {
"color": "#ff6b6b"
+ },
+ "code-reviewer": {
+ "color": "accent"
}
}
}
```
-Must be a valid hex color code like `#FF5733`.
-
---
### Top P