/**
 * System prompt construction and project context loading
 */
import { getDocsPath, getExamplesPath, getReadmePath } from "../config.js";
import { getMemoryInstructions } from "./memory-prompt.js";
import { formatSkillsForPrompt } from "./skills.js";
function formatMemoryScope(sources, heading) {
    if (sources.length === 0)
        return "";
    const drebSources = sources.filter((s) => s.source === "dreb");
    const claudeSources = sources.filter((s) => s.source === "claude");
    let out = `\n### ${heading}\n`;
    for (const source of drebSources) {
        out += `\n#### dreb memory (${source.dir}/)\n\n${source.content}\n`;
    }
    if (claudeSources.length > 0) {
        out += `\n#### Claude Code memory (read-only)\n`;
        out += `> **Note:** These memories were written by Claude Code and may reference Claude Code-specific features, tools, or conventions that don't exist in dreb. Treat the content as useful context, but verify any tool names or workflow references.\n`;
        for (const source of claudeSources) {
            out += `\nSource: ${source.dir}/\n\n${source.content}\n`;
        }
    }
    return out;
}
/**
 * Format a dream last-run ISO timestamp as a human-readable relative age.
 * Returns "Never" if timestamp is null.
 * Uses hours for <24h, days otherwise.
 * @param isoTimestamp ISO timestamp string or null
 * @param now Reference date for computing age (default: current time)
 */
export function formatDreamAge(isoTimestamp, now) {
    if (!isoTimestamp)
        return "Never";
    const then = new Date(isoTimestamp);
    if (Number.isNaN(then.getTime()))
        return "Never";
    const reference = now ?? new Date();
    const diffMs = reference.getTime() - then.getTime();
    // Future or zero — treat as just now
    if (diffMs <= 0)
        return "just now";
    const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
    if (diffHours < 1)
        return "less than an hour ago";
    if (diffHours < 24)
        return `${diffHours} ${diffHours === 1 ? "hour" : "hours"} ago`;
    const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
    return `${diffDays} ${diffDays === 1 ? "day" : "days"} ago`;
}
function buildMemorySection(memoryIndexes) {
    if (!memoryIndexes)
        return "";
    // Always include memory instructions so the agent knows the convention
    let section = `\n\n${getMemoryInstructions({ globalMemoryDir: memoryIndexes.globalMemoryDir, projectMemoryDir: memoryIndexes.projectMemoryDir })}`;
    const { global: globalSources, project: projectSources } = memoryIndexes;
    // Append dream last-run age indicator
    const dreamAge = formatDreamAge(memoryIndexes.dreamLastRun);
    if (dreamAge === "Never") {
        section += "\n\nMemory last consolidated: Never";
    }
    else {
        const dateStr = memoryIndexes.dreamLastRun.slice(0, 10);
        section += `\n\nMemory last consolidated: ${dateStr} (${dreamAge})`;
    }
    // Append the actual memory indexes if any exist
    if (globalSources.length > 0 || projectSources.length > 0) {
        section += "\n\n## Current Memory Indexes\n";
        section += formatMemoryScope(globalSources, "Global Memory");
        section += formatMemoryScope(projectSources, "Project Memory");
    }
    return section;
}
/** Build the root security warning section if running as UID 0 */
function buildRootSecuritySection() {
    if (process.getuid?.() !== 0)
        return "";
    return `

## ⚠️ Security: Running as Root

You are running as root (UID 0). You have unrestricted system access. This means:
- **Never** attempt privilege escalation (sudo, doas, su) — you already have full privileges
- Be extremely conservative with file modifications, package installations, and system commands
- Prefer the least-destructive approach for every operation
- If a task could affect system stability, inform the user before proceeding`;
}
/** UI type descriptions for system prompt context */
const UI_DESCRIPTIONS = {
    tui: "Terminal UI (interactive terminal with rich rendering)",
    telegram: "Telegram (mobile messaging app — the user is on their phone so messages may be shorter or have typos, but this doesn't reflect less thought or intent. The user sees tool names and arguments but not tool output/results, so summarize key findings or changes when relevant)",
    rpc: "RPC (programmatic interface — another application is consuming your output)",
    cli: "CLI (non-interactive command line — output will be printed and the process exits)",
    agent: "Subagent (running as a child agent — focus on the task, report results concisely)",
};
/** Format the UI context section for the system prompt */
function formatUiSection(uiType) {
    const description = UI_DESCRIPTIONS[uiType] || uiType;
    return `\nUI: ${description}`;
}
/** Format the git repo state section for the system prompt */
function formatGitStateSection(state) {
    let section = "\n\n## Project state (true at session start only)\n\n";
    section += `- Branch: \`${state.branch}\`\n`;
    section += `- Status: ${state.dirtyCount === 0 ? "clean" : `${state.dirtyCount} uncommitted ${state.dirtyCount === 1 ? "change" : "changes"}`}\n`;
    if (state.recentCommits.length > 0) {
        section += "- Recent commits:\n";
        for (const commit of state.recentCommits) {
            section += `  - \`${commit.hash} — ${commit.subject}\`\n`;
        }
    }
    if (state.recentTags.length > 0) {
        section += "- Recent releases:\n";
        for (const tag of state.recentTags) {
            section += `  - \`${tag.name}\` (${tag.date})\n`;
        }
    }
    if (state.openPRs.length > 0) {
        section += "- Open PRs on this branch:\n";
        for (const pr of state.openPRs) {
            section += `  - PR ${pr.number} — ${pr.title} (${pr.url})\n`;
        }
    }
    return section;
}
/** Build the system prompt with tools, guidelines, and context */
export function buildSystemPrompt(options = {}) {
    const { customPrompt, selectedTools, toolSnippets, promptGuidelines, appendSystemPrompt, cwd, contextFiles: providedContextFiles, skills: providedSkills, } = options;
    const resolvedCwd = cwd ?? process.cwd();
    const promptCwd = resolvedCwd.replace(/\\/g, "/");
    const date = new Date().toISOString().slice(0, 10);
    const appendSection = appendSystemPrompt ? `\n\n${appendSystemPrompt}` : "";
    const contextFiles = providedContextFiles ?? [];
    const skills = providedSkills ?? [];
    if (customPrompt) {
        let prompt = customPrompt;
        if (appendSection) {
            prompt += appendSection;
        }
        // Append project context files
        if (contextFiles.length > 0) {
            prompt += "\n\n# Project Context\n\n";
            prompt += "Project-specific instructions and guidelines:\n\n";
            for (const { path: filePath, content } of contextFiles) {
                prompt += `## ${filePath}\n\n${content}\n\n`;
            }
        }
        // Append skills section (when skill or read tool is available)
        const customPromptHasSkillAccess = !selectedTools || selectedTools.includes("skill") || selectedTools.includes("read");
        if (customPromptHasSkillAccess && skills.length > 0) {
            prompt += formatSkillsForPrompt(skills);
        }
        // Append memory indexes
        prompt += buildMemorySection(options.memoryIndexes);
        // Append git repo state
        if (options.gitRepoState) {
            prompt += formatGitStateSection(options.gitRepoState);
        }
        // Append root security warning if running as UID 0
        prompt += buildRootSecuritySection();
        // Add date and working directory last
        prompt += `\nCurrent date: ${date}`;
        prompt += `\nCurrent working directory: ${promptCwd}`;
        if (options.uiType) {
            prompt += formatUiSection(options.uiType);
        }
        if (options.currentModel) {
            prompt += `\nYou are running on: ${options.currentModel.provider}/${options.currentModel.id}`;
        }
        return prompt;
    }
    // Get absolute paths to documentation and examples
    const readmePath = getReadmePath();
    const docsPath = getDocsPath();
    const examplesPath = getExamplesPath();
    // Build tools list based on selected tools.
    // A tool appears in Available tools only when the caller provides a one-line snippet.
    const tools = selectedTools || [
        "read",
        "bash",
        "edit",
        "write",
        "grep",
        "find",
        "ls",
        "web_search",
        "web_fetch",
        "subagent",
        "wait",
    ];
    const visibleTools = tools.filter((name) => !!toolSnippets?.[name]);
    const toolsList = visibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets[name]}`).join("\n") : "(none)";
    // Build guidelines based on which tools are actually available
    const guidelinesList = [];
    const guidelinesSet = new Set();
    const addGuideline = (guideline) => {
        if (guidelinesSet.has(guideline)) {
            return;
        }
        guidelinesSet.add(guideline);
        guidelinesList.push(guideline);
    };
    const hasBash = tools.includes("bash");
    const hasGrep = tools.includes("grep");
    const hasFind = tools.includes("find");
    const hasLs = tools.includes("ls");
    const hasRead = tools.includes("read");
    const hasSearch = tools.includes("search");
    // File exploration guidelines
    if (hasBash && !hasGrep && !hasFind && !hasLs) {
        addGuideline("Use bash for file operations like ls, rg, find");
    }
    else if (hasBash && (hasGrep || hasFind || hasLs)) {
        if (hasSearch) {
            addGuideline("Start with `search` to explore and understand the codebase. Use grep/find/ls for exact text matches and specific file lookups. Prefer all of these over bash.");
        }
        else {
            addGuideline("Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)");
        }
    }
    for (const guideline of promptGuidelines ?? []) {
        const normalized = guideline.trim();
        if (normalized.length > 0) {
            addGuideline(normalized);
        }
    }
    // Always include these
    addGuideline("Be concise in your responses");
    addGuideline("Show file paths clearly when working with files");
    const guidelines = guidelinesList.map((g) => `- ${g}`).join("\n");
    let prompt = `You are an expert coding assistant operating inside dreb, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.

Available tools:
${toolsList}

In addition to the tools above, you may have access to other custom tools depending on the project.

Guidelines:
${guidelines}

Dreb documentation (read only when the user asks about dreb itself, its SDK, extensions, themes, skills, or TUI):
- Main documentation: ${readmePath}
- Additional docs: ${docsPath}
- Examples: ${examplesPath} (extensions, custom tools, SDK)
- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), dreb packages (docs/packages.md)
- When working on dreb topics, read the docs and examples, and follow .md cross-references before implementing
- Always read dreb .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;
    if (appendSection) {
        prompt += appendSection;
    }
    // Append project context files
    if (contextFiles.length > 0) {
        prompt += "\n\n# Project Context\n\n";
        prompt += "Project-specific instructions and guidelines:\n\n";
        for (const { path: filePath, content } of contextFiles) {
            prompt += `## ${filePath}\n\n${content}\n\n`;
        }
    }
    // Append skills section (when skill or read tool is available)
    const hasSkillAccess = hasRead || tools.includes("skill");
    if (hasSkillAccess && skills.length > 0) {
        prompt += formatSkillsForPrompt(skills);
    }
    // Append memory indexes
    prompt += buildMemorySection(options.memoryIndexes);
    // Append git repo state
    if (options.gitRepoState) {
        prompt += formatGitStateSection(options.gitRepoState);
    }
    // Append root security warning if running as UID 0
    prompt += buildRootSecuritySection();
    // Add date and working directory last
    prompt += `\nCurrent date: ${date}`;
    prompt += `\nCurrent working directory: ${promptCwd}`;
    if (options.uiType) {
        prompt += formatUiSection(options.uiType);
    }
    if (options.currentModel) {
        prompt += `\nYou are running on: ${options.currentModel.provider}/${options.currentModel.id}`;
    }
    return prompt;
}
//# sourceMappingURL=system-prompt.js.map