summaryrefslogtreecommitdiffhomepage
path: root/packages/kernel/src/contracts/extension.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/kernel/src/contracts/extension.ts')
-rw-r--r--packages/kernel/src/contracts/extension.ts338
1 files changed, 169 insertions, 169 deletions
diff --git a/packages/kernel/src/contracts/extension.ts b/packages/kernel/src/contracts/extension.ts
index 4d6cf07..fd1594b 100644
--- a/packages/kernel/src/contracts/extension.ts
+++ b/packages/kernel/src/contracts/extension.ts
@@ -9,11 +9,11 @@
import type { AuthContract } from "./auth.js";
import type {
- EventHandler,
- EventHookDescriptor,
- FilterDescriptor,
- FilterHandler,
- ServiceHandle,
+ EventHandler,
+ EventHookDescriptor,
+ FilterDescriptor,
+ FilterHandler,
+ ServiceHandle,
} from "./hooks.js";
import type { Logger } from "./logging.js";
@@ -32,16 +32,16 @@ export type TrustLevel = "bundled" | "local" | "external";
* discovery, dependency resolution, and the capability gate.
*/
export interface ManifestContributions {
- readonly tools?: readonly string[];
- readonly providers?: readonly string[];
- readonly auth?: readonly string[];
- readonly hooks?: readonly string[];
- readonly routes?: readonly string[];
- readonly commands?: readonly string[];
- readonly services?: readonly string[];
- readonly migrations?: readonly string[];
- readonly scheduledJobs?: readonly string[];
- readonly settings?: readonly string[];
+ readonly tools?: readonly string[];
+ readonly providers?: readonly string[];
+ readonly auth?: readonly string[];
+ readonly hooks?: readonly string[];
+ readonly routes?: readonly string[];
+ readonly commands?: readonly string[];
+ readonly services?: readonly string[];
+ readonly migrations?: readonly string[];
+ readonly scheduledJobs?: readonly string[];
+ readonly settings?: readonly string[];
}
/**
@@ -50,12 +50,12 @@ export interface ManifestContributions {
* declared capability for.
*/
export interface ManifestCapabilities {
- readonly fs?: boolean;
- readonly shell?: boolean;
- readonly network?: boolean;
- readonly secrets?: boolean;
- readonly db?: boolean;
- readonly spawn?: boolean;
+ readonly fs?: boolean;
+ readonly shell?: boolean;
+ readonly network?: boolean;
+ readonly secrets?: boolean;
+ readonly db?: boolean;
+ readonly spawn?: boolean;
}
/**
@@ -64,32 +64,32 @@ export interface ManifestCapabilities {
* compatibility, and enforce the capability gate.
*/
export interface Manifest {
- /** Unique extension identifier (e.g. "tools-fs", "provider-anthropic"). */
- readonly id: string;
+ /** Unique extension identifier (e.g. "tools-fs", "provider-anthropic"). */
+ readonly id: string;
- /** Human-readable display name. */
- readonly name: string;
+ /** Human-readable display name. */
+ readonly name: string;
- /** Extension's own version (semver). */
- readonly version: string;
+ /** Extension's own version (semver). */
+ readonly version: string;
- /** Semver range of kernel API versions this extension is compatible with. */
- readonly apiVersion: string;
+ /** Semver range of kernel API versions this extension is compatible with. */
+ readonly apiVersion: string;
- /** Ids of extensions this one depends on (resolved topologically). */
- readonly dependsOn?: readonly string[];
+ /** Ids of extensions this one depends on (resolved topologically). */
+ readonly dependsOn?: readonly string[];
- /** Activation strategy: "eager" (on boot) or lazy event triggers. */
- readonly activation?: "eager" | string;
+ /** Activation strategy: "eager" (on boot) or lazy event triggers. */
+ readonly activation?: "eager" | string;
- /** What this extension contributes to the system. */
- readonly contributes?: ManifestContributions;
+ /** What this extension contributes to the system. */
+ readonly contributes?: ManifestContributions;
- /** Capabilities this extension requires from the host. */
- readonly capabilities?: ManifestCapabilities;
+ /** Capabilities this extension requires from the host. */
+ readonly capabilities?: ManifestCapabilities;
- /** Trust level — bundled (first-party), local (project), or external. */
- readonly trust: TrustLevel;
+ /** Trust level — bundled (first-party), local (project), or external. */
+ readonly trust: TrustLevel;
}
// --- Storage interface ---
@@ -100,40 +100,40 @@ export interface Manifest {
* only the contract. Supports key-value and simple query operations.
*/
export interface StorageNamespace {
- readonly get: (key: string) => Promise<string | null>;
- readonly set: (key: string, value: string) => Promise<void>;
- readonly delete: (key: string) => Promise<void>;
- readonly has: (key: string) => Promise<boolean>;
- readonly keys: (prefix?: string) => Promise<readonly string[]>;
+ readonly get: (key: string) => Promise<string | null>;
+ readonly set: (key: string, value: string) => Promise<void>;
+ readonly delete: (key: string) => Promise<void>;
+ readonly has: (key: string) => Promise<boolean>;
+ readonly keys: (prefix?: string) => Promise<readonly string[]>;
}
// --- Permission ---
/** The outcome of a permission check. */
export interface PermissionDecision {
- readonly allowed: boolean;
- readonly reason?: string;
+ readonly allowed: boolean;
+ readonly reason?: string;
}
/** A request to check whether an action is permitted. */
export interface PermissionRequest {
- readonly tool: string;
- readonly action: string;
- readonly context?: Readonly<Record<string, unknown>>;
+ readonly tool: string;
+ readonly action: string;
+ readonly context?: Readonly<Record<string, unknown>>;
}
/** Permission gate exposed through the Host API. */
export interface PermissionGate {
- readonly check: (request: PermissionRequest) => Promise<PermissionDecision>;
+ readonly check: (request: PermissionRequest) => Promise<PermissionDecision>;
}
// --- Scheduler ---
/** A scheduled job definition an extension can register with the host. */
export interface ScheduledJob {
- readonly id: string;
- readonly cron: string;
- readonly execute: () => void | Promise<void>;
+ readonly id: string;
+ readonly cron: string;
+ readonly execute: () => void | Promise<void>;
}
// --- Logger is re-exported from logging.ts (structured, correlated) ---
@@ -142,24 +142,24 @@ export interface ScheduledJob {
/** Read-only config access for an extension's own settings namespace. */
export interface ConfigAccess {
- readonly get: <T = unknown>(key: string) => T | undefined;
- readonly getAll: () => Readonly<Record<string, unknown>>;
+ readonly get: <T = unknown>(key: string) => T | undefined;
+ readonly getAll: () => Readonly<Record<string, unknown>>;
}
// --- Secrets ---
/** Capability-gated access to the secret/credential vault. */
export interface SecretsAccess {
- readonly get: (key: string) => Promise<string | null>;
- readonly set: (key: string, value: string) => Promise<void>;
- readonly delete: (key: string) => Promise<void>;
+ readonly get: (key: string) => Promise<string | null>;
+ readonly set: (key: string, value: string) => Promise<void>;
+ readonly delete: (key: string) => Promise<void>;
}
// --- Events emitter ---
/** Outward event emitter available to extensions via the Host API. */
export interface EventsEmitter {
- readonly emit: (event: { readonly type: string; readonly [key: string]: unknown }) => void;
+ readonly emit: (event: { readonly type: string; readonly [key: string]: unknown }) => void;
}
// --- Host API ---
@@ -175,102 +175,102 @@ export interface EventsEmitter {
* module (not the kernel contracts).
*/
export interface HostAPI {
- /** Register a tool with the kernel's tool registry. */
- readonly defineTool: (tool: ToolContract) => void;
-
- /** Register a provider with the kernel's provider registry. */
- readonly defineProvider: (provider: ProviderContract) => void;
-
- /** Register an auth provider with the kernel's auth registry. */
- readonly defineAuth: (auth: AuthContract) => void;
-
- /** Subscribe to an event hook. Handlers are error-isolated per call. */
- readonly on: <TPayload>(
- hook: EventHookDescriptor<TPayload>,
- handler: EventHandler<TPayload>,
- ) => () => void;
-
- /**
- * Emit an event hook: fire-and-forget dispatch to every `on` subscriber,
- * error-isolated per handler (a thrown handler is caught + logged, never
- * breaks the caller). The counterpart of `on`.
- *
- * This lets a core extension that OWNS a lifecycle publish typed events that
- * standard extensions react to — e.g. the session-orchestrator emitting
- * per-turn start/settle events a cache-warming extension subscribes to. The
- * kernel owns the mechanism; the owner declares the typed `EventHookDescriptor`.
- */
- readonly emit: <TPayload>(hook: EventHookDescriptor<TPayload>, payload: TPayload) => void;
-
- /** Add a filter to a filter hook chain. Filters are awaited in-band. */
- readonly addFilter: <TValue>(
- hook: FilterDescriptor<TValue>,
- fn: FilterHandler<TValue>,
- ) => () => void;
-
- /**
- * Run a filter chain: thread `value` through every filter registered for
- * `hook` in priority/registration order and return the final value. The
- * single-value-in/value-out counterpart to `addFilter`. Awaited in-band.
- *
- * Fail-open by default (a thrown filter is logged and the value passes
- * through unchanged); pass `{ failClosed: true }` to make a thrown filter
- * reject. With no registered filters the input value is returned as-is.
- *
- * This is what lets a core extension expose a contribution point (e.g. the
- * session-orchestrator running a per-turn tool/context-assembly chain) that
- * standard extensions plug into via `addFilter` — the kernel owns the
- * mechanism, the owner declares the typed `FilterDescriptor`.
- */
- readonly applyFilters: <TValue>(
- hook: FilterDescriptor<TValue>,
- value: TValue,
- opts?: { readonly failClosed?: boolean },
- ) => Promise<TValue>;
-
- /** Provide an implementation for a typed service handle. */
- readonly provideService: <T>(handle: ServiceHandle<T>, impl: T) => void;
-
- /** Retrieve the implementation for a typed service handle. */
- readonly getService: <T>(handle: ServiceHandle<T>) => T;
-
- /** Get a namespaced storage interface for this extension. */
- readonly storage: (namespace: string) => StorageNamespace;
-
- /** Read-only access to merged config (global → project → extension). */
- readonly config: ConfigAccess;
-
- /** Capability-gated access to the secret/credential vault. */
- readonly secrets: SecretsAccess;
-
- /** Permission gate — check whether an action is allowed. */
- readonly permissions: PermissionGate;
-
- /** Emit outward events (transport pushes these to clients). */
- readonly events: EventsEmitter;
-
- /** Logger — always available, even before other extensions activate. */
- readonly logger: Logger;
-
- /** Read-only view of all registered providers. */
- readonly getProviders: () => ReadonlyMap<string, ProviderContract>;
-
- /** Read-only view of all registered tools. */
- readonly getTools: () => ReadonlyMap<string, ToolContract>;
-
- /** Read-only view of all registered auth providers. */
- readonly getAuthProviders: () => ReadonlyMap<string, AuthContract>;
-
- /** Look up a single auth provider by id. */
- readonly getAuthProvider: (id: string) => AuthContract | undefined;
-
- /** Read-only view of all activated extensions' manifests (what is loaded). */
- readonly getExtensions: () => readonly Manifest[];
-
- /** Register a scheduled job with the host's scheduler. */
- readonly scheduler: {
- readonly register: (job: ScheduledJob) => void;
- };
+ /** Register a tool with the kernel's tool registry. */
+ readonly defineTool: (tool: ToolContract) => void;
+
+ /** Register a provider with the kernel's provider registry. */
+ readonly defineProvider: (provider: ProviderContract) => void;
+
+ /** Register an auth provider with the kernel's auth registry. */
+ readonly defineAuth: (auth: AuthContract) => void;
+
+ /** Subscribe to an event hook. Handlers are error-isolated per call. */
+ readonly on: <TPayload>(
+ hook: EventHookDescriptor<TPayload>,
+ handler: EventHandler<TPayload>,
+ ) => () => void;
+
+ /**
+ * Emit an event hook: fire-and-forget dispatch to every `on` subscriber,
+ * error-isolated per handler (a thrown handler is caught + logged, never
+ * breaks the caller). The counterpart of `on`.
+ *
+ * This lets a core extension that OWNS a lifecycle publish typed events that
+ * standard extensions react to — e.g. the session-orchestrator emitting
+ * per-turn start/settle events a cache-warming extension subscribes to. The
+ * kernel owns the mechanism; the owner declares the typed `EventHookDescriptor`.
+ */
+ readonly emit: <TPayload>(hook: EventHookDescriptor<TPayload>, payload: TPayload) => void;
+
+ /** Add a filter to a filter hook chain. Filters are awaited in-band. */
+ readonly addFilter: <TValue>(
+ hook: FilterDescriptor<TValue>,
+ fn: FilterHandler<TValue>,
+ ) => () => void;
+
+ /**
+ * Run a filter chain: thread `value` through every filter registered for
+ * `hook` in priority/registration order and return the final value. The
+ * single-value-in/value-out counterpart to `addFilter`. Awaited in-band.
+ *
+ * Fail-open by default (a thrown filter is logged and the value passes
+ * through unchanged); pass `{ failClosed: true }` to make a thrown filter
+ * reject. With no registered filters the input value is returned as-is.
+ *
+ * This is what lets a core extension expose a contribution point (e.g. the
+ * session-orchestrator running a per-turn tool/context-assembly chain) that
+ * standard extensions plug into via `addFilter` — the kernel owns the
+ * mechanism, the owner declares the typed `FilterDescriptor`.
+ */
+ readonly applyFilters: <TValue>(
+ hook: FilterDescriptor<TValue>,
+ value: TValue,
+ opts?: { readonly failClosed?: boolean },
+ ) => Promise<TValue>;
+
+ /** Provide an implementation for a typed service handle. */
+ readonly provideService: <T>(handle: ServiceHandle<T>, impl: T) => void;
+
+ /** Retrieve the implementation for a typed service handle. */
+ readonly getService: <T>(handle: ServiceHandle<T>) => T;
+
+ /** Get a namespaced storage interface for this extension. */
+ readonly storage: (namespace: string) => StorageNamespace;
+
+ /** Read-only access to merged config (global → project → extension). */
+ readonly config: ConfigAccess;
+
+ /** Capability-gated access to the secret/credential vault. */
+ readonly secrets: SecretsAccess;
+
+ /** Permission gate — check whether an action is allowed. */
+ readonly permissions: PermissionGate;
+
+ /** Emit outward events (transport pushes these to clients). */
+ readonly events: EventsEmitter;
+
+ /** Logger — always available, even before other extensions activate. */
+ readonly logger: Logger;
+
+ /** Read-only view of all registered providers. */
+ readonly getProviders: () => ReadonlyMap<string, ProviderContract>;
+
+ /** Read-only view of all registered tools. */
+ readonly getTools: () => ReadonlyMap<string, ToolContract>;
+
+ /** Read-only view of all registered auth providers. */
+ readonly getAuthProviders: () => ReadonlyMap<string, AuthContract>;
+
+ /** Look up a single auth provider by id. */
+ readonly getAuthProvider: (id: string) => AuthContract | undefined;
+
+ /** Read-only view of all activated extensions' manifests (what is loaded). */
+ readonly getExtensions: () => readonly Manifest[];
+
+ /** Register a scheduled job with the host's scheduler. */
+ readonly scheduler: {
+ readonly register: (job: ScheduledJob) => void;
+ };
}
// --- Extension lifecycle ---
@@ -281,18 +281,18 @@ export interface HostAPI {
* `deactivate` is optional and called on shutdown or reload.
*/
export interface Extension {
- /** The extension's manifest — its declaration of identity and capabilities. */
- readonly manifest: Manifest;
-
- /**
- * Called by the host to activate the extension. The extension registers
- * its contributions (tools, providers, hooks, services) through the Host API.
- */
- readonly activate: (host: HostAPI) => void | Promise<void>;
-
- /**
- * Optional cleanup called when the extension is deactivated (shutdown,
- * reload, or auto-disable). Should dispose resources the extension owns.
- */
- readonly deactivate?: () => void | Promise<void>;
+ /** The extension's manifest — its declaration of identity and capabilities. */
+ readonly manifest: Manifest;
+
+ /**
+ * Called by the host to activate the extension. The extension registers
+ * its contributions (tools, providers, hooks, services) through the Host API.
+ */
+ readonly activate: (host: HostAPI) => void | Promise<void>;
+
+ /**
+ * Optional cleanup called when the extension is deactivated (shutdown,
+ * reload, or auto-disable). Should dispose resources the extension owns.
+ */
+ readonly deactivate?: () => void | Promise<void>;
}