diff --git a/src/hooks/keyword-detector/detector.ts b/src/hooks/keyword-detector/detector.ts index 2f57db2..e555a9e 100644 --- a/src/hooks/keyword-detector/detector.ts +++ b/src/hooks/keyword-detector/detector.ts @@ -4,6 +4,11 @@ import { INLINE_CODE_PATTERN, } from "./constants" +export interface DetectedKeyword { + type: "ultrawork" | "search" | "analyze" + message: string +} + export function removeCodeBlocks(text: string): string { return text.replace(CODE_BLOCK_PATTERN, "").replace(INLINE_CODE_PATTERN, "") } @@ -15,6 +20,18 @@ export function detectKeywords(text: string): string[] { ).map(({ message }) => message) } +export function detectKeywordsWithType(text: string): DetectedKeyword[] { + const textWithoutCode = removeCodeBlocks(text) + const types: Array<"ultrawork" | "search" | "analyze"> = ["ultrawork", "search", "analyze"] + return KEYWORD_DETECTORS.map(({ pattern, message }, index) => ({ + matches: pattern.test(textWithoutCode), + type: types[index], + message, + })) + .filter((result) => result.matches) + .map(({ type, message }) => ({ type, message })) +} + export function extractPromptText( parts: Array<{ type: string; text?: string }> ): string { diff --git a/src/hooks/keyword-detector/index.ts b/src/hooks/keyword-detector/index.ts index 8c4cdb7..49cf845 100644 --- a/src/hooks/keyword-detector/index.ts +++ b/src/hooks/keyword-detector/index.ts @@ -1,4 +1,5 @@ -import { detectKeywords, extractPromptText } from "./detector" +import type { PluginInput } from "@opencode-ai/plugin" +import { detectKeywords, detectKeywordsWithType, extractPromptText } from "./detector" import { log } from "../../shared" import { injectHookMessage } from "../../features/hook-message-injector" @@ -7,8 +8,9 @@ export * from "./constants" export * from "./types" const sessionFirstMessageProcessed = new Set() +const sessionUltraworkNotified = new Set() -export function createKeywordDetectorHook() { +export function createKeywordDetectorHook(ctx: PluginInput) { return { "chat.message": async ( input: { @@ -26,12 +28,28 @@ export function createKeywordDetectorHook() { sessionFirstMessageProcessed.add(input.sessionID) const promptText = extractPromptText(output.parts) - const messages = detectKeywords(promptText) + const detectedKeywords = detectKeywordsWithType(promptText) + const messages = detectedKeywords.map((k) => k.message) if (messages.length === 0) { return } + const hasUltrawork = detectedKeywords.some((k) => k.type === "ultrawork") + if (hasUltrawork && !sessionUltraworkNotified.has(input.sessionID)) { + sessionUltraworkNotified.add(input.sessionID) + log(`[keyword-detector] Ultrawork mode activated`, { sessionID: input.sessionID }) + + ctx.client.tui.showToast({ + body: { + title: "Ultrawork Mode Activated", + message: "Maximum precision engaged. All agents at your disposal.", + variant: "success" as const, + duration: 3000, + }, + }).catch((err) => log(`[keyword-detector] Failed to show toast`, { error: err, sessionID: input.sessionID })) + } + const context = messages.join("\n") // First message: transform parts directly (for title generation compatibility) diff --git a/src/index.ts b/src/index.ts index fb2cff3..e2a75d8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -237,7 +237,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { }) : null; const keywordDetector = isHookEnabled("keyword-detector") - ? createKeywordDetectorHook() + ? createKeywordDetectorHook(ctx) : null; const agentUsageReminder = isHookEnabled("agent-usage-reminder") ? createAgentUsageReminderHook(ctx)