feat(keyword-detector): add hyperplan keyword pattern, message and test

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-04-28 19:03:55 +09:00
parent b7dc4f9038
commit a3fb7d1d5c
3 changed files with 282 additions and 0 deletions

View File

@@ -0,0 +1,244 @@
import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
import type { PluginInput } from "@opencode-ai/plugin"
import { createKeywordDetectorHook } from "./index"
import { setMainSession, _resetForTesting } from "../../features/claude-code-session-state"
import * as sharedModule from "../../shared"
import * as sessionState from "../../features/claude-code-session-state"
describe("keyword-detector hyperplan keyword", () => {
let logSpy: ReturnType<typeof spyOn>
let getMainSessionSpy: ReturnType<typeof spyOn>
beforeEach(() => {
_resetForTesting()
logSpy = spyOn(sharedModule, "log").mockImplementation(() => {})
})
afterEach(() => {
logSpy?.mockRestore()
getMainSessionSpy?.mockRestore()
_resetForTesting()
})
function createMockPluginInput(options: { toastCalls?: string[] } = {}) {
const toastCalls = options.toastCalls ?? []
return {
client: {
tui: {
showToast: async (opts: { body: { title: string } }) => {
toastCalls.push(opts.body.title)
},
},
},
} as unknown as PluginInput
}
test("should inject hyperplan message when user types 'hyperplan'", async () => {
// given - main session typing the full keyword
const sessionID = "hyperplan-full-session"
getMainSessionSpy = spyOn(sessionState, "getMainSessionID").mockReturnValue(sessionID)
const hook = createKeywordDetectorHook(createMockPluginInput())
const output = {
message: {} as Record<string, unknown>,
parts: [{ type: "text", text: "hyperplan refactor the auth module" }],
}
// when - keyword detection runs
await hook["chat.message"]({ sessionID }, output)
// then - hyperplan-mode wrapper and skill-loading instruction should be present
const textPart = output.parts.find(p => p.type === "text")
expect(textPart).toBeDefined()
expect(textPart!.text).toContain("<hyperplan-mode>")
expect(textPart!.text).toContain('skill(name="hyperplan")')
expect(textPart!.text).toContain("HYPERPLAN MODE ENABLED")
expect(textPart!.text).toContain("refactor the auth module")
expect(textPart!.text).toContain("---")
})
test("should inject hyperplan message when user types 'hpp' shorthand", async () => {
// given - main session typing the short keyword
const sessionID = "hyperplan-short-session"
getMainSessionSpy = spyOn(sessionState, "getMainSessionID").mockReturnValue(sessionID)
const hook = createKeywordDetectorHook(createMockPluginInput())
const output = {
message: {} as Record<string, unknown>,
parts: [{ type: "text", text: "hpp how should I structure this feature" }],
}
// when - keyword detection runs
await hook["chat.message"]({ sessionID }, output)
// then - hyperplan injection should fire
const textPart = output.parts.find(p => p.type === "text")
expect(textPart).toBeDefined()
expect(textPart!.text).toContain("<hyperplan-mode>")
expect(textPart!.text).toContain('skill(name="hyperplan")')
})
test("should inject hyperplan message case-insensitively", async () => {
// given - main session typing in mixed case
const sessionID = "hyperplan-case-session"
getMainSessionSpy = spyOn(sessionState, "getMainSessionID").mockReturnValue(sessionID)
const hook = createKeywordDetectorHook(createMockPluginInput())
const output = {
message: {} as Record<string, unknown>,
parts: [{ type: "text", text: "HyperPlan something now" }],
}
// when - keyword detection runs with mixed case input
await hook["chat.message"]({ sessionID }, output)
// then - hyperplan should still fire
const textPart = output.parts.find(p => p.type === "text")
expect(textPart).toBeDefined()
expect(textPart!.text).toContain("<hyperplan-mode>")
})
test("should NOT trigger hyperplan when 'hpp' is a substring of another word", async () => {
// given - text contains 'hpp' only as part of larger string with no word boundary
const sessionID = "hyperplan-substring-session"
getMainSessionSpy = spyOn(sessionState, "getMainSessionID").mockReturnValue(sessionID)
const hook = createKeywordDetectorHook(createMockPluginInput())
const output = {
message: {} as Record<string, unknown>,
parts: [{ type: "text", text: "myhppvar = 1" }],
}
// when - keyword detection runs
await hook["chat.message"]({ sessionID }, output)
// then - hyperplan should NOT trigger because 'hpp' lacks word boundaries
const textPart = output.parts.find(p => p.type === "text")
expect(textPart).toBeDefined()
expect(textPart!.text).toBe("myhppvar = 1")
expect(textPart!.text).not.toContain("<hyperplan-mode>")
})
test("should fire 'Hyperplan Mode Activated' toast when keyword detected", async () => {
// given - main session and toast tracking
const sessionID = "hyperplan-toast-session"
getMainSessionSpy = spyOn(sessionState, "getMainSessionID").mockReturnValue(sessionID)
const toastCalls: string[] = []
const hook = createKeywordDetectorHook(createMockPluginInput({ toastCalls }))
const output = {
message: {} as Record<string, unknown>,
parts: [{ type: "text", text: "hyperplan this task" }],
}
// when - hyperplan keyword fires
await hook["chat.message"]({ sessionID }, output)
// then - toast title should be present in tracked calls
expect(toastCalls).toContain("Hyperplan Mode Activated")
})
test("should NOT inject hyperplan when disabled_keywords includes 'hyperplan'", async () => {
// given - keyword detector with hyperplan disabled
const sessionID = "hyperplan-disabled-session"
getMainSessionSpy = spyOn(sessionState, "getMainSessionID").mockReturnValue(sessionID)
const toastCalls: string[] = []
const hook = createKeywordDetectorHook(
createMockPluginInput({ toastCalls }),
undefined,
undefined,
{ disabled_keywords: ["hyperplan"] },
)
const output = {
message: {} as Record<string, unknown>,
parts: [{ type: "text", text: "hyperplan refactor this" }],
}
// when - hyperplan keyword would normally fire
await hook["chat.message"]({ sessionID }, output)
// then - neither injection nor toast should occur
const textPart = output.parts.find(p => p.type === "text")
expect(textPart).toBeDefined()
expect(textPart!.text).toBe("hyperplan refactor this")
expect(textPart!.text).not.toContain("<hyperplan-mode>")
expect(toastCalls).not.toContain("Hyperplan Mode Activated")
})
test("should filter hyperplan keyword in non-main session (only ultrawork allowed there)", async () => {
// given - main session set, different (subagent) session triggers hyperplan
const mainSessionID = "main-hyperplan"
const subagentSessionID = "subagent-hyperplan"
setMainSession(mainSessionID)
const hook = createKeywordDetectorHook(createMockPluginInput())
const output = {
message: {} as Record<string, unknown>,
parts: [{ type: "text", text: "hyperplan please" }],
}
// when - subagent session triggers hyperplan keyword
await hook["chat.message"]({ sessionID: subagentSessionID }, output)
// then - hyperplan injection should be skipped in non-main session
const textPart = output.parts.find(p => p.type === "text")
expect(textPart).toBeDefined()
expect(textPart!.text).toBe("hyperplan please")
expect(textPart!.text).not.toContain("<hyperplan-mode>")
})
test("should skip hyperplan injection when agent is prometheus (planner)", async () => {
// given - hook running with prometheus agent and a prompt that only triggers hyperplan
const sessionID = "hyperplan-prometheus-session"
const hook = createKeywordDetectorHook(createMockPluginInput())
const output = {
message: {} as Record<string, unknown>,
parts: [{ type: "text", text: "hyperplan refactor stuff" }],
}
// when - hyperplan keyword detected with prometheus agent
await hook["chat.message"]({ sessionID, agent: "prometheus" }, output)
// then - hyperplan should be filtered out for planner agents
const textPart = output.parts.find(p => p.type === "text")
expect(textPart).toBeDefined()
expect(textPart!.text).not.toContain("<hyperplan-mode>")
expect(textPart!.text).not.toContain('skill(name="hyperplan")')
expect(textPart!.text).toContain("hyperplan refactor stuff")
})
test("should skip hyperplan injection when agent name contains 'planner' token", async () => {
// given - hook running with planner-named agent and a prompt that only triggers hpp
const sessionID = "hyperplan-planner-session"
const hook = createKeywordDetectorHook(createMockPluginInput())
const output = {
message: {} as Record<string, unknown>,
parts: [{ type: "text", text: "hpp build the feature" }],
}
// when - hpp keyword detected with planner agent
await hook["chat.message"]({ sessionID, agent: "Plan Agent" }, output)
// then - hyperplan should be filtered out
const textPart = output.parts.find(p => p.type === "text")
expect(textPart).toBeDefined()
expect(textPart!.text).not.toContain("<hyperplan-mode>")
expect(textPart!.text).not.toContain('skill(name="hyperplan")')
expect(textPart!.text).toContain("hpp build the feature")
})
test("should inject hyperplan AND ultrawork together when both keywords present", async () => {
// given - main session typing both keywords in the same message
const sessionID = "hyperplan-combo-session"
getMainSessionSpy = spyOn(sessionState, "getMainSessionID").mockReturnValue(sessionID)
const hook = createKeywordDetectorHook(createMockPluginInput())
const output = {
message: {} as Record<string, unknown>,
parts: [{ type: "text", text: "ultrawork hyperplan ship this feature" }],
}
// when - both keywords trigger
await hook["chat.message"]({ sessionID }, output)
// then - both messages should be present
const textPart = output.parts.find(p => p.type === "text")
expect(textPart).toBeDefined()
expect(textPart!.text).toContain("<hyperplan-mode>")
expect(textPart!.text).toContain("YOU MUST LEVERAGE ALL AVAILABLE AGENTS")
expect(textPart!.text).toContain("ship this feature")
})
})

View File

@@ -0,0 +1,37 @@
/**
* Hyperplan keyword detector.
*
* Triggers when the user wants adversarial multi-agent planning via team-mode.
*
* Triggers (case-insensitive, word-bounded):
* - English: hyperplan, hpp
*
* The detector injects a thin wrapper that loads the `hyperplan` skill, which
* carries the full orchestration instructions for the 5-member adversarial team.
*/
export const HYPERPLAN_PATTERN = /\b(hyperplan|hpp)\b/i
export const HYPERPLAN_MESSAGE = `<hyperplan-mode>
**MANDATORY**: Say "HYPERPLAN MODE ENABLED!" as your first response, exactly once.
The user invoked **hyperplan mode** — adversarial multi-agent planning via team-mode.
LOAD THE HYPERPLAN SKILL IMMEDIATELY:
\`\`\`
skill(name="hyperplan")
\`\`\`
After loading, follow the skill's 6-phase workflow EXACTLY:
1. Acknowledge and capture the planning request
2. Spawn the 5-member adversarial team via team_create
3. Round 1 — Independent analysis (each member produces findings)
4. Round 2 — Cross-attack (each member ruthlessly attacks the other 4's findings)
5. Round 3 — Defend, refine, or concede
6. Synthesize defensible insights into a work plan + clean up the team
Do NOT improvise. Do NOT skip rounds. Be the lead orchestrator and let the adversarial members do the cross-critique.
If team-mode is unavailable (\`team_*\` tools missing), instruct the user to set \`team_mode.enabled: true\` in \`~/.config/opencode/oh-my-opencode.jsonc\` and restart opencode.
</hyperplan-mode>`

View File

@@ -0,0 +1 @@
export { HYPERPLAN_PATTERN, HYPERPLAN_MESSAGE } from "./default"