/**
 * Self-Registration Hook (W2.2 of F-NEW-PRODUCT-AGENT-VISIBILITY-CLUSTER-2026-05-12).
 *
 * Runtime-observed agent discovery: the first time an agent fires a tool
 * call, the hook records its identity and incrementally builds an
 * AgentManifest from observed activity. Complements W2.1 (static project
 * scan) — captures agents that don't show up in a code scan (dynamically
 * instantiated agents, framework-internal agents, agents authored as
 * notebook cells, etc.).
 *
 * Honors Invariant 10 (push-only): hook runs in the customer's process
 * and emits manifest events through an injected sink. We do not poll the
 * customer; the customer pushes events to us via the sink they configure.
 *
 * Idempotent: subsequent calls for an already-registered agent update the
 * observed-tools set but do not re-emit the REGISTERED event.
 *
 * @connexum/ai-governance  F-NEW-PRODUCT-AGENT-SELF-REGISTRATION
 */
/**
 * Per-process registry that observes ActionContext events from PreToolUse
 * hooks and produces / updates AgentManifests.
 */
export class SelfRegistrationHook {
    records = new Map();
    sink;
    defaultLlmProvider;
    constructor(options = {}) {
        this.sink = options.sink ?? (() => undefined);
        this.defaultLlmProvider = options.defaultLlmProvider;
    }
    /**
     * Record a single observed tool call. If the agent is unknown, emit
     * AGENT_REGISTERED. If the tool is new for a known agent, emit
     * AGENT_TOOL_OBSERVED. Otherwise no event is emitted.
     *
     * Always idempotent — safe to call from every PreToolUse fire.
     */
    observe(action) {
        const orgId = action.orgId ?? action.agent?.orgId ?? 'org-unknown';
        const agentName = action.agent?.name ?? 'agent-unknown';
        const key = `${orgId}::${agentName}`;
        const existing = this.records.get(key);
        const ts = action.timestamp ?? new Date().toISOString();
        if (!existing) {
            const tools = new Set([action.toolName]);
            const manifest = {
                agentId: agentName,
                name: agentName,
                tools: Array.from(tools),
                llmProvider: this.defaultLlmProvider,
                hooks: { preToolUse: true, postToolUse: false, postResponse: false },
            };
            this.records.set(key, { manifest, tools });
            this.sink({
                kind: 'AGENT_REGISTERED',
                agentId: agentName,
                orgId,
                tool: action.toolName,
                timestamp: ts,
                manifest,
            });
            return;
        }
        if (existing.tools.has(action.toolName)) {
            // No change — idempotent.
            return;
        }
        existing.tools.add(action.toolName);
        existing.manifest = {
            ...existing.manifest,
            tools: Array.from(existing.tools).sort(),
        };
        this.sink({
            kind: 'AGENT_TOOL_OBSERVED',
            agentId: agentName,
            orgId,
            tool: action.toolName,
            timestamp: ts,
            manifest: existing.manifest,
        });
    }
    /** Mark a hook stage as wired on an agent (PreToolUse/PostToolUse/PostResponse). */
    markHookWired(orgId, agentId, hook) {
        const key = `${orgId}::${agentId}`;
        const record = this.records.get(key);
        if (!record)
            return;
        record.manifest = {
            ...record.manifest,
            hooks: {
                preToolUse: record.manifest.hooks?.preToolUse ?? false,
                postToolUse: record.manifest.hooks?.postToolUse ?? false,
                postResponse: record.manifest.hooks?.postResponse ?? false,
                [hook]: true,
            },
        };
    }
    /** Read a manifest by orgId + agentId. */
    getManifest(orgId, agentId) {
        return this.records.get(`${orgId}::${agentId}`)?.manifest;
    }
    /** List all registered manifests. */
    listManifests() {
        return Array.from(this.records.values()).map((r) => r.manifest);
    }
    /** Clear state (typically for tests or per-test isolation). */
    clear() {
        this.records.clear();
    }
}
//# sourceMappingURL=self-registration-hook.js.map