feat(keyword-detector): show toast notification when ultrawork mode is activated (#393)

* feat(keyword-detector): show toast notification when ultrawork mode is activated

When users trigger ultrawork mode (via 'ultrawork' or 'ulw' keywords), a toast
notification now appears to confirm the mode is active. The notification is
shown once per session to avoid spamming.

Changes:
- Add detectKeywordsWithType() to identify which keyword type triggered
- Show 'Ultrawork Mode Activated' toast with success variant
- Track notified sessions to prevent duplicate toasts

Closes #392

* fix(keyword-detector): fix index bug in detectKeywordsWithType and add error logging

- Fix P1: detectKeywordsWithType now maps before filtering to preserve
  original KEYWORD_DETECTORS indices. Previously, the index used was from
  the filtered array, causing incorrect type assignment (e.g., 'search'
  match would incorrectly return 'ultrawork' type).

- Fix P2: Replace silent .catch(() => {}) with proper error logging using
  the log function for easier debugging when toast notifications fail.

---------

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
This commit is contained in:
Sisyphus
2026-01-01 20:58:02 +09:00
committed by GitHub
parent 1c55385cb5
commit f66c886e0d
3 changed files with 39 additions and 4 deletions
+17
View File
@@ -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 {