Files
oh-my-opencode/src/features/claude-code-session-state/state.test.ts
T
YeonGyu-Kim 333ad3aadd refactor(agents): drop ZWSP prefixes from agent display names
The sort shim from the previous commit enforces canonical core ordering at runtime, so ZWSP prefixes are no longer needed. Removing them eliminates the Bun.stringWidth vs terminal-width drift that broke the TUI status bar (#3259).

Drop AGENT_LIST_SORT_PREFIXES and getAgentRuntimeName from agent-display-names; switch all call sites to getAgentDisplayName. getAgentListDisplayName stays as a thin alias for external importers.

Keep stripInvisibleAgentCharacters and the ZWSP regex paths so legacy session state and configs from v3.14.0-v3.16.0 still resolve.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-27 18:59:49 +09:00

265 lines
8.4 KiB
TypeScript

/// <reference path="../../../bun-test.d.ts" />
import { describe, it as test, expect, beforeEach, afterEach } from "bun:test"
import {
setSessionAgent,
getSessionAgent,
clearSessionAgent,
updateSessionAgent,
setMainSession,
getMainSessionID,
registerAgentName,
isAgentRegistered,
resolveRegisteredAgentName,
_resetForTesting,
} from "./state"
describe("claude-code-session-state", () => {
beforeEach(() => {
// given - clean state before each test
_resetForTesting()
})
afterEach(() => {
// then - cleanup after each test to prevent pollution
_resetForTesting()
})
describe("setSessionAgent", () => {
test("should store agent for session", () => {
// given
const sessionID = "test-session-1"
const agent = "Prometheus - Plan Builder"
// when
setSessionAgent(sessionID, agent)
// then
expect(getSessionAgent(sessionID)).toBe(agent)
})
test("should strip zero-width ordering prefixes before storing agent for session", () => {
// given
const sessionID = "test-session-prefixed"
const agent = "\u200B\u200B\u200BPrometheus - Plan Builder"
// when
setSessionAgent(sessionID, agent)
// then
expect(getSessionAgent(sessionID)).toBe("Prometheus - Plan Builder")
})
test("should NOT overwrite existing agent (first-write wins)", () => {
// given
const sessionID = "test-session-1"
setSessionAgent(sessionID, "Prometheus - Plan Builder")
// when - try to overwrite
setSessionAgent(sessionID, "sisyphus")
// then - first agent preserved
expect(getSessionAgent(sessionID)).toBe("Prometheus - Plan Builder")
})
test("should return undefined for unknown session", () => {
// given - no session set
// when / then
expect(getSessionAgent("unknown-session")).toBe(undefined)
})
})
describe("updateSessionAgent", () => {
test("should overwrite existing agent", () => {
// given
const sessionID = "test-session-1"
setSessionAgent(sessionID, "Prometheus - Plan Builder")
// when - force update
updateSessionAgent(sessionID, "sisyphus")
// then
expect(getSessionAgent(sessionID)).toBe("sisyphus")
})
test("should strip zero-width ordering prefixes when overwriting existing agent", () => {
// given
const sessionID = "test-session-prefixed-update"
setSessionAgent(sessionID, "sisyphus")
// when
updateSessionAgent(sessionID, "\u200B\u200BHephaestus - Deep Agent")
// then
expect(getSessionAgent(sessionID)).toBe("Hephaestus - Deep Agent")
})
})
describe("clearSessionAgent", () => {
test("should remove agent from session", () => {
// given
const sessionID = "test-session-1"
setSessionAgent(sessionID, "Prometheus - Plan Builder")
expect(getSessionAgent(sessionID)).toBe("Prometheus - Plan Builder")
// when
clearSessionAgent(sessionID)
// then
expect(getSessionAgent(sessionID)).toBe(undefined)
})
})
describe("mainSessionID", () => {
test("should store and retrieve main session ID", () => {
// given
const mainID = "main-session-123"
// when
setMainSession(mainID)
// then
expect(getMainSessionID()).toBe(mainID)
})
test("should return undefined when not set", () => {
// given - explicit reset to ensure clean state (parallel test isolation)
_resetForTesting()
// then
expect(getMainSessionID()).toBe(undefined)
})
})
describe("agent registration", () => {
test("should register config-key lookup when given a display name", () => {
// given
registerAgentName("Atlas - Plan Executor")
// when / then
expect(isAgentRegistered("atlas")).toBe(true)
expect(isAgentRegistered("Atlas - Plan Executor")).toBe(true)
})
test("should resolve config keys back to the registered raw agent name", () => {
// given
registerAgentName("\u200B\u200B\u200B\u200BAtlas - Plan Executor")
// when / then
expect(resolveRegisteredAgentName("atlas")).toBe("\u200B\u200B\u200B\u200BAtlas - Plan Executor")
expect(resolveRegisteredAgentName("Atlas - Plan Executor")).toBe("\u200B\u200B\u200B\u200BAtlas - Plan Executor")
})
test("should resolve legacy parenthesized names to registered agent", () => {
// given - agent registered with new display name format
registerAgentName("\u200BSisyphus - Ultraworker")
// when - historical session has old parenthesized format
const resolved = resolveRegisteredAgentName("Sisyphus (Ultraworker)")
// then - resolves to registered name via config key lookup
expect(resolved).toBe("\u200BSisyphus - Ultraworker")
})
test("should resolve bare lowercase name from historical session", () => {
// given - agent registered with new display name
registerAgentName("Prometheus - Plan Builder")
// when - old session stored just "prometheus"
const resolved = resolveRegisteredAgentName("prometheus")
// then
expect(resolved).toBe("Prometheus - Plan Builder")
})
describe("#given atlas display name with zero-width prefix", () => {
describe("#when checking registration without the zero-width prefix", () => {
test("#then it treats the display name as registered", () => {
// given
registerAgentName("\u200BAtlas - Plan Executor")
// when
const isRegistered = isAgentRegistered("Atlas - Plan Executor")
// then
expect(isRegistered).toBe(true)
})
})
})
})
describe("prometheus-md-only integration scenario", () => {
test("should correctly identify Prometheus agent for permission checks", () => {
// given - Prometheus session
const sessionID = "test-prometheus-session"
const prometheusAgent = "Prometheus - Plan Builder"
// when - agent is set (simulating chat.message hook)
setSessionAgent(sessionID, prometheusAgent)
// then - getSessionAgent returns correct agent for prometheus-md-only hook
const agent = getSessionAgent(sessionID)
expect(agent).toBe("Prometheus - Plan Builder")
expect(["Prometheus - Plan Builder"].includes(agent!)).toBe(true)
})
test("should return undefined when agent not set (bug scenario)", () => {
// given - session exists but no agent set (the bug)
const sessionID = "test-prometheus-session"
// when / then - this is the bug: agent is undefined
expect(getSessionAgent(sessionID)).toBe(undefined)
})
})
describe("issue #893: custom agent switch reset", () => {
test("should preserve custom agent when default agent is sent on subsequent messages", () => {
// given - user switches to custom agent "MyCustomAgent"
const sessionID = "test-session-custom"
const customAgent = "MyCustomAgent"
const defaultAgent = "sisyphus"
// User switches to custom agent (via UI)
setSessionAgent(sessionID, customAgent)
expect(getSessionAgent(sessionID)).toBe(customAgent)
// when - first message after switch sends default agent
// This simulates the bug: input.agent = "Sisyphus" on first message
// Using setSessionAgent (first-write wins) should preserve custom agent
setSessionAgent(sessionID, defaultAgent)
// then - custom agent should be preserved, NOT overwritten
expect(getSessionAgent(sessionID)).toBe(customAgent)
})
test("should allow explicit agent update via updateSessionAgent", () => {
// given - custom agent is set
const sessionID = "test-session-explicit"
const customAgent = "MyCustomAgent"
const newAgent = "AnotherAgent"
setSessionAgent(sessionID, customAgent)
// when - explicit update (user intentionally switches)
updateSessionAgent(sessionID, newAgent)
// then - should be updated
expect(getSessionAgent(sessionID)).toBe(newAgent)
})
})
describe("backward compatibility", () => {
test("strips legacy ZWSP-prefixed agent names from persisted session state (GH-3259)", () => {
// given - persisted session payload from v3.14.0-v3.16.0 with ZWSP prefix
const sessionID = "test-session-legacy-zwsp"
const legacyAgent = "\u200B\u200BHephaestus - Deep Agent"
// when
setSessionAgent(sessionID, legacyAgent)
// then
expect(getSessionAgent(sessionID)).toBe("Hephaestus - Deep Agent")
})
})
})