/**
 * Centralized event logging for agents-cli.
 *
 * Structured JSONL audit logs at ~/.agents/.history/events/YYYY-MM-DD/events.jsonl with
 * lossless numbered gzip rotation at 10 MiB and bounded retention.
 *
 * Features:
 * - Rich metadata: hostname, platform, arch, pid, timezone
 * - Timing helpers: measure operation duration automatically
 * - Truncation: long inputs/outputs are trimmed with ellipsis
 * - Permissions: logs dir is 0700, files are 0600 (owner-only)
 * - Performance tracking: withTiming() wrapper for any async function
 */
import type { ActorKind } from '../actor.js';
export type EventLevel = 'audit' | 'warn' | 'info' | 'debug';
export type EventType = 'agent.run.start' | 'agent.run.end' | 'agent.spawn.start' | 'agent.spawn.end' | 'run.dispatched' | 'run.launch' | 'daemon.start' | 'daemon.stop' | 'daemon.error' | 'daemon.info' | 'routine.start' | 'routine.end' | 'watchdog.action' | 'version.install' | 'version.switch' | 'version.remove' | 'skill.install' | 'skill.remove' | 'browser.launch' | 'browser.close' | 'browser.navigate' | 'browser.screenshot' | 'computer.action' | 'secrets.get' | 'secrets.unlocked' | 'secrets.create' | 'secrets.import' | 'secrets.export' | 'secrets.view' | 'secrets.lease-denied' | 'secrets.lease-expire' | 'secrets.set' | 'secrets.delete' | 'secrets.rename' | 'cloud.dispatch' | 'cloud.complete' | 'cloud.cancel' | 'cloud.message' | 'teams.create' | 'teams.add' | 'teams.start' | 'teams.complete' | 'teams.disband' | 'hook.fire' | 'hook.complete' | 'hook.error' | 'mcp.add' | 'mcp.remove' | 'mcp.register' | 'resource.sync' | 'rotation.resolved' | 'rotation.unresolved' | 'command.start' | 'command.end' | 'perf.timing' | 'session.start' | 'session.end' | 'webhook.received' | 'webhook.authorized' | 'webhook.rejected' | 'webhook.matched' | 'webhook.fired' | 'webhook.failed' | 'webhook.handler.start' | 'webhook.handler.end' | 'plan.created' | 'pr.opened' | 'pr.merged' | 'worktree.created' | 'worktree.removed' | 'commit.created' | 'pushed' | 'subagent.spawned' | 'artifact.created' | 'task.completed' | 'checklist.created' | 'status.posted' | 'file.edited' | 'factory.command' | 'factory.action' | 'factory.uri' | 'factory.launch' | 'friction' | 'error' | 'warn' | 'info' | 'debug';
/** Every known event kind. Derived from {@link EVENT_TYPE_TABLE}, never hand-listed. */
export declare const EVENT_TYPES: readonly EventType[];
/** Runtime guard for an event kind arriving from outside this process. */
export declare function isEventType(value: string): value is EventType;
export declare function levelFor(event: EventType): EventLevel;
export interface EventMeta {
    ts: string;
    tz: string;
    tzName: string;
    hostname: string;
    /**
     * Normalized, joinable device id (`machine-id.ts::machineId()`) — the same key
     * `agents devices`/session-sync use, so an event can be matched to a device.
     * `hostname` is the raw `os.hostname()`; `machineId` is `zion` for `Zion.local`.
     * Optional on the type so legacy records (pre-provenance-floor) and the activity
     * stream still parse; `emit()` always stamps it on the operational log.
     */
    machineId?: string;
    platform: NodeJS.Platform;
    arch: string;
    pid: number;
    ppid: number;
    event: EventType;
    level: EventLevel;
    caller: string;
    session?: string;
    osUser: string;
    transport: 'local' | 'ssh';
    sshClientIp?: string;
    /** Resolved actor id — which human/agent is behind this event (RUSH-2020). */
    actor?: string;
    /** Actor kind (`human`/`agent`). */
    kind?: ActorKind | 'unknown';
}
export interface EventPayload {
    agent?: string;
    version?: string;
    sessionId?: string;
    /** Spawn-time join key (AGENT_LAUNCH_ID) mapping this action to its launch. */
    launchId?: string;
    /** The session that spawned this one (AGENTS_PARENT_SESSION_ID) — lineage edge. */
    parentSessionId?: string;
    cwd?: string;
    /** Top-level command group, e.g. 'teams', 'secrets' — the audit filter key. */
    module?: string;
    /** Full command path, e.g. 'teams create', 'secrets get'. */
    command?: string;
    args?: string[];
    input?: string;
    output?: string;
    prompt_length?: number;
    prompt_sha256?: string;
    durationMs?: number;
    startupMs?: number;
    exitCode?: number;
    status?: string;
    error?: string;
    errorStack?: string;
    [key: string]: unknown;
}
export type EventRecord = EventMeta & EventPayload;
/**
 * Move root-level and interim flat-history event families into dated directories.
 *
 * The common case is a whole-family rename into an empty destination. A
 * Each segment is assigned to the local calendar day of its filesystem mtime;
 * new writes are split by day at source. A partially completed migration keeps
 * the destination active file authoritative and assigns a fresh archive number,
 * so no record is overwritten or silently discarded. The legacy active-file
 * lock serializes this with older installed processes that still append there.
 */
export declare function migrateLegacyEventLogs(userDir?: string): number;
/**
 * Replace a prompt string with length + short SHA so we can correlate runs
 * without persisting the raw text. Returns the fields to spread into a payload.
 */
export declare function redactPrompt(prompt: string | null | undefined): {
    prompt_length?: number;
    prompt_sha256?: string;
};
/**
 * Mask argv entries that look like tokens or secret paths. Preserves structure
 * for debugging but drops the sensitive substring.
 */
export declare function redactArgs(args: string[] | undefined): string[] | undefined;
/**
 * Truncate a string to maxLength, adding ellipsis if truncated.
 * Returns undefined for null/undefined input.
 */
export declare function truncate(str: string | null | undefined, maxLength?: number): string | undefined;
export interface CallerIdentity {
    kind: string;
    session?: string;
}
/** Identify the environment that invoked agents-cli, not the source callsite. */
export declare function detectCaller(env?: NodeJS.ProcessEnv, stdoutIsTTY?: boolean): CallerIdentity;
export declare function emit(event: EventType, payload?: EventPayload, overrides?: {
    ts?: string;
}): void;
/**
 * Async, non-blocking counterpart of {@link emit} for callers on the daemon's
 * shared event loop (PHNX-3695). `emit` acquires the event-log lock with
 * `withFileLock` → `sleepSync` (`Atomics.wait`), which HALTS the loop for up to
 * 30s under contention (a peer appending to the same log). `emitAsync` acquires
 * it with `withFileLockAsync`, so the loop keeps turning. The under-lock body is
 * identical (a µs-scale append + a rare rotate). Best-effort like `emit`: never
 * throws; a caller on a tick fires it and moves on.
 */
export declare function emitAsync(event: EventType, payload?: EventPayload, overrides?: {
    ts?: string;
}): Promise<void>;
/**
 * Convenience wrapper for timed operations.
 * Returns a function to call when the operation completes.
 *
 * @example
 * const done = emitStart('agent.run.start', { agent: 'claude' });
 * // ... do work ...
 * done({ exitCode: 0 }); // emits agent.run.end with durationMs
 */
export declare function emitStart(startEvent: EventType, payload?: EventPayload): (endPayload?: EventPayload) => void;
interface RoutineEndMeta {
    jobName: string;
    runId?: string;
    status: string;
    duration?: number;
    exitCode?: number | null;
    detail?: string;
}
export declare function emitRoutineEnd(meta: RoutineEndMeta): void;
/**
 * Async, non-blocking `routine.end` for the daemon heartbeat tick (PHNX-3695):
 * the reaper (`reapExitedRunningJobs`) runs on the shared event loop, so it emits
 * through {@link emitAsync} rather than the `sleepSync`-locked {@link emit}.
 */
export declare function emitRoutineEndAsync(meta: RoutineEndMeta): Promise<void>;
/**
 * Measure execution time of a synchronous function.
 * Emits a perf.timing event with the duration.
 *
 * @example
 * const result = time('parse-config', () => parseConfig(path));
 */
export declare function time<T>(label: string, fn: () => T, payload?: EventPayload): T;
/**
 * Measure execution time of an async function.
 * Emits a perf.timing event with the duration.
 *
 * @example
 * const result = await timeAsync('fetch-data', () => fetchData(url));
 */
export declare function timeAsync<T>(label: string, fn: () => Promise<T>, payload?: EventPayload): Promise<T>;
/**
 * Create a timing context for measuring multiple phases of an operation.
 * Useful for tracking startup time vs execution time.
 *
 * @example
 * const timer = createTimer('agent.run', { agent: 'claude' });
 * // ... setup work ...
 * timer.mark('startup'); // records startup time
 * // ... main work ...
 * timer.end({ exitCode: 0 }); // records total time and emits event
 */
export declare function createTimer(label: string, payload?: EventPayload): {
    mark: (phase: string) => number;
    end: (endPayload?: EventPayload) => void;
    elapsed: () => number;
};
/**
 * Higher-order function that wraps an async function with timing.
 * The wrapper emits start/end events automatically.
 *
 * @example
 * const timedFetch = withTiming('fetch', fetchData, { service: 'api' });
 * const result = await timedFetch(url);
 */
export declare function withTiming<Args extends unknown[], R>(label: string, fn: (...args: Args) => Promise<R>, basePayload?: EventPayload): (...args: Args) => Promise<R>;
/**
 * Emit a command.start event with CLI args.
 * Returns a done() function to emit command.end with duration.
 *
 * @example
 * // At CLI entry point:
 * const done = emitCommand('run', process.argv.slice(2));
 * // ... execute command ...
 * done({ exitCode: 0 });
 */
export declare function emitCommand(command: string, args?: string[], payload?: EventPayload): (endPayload?: EventPayload) => void;
/**
 * Emit an error event with full details.
 */
export declare function emitError(err: Error | string, payload?: EventPayload): void;
/**
 * Emit a friction event — a structured, point-of-use record of a failure or
 * block the CLI just hit. `surface` is the subsystem (teams, browser, secrets,
 * guard, …); `failureId` is a stable slug that lets the nightly routine group
 * the same failure across sessions (e.g. 'remote-cwd-on-add', 'not-installed').
 */
export declare function emitFriction(surface: string, failureId: string, payload?: EventPayload): void;
export interface RotationResult {
    removedByAge: number;
    removedBySize: number;
    bytesReclaimed: number;
}
/** Apply age retention and the total-size ceiling immediately. */
export declare function rotate(retentionDays?: number, maxStorageBytes?: number): RotationResult;
/**
 * Read events from log files within a date range.
 *
 * @param options - Query options
 * @returns Array of event records
 */
export declare function query(options: {
    startDate?: Date;
    endDate?: Date;
    eventTypes?: EventType[];
    level?: EventLevel;
    agent?: string;
    /** Only events stamped with this session id (payload `sessionId`, the provenance floor). */
    sessionId?: string;
    caller?: string;
    command?: string;
    module?: string;
    /** Only events carrying this bundle name in their payload (e.g. secrets events). */
    bundle?: string;
    limit?: number;
}): EventRecord[];
/**
 * Scan event logs once for a set of session IDs and return browser/computer
 * usage flags for each. O(files) instead of O(N × files) — safe to call
 * outside a SQLite write transaction.
 */
export declare function queryToolUsageForSessions(sessionIds: ReadonlySet<string>): Map<string, {
    usedBrowser: boolean;
    usedComputer: boolean;
}>;
/**
 * Get performance stats for a specific label.
 */
export declare function getTimingStats(label: string, options?: {
    days?: number;
}): {
    count: number;
    avgMs: number;
    minMs: number;
    maxMs: number;
    p50Ms: number;
    p95Ms: number;
} | null;
export interface EventStats {
    totalEvents: number;
    byLevel: Record<string, number>;
    byEvent: Record<string, number>;
    byModule: Record<string, number>;
    byUser: Record<string, number>;
    /** Event counts grouped by resolved actor id (the human/agent behind them). */
    byActor: Record<string, number>;
    fileCount: number;
    totalBytes: number;
}
export declare function stats(options?: {
    days?: number;
}): EventStats;
export declare function getLogsPath(): string;
export declare function _resetForTest(overrideEventsPath?: string, overrideUserAgentsDir?: string): void;
export {};
