fix(keyword-detector): yield to slash commands so /hyperplan executes its template
When user types /hyperplan something, two pipelines race for the message:
1. keyword-detector hook (chat.message): the regex \b(hyperplan|hpp)\b
matches /hyperplan because \b is satisfied by the / boundary, so the
hook prepends <hyperplan-mode> to the text part.
2. auto-slash-command hook (chat.message, runs immediately after):
detectSlashCommand() checks `text.trimStart().startsWith("/")`. After
keyword-detector's prepend, the part now starts with <hyperplan-mode>
and the slash check fails, so the builtin command template
(with $ARGUMENTS substituted) is never injected.
The visible symptom: /hyperplan refactor X never runs the actual
HYPERPLAN_TEMPLATE - the user sees only the keyword-detector wrapper, which
is similar but not identical, and the slash command's $ARGUMENTS payload
is silently lost.
Fix: at the top of the keyword-detector hook, after isSystemDirective() but
before any keyword scan, bail out if the prompt text starts with a slash
command (^\s*\/[a-zA-Z][\w-]*\b). Slash commands are explicit invocations
and own their own mode-injection path; the keyword detector must not race
them. Free-form mentions like "hyperplan: refactor X" still trigger
keyword detection - only the leading-slash form is suppressed.
Lock the contract with three regression tests:
- /hyperplan refactor ... must NOT inject <hyperplan-mode>
- /hpp investigate ... must NOT inject (shorthand slash command)
- "hyperplan: refactor src/auth/handler.ts" still injects (free-form)
Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode).
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import type { KeywordDetectorConfig } from "../../config/schema/keyword-detector"
|
||||
import type { DetectedKeyword } from "./detector"
|
||||
import { detectKeywordsWithType, extractPromptText } from "./detector"
|
||||
import { detectKeywordsWithType, extractPromptText, looksLikeSlashCommand } from "./detector"
|
||||
import { isPlannerAgent, isNonOmoAgent } from "./constants"
|
||||
import { log } from "../../shared"
|
||||
import {
|
||||
@@ -58,6 +58,11 @@ export function createKeywordDetectorHook(
|
||||
return
|
||||
}
|
||||
|
||||
if (looksLikeSlashCommand(promptText)) {
|
||||
log(`[keyword-detector] Skipping slash command invocation`, { sessionID: input.sessionID })
|
||||
return
|
||||
}
|
||||
|
||||
const currentAgent = getSessionAgent(input.sessionID) ?? input.agent
|
||||
|
||||
// Skip all keyword injection for non-OMO agents (e.g., OpenCode-Builder, Plan)
|
||||
|
||||
Reference in New Issue
Block a user