/**
 * Task-and-quality-validated success evaluation for V3 agent runs.
 * Decouples CLI verdict from raw file-change counts (1.11.0+).
 */
export function createLiveOutcome() {
    return {
        executorFailed: false,
        plannerError: null,
        executorError: null,
        tasksTotal: 0,
        tasksSucceeded: 0,
        changedFileCount: 0,
        requiresWorkspaceChanges: false,
        workspaceHasOutput: false,
        failedTaskIds: new Set(),
        completedTaskIds: new Set(),
        analysisToolsUsed: 0,
        analysisReadToolsUsed: 0,
        answerContent: '',
        deepAnalysisRequired: false,
        streamAborted: false,
    };
}
const EXECUTOR_PLACEHOLDER_RE = /read-only analysis turn|run at least one discovery tool|reviewing attached files and workspace findings/i;
const BOOTSTRAP_PLACEHOLDER_RE = /bootstrap discovery completed|inspect the most relevant files next|reviewing attached files and workspace findings/i;
const LIST_ONLY_DISCOVERY_TOOLS = new Set([
    'list_directory',
    'list_dir',
    'glob',
    'dir',
]);
const GENERIC_SUMMARY_RE = /^(completed the requested analysis|reviewed the workspace without writing changes|task completed|done|finished|analysis completed)([.\s]|$)/i;
/** Planner fallback / degraded inference — generic greeting unrelated to the user question. */
const GENERIC_FALLBACK_GREETING_RE = /^(?:hello!?|hi!?|hey!?)\s*(?:how can i assist|how can i help|what would you like|whether you'?re looking to build)/i;
/** System-prompt fragments leaked when the model falls back without real context. */
const SYSTEM_PROMPT_LEAK_RE = /avoid global namespace pollution unless explicitly needed|minify assets only when explicitly requested|include proper accessibility attributes \(aria-label/i;
export function isExecutorTimeoutFailure(liveOutcome) {
    const errorText = String(liveOutcome.executorError || '').trim();
    return /executor llm call timed out|fast fallback also failed|executor model timed out/i.test(errorText);
}
export function isInferenceDegradedFailure(liveOutcome) {
    const answer = stripAgentThinkingTags(liveOutcome.answerContent || '');
    if (!answer)
        return false;
    return isGenericFallbackAnswer(answer)
        && (liveOutcome.analysisToolsUsed > 0 || liveOutcome.requiresWorkspaceChanges);
}
function looksLikeRawV3EventPayload(text) {
    const trimmed = String(text || '').trim();
    if (!/^[{[]/.test(trimmed))
        return false;
    try {
        const parsed = JSON.parse(trimmed);
        const root = Array.isArray(parsed) ? { events: parsed } : parsed;
        if (!root || typeof root !== 'object')
            return false;
        if (Array.isArray(root.events) && root.events.some((event) => event && typeof event === 'object' && typeof event.type === 'string')) {
            return true;
        }
        return Boolean(root.context_id
            || root.mcp_context_id
            || root.workspace_uri
            || root.execution_surface
            || root.task_id);
    }
    catch {
        return false;
    }
}
/** Strip model thinking blocks and stray closing tags from user-visible answer text. */
export function stripAgentThinkingTags(text) {
    let output = String(text || '');
    if (!output)
        return '';
    output = output.replace(/<\/think>/gi, '</thinking>');
    output = output.replace(/<think>/gi, '<thinking>');
    output = output.replace(/<\/redacted_thinking>/gi, '</thinking>');
    output = output.replace(/<thinking>[\s\S]*?<\/thinking>/gi, '');
    output = output.replace(/<thinking>[\s\S]*$/i, '');
    output = output.replace(/<\/thinking>/gi, '');
    return output.trim();
}
export function isGenericFallbackAnswer(text) {
    const trimmed = stripAgentThinkingTags(text);
    if (!trimmed)
        return true;
    if (GENERIC_FALLBACK_GREETING_RE.test(trimmed))
        return true;
    if (SYSTEM_PROMPT_LEAK_RE.test(trimmed))
        return true;
    if (/^now,?\s+i'?m ready to assist/i.test(trimmed) && trimmed.length < 400)
        return true;
    return false;
}
/** Tool-trace stubs like `[read_file] "index.html"` or `<read_file>…</read_file>` — not a user-facing answer. */
export function isToolEvidenceStubAnswer(text) {
    const trimmed = stripAgentThinkingTags(text);
    if (!trimmed)
        return true;
    if (looksLikeRawV3EventPayload(trimmed))
        return true;
    if (BOOTSTRAP_PLACEHOLDER_RE.test(trimmed))
        return true;
    if (GENERIC_SUMMARY_RE.test(trimmed.replace(/\.\s*\d+\s+tool steps.*$/i, '').trim()))
        return true;
    const lines = trimmed.split('\n').map((line) => line.trim()).filter(Boolean);
    if (lines.length === 0)
        return true;
    const stubLine = /^\[(?:read_file|grep|list_directory|search_files|glob|tool_call)\]/i;
    const xmlToolLine = /^<\/?(?:read_file|grep|list_directory|search_files|glob|tool_call|tool_result|path)\b[^>]*>/i;
    const xmlToolBlockOnly = trimmed
        .replace(/<read_file>\s*<path>[\s\S]*?<\/path>\s*<\/read_file>/gi, '')
        .replace(/<(?:grep|list_directory|search_files|glob|tool_call|tool_result)\b[\s\S]*?<\/(?:grep|list_directory|search_files|glob|tool_call|tool_result)>/gi, '')
        .replace(/\s+/g, '')
        .trim();
    if (!xmlToolBlockOnly)
        return true;
    const filesOnly = /^Files inspected:/i;
    const stubLines = lines.filter((line) => stubLine.test(line) || xmlToolLine.test(line) || filesOnly.test(line)).length;
    if (stubLines === lines.length)
        return true;
    if (stubLines > 0 && stubLines / lines.length >= 0.6 && trimmed.length < 400)
        return true;
    return false;
}
/** True when text looks like a real answer, not an executor/system placeholder. */
export function isSubstantiveAgentAnswer(text) {
    const trimmed = stripAgentThinkingTags(text);
    if (trimmed.length < 80)
        return false;
    if (EXECUTOR_PLACEHOLDER_RE.test(trimmed))
        return false;
    if (/^v3 agent workflow completed\.?$/i.test(trimmed))
        return false;
    if (isGenericFallbackAnswer(trimmed))
        return false;
    if (isToolEvidenceStubAnswer(trimmed))
        return false;
    return true;
}
/** Pick the first substantive answer from response body and/or streamed text. */
export function normalizeAgentAnswerContent(...sources) {
    for (const source of sources) {
        const text = stripAgentThinkingTags(String(source || ''));
        if (isSubstantiveAgentAnswer(text))
            return text;
    }
    return '';
}
/** Process executor_complete / task summary events from the V3 SSE stream. */
export function handleTaskEvent(summary, liveOutcome) {
    const tid = summary.task_id || summary.id;
    const status = String(summary.status || '').toLowerCase();
    if (!liveOutcome.completedTaskIds) {
        liveOutcome.completedTaskIds = new Set();
    }
    if (status === 'completed' || status === 'success') {
        if (tid) {
            const id = String(tid);
            if (liveOutcome.completedTaskIds.has(id))
                return;
            liveOutcome.completedTaskIds.add(id);
            liveOutcome.failedTaskIds.delete(id);
        }
        liveOutcome.tasksSucceeded += 1;
    }
    else if (status === 'failed' || status === 'blocked' || status === 'stalled_error') {
        if (tid) {
            liveOutcome.failedTaskIds.add(String(tid));
        }
        liveOutcome.executorFailed = true;
        if (status === 'stalled_error') {
            liveOutcome.streamAborted = true;
        }
    }
}
const READ_DISCOVERY_TOOLS = new Set([
    'read_file',
    'grep',
    'list_directory',
    'glob',
    'search_files',
    'search_project',
    'list_dir',
    'dir',
    'read',
]);
/** Track read/discovery tool usage for analysis-turn accountability. */
export function noteAnalysisToolUse(toolName, liveOutcome) {
    const normalized = String(toolName || '').trim().toLowerCase();
    if (READ_DISCOVERY_TOOLS.has(normalized)) {
        liveOutcome.analysisToolsUsed += 1;
        if (!LIST_ONLY_DISCOVERY_TOOLS.has(normalized)) {
            liveOutcome.analysisReadToolsUsed += 1;
        }
    }
}
/**
 * Compute the real CLI success verdict.
 * When tasks were planned, ALL must succeed — file changes alone never imply victory.
 */
export function evaluateExecutorSuccess(liveOutcome) {
    const hasFatalError = liveOutcome.executorFailed
        || Boolean(liveOutcome.plannerError)
        || Boolean(liveOutcome.executorError)
        || Boolean(liveOutcome.streamAborted);
    if (liveOutcome.streamAborted && liveOutcome.tasksTotal > 0) {
        const partial = liveOutcome.tasksSucceeded > 0;
        if (isExecutorTimeoutFailure(liveOutcome)) {
            return {
                executorSucceeded: false,
                statusHeadline: partial
                    ? `⚠ ${liveOutcome.tasksSucceeded}/${liveOutcome.tasksTotal} tasks completed — executor model timed out`
                    : `✕ Executor model timed out — 0/${liveOutcome.tasksTotal} tasks completed`,
                uiTheme: 'warning',
            };
        }
        return {
            executorSucceeded: false,
            statusHeadline: partial
                ? `⚠ ${liveOutcome.tasksSucceeded}/${liveOutcome.tasksTotal} tasks completed — connection aborted`
                : `✕ Connection aborted — 0/${liveOutcome.tasksTotal} tasks completed`,
            uiTheme: 'warning',
        };
    }
    if (liveOutcome.tasksTotal > 0 && isExecutorTimeoutFailure(liveOutcome)) {
        const partial = liveOutcome.tasksSucceeded > 0;
        return {
            executorSucceeded: false,
            statusHeadline: partial
                ? `⚠ ${liveOutcome.tasksSucceeded}/${liveOutcome.tasksTotal} tasks completed — executor model timed out`
                : `✕ Executor model timed out — 0/${liveOutcome.tasksTotal} tasks completed`,
            uiTheme: 'error',
        };
    }
    if (hasFatalError && liveOutcome.tasksTotal === 0) {
        return {
            executorSucceeded: false,
            statusHeadline: '✕ Execution Error',
            uiTheme: 'error',
        };
    }
    if (liveOutcome.tasksTotal > 0) {
        const allTasksPassed = liveOutcome.tasksSucceeded === liveOutcome.tasksTotal;
        const partialTasksPassed = liveOutcome.tasksSucceeded > 0;
        const failedCount = liveOutcome.failedTaskIds.size;
        if (allTasksPassed && failedCount === 0 && !liveOutcome.streamAborted) {
            const qualityOnlyPlannerNote = Boolean(liveOutcome.plannerError)
                && /Planner-Executor completed:\s*\d+\s*\/\s*\d+\s+tasks succeeded/i.test(String(liveOutcome.plannerError));
            const recoveredAfterTransientErrors = liveOutcome.executorFailed
                || Boolean(liveOutcome.executorError)
                || qualityOnlyPlannerNote;
            if (!liveOutcome.plannerError || qualityOnlyPlannerNote || recoveredAfterTransientErrors) {
                const qualityNote = qualityOnlyPlannerNote || /Quality (?:audit|blockers)/i.test(String(liveOutcome.plannerError || ''));
                return {
                    executorSucceeded: true,
                    statusHeadline: qualityNote
                        ? `✓ Tasks complete (${liveOutcome.tasksSucceeded}/${liveOutcome.tasksTotal}) — quality audit below target`
                        : `✓ Agent run finished (${liveOutcome.tasksSucceeded}/${liveOutcome.tasksTotal} tasks completed)`,
                    uiTheme: qualityNote ? 'warning' : 'success',
                };
            }
        }
        if (allTasksPassed && !hasFatalError) {
            return {
                executorSucceeded: true,
                statusHeadline: `✓ Agent run finished (${liveOutcome.tasksSucceeded}/${liveOutcome.tasksTotal} tasks completed)`,
                uiTheme: 'success',
            };
        }
        if (partialTasksPassed) {
            return {
                executorSucceeded: false,
                statusHeadline: `⚠ Warning: Partial Run (${liveOutcome.tasksSucceeded}/${liveOutcome.tasksTotal} tasks completed${failedCount ? `, ${failedCount} failed` : ''})`,
                uiTheme: 'warning',
            };
        }
        return {
            executorSucceeded: false,
            statusHeadline: `✕ Failed: 0/${liveOutcome.tasksTotal} tasks completed${liveOutcome.changedFileCount > 0 ? ' (stub writes or stalls detected)' : ''}`,
            uiTheme: 'error',
        };
    }
    // Analysis / verification turns with no planned task graph
    if (!liveOutcome.requiresWorkspaceChanges) {
        const answerText = normalizeAgentAnswerContent(liveOutcome.answerContent);
        const hasSubstantiveAnswer = isSubstantiveAgentAnswer(answerText);
        const hasDeepRead = liveOutcome.analysisReadToolsUsed > 0;
        const meetsDeepAnalysisDepth = !liveOutcome.deepAnalysisRequired
            || (liveOutcome.analysisToolsUsed >= 4
                && liveOutcome.analysisReadToolsUsed >= 3
                && answerText.length >= 700);
        if (isInferenceDegradedFailure(liveOutcome)) {
            return {
                executorSucceeded: false,
                statusHeadline: '✕ Model inference degraded — generic fallback answer, not your question — try /retry',
                uiTheme: 'error',
            };
        }
        if (hasFatalError && !hasSubstantiveAnswer) {
            return {
                executorSucceeded: false,
                statusHeadline: '✕ Analysis failed — no answer produced',
                uiTheme: 'error',
            };
        }
        if (!hasSubstantiveAnswer) {
            if (liveOutcome.analysisToolsUsed > 0) {
                return {
                    executorSucceeded: false,
                    statusHeadline: '⚠ Analysis browsed the workspace but did not answer your question — try /retry',
                    uiTheme: 'warning',
                };
            }
            return {
                executorSucceeded: false,
                statusHeadline: '⚠ Warning: No read tools confirmed — answer may be incomplete',
                uiTheme: 'warning',
            };
        }
        if (!hasDeepRead) {
            return {
                executorSucceeded: false,
                statusHeadline: '⚠ Analysis answer was not verified against source files — try /retry',
                uiTheme: 'warning',
            };
        }
        if (!meetsDeepAnalysisDepth) {
            return {
                executorSucceeded: false,
                statusHeadline: '⚠ Deep analysis was too shallow — retrying needs a project map, multiple file reads, and a structured report',
                uiTheme: 'warning',
            };
        }
        return {
            executorSucceeded: true,
            statusHeadline: '✓ Analysis completed',
            uiTheme: 'success',
        };
    }
    if (isInferenceDegradedFailure(liveOutcome)) {
        return {
            executorSucceeded: false,
            statusHeadline: '✕ Model inference degraded — server could not run the code model — try /retry in a minute',
            uiTheme: 'error',
        };
    }
    const legacySuccess = liveOutcome.workspaceHasOutput && liveOutcome.changedFileCount > 0;
    return {
        executorSucceeded: legacySuccess && !hasFatalError,
        statusHeadline: legacySuccess && !hasFatalError
            ? '✓ Agent run finished'
            : '✕ No validated workspace output',
        uiTheme: legacySuccess && !hasFatalError ? 'success' : 'error',
    };
}
