import type { CordisContext } from '../types.js'; /** A live tool definition as the tools registry holds it (shape kept loose on purpose). */ export interface ToolDefinitionLike { name?: string; description?: string; parameters?: Record; execute?: (args: Record, exec: unknown) => Promise; [key: string]: unknown; } /** One permission preset row as the `permissionPresets` table stores it. */ export interface PermissionPresetLike { sandbox: string; approval: string; name?: string; description?: string; [key: string]: unknown; } /** The optional dsh modules the facades need, resolved once at boot. */ export interface RegistryModules { /** `@deepseek-ai/dsh-sandbox` — for `ESCALATION_TARGETS`. */ sandbox?: { ESCALATION_TARGETS?: readonly string[]; }; /** `@deepseek-ai/dsh-permission-presets` — for `effectivePermissionPreset`. */ permissionPresets?: { effectivePermissionPreset?: (events: readonly unknown[]) => string | undefined; }; /** * `@deepseek-ai/dsh-settings` — the settings facade DELEGATES to these rather * than reimplementing them. `installSettingsSection` in particular carries * real upstream behaviour (register `base` from the composition entry, point * the source thunk at the resolved scope, fall back to the entry when the * service goes away, all riding the scoped fiber); copying that into a shim * would be a bug farm. */ settings?: { installSettingsSection?: (ctx: unknown, ns: unknown, schema: unknown, entry: unknown, hooks: unknown) => void; settingsNamespace?: (id: string) => unknown; SettingsConflictError?: new (...args: never[]) => Error; }; /** * `@deepseek-ai/dsh-llm` — message-construction helpers are MODULE-level * exports, not service methods, so `services.get('llm')` cannot reach them. */ llm?: import('./llm.js').LlmModule; /** `@deepseek-ai/dsh-tools` — `defineTool` / `ToolArgsError` are module-level. */ tools?: { defineTool?: unknown; ToolArgsError?: unknown; }; /** `@deepseek-ai/dsh-timeout` — `deadline` / `MAX_TIMER_DELAY_MS`. */ timeout?: { deadline?: unknown; MAX_TIMER_DELAY_MS?: number; }; /** `@deepseek-ai/dsh-credentials` — `credentialRef`. */ credentials?: { credentialRef?: unknown; }; /** `@deepseek-ai/dsh-subagent` — `delegationDepthOf`. */ subagent?: { delegationDepthOf?: unknown; }; /** `@deepseek-ai/dsh-compaction-basic` — the `BasicCompactionEngine` base class. */ compaction?: { BasicCompactionEngine?: unknown; }; } /** * Load the optional dsh modules the facades proxy. * * The specifiers are held in variables so TypeScript does not try to resolve * them at build time: dshloader declares no `@deepseek-ai/*` dependency, and * these packages only exist in the dsh runtime that loads the profile. * * @returns whatever resolved; a missing module simply stays `undefined`. */ export declare function preloadRegistryModules(): Promise; /** Tool-registry accessors. */ export interface ToolsRegistryAPI { /** Every registered tool definition; `[]` when the registry shape is unreachable. */ list(): ToolDefinitionLike[]; /** One definition by tool name. */ get(name: string): ToolDefinitionLike | undefined; /** * Run `patcher` over every registered definition now and after every * `tools/change`, so load order between this plugin and the tool plugins does * not matter. * * A definition is handed to a given `id` at most once (a non-enumerable * `Symbol.for` marker on the definition), which is what stops a `tools/change` * storm from wrapping `execute` again and again. * * @param patcher - mutates one live definition; throwing is contained and logged. * @param options.id - stable patch id, used for the once-per-definition marker. * @returns a disposer that stops the replay (already-applied patches stay). */ patchAll(patcher: (def: ToolDefinitionLike) => void, options: { id: string; }): () => void; } /** Sandbox-registry accessors. */ export interface SandboxRegistryAPI { /** The escalation modes escalation tools advertise; `[]` when unreachable. */ escalationTargets(): readonly string[]; /** * Advertise one extra escalation mode (idempotent). * @returns a disposer removing the mode again; a no-op when unreachable. */ addEscalationTarget(mode: string): () => void; } /** Permission-preset registry accessors. */ export interface PermissionPresetsRegistryAPI { /** The live preset table, or `undefined` when the service is absent. */ table(): Record | undefined; /** * Define a preset unless the key already exists (declaration in a * `cordis.patch.yml` layer wins). * @returns a disposer removing only a preset this call actually added. */ define(key: string, preset: PermissionPresetLike): () => void; /** * Fold a session's effective permission-preset key from its event log. * @returns the preset key, or `undefined` when the helper is unavailable. */ effective(events: readonly unknown[]): string | undefined; } /** The `registry` facade exposed on the host API. */ export interface RegistryAPI { tools: ToolsRegistryAPI; sandbox: SandboxRegistryAPI; permissionPresets: PermissionPresetsRegistryAPI; } /** * Build the `ctx.dshLoader.registry` facade. * * @param opts.ctx - the cordis context (services are read lazily, never cached, * so a service arriving later is still picked up). * @param opts.modules - optional dsh modules from {@link preloadRegistryModules}. */ export declare function createRegistryAPI(opts: { ctx: CordisContext; modules?: RegistryModules; }): RegistryAPI;