/** * Source-attributed agent export — faithful port of `core/agents_export.py`. * * The single place that turns a directory of `*.l5.yaml` manifests into the * stable, redacted `bourdon.agents/v1` JSON shape the desktop tray consumes. * The `export_agents` MCP tool calls `exportLocalAgents` here (NOT * `L6Store.exportAgents`, which serves the different federated-merge shape). * * Redaction reuses the `@getbourdon/redaction` SSOT — `_safe_native_memory_text` * in Python is a thin wrapper over `redact_text(value, limit=180)`, so the tray * never sees a raw credential regardless of session visibility. `source` / * `source_kind` are stamped by the caller (this machine), never read from the * agent's self-reported manifest. * * EGRESS visibility gate (3-Star audit P0-1): the peer-facing export path passes * `access_level="team"`/`"public"` so PRIVATE session content never crosses the * federation wire. The default `"private"` admits every well-formed session for * the operator's own local tray view. Session visibility is resolved by the * shared `@getbourdon/l5` visibility policy -- the same one every other egress * surface applies -- and an unknown access level throws rather than widening. */ import { type TitleLookup } from "@getbourdon/federation"; export declare const AGENTS_SCHEMA = "bourdon.agents/v1"; export declare const MAX_RECENT_SESSIONS = 10; type Dict = Record; /** * Resolve this machine's label for source attribution. Honors * `BOURDON_LOCAL_NAME` (a deployment can pin a stable, friendly label), else * `os.hostname()`. Computed at call time so tests can override either source. */ export declare function resolveLocalName(): string; /** * Build one redacted, source-attributed summary from a parsed L5 manifest. The * canonical per-agent tray shape plus the two source-attribution fields. */ export declare function summarizeAgentManifest(manifest: Dict, opts: { source: string; sourceKind?: string; accessLevel?: string; }): Dict; /** Partial-failure entry so the tray can represent a broken manifest. */ export declare function errorAgentEntry(agentId: string, message: string, opts: { source: string; sourceKind?: string; }): Dict; /** * Enrich each agent row in place with live-session presence — port of * `_join_live_presence()` in `core/agents_export.py`. * * Adds `live_sessions` (a possibly-empty list of {instance, title, host, * project, started_at, age_s}) and `live_count` to every agent, read from * `~/.bourdon/presence` via `@getbourdon/federation`. Presence is ephemeral and * orthogonal to the durable L5 manifests. Best-effort: a read failure never * sinks the export — every agent just gets `live_count=0`. * * EGRESS GATE (parity with the per-session access gate): presence reveals what * you are actively working on *right now* (project, host). It is emitted for * the local tray (`private`) and for TRUSTED team peers (`team`) — the latter * is what makes the federated cross-machine live-session view work — but NEVER * for a `public`/untrusted caller, who gets `live_count=0` and for whom the * presence directory is not read at all. * * An agent with live sessions but NO L5 manifest yet (registered before its * first export) gets a minimal synthesized row — a running session must never * be invisible in the tray. Synthesized rows carry only the id + live fields * (`session_count` 0, no durable data to show). * * Live sessions carry a human `title` when one can be resolved — see * {@link codexTitleLookup}. The title is redacted on the way out like every * other emitted string. */ /** * Build a `(agentId, sessionId) -> title` resolver for presence — port of * `_codex_title_lookup()` in `core/agents_export.py`. * * Titles come from the Codex/ChatGPT-app `session_index.jsonl` (`thread_name`) * — the app's Work and Codex modes share `~/.codex`, so one lookup covers both. * Only agents whose base id is `codex` are resolved; other agents' session ids * live in other namespaces. The index is read ONCE per export (the closure * captures the map), not once per session. * * Returns `null` (no lookup at all) when the map can't be built or is empty — * presence then behaves exactly as it did before titles existed. * * SECURITY: the resolver receives the FULL session id, which is the whole point * — it is invoked inside `summarize()`, the one place the full id is still in * hand, so a title can be carried out while only the 8-char `instance` prefix * ever egresses. The returned title is RAW USER TEXT and is redacted by the * caller (`attach()` below) before it reaches a peer. */ export declare function codexTitleLookup(): TitleLookup | null; /** * Summarize every local `*.l5.yaml` manifest into the tray envelope. Agents are * sorted by live-now then `last_updated` descending; per-manifest parse failures * are represented inline (`parse_error`) rather than raised, so one broken file * never sinks the whole export. */ export declare function exportLocalAgents(agentsDir: string, localName: string, accessLevel?: string): Dict; export {};