import type { AutoDecisionState } from './auto-decision-state'; import type { NativePublicToolEvent, PlanCountTranscript } from './plan-count-transcript'; export interface NativeAutoDecision { sessionId: string; skillToolUseId?: string; preambleToolUseId?: string; preferenceToolUseId?: string; questionLogToolUseId?: string; timestamp: string; summary: string; option: string; annotation: string; stateRecord?: Record; } const plain = (text: string) => text.replace(/\*\*([^*]+)\*\*/g, '$1').trim(); const annotationLine = /^Auto-decided ([^\r\n→]{1,240}) → ([^\r\n→]{1,200}) \(your (?:preference|saved preference on `([a-z][a-z0-9-]*)`)\)\. Change with \/plan-tune\.$/; /** Asserted prose only; later quoted examples cannot retract a current decision. */ function publicProse(text: string): string { const lines: string[] = []; let fence: { char: string; length: number } | undefined; for (const line of text.split(/\r?\n/)) { const marker = /^ {0,3}(`{3,}|~{3,})/.exec(line); if (marker) { if (!fence) fence = { char: marker[1]![0]!, length: marker[1]!.length }; else if (marker[1]![0] === fence.char && marker[1]!.length >= fence.length && /^\s*$/.test(line.slice(marker[0].length))) fence = undefined; continue; } if (fence || /^(?: {4}|\t|\s*>)/.test(line)) continue; const current = plain(line); // A quoted name is still the target of an otherwise asserted mode field. // Preserve only that slot; whole quoted declarations remain non-assertions. const correction = /^(?:Correction|Actually|Update):\s*/i.test(current); lines.push(current.replace(/"(?:[^"\\]|\\.)*"|“[^”]*”|`[^`]*`/g, (quoted, offset) => { const field = modeField(current.slice(0, offset) + '""'); if (field && modeNames.some(mode => field.value.toUpperCase() === `${mode} FOR ""`)) return quoted; return correction ? quoted.replace(/["“”`]/g, '') : '""'; })); } return lines.join('\n'); } // The same current-mode field grammar owns declarations and later corrections. function modeField(line: string): { value: string; completed: boolean } | null { const match = /^(?:(?:Correction|Actually|Update):\s*)?(?