/** * Keyword Detection Engine * * In OMC/legacy OMX flows, this logic detects workflow keywords and can inject * prompt-side routing guidance. * * In current OMX, native `UserPromptSubmit` is the canonical execution surface: * this module owns the keyword registry, runtime gating, and hook-seeded * skill/workflow state. AGENTS.md now carries the behavioral fallback contract * rather than the full keyword/state table. */ import { type TaskSizeResult } from './task-size-detector.js'; import { type SkillActiveEntry } from '../state/skill-active.js'; import { type DeepInterviewQuestionEnforcementState } from '../question/deep-interview.js'; import { type DeepInterviewRuntimeConfig } from '../config/deep-interview.js'; import { type PromptDiagnosticDescriptor, type ResolvedPromptTurnContext } from './prompt-session-provenance.js'; export interface KeywordMatch { keyword: string; skill: string; priority: number; } export type KeywordReservedInput = 'omx-question-answered' | 'prompts' | null; /** Stable diagnostic precedence for explicit candidates. */ export declare const KEYWORD_INERT_DIAGNOSTIC_ORDER: readonly ["fenced-code", "indented-code", "blockquote", "inline-code", "quote", "escaped", "not-leading-region"]; export type KeywordInertDiagnostic = (typeof KEYWORD_INERT_DIAGNOSTIC_ORDER)[number]; export interface ExplicitSkillCandidate { readonly rawKeyword: string; readonly normalizedToken: string; readonly skill: string | null; readonly priority: number | null; readonly reasons: readonly KeywordInertDiagnostic[]; } export interface RemovedSkillMatch { readonly rawKeyword: string; readonly normalizedToken: string; readonly message: string; } export interface KeywordInputClassification { readonly originalText: string; readonly normalizedText: string; readonly candidates: readonly ExplicitSkillCandidate[]; readonly explicitMatches: readonly KeywordMatch[]; readonly removedMatches: readonly RemovedSkillMatch[]; readonly hasExplicitLikeInvocation: boolean; readonly reservedInput: KeywordReservedInput; readonly implicitMatches: readonly KeywordMatch[]; readonly matches: readonly KeywordMatch[]; } export type SkillActivePhase = 'planning' | 'executing' | 'reviewing' | 'completing' | 'ralplan' | 'deep-interview'; export interface DeepInterviewInputLock { active: boolean; scope: 'deep-interview-auto-approval'; acquired_at: string; released_at?: string; exit_reason?: 'success' | 'error' | 'abort' | 'handoff'; blocked_inputs: string[]; message: string; } export interface SkillActiveState { version: 1; active: boolean; skill: string; keyword: string; phase: string; activated_at: string; updated_at: string; source: 'keyword-detector'; session_id?: string; thread_id?: string; turn_id?: string; input_lock?: DeepInterviewInputLock; deep_interview_config?: DeepInterviewRuntimeConfig; active_skills?: SkillActiveEntry[]; initialized_mode?: string; initialized_state_path?: string; transition_error?: string; transition_message?: string; transition_messages?: string[]; workflow_variant?: 'advisory'; advisory_generation_id?: string; requested_skills?: string[]; deferred_skills?: string[]; [key: string]: unknown; } export interface RecordSkillActivationInput { stateDir: string; sourceCwd?: string; text: string; sessionId?: string; threadId?: string; turnId?: string; nowIso?: string; classification?: KeywordInputClassification; allowSecondaryTeam?: boolean; allowSecondaryAutopilot?: boolean; resolvedPromptTurnContext?: ResolvedPromptTurnContext; onProvenanceRejected?: (diagnostic: PromptDiagnosticDescriptor) => void | Promise; } interface RecordSkillActivationDependencies { advisoryActivationFailpoint?: (name: 'rollover_intent' | 'rollover_activation' | 'rollover_pointer' | 'intent_committed') => void | Promise; advisoryAfterModeBindingFailpoint?: () => void | Promise; } export interface DeepInterviewModeStatePersistenceInput { sessionId?: string; threadId?: string; turnId?: string; } export declare const DEEP_INTERVIEW_STATE_FILE = "deep-interview-state.json"; export declare const DEEP_INTERVIEW_BLOCKED_APPROVAL_INPUTS: readonly ['yes', 'y', 'proceed', 'continue', 'ok', 'sure', 'go ahead', 'next i should']; export declare const DEEP_INTERVIEW_INPUT_LOCK_MESSAGE = "Deep interview is active; auto-approval shortcuts are blocked until the interview finishes."; export interface DeepInterviewModeState { active: boolean; mode: 'deep-interview'; tmux_pane_id?: string; tmux_pane_set_at?: string; current_phase: string; started_at: string; updated_at: string; completed_at?: string; session_id?: string; thread_id?: string; turn_id?: string; input_lock?: DeepInterviewInputLock; question_enforcement?: DeepInterviewQuestionEnforcementState; [key: string]: unknown; } export declare function persistDeepInterviewModeState(stateDir: string, nextSkill: SkillActiveState | null, nowIso: string, previousSkill: SkillActiveState | null, input: DeepInterviewModeStatePersistenceInput): Promise; /** * Classify one prompt with the direct-only explicit grammar and immutable * diagnostics. Consumers must share this result rather than re-detecting. */ export declare function classifyKeywordInput(text: string): KeywordInputClassification; /** Detect workflow matches using a fresh immutable input classification. */ export declare function detectKeywords(text: string): KeywordMatch[]; /** Get the first match in classification order. */ export declare function detectPrimaryKeyword(text: string): KeywordMatch | null; export declare function recordSkillActivation(input: RecordSkillActivationInput, dependencies?: RecordSkillActivationDependencies): Promise; /** * Options for task-size-aware keyword filtering */ export interface TaskSizeFilterOptions { /** Enable task-size detection. Default: true */ enabled?: boolean; /** Word count threshold for small tasks. Default: 50 */ smallWordLimit?: number; /** Word count threshold for large tasks. Default: 200 */ largeWordLimit?: number; /** Suppress heavy modes for small tasks. Default: true */ suppressHeavyModesForSmallTasks?: boolean; } /** * Get all keywords with task-size-based filtering applied. * For small tasks, heavy orchestration modes (ralph/autopilot/team/ultrawork etc.) * are suppressed to avoid over-orchestration. */ export declare function getAllKeywordsWithSizeCheck(text: string, options?: TaskSizeFilterOptions): { keywords: string[]; taskSizeResult: TaskSizeResult | null; suppressedKeywords: string[]; }; export {}; //# sourceMappingURL=keyword-detector.d.ts.map