/**
 * Get the current git branch name.
 * Moved here from cadence.ts and session-memory.ts to deduplicate.
 */
export async function getCurrentBranch() {
    try {
        const proc = Bun.spawn(['git', 'branch', '--show-current'], {
            stdout: 'pipe',
            stderr: 'pipe',
        });
        const stdout = await new Response(proc.stdout).text();
        await proc.exited;
        return stdout.trim() || 'unknown';
    }
    catch {
        return 'unknown';
    }
}
/**
 * Access Agentuity KV storage via CLI.
 * All calls are wrapped in try/catch — returns null on failure.
 */
async function withCliTimeout(promise, proc, timeoutMs) {
    let timer;
    try {
        return await Promise.race([
            promise,
            new Promise((resolve) => {
                timer = setTimeout(() => {
                    proc.kill();
                    resolve(null);
                }, timeoutMs);
            }),
        ]);
    }
    catch {
        return null;
    }
    finally {
        if (timer)
            clearTimeout(timer);
    }
}
async function kvGet(namespace, key) {
    try {
        const proc = Bun.spawn(['agentuity', 'cloud', 'kv', 'get', namespace, key, '--json'], {
            stdout: 'pipe',
            stderr: 'pipe',
        });
        return await withCliTimeout((async () => {
            const output = await new Response(proc.stdout).text();
            const exitCode = await proc.exited;
            if (exitCode !== 0)
                return null;
            return JSON.parse(output);
        })(), proc, 2_000);
    }
    catch {
        return null;
    }
}
async function kvSet(namespace, key, value) {
    try {
        const proc = Bun.spawn(['agentuity', 'cloud', 'kv', 'set', namespace, key, JSON.stringify(value)], { stdout: 'pipe', stderr: 'pipe' });
        const exitCode = await withCliTimeout(proc.exited, proc, 2_000);
        return exitCode === 0;
    }
    catch {
        return false;
    }
}
/**
 * Build the custom compaction prompt for our agent system.
 * This REPLACES the default OpenCode compaction prompt via output.prompt.
 */
export function buildCustomCompactionPrompt(mode) {
    const cadenceSection = mode === 'cadence'
        ? `

## Cadence Loop State
- Loop ID, iteration number, max iterations
- Current phase and what's in progress
- Whether this is a Lead-of-Leads session with child tasks`
        : '';
    return `You are generating a continuation context for a multi-agent coding system (Agentuity Coder). Your summary will be the ONLY context the orchestrating Lead agent has after this compaction. Preserve everything needed for seamless continuation.

## CRITICAL — Preserve These Verbatim
1. The current task/objective (quote the user's original request exactly)
2. Active planning state: current phase, completed phases, next steps, blockers
3. ALL file paths being actively worked on (with role: created/modified/read)
4. Key decisions made and their rationale
5. Any corrections or gotchas discovered during the session
6. Todo list state (what's done, in progress, pending)
7. Descriptions of any images or attachments that appeared in conversation${cadenceSection}

## Structure Your Summary As:

### Active Task
[Verbatim objective + what the agent was doing when compaction fired]

### Planning State
[Phases with status. Include phase notes, not just titles.]

### Key Context
[Decisions, constraints, user preferences, corrections discovered]

### Active Files
[filepath → role (creating/modifying/reading) + what's being done to it]

### Images & Attachments
[Describe any images/screenshots: what they showed, when they appeared, why they mattered]

### Next Steps
[What should happen immediately after compaction resumes]

## Rules
- Use specific file paths, task IDs, phase names — NOT vague references.
- State what tools returned, not just that they were called.
- Prefer completeness over brevity — this is the agent's entire working memory.`;
}
/**
 * Fetch planning state from KV and format as markdown.
 * Returns null if KV is unavailable or no planning state exists.
 */
export async function fetchAndFormatPlanningState(sessionId) {
    try {
        const record = await kvGet('agentuity-opencode-memory', `session:${sessionId}`);
        if (!record || typeof record !== 'object')
            return null;
        const data = record.data ?? record;
        const planning = data.planning;
        if (!planning)
            return null;
        const lines = ['## Planning State (from KV)'];
        if (planning.objective)
            lines.push(`**Objective:** ${planning.objective}`);
        if (planning.current)
            lines.push(`**Current:** ${planning.current}`);
        if (planning.next)
            lines.push(`**Next:** ${planning.next}`);
        const phases = planning.phases;
        if (phases?.length) {
            lines.push('', '### Phases:');
            for (const p of phases) {
                const status = p.status ?? 'unknown';
                const title = p.title ?? p.content ?? 'untitled';
                const notes = p.notes ? ` — ${String(p.notes).slice(0, 100)}` : '';
                lines.push(`- [${status}] ${title}${notes}`);
            }
        }
        const findings = planning.findings;
        if (findings?.length) {
            lines.push('', '### Key Findings:');
            for (const f of findings.slice(0, 5)) {
                lines.push(`- ${String(f).slice(0, 150)}`);
            }
        }
        const errors = planning.errors;
        if (errors?.length) {
            lines.push('', '### Errors to Avoid:');
            for (const e of errors.slice(0, 3)) {
                lines.push(`- ${String(e).slice(0, 150)}`);
            }
        }
        return lines.join('\n');
    }
    catch {
        return null;
    }
}
/**
 * Get image/attachment descriptions from SQLite for compaction context.
 * Returns brief metadata about non-text parts in the conversation.
 */
export function getImageDescriptions(dbReader, sessionId) {
    if (!dbReader?.isAvailable())
        return null;
    try {
        const parts = dbReader.getNonTextParts(sessionId);
        if (!parts.length)
            return null;
        // Filter to image-like parts (not tool calls — those are separate)
        const imageParts = parts.filter((p) => !['tool-invocation', 'tool-result', 'text'].includes(p.type));
        if (!imageParts.length)
            return null;
        const lines = ['## Images & Attachments'];
        for (const part of imageParts.slice(0, 10)) {
            const when = part.timestamp ? ` at ${part.timestamp}` : '';
            lines.push(`- [${part.type}]${when}: message ${part.messageId}`);
        }
        return lines.join('\n');
    }
    catch {
        return null;
    }
}
/**
 * Get recent tool call summaries for compaction context.
 * CONCISE — capped at limit calls, brief descriptions only.
 */
export function getRecentToolCallSummaries(dbReader, sessionId, limit = 5) {
    if (!dbReader?.isAvailable() || limit <= 0)
        return null;
    try {
        const calls = dbReader.getRecentToolCalls(sessionId, limit);
        if (!calls.length)
            return null;
        const lines = ['## Recent Tool Activity'];
        for (const call of calls) {
            const inputBrief = call.input ? ` — ${String(call.input).slice(0, 80)}` : '';
            const outputBrief = call.output ? ` → ${String(call.output).slice(0, 80)}` : '';
            lines.push(`- ${call.toolName}${inputBrief}${outputBrief}`);
        }
        return lines.join('\n');
    }
    catch {
        return null;
    }
}
/**
 * Store a pre-compaction snapshot to KV as a recovery mechanism.
 */
export async function storePreCompactionSnapshot(sessionId, snapshot) {
    try {
        await kvSet('agentuity-opencode-memory', `compaction:snapshot:${sessionId}`, snapshot);
    }
    catch {
        // Silently fail — this is a best-effort recovery mechanism
    }
}
/**
 * Persist Cadence session state to KV for recovery after plugin restart.
 */
export async function persistCadenceStateToKV(sessionId, state) {
    try {
        await kvSet('agentuity-opencode-memory', `cadence:active:${sessionId}`, state);
    }
    catch {
        // Silently fail
    }
}
/**
 * Restore Cadence session state from KV.
 */
export async function restoreCadenceStateFromKV(sessionId) {
    try {
        const state = await kvGet('agentuity-opencode-memory', `cadence:active:${sessionId}`);
        return state;
    }
    catch {
        return null;
    }
}
/**
 * Format compaction diagnostics — brief summary of what was preserved.
 */
export function formatCompactionDiagnostics(stats) {
    const parts = [];
    if (stats.planningPhasesCount > 0)
        parts.push(`${stats.planningPhasesCount} planning phases`);
    if (stats.imageDescriptionsCount > 0)
        parts.push(`${stats.imageDescriptionsCount} image refs`);
    if (stats.toolCallSummariesCount > 0)
        parts.push(`${stats.toolCallSummariesCount} tool calls`);
    if (!parts.length)
        return '';
    return `> **Compaction preserved:** ${parts.join(', ')} (~${stats.estimatedTokens} tokens injected)`;
}
/** Count markdown list items in a string */
export function countListItems(s) {
    if (!s)
        return 0;
    return (s.match(/^- /gm) ?? []).length;
}
//# sourceMappingURL=compaction-utils.js.map