/**
 * Dynamic Cordis Plugin service: immutable package definitions, one active run
 * per Plugin, human-approved Client activation, and Host/Client invocation.
 * @module @deepseek-ai/dsh-cordis-host-runner
 */
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
    var useValue = arguments.length > 2;
    for (var i = 0; i < initializers.length; i++) {
        value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
    }
    return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
    function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
    var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
    var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
    var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
    var _, done = false;
    for (var i = decorators.length - 1; i >= 0; i--) {
        var context = {};
        for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
        for (var p in contextIn.access) context.access[p] = contextIn.access[p];
        context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
        var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
        if (kind === "accessor") {
            if (result === void 0) continue;
            if (result === null || typeof result !== "object") throw new TypeError("Object expected");
            if (_ = accept(result.get)) descriptor.get = _;
            if (_ = accept(result.set)) descriptor.set = _;
            if (_ = accept(result.init)) initializers.unshift(_);
        }
        else if (_ = accept(result)) {
            if (kind === "field") initializers.unshift(_);
            else descriptor[key] = _;
        }
    }
    if (target) Object.defineProperty(target, contextIn.name, descriptor);
    done = true;
};
import z from '@deepseek-ai/schemastery';
import { createUserMessage } from '@deepseek-ai/dsh-llm';
import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol';
import { isPlugin, normalizeHandler } from "./guard.js";
import { CordisInspectRegistryService } from "./inspect-registry.js";
import { missingServices, startHostHalf } from "./lifecycle.js";
import { DynamicCordisRegistry } from "./registry.js";
import { createSandbox, evaluateHostCode, precheckCode } from "./sandbox.js";
export { CordisInspectRegistryService } from "./inspect-registry.js";
export { HOST_BUILTIN_INSPECTION } from "./sandbox.js";
/**
 * Brand a Host-minted Plugin ID.
 * @param id - opaque identifier minted by the Host registry.
 * @returns the branded Plugin identifier.
 */
export function CordisDynamicPluginId(id) {
    return id;
}
/**
 * Brand a Host-minted Package ID.
 * @param id - opaque identifier minted by the Host registry.
 * @returns the branded Package identifier.
 */
export function CordisDynamicPackageId(id) {
    return id;
}
/**
 * Brand a Host-minted Plugin Run ID.
 * @param id - opaque identifier minted by the Host registry.
 * @returns the branded Plugin Run identifier.
 */
export function CordisDynamicPluginRunId(id) {
    return id;
}
/**
 * Brand a Host-minted approval request ID.
 * @param id - opaque identifier minted by the Host registry.
 * @returns the branded approval request identifier.
 */
export function ApprovalRequestId(id) {
    return id;
}
/** Dynamic Plugin registry and Host-half lifecycle. */
let DynamicCordisRunnerService = (() => {
    let _classSuper = TypertRemoteService;
    let _instanceExtraInitializers = [];
    let _undefineFromPanel_decorators;
    let _runHostHalf_decorators;
    let _getClientCode_decorators;
    let _resolveRequestRun_decorators;
    let _settleUserRun_decorators;
    let _stopFromPanel_decorators;
    let _syncInspectManifest_decorators;
    let _resolveInspectQuery_decorators;
    let _inventory_decorators;
    let _reportRenderFailure_decorators;
    let _reportClientGuardFailure_decorators;
    let _invoke_decorators;
    return class DynamicCordisRunnerService extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _undefineFromPanel_decorators = [Remote('undefineFromPanel')];
            _runHostHalf_decorators = [Remote('runHostHalf')];
            _getClientCode_decorators = [Remote('getClientCode')];
            _resolveRequestRun_decorators = [Remote('resolveRequestRun')];
            _settleUserRun_decorators = [Remote('settleUserRun')];
            _stopFromPanel_decorators = [Remote('stopFromPanel')];
            _syncInspectManifest_decorators = [Remote('syncInspectManifest')];
            _resolveInspectQuery_decorators = [Remote('resolveInspectQuery')];
            _inventory_decorators = [Remote('inventory')];
            _reportRenderFailure_decorators = [Remote('reportRenderFailure')];
            _reportClientGuardFailure_decorators = [Remote('reportClientGuardFailure')];
            _invoke_decorators = [Remote('invoke')];
            __esDecorate(this, null, _undefineFromPanel_decorators, { kind: "method", name: "undefineFromPanel", static: false, private: false, access: { has: obj => "undefineFromPanel" in obj, get: obj => obj.undefineFromPanel }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _runHostHalf_decorators, { kind: "method", name: "runHostHalf", static: false, private: false, access: { has: obj => "runHostHalf" in obj, get: obj => obj.runHostHalf }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _getClientCode_decorators, { kind: "method", name: "getClientCode", static: false, private: false, access: { has: obj => "getClientCode" in obj, get: obj => obj.getClientCode }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _resolveRequestRun_decorators, { kind: "method", name: "resolveRequestRun", static: false, private: false, access: { has: obj => "resolveRequestRun" in obj, get: obj => obj.resolveRequestRun }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _settleUserRun_decorators, { kind: "method", name: "settleUserRun", static: false, private: false, access: { has: obj => "settleUserRun" in obj, get: obj => obj.settleUserRun }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _stopFromPanel_decorators, { kind: "method", name: "stopFromPanel", static: false, private: false, access: { has: obj => "stopFromPanel" in obj, get: obj => obj.stopFromPanel }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _syncInspectManifest_decorators, { kind: "method", name: "syncInspectManifest", static: false, private: false, access: { has: obj => "syncInspectManifest" in obj, get: obj => obj.syncInspectManifest }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _resolveInspectQuery_decorators, { kind: "method", name: "resolveInspectQuery", static: false, private: false, access: { has: obj => "resolveInspectQuery" in obj, get: obj => obj.resolveInspectQuery }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _inventory_decorators, { kind: "method", name: "inventory", static: false, private: false, access: { has: obj => "inventory" in obj, get: obj => obj.inventory }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _reportRenderFailure_decorators, { kind: "method", name: "reportRenderFailure", static: false, private: false, access: { has: obj => "reportRenderFailure" in obj, get: obj => obj.reportRenderFailure }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _reportClientGuardFailure_decorators, { kind: "method", name: "reportClientGuardFailure", static: false, private: false, access: { has: obj => "reportClientGuardFailure" in obj, get: obj => obj.reportClientGuardFailure }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _invoke_decorators, { kind: "method", name: "invoke", static: false, private: false, access: { has: obj => "invoke" in obj, get: obj => obj.invoke }, metadata: _metadata }, null, _instanceExtraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        static inject = ['tools'];
        static Config = z.object({
            vmTimeoutMs: z.number().min(1).default(5000),
        });
        rootCtx = __runInitializers(this, _instanceExtraInitializers);
        registry = new DynamicCordisRegistry();
        inspectRegistry;
        starting = new Map();
        resolved;
        group;
        /** Create the service under the Host composition. */
        constructor(ctx, config) {
            super(ctx, 'dynamicCordisRunner');
            this.rootCtx = ctx;
            this.resolved = config;
            this.inspectRegistry = new CordisInspectRegistryService(ctx);
        }
        /**
         * Define a new Plugin's first Package or append a Package to an existing Plugin.
         * @param request - Session ownership, Plugin selection, metadata, and source code.
         * @returns Host-minted Plugin and Package identities with declared-half metadata.
         */
        define(request) {
            const name = request.name.trim();
            const purpose = request.purpose.trim();
            if (name.length === 0)
                throw new Error('cordis_define needs a non-empty `name`');
            if (purpose.length === 0)
                throw new Error('cordis_define needs a non-empty `purpose`');
            if (request.code.host === undefined && request.code.client === undefined) {
                throw new Error('cordis_define needs `code.host`, `code.client`, or both');
            }
            if (request.code.host !== undefined)
                precheckCode(request.code.host, 'code.host');
            if (request.code.client !== undefined)
                precheckCode(request.code.client, 'code.client');
            let plugin;
            if (request.plugin.kind === 'new') {
                const prefix = request.plugin.idPrefix.trim();
                if (!/^[a-z]{3,6}$/.test(prefix)) {
                    throw new Error('cordis_define `plugin.idPrefix` must contain 3–6 lowercase English letters');
                }
                const pluginId = CordisDynamicPluginId(this.registry.mintPluginId(prefix));
                plugin = {
                    pluginId,
                    sessionId: request.sessionId,
                    packages: new Map(),
                    approvedClientPackages: new Set(),
                    clientVersionUpdatesApproved: false,
                };
                this.registry.add(plugin);
            }
            else {
                const found = this.registry.get(request.plugin.pluginId);
                if (found === undefined || found.sessionId !== request.sessionId) {
                    throw new Error(missingPluginMessage(request.plugin.pluginId));
                }
                plugin = found;
            }
            const packageId = CordisDynamicPackageId(this.registry.mintPackageId());
            const definition = {
                packageId,
                name,
                purpose,
                ...request.code.host === undefined ? {} : { hostCode: request.code.host },
                ...request.code.client === undefined ? {} : { clientCode: request.code.client },
            };
            plugin.packages.set(packageId, definition);
            return {
                pluginId: plugin.pluginId,
                packageId,
                name,
                purpose,
                hasHostHalf: definition.hostCode !== undefined,
                hasClientHalf: definition.clientCode !== undefined,
            };
        }
        /**
         * Remove a Plugin, its active run, and all immutable Packages.
         * @param agent - Agent whose Session must own the Plugin.
         * @param pluginId - Stable Plugin identity to remove.
         * @returns Whether removal succeeded and whether it stopped an active run.
         */
        async undefine(agent, pluginId) {
            const plugin = this.owned(agent, pluginId);
            if (plugin === undefined)
                return { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) };
            const wasRunning = plugin.run !== undefined;
            this.cancelPending(pluginId, `dynamic plugin "${pluginId}" was removed before approval`);
            if (plugin.run !== undefined)
                await this.retract(plugin);
            this.registry.delete(pluginId);
            return { ok: true, wasRunning };
        }
        /**
         * Remove a Plugin from the user panel and queue the resulting state change for the model's next step.
         * @param agent - Agent whose Session owns the Plugin and receives the context.
         * @param pluginId - Stable Plugin identity to remove.
         * @returns Whether removal succeeded and whether it stopped an active run.
         */
        async undefineFromPanel(agent, pluginId) {
            const result = await this.undefine(agent, pluginId);
            if (result.ok) {
                this.injectUserContext(agent, `The user removed Cordis Plugin ${pluginId} and all of its Packages. The Plugin no longer exists.`);
            }
            return result;
        }
        /**
         * Start or update one Package for a model tool call. An unauthorized Client
         * Package waits for approval; Plugin-wide authorization covers later versions.
         * @param agent - Agent whose Session must own the Plugin.
         * @param pluginId - Stable Plugin identity to activate.
         * @param packageId - Immutable Package version to activate.
         * @param mode - Whether to run the current version or switch versions.
         * @param signal - Tool-call cancellation signal while the activation request is being created.
         * @returns The successful activation identity or an actionable refusal.
         */
        async run(agent, pluginId, packageId, mode, signal) {
            const plan = this.resolvePlan(agent, pluginId, packageId, mode);
            if (!plan.ok)
                return plan.response;
            if (signal?.aborted === true) {
                return {
                    ok: false,
                    reason: 'cancelled',
                    message: `the run request for dynamic plugin "${pluginId}" was cancelled before activation`,
                };
            }
            if (this.registry.pendingRequestFor(pluginId) !== undefined) {
                return { ok: false, reason: 'transition-in-flight', message: `dynamic plugin "${pluginId}" already has a pending run request` };
            }
            const attempt = this.createAttempt(plan);
            plan.plugin.nextPackageId = packageId;
            plan.plugin.latestRun = attempt;
            if (plan.definition.clientCode === undefined) {
                const started = await this.activate(plan, undefined, false, attempt);
                if (started.ok)
                    return this.runResponse(plan.plugin, started);
                this.failAttempt(plan.plugin, attempt, 'host-load', started);
                return { ...started, reason: 'host-half-failed' };
            }
            const requestId = ApprovalRequestId(this.registry.mintApprovalRequestId());
            const requiresApproval = !plan.plugin.clientVersionUpdatesApproved
                && !plan.plugin.approvedClientPackages.has(packageId);
            attempt.approvalRequestId = requestId;
            attempt.requiresApproval = requiresApproval;
            attempt.status = requiresApproval ? 'awaiting-approval' : 'starting-host';
            this.registry.armRequest(requestId, {
                agentId: agent.id,
                pluginId,
                packageId,
                pluginRunId: attempt.pluginRunId,
                mode,
                requiresApproval,
            });
            this.ctx.emit('cordis/request-run', {
                requestId,
                agentId: agent.id,
                pluginId,
                packageId,
                mode,
                name: plan.definition.name,
                purpose: plan.definition.purpose,
                requiresApproval,
            });
            return {
                ok: true,
                status: requiresApproval ? 'awaiting-approval' : 'starting',
                pluginId,
                packageId,
                pluginRunId: attempt.pluginRunId,
                mode,
                waitingFor: [],
                ...plan.plugin.currentPackageId === undefined ? {} : { currentPackageId: plan.plugin.currentPackageId },
                nextPackageId: packageId,
            };
        }
        /**
         * Start Host code for an approved request or a direct panel gesture.
         * @param agent - Agent whose Session must own the Plugin.
         * @param pluginId - Stable Plugin identity to activate.
         * @param packageId - Immutable Package version to activate.
         * @param mode - Whether to run the current version or switch versions.
         * @param requestId - Model-driven request identity, or null for a direct user gesture.
         * @param approveFutureVersions - Whether this approval covers later Packages of the same Plugin.
         * @returns The exact Host activation or a failure message.
         */
        async runHostHalf(agent, pluginId, packageId, mode, requestId, approveFutureVersions) {
            const plan = this.resolvePlan(agent, pluginId, packageId, mode, requestId === null);
            if (!plan.ok)
                return { ok: false, message: plan.response.message };
            let attempt;
            if (requestId !== null) {
                const pending = this.registry.peekRequest(requestId);
                if (pending === undefined || pending.pluginId !== pluginId || pending.packageId !== packageId || pending.mode !== mode) {
                    return { ok: false, message: `run request "${requestId}" does not authorize ${pluginId}/${packageId}` };
                }
                const latest = plan.plugin.latestRun;
                const expectedStatus = pending.requiresApproval ? 'awaiting-approval' : 'starting-host';
                if (latest === undefined || latest.pluginRunId !== pending.pluginRunId
                    || (latest.status !== expectedStatus && (!pending.requiresApproval && latest.status !== 'client-pending'))) {
                    return { ok: false, message: `run request "${requestId}" no longer identifies the latest run of ${pluginId}` };
                }
                attempt = latest;
                if (pending.requiresApproval) {
                    plan.plugin.approvedClientPackages.add(packageId);
                    if (approveFutureVersions)
                        plan.plugin.clientVersionUpdatesApproved = true;
                }
            }
            else {
                const pending = this.registry.pendingRequestFor(pluginId);
                if (pending !== undefined)
                    return { ok: false, message: `dynamic plugin "${pluginId}" has pending run request ${pending}` };
                const attached = plan.plugin.run?.packageId === packageId
                    && plan.plugin.latestRun?.pluginRunId === plan.plugin.run.pluginRunId
                    ? plan.plugin.latestRun
                    : undefined;
                attempt = attached ?? this.createAttempt(plan);
                if (attached === undefined) {
                    plan.plugin.nextPackageId = packageId;
                    plan.plugin.latestRun = attempt;
                }
                if (plan.definition.clientCode !== undefined)
                    plan.plugin.approvedClientPackages.add(packageId);
            }
            const attaching = attempt.pluginRunId === plan.plugin.run?.pluginRunId;
            if (!attaching) {
                attempt.status = 'starting-host';
                if (attempt.host.status !== 'absent')
                    attempt.host = { status: 'pending', waitingFor: [] };
            }
            const started = await this.activate(plan, requestId ?? undefined, attaching, attempt);
            if (!started.ok)
                this.failAttempt(plan.plugin, attempt, 'host-load', started);
            return started;
        }
        /**
         * Fetch Client code for the exact active run.
         * @param agent - Agent whose Session must own the Plugin.
         * @param pluginId - Stable Plugin identity to read.
         * @param pluginRunId - Exact active run authorized to receive source.
         * @returns Client source and its Plugin, Package, and run identities.
         */
        getClientCode(agent, pluginId, pluginRunId) {
            const plugin = this.owned(agent, pluginId);
            if (plugin === undefined)
                throw new Error(missingPluginMessage(pluginId));
            const run = plugin.run;
            if (run === undefined || run.pluginRunId !== pluginRunId) {
                throw new Error(`dynamic plugin "${pluginId}" is not running activation "${pluginRunId}"`);
            }
            const definition = plugin.packages.get(run.packageId);
            if (definition?.clientCode === undefined)
                throw new Error(`package "${run.packageId}" has no Client half`);
            return {
                code: definition.clientCode,
                name: definition.name,
                pluginId,
                packageId: run.packageId,
                pluginRunId,
            };
        }
        /**
         * Resolve one model-driven Client activation request.
         * @param requestId - Request identity to settle once.
         * @param resolution - Browser refusal or exact Client activation result.
         * @returns Whether the still-pending request accepted this resolution.
         */
        async resolveRequestRun(requestId, resolution) {
            const pending = this.registry.peekRequest(requestId);
            if (pending === undefined)
                return { accepted: false };
            const plugin = this.registry.get(pending.pluginId);
            if (resolution.ok && plugin?.run?.pluginRunId !== resolution.pluginRunId)
                return { accepted: false };
            if (!resolution.ok && resolution.pluginRunId !== undefined
                && plugin?.run?.pluginRunId !== resolution.pluginRunId)
                return { accepted: false };
            this.registry.claimRequest(requestId);
            const settled = await this.settleActivation(plugin, resolution, requestId);
            this.announceResolved(requestId, resolution, pending.requiresApproval ? undefined : 'completed');
            this.steerRunOutcome(pending, settled);
            return { accepted: true };
        }
        /**
         * Settle a direct panel run after this page loaded or failed its Client half.
         * @param agent - Agent whose Session must own the Plugin.
         * @param pluginId - Stable Plugin identity being settled.
         * @param resolution - Exact Client activation result from the acting page.
         * @returns The committed activation or its failure.
         */
        async settleUserRun(agent, pluginId, resolution) {
            const plugin = this.owned(agent, pluginId);
            if (plugin === undefined)
                return { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) };
            const settled = await this.settleActivation(plugin, resolution);
            this.injectUserRunOutcome(agent, pluginId, settled);
            return settled;
        }
        /**
         * Stop the active run while retaining every Package version.
         * @param agent - Agent whose Session must own the Plugin.
         * @param pluginId - Stable Plugin identity to stop.
         * @returns Success or the reason no run was stopped.
         */
        async stop(agent, pluginId) {
            const plugin = this.owned(agent, pluginId);
            if (plugin === undefined)
                return { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) };
            const pending = this.registry.pendingRequestFor(pluginId);
            if (plugin.run === undefined && pending === undefined) {
                return { ok: false, reason: 'not-running', message: `dynamic plugin "${pluginId}" is not running` };
            }
            if (pending !== undefined)
                this.cancelPending(pluginId, `dynamic plugin "${pluginId}" was stopped before approval`);
            if (plugin.run !== undefined)
                await this.retract(plugin);
            if (plugin.latestRun !== undefined) {
                plugin.latestRun.status = 'stopped';
                if (plugin.latestRun.host.status !== 'absent')
                    plugin.latestRun.host = { status: 'stopped', waitingFor: [] };
                if (plugin.latestRun.client.status !== 'absent')
                    plugin.latestRun.client = { status: 'stopped', waitingFor: [] };
            }
            return { ok: true };
        }
        /**
         * Stop a Plugin from the user panel and queue the resulting state change for the model's next step.
         * @param agent - Agent whose Session owns the Plugin and receives the context.
         * @param pluginId - Stable Plugin identity to stop.
         * @returns Success or the reason no run was stopped.
         */
        async stopFromPanel(agent, pluginId) {
            const result = await this.stop(agent, pluginId);
            if (!result.ok)
                return result;
            const plugin = this.owned(agent, pluginId);
            this.injectUserContext(agent, `The user stopped Cordis Plugin ${pluginId}. Its Packages remain defined; currentPackageId is `
                + `${plugin?.currentPackageId ?? 'none'}.`);
            return result;
        }
        /**
         * Replace the Host mirror of the Client inspect provider directory.
         * @param providers - complete Client provider manifest.
         * @returns null after accepting the manifest.
         */
        syncInspectManifest(providers) {
            this.inspectRegistry.syncClientManifest(providers);
            return null;
        }
        /**
         * Claim one pending Client inspect query with its live result.
         * @param agent - Session that owns the query.
         * @param requestId - exact pending query identity.
         * @param resolution - provider result or structured refusal.
         * @returns whether this answer won the query.
         */
        resolveInspectQuery(agent, requestId, resolution) {
            return this.inspectRegistry.resolveClientQuery(agent, requestId, resolution);
        }
        /**
         * Frame-wide inventory, grouped as one row per stable Plugin.
         * @returns Source-free metadata for every process-local Plugin.
         */
        /* jscpd:ignore-start */
        inventory() {
            return this.registry.all().map(plugin => ({
                pluginId: plugin.pluginId,
                agentId: plugin.sessionId,
                packages: [...plugin.packages.values()].map(definition => ({
                    packageId: definition.packageId,
                    name: definition.name,
                    purpose: definition.purpose,
                    hasHostHalf: definition.hostCode !== undefined,
                    hasClientHalf: definition.clientCode !== undefined,
                })),
                ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId },
                ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId },
                ...plugin.run === undefined ? {} : {
                    activeRun: { pluginRunId: plugin.run.pluginRunId, packageId: plugin.run.packageId },
                },
                ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) },
            }));
        }
        /* jscpd:ignore-end */
        /**
         * Read one Session's Host-rich state for inspection and result rendering.
         * @param agent - Agent whose Session selects visible Plugins.
         * @returns Plugin versions, active runs, Host fibers, and render failures.
         */
        snapshot(agent) {
            return this.registry.ofSession(agent.id).map(plugin => ({
                pluginId: plugin.pluginId,
                ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId },
                ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId },
                packages: [...plugin.packages.values()].map(definition => ({
                    packageId: definition.packageId,
                    name: definition.name,
                    purpose: definition.purpose,
                    hasHostHalf: definition.hostCode !== undefined,
                    hasClientHalf: definition.clientCode !== undefined,
                })),
                ...plugin.run === undefined ? {} : {
                    activeRun: {
                        pluginRunId: plugin.run.pluginRunId,
                        packageId: plugin.run.packageId,
                        ...plugin.run.fiber === undefined ? {} : { fiber: plugin.run.fiber },
                        handlers: [...plugin.run.handlers.keys()],
                        ...plugin.run.renderFailure === undefined ? {} : { renderFailure: plugin.run.renderFailure },
                    },
                },
                ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) },
            }));
        }
        /**
         * Read source-free context for an explicit `@pluginId` user gesture.
         * @param agent - Agent whose Session must own the Plugin.
         * @param pluginId - Stable Plugin identity referenced by the user.
         * @returns The preferred modification base, or undefined when unavailable.
         */
        reference(agent, pluginId) {
            const plugin = this.owned(agent, pluginId);
            if (plugin === undefined)
                return undefined;
            const packageId = plugin.nextPackageId
                ?? plugin.currentPackageId
                ?? [...plugin.packages.keys()].at(-1);
            if (packageId === undefined)
                return undefined;
            const definition = plugin.packages.get(packageId);
            if (definition === undefined)
                return undefined;
            return {
                pluginId,
                packageId,
                name: definition.name,
                purpose: definition.purpose,
                ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId },
                ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId },
                ...plugin.run === undefined ? {} : {
                    activeRun: { pluginRunId: plugin.run.pluginRunId, packageId: plugin.run.packageId },
                },
                ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) },
            };
        }
        /**
         * List source-free Plugin summaries owned by one Session.
         * @param agent - Agent whose Session selects visible Plugins.
         * @returns one summary per Plugin in creation order.
         */
        listPlugins(agent) {
            return this.registry.ofSession(agent.id).map(plugin => this.inspectPlugin(agent, plugin.pluginId));
        }
        /**
         * Inspect one Plugin without returning Package source.
         * @param agent - Agent whose Session must own the Plugin.
         * @param pluginId - stable Plugin identity.
         * @returns version pointers, latest run, and all Package summaries.
         */
        inspectPlugin(agent, pluginId) {
            const plugin = this.owned(agent, pluginId);
            if (plugin === undefined)
                throw new Error(missingPluginMessage(pluginId));
            const reference = this.reference(agent, pluginId);
            if (reference === undefined)
                throw new Error(`dynamic plugin "${pluginId}" has no package`);
            return {
                ...reference,
                packages: [...plugin.packages.values()].map(definition => ({
                    packageId: definition.packageId,
                    name: definition.name,
                    purpose: definition.purpose,
                    hasHostHalf: definition.hostCode !== undefined,
                    hasClientHalf: definition.clientCode !== undefined,
                })),
            };
        }
        /**
         * Read one exact immutable Package and its Host and Client source.
         * @param agent - Agent whose Session must own the Plugin.
         * @param pluginId - Stable Plugin identity that owns the Package.
         * @param packageId - Exact immutable Package identity to inspect.
         * @returns Package metadata, source, and the Plugin's lifecycle pointers.
         */
        inspectPackage(agent, pluginId, packageId) {
            const plugin = this.owned(agent, pluginId);
            if (plugin === undefined)
                throw new Error(missingPluginMessage(pluginId));
            const definition = plugin.packages.get(packageId);
            if (definition === undefined) {
                throw new Error(`dynamic package "${packageId}" does not exist on plugin "${pluginId}"`);
            }
            return {
                pluginId,
                packageId,
                name: definition.name,
                purpose: definition.purpose,
                code: {
                    ...definition.hostCode === undefined ? {} : { host: definition.hostCode },
                    ...definition.clientCode === undefined ? {} : { client: definition.clientCode },
                },
                /* jscpd:ignore-start */
                ...plugin.currentPackageId === undefined ? {} : { currentPackageId: plugin.currentPackageId },
                ...plugin.nextPackageId === undefined ? {} : { nextPackageId: plugin.nextPackageId },
                ...plugin.run === undefined ? {} : {
                    activeRun: { pluginRunId: plugin.run.pluginRunId, packageId: plugin.run.packageId },
                },
                ...plugin.latestRun === undefined ? {} : { latestRun: cloneAttempt(plugin.latestRun) },
                /* jscpd:ignore-end */
            };
        }
        /**
         * Record a post-load render failure for the exact active run.
         * @param agent - Agent whose Session must own the Plugin.
         * @param pluginId - Stable Plugin identity that rendered.
         * @param pluginRunId - Exact active run that produced the failure.
         * @param failure - Slot, message, and entry-retirement result.
         * @returns Null after recording or ignoring a stale report.
         */
        async reportRenderFailure(agent, pluginId, pluginRunId, failure) {
            const plugin = this.owned(agent, pluginId);
            if (plugin?.run?.pluginRunId === pluginRunId) {
                const run = plugin.run;
                const definition = plugin.packages.get(plugin.run.packageId);
                const shouldSteer = run.renderFailure === undefined;
                run.renderFailure = failure;
                const attempt = plugin.latestRun;
                if (attempt?.pluginRunId === pluginRunId) {
                    attempt.error = this.diagnostic(plugin, attempt, 'client-render', failure);
                    attempt.client = { status: 'failed', waitingFor: attempt.client.waitingFor, error: failure.message };
                    attempt.status = 'failed';
                }
                if (definition !== undefined && shouldSteer) {
                    this.steerRenderFailure(agent, plugin, definition, pluginRunId, failure);
                }
            }
            return await Promise.resolve(null);
        }
        /**
         * Report a Client guard rejection that happened after the Package completed activation.
         * @param agent - Agent whose Session must own the Plugin.
         * @param pluginId - Stable Plugin identity whose Client code was rejected.
         * @param pluginRunId - Exact active run that produced the rejection.
         * @param failure - Original guard message and stack.
         * @returns Null after reporting or ignoring a stale/startup failure.
         */
        async reportClientGuardFailure(agent, pluginId, pluginRunId, failure) {
            const plugin = this.owned(agent, pluginId);
            const run = plugin?.run;
            if (plugin !== undefined && run?.pluginRunId === pluginRunId) {
                this.steerGuardFailure(plugin, run, 'Client', failure);
            }
            return await Promise.resolve(null);
        }
        /**
         * Invoke an active Host method while rejecting stale Client runs.
         * @param pluginId - Stable Plugin identity that owns the method.
         * @param pluginRunId - Exact active run authorizing the call.
         * @param method - Registered Host handler name.
         * @param args - JSON argument delivered to the handler.
         * @returns The JSON result or a typed invocation failure.
         */
        async invoke(pluginId, pluginRunId, method, args) {
            const plugin = this.registry.get(pluginId);
            if (plugin === undefined || plugin.run === undefined) {
                return { ok: false, code: 'plugin-not-running', message: `dynamic plugin "${pluginId}" is not running` };
            }
            const run = plugin.run;
            if (run.pluginRunId !== pluginRunId) {
                return { ok: false, code: 'stale-run', message: `activation "${pluginRunId}" is no longer active` };
            }
            const handler = run.handlers.get(method);
            if (handler === undefined) {
                return { ok: false, code: 'method-not-found', message: `dynamic plugin "${pluginId}" registered no Host method "${method}"` };
            }
            try {
                return { ok: true, value: await handler(args) };
            }
            catch (error) {
                const failure = errorDetails(error);
                this.steerHostHandlerFailure(plugin, run, method, failure);
                return { ok: false, code: 'handler-error', ...failure };
            }
        }
        resolvePlan(agent, pluginId, packageId, mode, allowActiveAttach = false) {
            const plugin = this.owned(agent, pluginId);
            if (plugin === undefined)
                return { ok: false, response: { ok: false, reason: 'plugin-missing', message: missingPluginMessage(pluginId) } };
            const definition = plugin.packages.get(packageId);
            if (definition === undefined) {
                return { ok: false, response: { ok: false, reason: 'package-missing', message: `plugin "${pluginId}" has no package "${packageId}"` } };
            }
            const current = plugin.currentPackageId;
            if (mode === 'update' && (current === undefined || current === packageId)) {
                return {
                    ok: false,
                    response: {
                        ok: false,
                        reason: 'invalid-mode',
                        message: current === undefined
                            ? `plugin "${pluginId}" has no successful version yet; start "${packageId}" with mode "run"`
                            : `package "${packageId}" is already current; use mode "run"`,
                    },
                };
            }
            if (mode === 'run' && current !== undefined && current !== packageId) {
                return {
                    ok: false,
                    response: {
                        ok: false,
                        reason: 'invalid-mode',
                        message: `package "${packageId}" differs from current "${current}"; use mode "update"`,
                    },
                };
            }
            if (!allowActiveAttach && this.starting.has(pluginId)) {
                return { ok: false, response: { ok: false, reason: 'transition-in-flight', message: `plugin "${pluginId}" is already starting` } };
            }
            return { ok: true, plugin, definition, mode };
        }
        activate(plan, requestId, allowActiveAttach, attempt) {
            const inFlight = this.starting.get(plan.plugin.pluginId);
            if (inFlight !== undefined)
                return inFlight;
            const starting = this.startFresh(plan, requestId, allowActiveAttach, attempt);
            this.starting.set(plan.plugin.pluginId, starting);
            return starting.finally(() => { this.starting.delete(plan.plugin.pluginId); });
        }
        async startFresh(plan, requestId, allowActiveAttach, attempt) {
            const { plugin, definition, mode } = plan;
            if (allowActiveAttach
                && plugin.run?.packageId === definition.packageId
                && plugin.run.pluginRunId === attempt.pluginRunId) {
                return {
                    ok: true,
                    pluginId: plugin.pluginId,
                    packageId: definition.packageId,
                    pluginRunId: plugin.run.pluginRunId,
                    waitingFor: missingFor(this.ctx, plugin.run),
                    startedHere: false,
                };
            }
            if (plugin.run !== undefined)
                await this.retract(plugin);
            if (mode === 'update' || plugin.currentPackageId === undefined)
                plugin.nextPackageId = definition.packageId;
            const run = {
                pluginRunId: attempt.pluginRunId,
                packageId: definition.packageId,
                handlers: new Map(),
                handlerDisposers: [],
                reportedRuntimeErrors: new Set(),
                ...requestId === undefined ? {} : { startedForRequest: requestId },
            };
            if (definition.hostCode !== undefined) {
                const failure = await this.startHost(plugin, definition.hostCode, run);
                if (failure !== undefined)
                    return { ok: false, ...failure };
            }
            plugin.run = run;
            this.ctx.emit('cordis/dynamic-package', {
                pluginId: plugin.pluginId,
                packageId: definition.packageId,
                pluginRunId: run.pluginRunId,
                name: definition.name,
            });
            attempt.host = {
                status: run.fiber === undefined ? 'absent' : missingFor(this.ctx, run).length === 0 ? 'running' : 'waiting',
                waitingFor: missingFor(this.ctx, run),
            };
            if (definition.clientCode === undefined) {
                this.commitActivation(plugin, run);
            }
            else {
                attempt.status = 'client-pending';
                attempt.client = { status: 'pending', waitingFor: [] };
            }
            return {
                ok: true,
                pluginId: plugin.pluginId,
                packageId: definition.packageId,
                pluginRunId: run.pluginRunId,
                waitingFor: missingFor(this.ctx, run),
                startedHere: true,
            };
        }
        async startHost(plugin, hostCode, run) {
            const handle = (method, fn) => {
                const normalized = normalizeHandler(method, fn);
                run.handlers.set(normalized.method, normalized.handler);
                const dispose = () => {
                    if (run.handlers.get(normalized.method) === normalized.handler)
                        run.handlers.delete(normalized.method);
                };
                run.handlerDisposers.push(dispose);
                return dispose;
            };
            try {
                const sandbox = createSandbox(plugin.pluginId, { handle });
                const evaluated = await evaluateHostCode(sandbox, hostCode, plugin.pluginId, this.resolved.vmTimeoutMs);
                if (!isPlugin(evaluated)) {
                    throw new Error(evaluated === undefined
                        ? 'the Host half returned `undefined` — did you forget `return`?'
                        : 'the Host half must return a Plugin function or an object with apply(ctx)');
                }
                run.fiber = await startHostHalf(this.requireGroup(), evaluated, (error) => { this.steerGuardFailure(plugin, run, 'Host', errorDetails(error)); });
                return undefined;
            }
            catch (error) {
                for (const dispose of run.handlerDisposers.splice(0))
                    dispose();
                return errorDetails(error);
            }
        }
        async settleActivation(plugin, resolution, requestId) {
            if (plugin === undefined)
                return { ok: false, reason: 'plugin-missing', message: 'the dynamic plugin was removed during activation' };
            const attempt = plugin.latestRun;
            if (!resolution.ok) {
                if (resolution.reason === 'rejected') {
                    if (attempt !== undefined) {
                        attempt.status = 'rejected';
                        attempt.error = this.diagnostic(plugin, attempt, 'approval', resolution.message ?? 'the run request was declined');
                        attempt.client = { status: 'stopped', waitingFor: [] };
                    }
                    return { ok: false, reason: 'rejected', message: resolution.message ?? 'the run request was declined' };
                }
                const run = plugin.run;
                const ownsRun = run !== undefined
                    && resolution.pluginRunId === run.pluginRunId
                    && (requestId === undefined || run.startedForRequest === requestId)
                    && resolution.startedHere !== false;
                if (ownsRun)
                    await this.retract(plugin);
                if (attempt !== undefined && (resolution.pluginRunId === undefined || attempt.pluginRunId === resolution.pluginRunId)) {
                    this.failAttempt(plugin, attempt, resolution.reason === 'host-half-failed' ? 'host-apply' : 'client-apply', {
                        message: resolution.message ?? resolution.reason,
                        ...resolution.stack === undefined ? {} : { stack: resolution.stack },
                    });
                }
                return {
                    ok: false,
                    reason: resolution.reason,
                    message: resolution.message ?? resolution.reason,
                    ...resolution.stack === undefined ? {} : { stack: resolution.stack },
                };
            }
            const run = plugin.run;
            if (run === undefined || run.pluginRunId !== resolution.pluginRunId) {
                return { ok: false, reason: 'client-half-failed', message: `activation "${resolution.pluginRunId}" is no longer active` };
            }
            if (attempt !== undefined && attempt.pluginRunId === run.pluginRunId) {
                attempt.client = {
                    status: resolution.waitingFor === undefined || resolution.waitingFor.length === 0 ? 'running' : 'waiting',
                    waitingFor: resolution.waitingFor ?? [],
                };
            }
            this.commitActivation(plugin, run);
            return {
                ...this.runResponse(plugin, {
                    ok: true,
                    pluginId: plugin.pluginId,
                    packageId: run.packageId,
                    pluginRunId: run.pluginRunId,
                    waitingFor: missingFor(this.ctx, run),
                    startedHere: false,
                }),
                ...resolution.waitingFor === undefined ? {} : { clientWaitingFor: resolution.waitingFor },
            };
        }
        commitActivation(plugin, run) {
            plugin.currentPackageId = run.packageId;
            delete plugin.nextPackageId;
            delete run.startedForRequest;
            const attempt = plugin.latestRun;
            if (attempt?.pluginRunId === run.pluginRunId) {
                attempt.status = attempt.host.status === 'waiting' || attempt.client.status === 'waiting' ? 'waiting' : 'running';
                delete attempt.approvalRequestId;
                delete attempt.requiresApproval;
                delete attempt.error;
            }
        }
        runResponse(plugin, started) {
            return {
                ok: true,
                status: 'running',
                pluginId: plugin.pluginId,
                packageId: started.packageId,
                pluginRunId: started.pluginRunId,
                waitingFor: started.waitingFor,
                currentPackageId: started.packageId,
                mode: plugin.latestRun?.pluginRunId === started.pluginRunId ? plugin.latestRun.mode : 'run',
            };
        }
        announceResolved(requestId, resolution, override) {
            const outcome = override ?? (resolution.ok ? 'approved' : resolution.reason === 'rejected' ? 'rejected' : 'failed');
            this.ctx.emit('cordis/request-run-resolved', { requestId, outcome });
        }
        steerRunOutcome(pending, settled) {
            const agents = this.rootCtx.get('agents');
            const agent = agents?.get(pending.agentId);
            if (agent === undefined)
                return;
            const plugin = this.registry.get(pending.pluginId);
            const identity = `${pending.pluginId}/${pending.packageId} (${pending.pluginRunId})`;
            let text;
            if (settled.ok) {
                text = `Cordis ${pending.mode} ${identity} completed successfully. `
                    + `currentPackageId is ${settled.currentPackageId ?? pending.packageId}. Continue using the running Plugin.`;
            }
            else if (settled.reason === 'rejected') {
                text = `The user rejected Cordis ${pending.mode} ${identity}. `
                    + 'Do not request the same activation again unless the user asks.';
            }
            else {
                const returnedStatus = pending.requiresApproval ? 'awaiting-approval' : 'starting';
                text = `Cordis ${pending.mode} ${identity} failed after cordis_run returned ${returnedStatus}: `
                    + `${settled.reason}\n${formatErrorDetails(settled)}\n`
                    + `currentPackageId: ${plugin?.currentPackageId ?? 'none'}\n`
                    + `nextPackageId: ${plugin?.nextPackageId ?? pending.packageId}\n`
                    + 'Inspect the failed Package, correct it on the same Plugin when needed, and retry the activation autonomously.';
            }
            agent.steer(createUserMessage({
                content: [{ type: 'text', text }],
                source: { kind: 'plugin', plugin: 'cordis-host-runner' },
            }));
        }
        steerRenderFailure(agent, plugin, definition, pluginRunId, failure) {
            agent.steer(createUserMessage({
                content: [{
                        type: 'text',
                        text: `Cordis Client UI ${plugin.pluginId}/${definition.packageId} (${pluginRunId}) failed while rendering `
                            + `Slot "${failure.slot}" after activation.\n`
                            + `${formatErrorDetails(failure)}\n`
                            + `entryAbdicated: ${failure.abdicated}\n`
                            + 'Inspect the failed Package, fix the Client code by defining a new Package on the same Plugin, and '
                            + 'activate that Package autonomously with cordis_run mode:"update".',
                    }],
                source: { kind: 'plugin', plugin: 'cordis-host-runner' },
            }));
        }
        steerHostHandlerFailure(plugin, run, method, failure) {
            const reportKey = `Host\u0000handler\u0000${method}\u0000${failure.message}`;
            if (!this.claimRuntimeFailure(plugin, run, reportKey))
                return;
            const agents = this.rootCtx.get('agents');
            const agent = agents?.get(plugin.sessionId);
            if (agent === undefined)
                return;
            agent.steer(createUserMessage({
                content: [{
                        type: 'text',
                        text: `Cordis Host handler ${plugin.pluginId}/${run.packageId} (${run.pluginRunId}) failed when the Client called `
                            + `host.call(${JSON.stringify(method)}).\n`
                            + `${formatErrorDetails(failure)}\n`
                            + 'The Plugin remains running. Inspect this Package, correct the Host code on the same Plugin, and activate '
                            + 'the new Package autonomously with cordis_run mode:"update". If the handler needs a Service, either declare '
                            + 'that Service in the returned Plugin inject list or read it with ctx.get(name) and handle undefined.',
                    }],
                source: { kind: 'plugin', plugin: 'cordis-host-runner' },
            }));
        }
        /* jscpd:ignore-start */
        steerGuardFailure(plugin, run, platform, failure) {
            const reportKey = `${platform}\u0000guard\u0000${failure.message}`;
            if (!this.claimRuntimeFailure(plugin, run, reportKey))
                return;
            const agents = this.rootCtx.get('agents');
            const agent = agents?.get(plugin.sessionId);
            if (agent === undefined)
                return;
            agent.steer(createUserMessage({
                content: [{
                        type: 'text',
                        text: `Cordis ${platform} guard rejected runtime code in ${plugin.pluginId}/${run.packageId} `
                            + `(${run.pluginRunId}) after activation.\n${formatErrorDetails(failure)}\n`
                            + 'The Plugin remains running. Inspect this Package, define a corrected Package on the same Plugin, and '
                            + 'activate it autonomously with cordis_run mode:"update".',
                    }],
                source: { kind: 'plugin', plugin: 'cordis-host-runner' },
            }));
        }
        /* jscpd:ignore-end */
        claimRuntimeFailure(plugin, run, key) {
            const attempt = plugin.latestRun;
            if (plugin.run !== run || attempt?.pluginRunId !== run.pluginRunId
                || (attempt.status !== 'running' && attempt.status !== 'waiting'))
                return false;
            if (run.reportedRuntimeErrors.has(key))
                return false;
            run.reportedRuntimeErrors.add(key);
            return true;
        }
        injectUserRunOutcome(agent, pluginId, settled) {
            const plugin = this.owned(agent, pluginId);
            let text;
            if (settled.ok) {
                text = `The user manually ran Cordis Plugin ${pluginId}, Package ${settled.packageId}, `
                    + `as ${settled.pluginRunId}. The activation succeeded; currentPackageId is ${settled.currentPackageId}.`;
            }
            else {
                const attempt = plugin?.latestRun;
                text = `The user manually ran Cordis Plugin ${pluginId}`
                    + `${attempt === undefined ? '' : `, Package ${attempt.packageId}, as ${attempt.pluginRunId}`}, but it failed: `
                    + `${settled.reason}\n${formatErrorDetails(settled)}\n`
                    + `currentPackageId: ${plugin?.currentPackageId ?? 'none'}\n`
                    + `nextPackageId: ${plugin?.nextPackageId ?? 'none'}`;
            }
            this.injectUserContext(agent, text);
        }
        injectUserContext(agent, text) {
            const agents = this.rootCtx.get('agents');
            if (agents?.get(agent.id) !== agent)
                return;
            agent.inject(createUserMessage({
                content: [{ type: 'text', text }],
                source: { kind: 'plugin', plugin: 'cordis-host-runner' },
            }));
        }
        cancelPending(pluginId, message) {
            const requestId = this.registry.pendingRequestFor(pluginId);
            if (requestId === undefined)
                return;
            const pending = this.registry.claimRequest(requestId);
            if (pending === undefined)
                return;
            const plugin = this.registry.get(pluginId);
            if (plugin?.latestRun?.pluginRunId === pending.pluginRunId) {
                plugin.latestRun.status = 'cancelled';
                plugin.latestRun.error = this.diagnostic(plugin, plugin.latestRun, 'approval', message);
                delete plugin.latestRun.approvalRequestId;
                delete plugin.latestRun.requiresApproval;
            }
            this.announceResolved(requestId, { ok: false, reason: 'rejected' }, 'cancelled');
        }
        createAttempt(plan) {
            return {
                pluginRunId: CordisDynamicPluginRunId(this.registry.mintPluginRunId()),
                packageId: plan.definition.packageId,
                mode: plan.mode,
                status: 'starting-host',
                host: {
                    status: plan.definition.hostCode === undefined ? 'absent' : 'pending',
                    waitingFor: [],
                },
                client: {
                    status: plan.definition.clientCode === undefined ? 'absent' : 'pending',
                    waitingFor: [],
                },
            };
        }
        failAttempt(plugin, attempt, phase, failure) {
            attempt.status = 'failed';
            attempt.error = this.diagnostic(plugin, attempt, phase, failure);
            if (phase.startsWith('host'))
                attempt.host = { status: 'failed', waitingFor: [], error: failure.message };
            else
                attempt.client = { status: 'failed', waitingFor: [], error: failure.message };
        }
        diagnostic(plugin, attempt, phase, failure) {
            const details = typeof failure === 'string' ? { message: failure } : failure;
            return {
                phase,
                ...details,
                pluginId: plugin.pluginId,
                packageId: attempt.packageId,
                pluginRunId: attempt.pluginRunId,
            };
        }
        async retract(plugin) {
            const run = plugin.run;
            if (run === undefined)
                return;
            delete plugin.run;
            for (const dispose of run.handlerDisposers.splice(0))
                dispose();
            if (run.fiber !== undefined)
                await run.fiber.dispose();
            this.ctx.emit('cordis/dynamic-retract', {
                pluginId: plugin.pluginId,
                packageId: run.packageId,
                pluginRunId: run.pluginRunId,
            });
        }
        owned(agent, pluginId) {
            const plugin = this.registry.get(pluginId);
            return plugin?.sessionId === agent.id ? plugin : undefined;
        }
        requireGroup() {
            this.group ??= this.rootCtx.plugin({ name: 'cordis-dynamic', apply: () => { } });
            return this.group;
        }
    };
})();
export { DynamicCordisRunnerService };
function missingFor(ctx, run) {
    return run.fiber === undefined ? [] : missingServices(ctx, run.fiber);
}
function missingPluginMessage(id) {
    return `no dynamic plugin "${id}" in this process — it may have been removed or lost on DSH restart`;
}
function errorDetails(error) {
    if (typeof error !== 'object' || error === null)
        return { message: String(error) };
    const message = 'message' in error && typeof error.message === 'string'
        ? error.message
        : Object.prototype.toString.call(error);
    const stack = 'stack' in error && typeof error.stack === 'string' ? error.stack : undefined;
    return { message, ...stack === undefined ? {} : { stack } };
}
function formatErrorDetails(failure) {
    return `message: ${failure.message}`
        + (failure.stack === undefined ? '' : `\nstack:\n${failure.stack}`);
}
function cloneAttempt(attempt) {
    return {
        ...attempt,
        host: { ...attempt.host, waitingFor: [...attempt.host.waitingFor] },
        client: { ...attempt.client, waitingFor: [...attempt.client.waitingFor] },
        ...attempt.error === undefined ? {} : { error: { ...attempt.error } },
    };
}
export default DynamicCordisRunnerService;
//# sourceMappingURL=index.js.map