refactor: major codebase cleanup - BDD comments, file splitting, bug fixes (#1350)

* style(tests): normalize BDD comments from '// #given' to '// given'

- Replace 4,668 Python-style BDD comments across 107 test files
- Patterns changed: // #given -> // given, // #when -> // when, // #then -> // then
- Also handles no-space variants: //#given -> // given

* fix(rules-injector): prefer output.metadata.filePath over output.title

- Extract file path resolution to dedicated output-path.ts module
- Prefer metadata.filePath which contains actual file path
- Fall back to output.title only when metadata unavailable
- Fixes issue where rules weren't injected when tool output title was a label

* feat(slashcommand): add optional user_message parameter

- Add user_message optional parameter for command arguments
- Model can now call: command='publish' user_message='patch'
- Improves error messages with clearer format guidance
- Helps LLMs understand correct parameter usage

* feat(hooks): restore compaction-context-injector hook

- Restore hook deleted in cbbc7bd0 for session compaction context
- Injects 7 mandatory sections: User Requests, Final Goal, Work Completed,
  Remaining Tasks, Active Working Context, MUST NOT Do, Agent Verification State
- Re-register in hooks/index.ts and main plugin entry

* refactor(background-agent): split manager.ts into focused modules

- Extract constants.ts for TTL values and internal types (52 lines)
- Extract state.ts for TaskStateManager class (204 lines)
- Extract spawner.ts for task creation logic (244 lines)
- Extract result-handler.ts for completion handling (265 lines)
- Reduce manager.ts from 1377 to 755 lines (45% reduction)
- Maintain backward compatible exports

* refactor(agents): split prometheus-prompt.ts into subdirectory

- Move 1196-line prometheus-prompt.ts to prometheus/ subdirectory
- Organize prompt sections into separate files for maintainability
- Update agents/index.ts exports

* refactor(delegate-task): split tools.ts into focused modules

- Extract categories.ts for category definitions and routing
- Extract executor.ts for task execution logic
- Extract helpers.ts for utility functions
- Extract prompt-builder.ts for prompt construction
- Reduce tools.ts complexity with cleaner separation of concerns

* refactor(builtin-skills): split skills.ts into individual skill files

- Move each skill to dedicated file in skills/ subdirectory
- Create barrel export for backward compatibility
- Improve maintainability with focused skill modules

* chore: update import paths and lockfile

- Update prometheus import path after refactor
- Update bun.lock

* fix(tests): complete BDD comment normalization

- Fix remaining #when/#then patterns missed by initial sed
- Affected: state.test.ts, events.test.ts

---------

Co-authored-by: justsisyphus <justsisyphus@users.noreply.github.com>
This commit is contained in:
YeonGyu-Kim
2026-02-01 16:47:50 +09:00
committed by GitHub
parent c83150d9ea
commit f146aeff0f
145 changed files with 10307 additions and 9562 deletions
+93 -93
View File
@@ -9,53 +9,53 @@ const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-5"
describe("createBuiltinAgents with model overrides", () => {
test("Sisyphus with default model has thinking config", async () => {
// #given - no overrides, using systemDefaultModel
// given - no overrides, using systemDefaultModel
// #when
// when
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
// #then
// then
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-5")
expect(agents.sisyphus.thinking).toEqual({ type: "enabled", budgetTokens: 32000 })
expect(agents.sisyphus.reasoningEffort).toBeUndefined()
})
test("Sisyphus with GPT model override has reasoningEffort, no thinking", async () => {
// #given
// given
const overrides = {
sisyphus: { model: "github-copilot/gpt-5.2" },
}
// #when
// when
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
// #then
// then
expect(agents.sisyphus.model).toBe("github-copilot/gpt-5.2")
expect(agents.sisyphus.reasoningEffort).toBe("medium")
expect(agents.sisyphus.thinking).toBeUndefined()
})
test("Sisyphus uses system default when no availableModels provided", async () => {
// #given
// given
const systemDefaultModel = "anthropic/claude-opus-4-5"
// #when
// when
const agents = await createBuiltinAgents([], {}, undefined, systemDefaultModel)
// #then - falls back to system default when no availability match
// then - falls back to system default when no availability match
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-5")
expect(agents.sisyphus.thinking).toEqual({ type: "enabled", budgetTokens: 32000 })
expect(agents.sisyphus.reasoningEffort).toBeUndefined()
})
test("Oracle uses connected provider fallback when availableModels is empty and cache exists", async () => {
// #given - connected providers cache has "openai", which matches oracle's first fallback entry
// given - connected providers cache has "openai", which matches oracle's first fallback entry
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai"])
// #when
// when
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
// #then - oracle resolves via connected cache fallback to openai/gpt-5.2 (not system default)
// then - oracle resolves via connected cache fallback to openai/gpt-5.2 (not system default)
expect(agents.oracle.model).toBe("openai/gpt-5.2")
expect(agents.oracle.reasoningEffort).toBe("medium")
expect(agents.oracle.thinking).toBeUndefined()
@@ -63,28 +63,28 @@ describe("createBuiltinAgents with model overrides", () => {
})
test("Oracle created without model field when no cache exists (first run scenario)", async () => {
// #given - no cache at all (first run)
// given - no cache at all (first run)
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
// #when
// when
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
// #then - oracle should be created with system default model (fallback to systemDefaultModel)
// then - oracle should be created with system default model (fallback to systemDefaultModel)
expect(agents.oracle).toBeDefined()
expect(agents.oracle.model).toBe(TEST_DEFAULT_MODEL)
cacheSpy.mockRestore?.()
})
test("Oracle with GPT model override has reasoningEffort, no thinking", async () => {
// #given
// given
const overrides = {
oracle: { model: "openai/gpt-5.2" },
}
// #when
// when
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
// #then
// then
expect(agents.oracle.model).toBe("openai/gpt-5.2")
expect(agents.oracle.reasoningEffort).toBe("medium")
expect(agents.oracle.textVerbosity).toBe("high")
@@ -92,15 +92,15 @@ describe("createBuiltinAgents with model overrides", () => {
})
test("Oracle with Claude model override has thinking, no reasoningEffort", async () => {
// #given
// given
const overrides = {
oracle: { model: "anthropic/claude-sonnet-4" },
}
// #when
// when
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
// #then
// then
expect(agents.oracle.model).toBe("anthropic/claude-sonnet-4")
expect(agents.oracle.thinking).toEqual({ type: "enabled", budgetTokens: 32000 })
expect(agents.oracle.reasoningEffort).toBeUndefined()
@@ -108,15 +108,15 @@ describe("createBuiltinAgents with model overrides", () => {
})
test("non-model overrides are still applied after factory rebuild", async () => {
// #given
// given
const overrides = {
sisyphus: { model: "github-copilot/gpt-5.2", temperature: 0.5 },
}
// #when
// when
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
// #then
// then
expect(agents.sisyphus.model).toBe("github-copilot/gpt-5.2")
expect(agents.sisyphus.temperature).toBe(0.5)
})
@@ -124,38 +124,38 @@ describe("createBuiltinAgents with model overrides", () => {
describe("createBuiltinAgents without systemDefaultModel", () => {
test("agents created via connected cache fallback even without systemDefaultModel", async () => {
// #given - connected cache has "openai", which matches oracle's fallback chain
// given - connected cache has "openai", which matches oracle's fallback chain
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai"])
// #when
// when
const agents = await createBuiltinAgents([], {}, undefined, undefined)
// #then - connected cache enables model resolution despite no systemDefaultModel
// then - connected cache enables model resolution despite no systemDefaultModel
expect(agents.oracle).toBeDefined()
expect(agents.oracle.model).toBe("openai/gpt-5.2")
cacheSpy.mockRestore?.()
})
test("agents NOT created when no cache and no systemDefaultModel (first run without defaults)", async () => {
// #given
// given
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
// #when
// when
const agents = await createBuiltinAgents([], {}, undefined, undefined)
// #then
// then
expect(agents.oracle).toBeUndefined()
cacheSpy.mockRestore?.()
})
test("sisyphus created via connected cache fallback even without systemDefaultModel", async () => {
// #given - connected cache has "anthropic", which matches sisyphus's first fallback entry
// given - connected cache has "anthropic", which matches sisyphus's first fallback entry
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic"])
// #when
// when
const agents = await createBuiltinAgents([], {}, undefined, undefined)
// #then - connected cache enables model resolution despite no systemDefaultModel
// then - connected cache enables model resolution despite no systemDefaultModel
expect(agents.sisyphus).toBeDefined()
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-5")
cacheSpy.mockRestore?.()
@@ -171,7 +171,7 @@ describe("buildAgent with category and skills", () => {
})
test("agent with category inherits category settings", () => {
// #given - agent factory that sets category but no model
// given - agent factory that sets category but no model
const source = {
"test-agent": () =>
({
@@ -180,15 +180,15 @@ describe("buildAgent with category and skills", () => {
}) as AgentConfig,
}
// #when
// when
const agent = buildAgent(source["test-agent"], TEST_MODEL)
// #then - category's built-in model is applied
// then - category's built-in model is applied
expect(agent.model).toBe("google/gemini-3-pro")
})
test("agent with category and existing model keeps existing model", () => {
// #given
// given
const source = {
"test-agent": () =>
({
@@ -198,15 +198,15 @@ describe("buildAgent with category and skills", () => {
}) as AgentConfig,
}
// #when
// when
const agent = buildAgent(source["test-agent"], TEST_MODEL)
// #then - explicit model takes precedence over category
// then - explicit model takes precedence over category
expect(agent.model).toBe("custom/model")
})
test("agent with category inherits variant", () => {
// #given
// given
const source = {
"test-agent": () =>
({
@@ -222,16 +222,16 @@ describe("buildAgent with category and skills", () => {
},
}
// #when
// when
const agent = buildAgent(source["test-agent"], TEST_MODEL, categories)
// #then
// then
expect(agent.model).toBe("openai/gpt-5.2")
expect(agent.variant).toBe("xhigh")
})
test("agent with skills has content prepended to prompt", () => {
// #given
// given
const source = {
"test-agent": () =>
({
@@ -241,17 +241,17 @@ describe("buildAgent with category and skills", () => {
}) as AgentConfig,
}
// #when
// when
const agent = buildAgent(source["test-agent"], TEST_MODEL)
// #then
// then
expect(agent.prompt).toContain("Role: Designer-Turned-Developer")
expect(agent.prompt).toContain("Original prompt content")
expect(agent.prompt).toMatch(/Designer-Turned-Developer[\s\S]*Original prompt content/s)
})
test("agent with multiple skills has all content prepended", () => {
// #given
// given
const source = {
"test-agent": () =>
({
@@ -261,16 +261,16 @@ describe("buildAgent with category and skills", () => {
}) as AgentConfig,
}
// #when
// when
const agent = buildAgent(source["test-agent"], TEST_MODEL)
// #then
// then
expect(agent.prompt).toContain("Role: Designer-Turned-Developer")
expect(agent.prompt).toContain("Agent prompt")
})
test("agent without category or skills works as before", () => {
// #given
// given
const source = {
"test-agent": () =>
({
@@ -281,17 +281,17 @@ describe("buildAgent with category and skills", () => {
}) as AgentConfig,
}
// #when
// when
const agent = buildAgent(source["test-agent"], TEST_MODEL)
// #then
// then
expect(agent.model).toBe("custom/model")
expect(agent.temperature).toBe(0.5)
expect(agent.prompt).toBe("Base prompt")
})
test("agent with category and skills applies both", () => {
// #given
// given
const source = {
"test-agent": () =>
({
@@ -302,10 +302,10 @@ describe("buildAgent with category and skills", () => {
}) as AgentConfig,
}
// #when
// when
const agent = buildAgent(source["test-agent"], TEST_MODEL)
// #then - category's built-in model and skills are applied
// then - category's built-in model and skills are applied
expect(agent.model).toBe("openai/gpt-5.2-codex")
expect(agent.variant).toBe("xhigh")
expect(agent.prompt).toContain("Role: Designer-Turned-Developer")
@@ -313,7 +313,7 @@ describe("buildAgent with category and skills", () => {
})
test("agent with non-existent category has no effect", () => {
// #given
// given
const source = {
"test-agent": () =>
({
@@ -323,10 +323,10 @@ describe("buildAgent with category and skills", () => {
}) as AgentConfig,
}
// #when
// when
const agent = buildAgent(source["test-agent"], TEST_MODEL)
// #then
// then
// Note: The factory receives model, but if category doesn't exist, it's not applied
// The agent's model comes from the factory output (which doesn't set model)
expect(agent.model).toBeUndefined()
@@ -334,7 +334,7 @@ describe("buildAgent with category and skills", () => {
})
test("agent with non-existent skills only prepends found ones", () => {
// #given
// given
const source = {
"test-agent": () =>
({
@@ -344,16 +344,16 @@ describe("buildAgent with category and skills", () => {
}) as AgentConfig,
}
// #when
// when
const agent = buildAgent(source["test-agent"], TEST_MODEL)
// #then
// then
expect(agent.prompt).toContain("Role: Designer-Turned-Developer")
expect(agent.prompt).toContain("Base prompt")
})
test("agent with empty skills array keeps original prompt", () => {
// #given
// given
const source = {
"test-agent": () =>
({
@@ -363,15 +363,15 @@ describe("buildAgent with category and skills", () => {
}) as AgentConfig,
}
// #when
// when
const agent = buildAgent(source["test-agent"], TEST_MODEL)
// #then
// then
expect(agent.prompt).toBe("Base prompt")
})
test("agent with agent-browser skill resolves when browserProvider is set", () => {
// #given
// given
const source = {
"test-agent": () =>
({
@@ -381,16 +381,16 @@ describe("buildAgent with category and skills", () => {
}) as AgentConfig,
}
// #when - browserProvider is "agent-browser"
// when - browserProvider is "agent-browser"
const agent = buildAgent(source["test-agent"], TEST_MODEL, undefined, undefined, "agent-browser")
// #then - agent-browser skill content should be in prompt
// then - agent-browser skill content should be in prompt
expect(agent.prompt).toContain("agent-browser")
expect(agent.prompt).toContain("Base prompt")
})
test("agent with agent-browser skill NOT resolved when browserProvider not set", () => {
// #given
// given
const source = {
"test-agent": () =>
({
@@ -400,10 +400,10 @@ describe("buildAgent with category and skills", () => {
}) as AgentConfig,
}
// #when - no browserProvider (defaults to playwright)
// when - no browserProvider (defaults to playwright)
const agent = buildAgent(source["test-agent"], TEST_MODEL)
// #then - agent-browser skill not found, only base prompt remains
// then - agent-browser skill not found, only base prompt remains
expect(agent.prompt).toBe("Base prompt")
expect(agent.prompt).not.toContain("agent-browser open")
})
@@ -411,36 +411,36 @@ describe("buildAgent with category and skills", () => {
describe("override.category expansion in createBuiltinAgents", () => {
test("standard agent override with category expands category properties", async () => {
// #given
// given
const overrides = {
oracle: { category: "ultrabrain" } as any,
}
// #when
// when
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
// #then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
// then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
expect(agents.oracle).toBeDefined()
expect(agents.oracle.model).toBe("openai/gpt-5.2-codex")
expect(agents.oracle.variant).toBe("xhigh")
})
test("standard agent override with category AND direct variant - direct wins", async () => {
// #given - ultrabrain has variant=xhigh, but direct override says "max"
// given - ultrabrain has variant=xhigh, but direct override says "max"
const overrides = {
oracle: { category: "ultrabrain", variant: "max" } as any,
}
// #when
// when
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
// #then - direct variant overrides category variant
// then - direct variant overrides category variant
expect(agents.oracle).toBeDefined()
expect(agents.oracle.variant).toBe("max")
})
test("standard agent override with category AND direct reasoningEffort - direct wins", async () => {
// #given - custom category has reasoningEffort=xhigh, direct override says "low"
// given - custom category has reasoningEffort=xhigh, direct override says "low"
const categories = {
"test-cat": {
model: "openai/gpt-5.2",
@@ -451,16 +451,16 @@ describe("override.category expansion in createBuiltinAgents", () => {
oracle: { category: "test-cat", reasoningEffort: "low" } as any,
}
// #when
// when
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL, categories)
// #then - direct reasoningEffort wins over category
// then - direct reasoningEffort wins over category
expect(agents.oracle).toBeDefined()
expect(agents.oracle.reasoningEffort).toBe("low")
})
test("standard agent override with category applies reasoningEffort from category when no direct override", async () => {
// #given - custom category has reasoningEffort, no direct reasoningEffort in override
// given - custom category has reasoningEffort, no direct reasoningEffort in override
const categories = {
"reasoning-cat": {
model: "openai/gpt-5.2",
@@ -471,54 +471,54 @@ describe("override.category expansion in createBuiltinAgents", () => {
oracle: { category: "reasoning-cat" } as any,
}
// #when
// when
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL, categories)
// #then - category reasoningEffort is applied
// then - category reasoningEffort is applied
expect(agents.oracle).toBeDefined()
expect(agents.oracle.reasoningEffort).toBe("high")
})
test("sisyphus override with category expands category properties", async () => {
// #given
// given
const overrides = {
sisyphus: { category: "ultrabrain" } as any,
}
// #when
// when
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
// #then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
// then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
expect(agents.sisyphus).toBeDefined()
expect(agents.sisyphus.model).toBe("openai/gpt-5.2-codex")
expect(agents.sisyphus.variant).toBe("xhigh")
})
test("atlas override with category expands category properties", async () => {
// #given
// given
const overrides = {
atlas: { category: "ultrabrain" } as any,
}
// #when
// when
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
// #then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
// then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
expect(agents.atlas).toBeDefined()
expect(agents.atlas.model).toBe("openai/gpt-5.2-codex")
expect(agents.atlas.variant).toBe("xhigh")
})
test("override with non-existent category has no effect on config", async () => {
// #given
// given
const overrides = {
oracle: { category: "non-existent-category" } as any,
}
// #when
// when
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
// #then - no category-specific variant/reasoningEffort applied from non-existent category
// then - no category-specific variant/reasoningEffort applied from non-existent category
expect(agents.oracle).toBeDefined()
const agentsWithoutOverride = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
expect(agents.oracle.model).toBe(agentsWithoutOverride.oracle.model)
@@ -527,7 +527,7 @@ describe("override.category expansion in createBuiltinAgents", () => {
describe("Deadlock prevention - fetchAvailableModels must not receive client", () => {
test("createBuiltinAgents should call fetchAvailableModels with undefined client to prevent deadlock", async () => {
// #given - This test ensures we don't regress on issue #1301
// given - This test ensures we don't regress on issue #1301
// Passing client to fetchAvailableModels during createBuiltinAgents (called from config handler)
// causes deadlock:
// - Plugin init waits for server response (client.provider.list())
@@ -540,7 +540,7 @@ describe("Deadlock prevention - fetchAvailableModels must not receive client", (
model: { list: () => Promise.resolve({ data: [] }) },
}
// #when - Even when client is provided, fetchAvailableModels must be called with undefined
// when - Even when client is provided, fetchAvailableModels must be called with undefined
await createBuiltinAgents(
[],
{},
@@ -552,7 +552,7 @@ describe("Deadlock prevention - fetchAvailableModels must not receive client", (
mockClient // client is passed but should NOT be forwarded to fetchAvailableModels
)
// #then - fetchAvailableModels must be called with undefined as first argument (no client)
// then - fetchAvailableModels must be called with undefined as first argument (no client)
// This prevents the deadlock described in issue #1301
expect(fetchSpy).toHaveBeenCalled()
const firstCallArgs = fetchSpy.mock.calls[0]