feat(keyword-detector): add per-keyword disable config
Adds keyword_detector.disabled_keywords config so users can opt out of
specific keyword detectors individually without disabling the entire
keyword-detector hook. Allowed values: 'ultrawork', 'search', 'analyze',
'team'. Default empty/missing -> all four detectors active (no behavior
change for existing configs).
Motivation: an audit revealed search and analyze patterns trigger on
~30-60% of normal conversational user messages (e.g. 'how to', 'why is',
'show me', '왜', '어떻게'). The disable list is the immediate kill switch
while the patterns themselves are tightened in a separate PR.
Schema follows the existing per-feature config block convention shared
by team_mode, ralph_loop, runtime_fallback, and comment_checker. The
KeywordType enum (z.enum) lives next to the config schema and is
re-imported by the detector to keep the union type in lockstep with the
schema.
Threading:
pluginConfig.keyword_detector
-> create-transform-hooks.ts (factory wiring)
-> createKeywordDetectorHook(config)
-> detectKeywordsWithType(text, agent, model, disabledKeywords)
-> Set-based filter at the source-of-truth detector
Adds 8 regression tests covering per-keyword disable, multi-keyword
disable, partial disable (one keyword off, another still firing),
ultrawork toast suppression, undefined config, and empty array.
This commit is contained in:
@@ -22,4 +22,6 @@ export type {
|
||||
ModelCapabilitiesConfig,
|
||||
FallbackModels,
|
||||
TeamModeConfig,
|
||||
KeywordDetectorConfig,
|
||||
KeywordType,
|
||||
} from "./schema"
|
||||
|
||||
@@ -13,6 +13,7 @@ export * from "./schema/fallback-models"
|
||||
export * from "./schema/git-env-prefix"
|
||||
export * from "./schema/git-master"
|
||||
export * from "./schema/hooks"
|
||||
export * from "./schema/keyword-detector"
|
||||
export * from "./schema/model-capabilities"
|
||||
export * from "./schema/notification"
|
||||
export * from "./schema/oh-my-opencode-config"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { z } from "zod"
|
||||
|
||||
export const KeywordTypeSchema = z.enum(["ultrawork", "search", "analyze", "team"])
|
||||
export type KeywordType = z.infer<typeof KeywordTypeSchema>
|
||||
|
||||
export const KeywordDetectorConfigSchema = z.object({
|
||||
disabled_keywords: z.array(KeywordTypeSchema).optional(),
|
||||
})
|
||||
|
||||
export type KeywordDetectorConfig = z.infer<typeof KeywordDetectorConfigSchema>
|
||||
@@ -12,6 +12,7 @@ import { CommentCheckerConfigSchema } from "./comment-checker"
|
||||
import { BuiltinCommandNameSchema } from "./commands"
|
||||
import { ExperimentalConfigSchema } from "./experimental"
|
||||
import { GitMasterConfigSchema } from "./git-master"
|
||||
import { KeywordDetectorConfigSchema } from "./keyword-detector"
|
||||
import { NotificationConfigSchema } from "./notification"
|
||||
import { OpenClawConfigSchema } from "./openclaw"
|
||||
import { ModelCapabilitiesConfigSchema } from "./model-capabilities"
|
||||
@@ -65,6 +66,8 @@ export const OhMyOpenCodeConfigSchema = z.object({
|
||||
model_capabilities: ModelCapabilitiesConfigSchema.optional(),
|
||||
openclaw: OpenClawConfigSchema.optional(),
|
||||
team_mode: TeamModeConfigSchema.optional(),
|
||||
/** Per-keyword disable list for the keyword-detector transform hook. Allowed values: "ultrawork", "search", "analyze", "team". */
|
||||
keyword_detector: KeywordDetectorConfigSchema.optional(),
|
||||
babysitting: BabysittingConfigSchema.optional(),
|
||||
git_master: GitMasterConfigSchema.default({
|
||||
commit_footer: true,
|
||||
|
||||
Reference in New Issue
Block a user