/**
 * Unified in-process MCP server for the Amplitude wizard.
 *
 * Provides tools that run locally (secret values never leave the machine):
 * - check_env_keys: Check which env var keys exist in a .env file
 * - set_env_values: Create/update env vars in a .env file
 * - detect_package_manager: Detect the project's package manager(s)
 */
import type { PackageManagerDetector } from './package-manager-detection';
export declare function isAllowedSkillUrl(rawUrl: string): boolean;
export type SkillEntry = {
    id: string;
    name: string;
    downloadUrl: string;
};
export interface SkillMenu {
    categories: Record<string, SkillEntry[]>;
}
/**
 * Fetch the skill menu from a remote skills server (GitHub Releases).
 * Returns parsed data on success, `null` on failure (including timeout —
 * the caller falls back to bundled skills, so silently swallowing a slow
 * network is the correct behavior).
 */
export declare function fetchSkillMenu(skillsBaseUrl: string): Promise<SkillMenu | null>;
/**
 * Download and extract a skill from a remote URL.
 * Installs to `<installDir>/.claude/skills/<id>/`.
 *
 * Hardened against three classes of local-attacker exploit:
 *
 * 1. **Symlink race** — the previous version wrote to a hardcoded path
 *    `/tmp/amplitude-skill-<id>.zip`. A local user could pre-create that
 *    path as a symlink to e.g. `~/.ampli.json`, and `curl -o` would follow
 *    the link and overwrite the OAuth tokens. We now use `mkdtempSync` to
 *    get a unique, mode-0700, unguessable temp directory.
 * 2. **Untrusted host** — the previous version downloaded from any URL the
 *    skill manifest contained. Skills are only ever published by
 *    amplitude/context-hub via GitHub Releases, so we allowlist the
 *    GitHub-owned hosts and reject anything else.
 * 3. **Zip-slip** — naive zip extractors will follow `../../../etc/passwd`
 *    entries straight out of the target dir. We extract into the scratch
 *    tmp dir first, then walk the result and reject any entry whose
 *    resolved real path escapes the scratch root.
 *
 * Cross-platform note: extraction goes through `adm-zip` rather than the
 * `unzip` CLI so this works on Windows (which has no `unzip` by default).
 * `adm-zip`'s API is sync, matching the rest of this function.
 */
export declare function downloadSkill(skillEntry: SkillEntry, installDir: string): {
    success: boolean;
    error?: string;
};
/**
 * Build skill menu from bundled skill directories.
 * Scans skills/<category>/ subdirectories for folders containing SKILL.md.
 * Each subdirectory of skills/ becomes a category (e.g. integration, instrumentation).
 */
export declare function loadBundledSkillMenu(): SkillMenu;
/**
 * Check whether a bundled skill exists on disk by searching across all
 * category subdirectories under skills/. Used to decide whether to pre-stage
 * a skill before the agent runs vs leave integration entry to the agent
 * prompt's on-disk discovery path (`Glob` under `.claude/skills/` — the
 * wizard-tools skill menu tools stay disabled).
 */
export declare function bundledSkillExists(skillId: string): boolean;
/**
 * Pre-stage a deterministic set of skills into the user's `.claude/skills/`
 * directory before the agent runs, so the agent can load them via the Skill
 * tool without having to call load_skill_menu / install_skill in a loop.
 *
 * The constant skills (taxonomy + instrumentation + dashboard) are always
 * the same; the integration skill is resolved per framework via the optional
 * resolver and may be null if no matching skill exists on disk.
 *
 * Returns the list of skill IDs that were successfully staged.
 */
export declare function preStageSkills(installDir: string, integrationSkillId: string | null): {
    staged: string[];
    integrationStaged: boolean;
};
/**
 * Install a bundled skill by copying it to the project's .claude/skills/ dir.
 * Searches across all category subdirectories under skills/.
 */
export declare function installBundledSkill(skillId: string, installDir: string): {
    success: boolean;
    error?: string;
};
/**
 * Filename of the single archived prior report kept in the install dir.
 * Hoisted above WIZARD_GITIGNORE_PATTERNS so the array initializer can
 * reference it — without this hoist, the temporal-dead-zone forces a
 * duplicate string literal which silently drifts. Exported for tests
 * and OutroScreen so the constant doesn't drift downstream either.
 */
export declare const PREVIOUS_SETUP_REPORT_FILENAME = "amplitude-setup-report.previous.md";
/**
 * Patterns the wizard writes into the user's project that should never be
 * committed to git. Kept as a const so `ensureWizardArtifactsIgnored` has a
 * single source of truth for what to add to the user's .gitignore.
 *
 * The list is broader than what `cleanupWizardArtifacts` removes on exit:
 * several entries are kept on disk on purpose (the user-facing setup report,
 * canonical `.amplitude/` metadata, optional legacy dotfiles from older runs)
 * but selected paths should still never be committed.
 *
 * Notes on each entry:
 *   - `.amplitude/dashboard.json` — dashboard URL; often treated as
 *     machine-local. Other `.amplitude/*` files (`events.json`,
 *     `project-binding.json`) are intentionally not gitignored here so teams
 *     can commit metadata when they want.
 *   - `.amplitude-events.json` / `.amplitude-dashboard.json` — legacy paths
 *     from older wizard or skill versions. The wizard writes the canonical
 *     plan under `.amplitude/events.json` (see `persistEventPlan`) but still
 *     reads these when present; keep them gitignored so stray copies never get
 *     committed.
 *   - `amplitude-setup-report.previous.md` — wizard-managed archive of the
 *     prior run's setup report. The CURRENT report
 *     (`amplitude-setup-report.md`) is intentionally NOT gitignored —
 *     many users want to commit it as part of their analytics docs. Only
 *     the archived prior copy is a wizard implementation detail. (PR 316.)
 *   - `.claude/skills/integration-...` — single-use SDK-setup workflows;
 *     removed at end of run. (Pattern is `integration-...slash` in gitignore.)
 *   - The instrumentation/taxonomy skills are kept on disk so users can
 *     invoke them later ("Claude, use the chart-dashboard-plan skill"), but
 *     they're still gitignored — committing them would balloon every PR
 *     diff and surprise users who run `git add .` after the wizard.
 */
export declare const WIZARD_GITIGNORE_PATTERNS: readonly string[];
/**
 * Append the wizard's artifact patterns to `<installDir>/.gitignore`.
 * Idempotent: re-running after the patterns are already present is a no-op.
 * Creates the file if it doesn't exist.
 *
 * Patterns are written in a single contiguous block under a marker comment
 * so future edits / removals can target the block without disturbing the
 * user's other gitignore content. Silent on I/O errors so a gitignore
 * write failure never blocks the wizard run.
 */
export declare function ensureWizardArtifactsIgnored(installDir: string): void;
/**
 * Archive `<installDir>/amplitude-setup-report.md` to a single sibling
 * `amplitude-setup-report.previous.md` if present.
 *
 * Called at the START of a wizard run so the outro screen never advertises
 * a stale report from a previous run (e.g. against a different workspace,
 * or before the user re-authenticated) as if it described THIS run. The
 * fresh report still lands at the canonical `amplitude-setup-report.md`
 * path so existing tooling, CI, and gitignore rules don't need to change.
 *
 * UX choice: we keep exactly ONE prior report, not a timestamped history.
 * Most users want "the latest report" and at most "the one before that"
 * for comparison after a workspace switch. A growing pile of timestamped
 * files (`amplitude-setup-report.2026-04-27T09-16-23.md`, ...) clutters
 * the project root after a handful of runs and adds zero value over the
 * previous-only approach for the typical workflow. If anyone needs a
 * deeper audit trail, git history or CI logs are the right place — not
 * the project root.
 *
 * Silent on I/O errors so a failed archive never blocks the wizard run.
 */
export declare function archiveSetupReportFile(installDir: string): void;
/**
 * Inverse of {@link archiveSetupReportFile}. Restores
 * `amplitude-setup-report.previous.md` back to `amplitude-setup-report.md`
 * if and only if the canonical path is currently absent.
 *
 * This protects against data loss on cancel / error paths: the wizard
 * archives the prior report at run start, but if the run never reaches
 * the conclude phase (Ctrl+C, agent crash, network error, etc.) nothing
 * writes a fresh canonical report. Without this restore, the user is
 * left with NO report at the canonical path — only the archive — which
 * is functionally the same as deleting their previous report.
 *
 * Silent on I/O errors so a failed restore never blocks teardown.
 */
export declare function restoreSetupReportIfMissing(installDir: string): void;
/**
 * Run wizard-artifact cleanup.
 *
 * Currently composes a single step:
 *   - cleanupIntegrationSkills (remove `.claude/skills/integration-*`,
 *     onSuccess only — preserves them on cancel/error so a re-run
 *     doesn't re-download the skill)
 *
 * Notes on what's intentionally PRESERVED on every exit (success, cancel,
 * error):
 *   - `<installDir>/.amplitude/events.json`, `project-binding.json`, and
 *     `dashboard.json` — canonical project metadata. `events.json` is the
 *     authoritative record of the user's confirmed event plan and is reused
 *     across runs for re-instrumentation. `dashboard.json` is gitignored via
 *     `.amplitude/dashboard.json` so machine-local URLs do not pollute commits;
 *     other `.amplitude/*` files may be committed when teams want.
 *   - Legacy `<installDir>/.amplitude-events.json` and
 *     `.amplitude-dashboard.json` when they already exist — the wizard no
 *     longer writes these paths but does not delete them; readers prefer
 *     `.amplitude/` and fall back to legacy for migration.
 *   - `<installDir>/amplitude-setup-report.md` — user-facing summary the
 *     OutroScreen points at. Kept on disk so the user can read it after
 *     exit; the next run overwrites it.
 *   - Instrumentation and taxonomy skills (everything in
 *     `.claude/skills/` that isn't `integration-*`) — users invoke
 *     these later for event discovery and dashboard planning.
 *     `ensureWizardArtifactsIgnored` keeps them out of git.
 *
 * Silent on errors. Safe to call from any exit path; idempotent.
 */
export declare function cleanupWizardArtifacts(installDir: string, options?: {
    onSuccess?: boolean;
}): void;
/**
 * Remove wizard-installed integration skills from `<installDir>/.claude/skills/`.
 *
 * Integration skills are a single-use SDK-setup workflow — they're dead
 * weight once the run completes. Instrumentation and taxonomy skills stay
 * on disk because users can invoke them later for event discovery, chart
 * building, and dashboard planning.
 *
 * Only directories whose name starts with `integration-` are removed; other
 * content under `.claude/skills/` (user-owned skills, instrumentation-*,
 * taxonomy-*) is left alone. Silent on I/O errors so a cleanup failure
 * never blocks the success path.
 */
export declare function cleanupIntegrationSkills(installDir: string): void;
export interface WizardToolsOptions {
    /** Root directory of the project being analyzed */
    workingDirectory: string;
    /** Framework-specific package manager detector */
    detectPackageManager: PackageManagerDetector;
    /**
     * Remote skills server URL (e.g. GitHub Releases base URL).
     * When set, skills are fetched from this URL instead of bundled files.
     * Set via SKILLS_URL env var or pass directly.
     * Example: https://github.com/amplitude/context-hub/releases/latest/download
     */
    skillsBaseUrl?: string;
    /**
     * Returns the StatusReporter for the current agent run. A getter (rather
     * than a direct reference) is used so `createWizardToolsServer` can be
     * called once at process start while the reporter rotates per run/attempt.
     */
    statusReporter?: () => StatusReporter | undefined;
}
/** Structured status / error events emitted by the agent. */
export type StatusKind = 'status' | 'error';
export interface StatusReport {
    kind: StatusKind;
    /**
     * Machine-readable code. For errors, one of the known AgentErrorType values
     * (MCP_MISSING, RESOURCE_MISSING, API_ERROR, RATE_LIMIT, AUTH_ERROR). For
     * status updates, a short identifier like 'skill-loaded' or 'events-drafted'.
     */
    code: string;
    /** Short human-readable detail to surface in the spinner / error outro. */
    detail: string;
}
/** Implemented by the caller (agent-interface) to route status events. */
export interface StatusReporter {
    onStatus(report: StatusReport): void;
    onError(report: StatusReport): void;
}
/**
 * Resolve filePath relative to workingDirectory, rejecting path traversal.
 */
export declare function resolveEnvPath(workingDirectory: string, filePath: string): string;
/**
 * Env file basenames that are often **committed** as shared defaults (Vite,
 * CRA, monorepos). Auto-appending them to `.gitignore` after `set_env_values`
 * breaks those workflows and encourages putting API keys in tracked files.
 * Browser Amplitude keys should live in `*.local` siblings instead.
 */
export declare const SHARED_COMMITTED_ENV_BASENAMES: ReadonlySet<string>;
export declare function shouldSkipAutoGitignoreForEnvBasename(envBasename: string): boolean;
/**
 * Ensure the given env file basename is covered by .gitignore in the working directory.
 * Creates .gitignore if it doesn't exist; appends the entry if missing.
 *
 * Skips shared template names (see {@link SHARED_COMMITTED_ENV_BASENAMES}) so
 * we never gitignore files many repos intentionally track.
 */
export declare function ensureGitignoreCoverage(workingDirectory: string, envFileName: string): void;
/**
 * Parse a .env file's content and return the set of defined key names.
 */
export declare function parseEnvKeys(content: string): Set<string>;
/**
 * Merge key-value pairs into existing .env content.
 * Updates existing keys in-place, appends new keys at the end.
 */
export declare function mergeEnvValues(content: string, values: Record<string, string>): string;
/**
 * Normalize an event name to the canonical Title Case shape mandated by
 * the wizard commandments ("[Noun] [Past-Tense Verb]", 2–5 words, ≤50
 * chars).
 *
 * The system prompt asks the model for Title Case, but the
 * `confirm_event_plan` tool schema historically said "lowercase". When
 * the agent saw both, it sometimes emitted snake_case or all-lowercase
 * names, which then rendered as ugly bullets in the Event Plan viewer
 * and broke chart legends downstream. Rather than reject and force a
 * second prompt round-trip, normalize forgivingly here so the contract
 * is always met regardless of which guidance the model believed.
 *
 * Soft normalization — never throws, never rejects. Returns the name
 * unchanged if it's already correctly shaped; converts snake_case,
 * kebab-case, camelCase, and ALL-LOWERCASE inputs into Title Case.
 *
 * Exported for unit testing.
 */
export declare function normalizeEventName(raw: string): string;
/**
 * Write the canonical event plan to `<workingDirectory>/.amplitude/events.json`
 * using the shape the wizard UI expects: `[{name, description}]`.
 *
 * Does not write the legacy root `.amplitude-events.json` — readers use
 * {@link readLocalEventPlan} which prefers the canonical file and still
 * honors a pre-existing legacy dotfile from older runs.
 *
 * The agent is instructed (via commandments + integration skills) not to
 * write the canonical file itself — the wizard tool is the single writer so
 * the shape cannot drift. Exported for testing.
 *
 * The `.amplitude/` directory is created lazily on first write and is
 * gitignored as a single line.
 *
 * Returns true on success, false on any filesystem error (the caller logs
 * but doesn't fail the tool call over persistence issues).
 */
export declare function persistEventPlan(workingDirectory: string, events: Array<{
    name: string;
    description: string;
}>): boolean;
/**
 * Write the dashboard payload to the canonical
 * `<workingDirectory>/.amplitude/dashboard.json`.
 *
 * Called from the dashboard file-watcher in `agent-interface.ts` whenever a
 * valid dashboard file is detected. Idempotent and silent on errors.
 */
export declare function persistDashboard(workingDirectory: string, content: Record<string, unknown>): boolean;
/**
 * Information the fallback writer needs to produce a minimal report.
 * All fields are optional — the writer degrades gracefully when something
 * isn't available (e.g. the dashboard step never ran, the events file was
 * never persisted, the framework wasn't detected).
 */
export interface FallbackReportContext {
    /** Project root where the report file lands. Required. */
    installDir: string;
    /** Detected integration name (e.g. "nextjs", "vue"). */
    integration?: string | null;
    /** Dashboard URL returned by the Amplitude MCP. */
    dashboardUrl?: string | null;
    /** Workspace / project name shown in Amplitude UI. */
    workspaceName?: string | null;
    /** Environment name (e.g. "production", "development"). */
    envName?: string | null;
}
/**
 * Render a minimal Markdown setup report from session state. Exported so
 * tests can lock down the formatting without going through the filesystem.
 */
export declare function buildFallbackReport(ctx: FallbackReportContext): string;
/**
 * Write `<installDir>/amplitude-setup-report.md` when the canonical
 * path is empty. Safety net for runs where the agent skipped the
 * conclude-phase report (model variance, ran out of turns, mid-run
 * cancel before conclude, etc.).
 *
 * The companion `archiveSetupReportFile()` (run at the start of every
 * run, in PR #316) moves any prior report to
 * `amplitude-setup-report.previous.md`, so the canonical path is
 * guaranteed to either be empty or freshly written by the current run
 * when this function is called. There's no need for mtime / staleness
 * logic — `existsSync` is authoritative.
 *
 * Returns:
 *   - 'agent-wrote'    — agent wrote a fresh report this run; left untouched.
 *   - 'fallback-wrote' — canonical was missing; wrote a stub.
 *   - 'failed'         — write threw (permissions, disk full, etc.).
 *
 * Silent on errors; never throws — the wizard's outcome must not be
 * blocked by a failed report write.
 */
export declare function writeFallbackReportIfMissing(ctx: FallbackReportContext): 'agent-wrote' | 'fallback-wrote' | 'failed';
/**
 * Create the unified in-process MCP server with all wizard tools.
 * Must be called asynchronously because the SDK is an ESM module loaded via dynamic import.
 */
export declare function createWizardToolsServer(options: WizardToolsOptions): Promise<object>;
/** Tool names exposed by the wizard-tools server, for use in allowedTools */
export declare const WIZARD_TOOL_NAMES: string[];
/** Stable server name — used by hooks to namespace `mcp__wizard-tools__*` tool calls. */
export declare const WIZARD_TOOLS_SERVER_NAME = "wizard-tools";
