@wrongstack/core 0.2.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/{agent-bridge-DmBiCipY.d.ts → agent-bridge-C3DUGjSb.d.ts} +1 -1
  2. package/dist/{compactor-DSl2FK7a.d.ts → compactor-DpJBI1YH.d.ts} +8 -2
  3. package/dist/{config-DXrqb41m.d.ts → config-D2qvAxVd.d.ts} +39 -2
  4. package/dist/{context-u0bryklF.d.ts → context-IovtuTf8.d.ts} +2 -0
  5. package/dist/coordination/index.d.ts +11 -11
  6. package/dist/coordination/index.js +307 -245
  7. package/dist/coordination/index.js.map +1 -1
  8. package/dist/defaults/index.d.ts +30 -15
  9. package/dist/defaults/index.js +1077 -479
  10. package/dist/defaults/index.js.map +1 -1
  11. package/dist/{events-B6Q03pTu.d.ts → events-BHIQs4o1.d.ts} +34 -1
  12. package/dist/execution/index.d.ts +17 -14
  13. package/dist/execution/index.js +166 -18
  14. package/dist/execution/index.js.map +1 -1
  15. package/dist/extension/index.d.ts +9 -0
  16. package/dist/extension/index.js +241 -0
  17. package/dist/extension/index.js.map +1 -0
  18. package/dist/{plugin-CoYYZKdn.d.ts → index-hWNybrNZ.d.ts} +368 -11
  19. package/dist/index.d.ts +76 -26
  20. package/dist/index.js +1595 -748
  21. package/dist/index.js.map +1 -1
  22. package/dist/infrastructure/index.d.ts +6 -6
  23. package/dist/infrastructure/index.js +191 -20
  24. package/dist/infrastructure/index.js.map +1 -1
  25. package/dist/kernel/index.d.ts +12 -9
  26. package/dist/kernel/index.js +73 -7
  27. package/dist/kernel/index.js.map +1 -1
  28. package/dist/{mcp-servers-BA1Ofmfj.d.ts → mcp-servers-C2OopXOn.d.ts} +21 -5
  29. package/dist/models/index.d.ts +2 -2
  30. package/dist/models/index.js +24 -1
  31. package/dist/models/index.js.map +1 -1
  32. package/dist/{multi-agent-BDfkxL5C.d.ts → multi-agent-B9a6sflH.d.ts} +2 -2
  33. package/dist/observability/index.d.ts +2 -2
  34. package/dist/{path-resolver-Crkt8wTQ.d.ts → path-resolver--59rCou3.d.ts} +2 -2
  35. package/dist/provider-runner-B39miKRw.d.ts +36 -0
  36. package/dist/sdd/index.d.ts +3 -3
  37. package/dist/{secret-scrubber-3TLUkiCV.d.ts → secret-scrubber-CgG2tV2B.d.ts} +1 -1
  38. package/dist/{secret-scrubber-CwYliRWd.d.ts → secret-scrubber-Cuy5afaQ.d.ts} +1 -1
  39. package/dist/security/index.d.ts +3 -3
  40. package/dist/security/index.js +24 -1
  41. package/dist/security/index.js.map +1 -1
  42. package/dist/{selector-BRqzvugb.d.ts → selector-wT2fv9Fg.d.ts} +1 -1
  43. package/dist/{session-reader-C3x96CDR.d.ts → session-reader-CcPi4BQ8.d.ts} +1 -1
  44. package/dist/{skill-Bx8jxznf.d.ts → skill-C_7znCIC.d.ts} +2 -2
  45. package/dist/storage/index.d.ts +7 -6
  46. package/dist/storage/index.js +204 -14
  47. package/dist/storage/index.js.map +1 -1
  48. package/dist/{renderer-0A2ZEtca.d.ts → system-prompt-Dk1qm8ey.d.ts} +30 -2
  49. package/dist/{tool-executor-CYdZdtno.d.ts → tool-executor-HsBLGRaA.d.ts} +5 -5
  50. package/dist/types/index.d.ts +16 -16
  51. package/dist/types/index.js +230 -10
  52. package/dist/types/index.js.map +1 -1
  53. package/dist/utils/index.d.ts +23 -2
  54. package/dist/utils/index.js +117 -2
  55. package/dist/utils/index.js.map +1 -1
  56. package/package.json +5 -1
  57. package/dist/system-prompt-CG9jU5-5.d.ts +0 -31
@@ -1,12 +1,34 @@
1
- import { u as Tool, z as ToolResultBlock, g as Provider, R as Request, j as Response, D as ToolUseBlock, a0 as Context, b as ContentBlock, T as TextBlock, a7 as RunOptions, W as WrongStackError, J as JSONSchema } from './context-u0bryklF.js';
1
+ import { u as Tool, z as ToolResultBlock, T as TextBlock, a0 as Context, R as Request, j as Response, D as ToolUseBlock, g as Provider, W as WrongStackError, b as ContentBlock, a7 as RunOptions, J as JSONSchema } from './context-IovtuTf8.js';
2
+ import { L as Logger } from './logger-BMQgxvdy.js';
3
+ import { R as Renderer, B as BuildContext, C as Container, P as Pipeline, e as ReadonlyPipeline } from './system-prompt-Dk1qm8ey.js';
2
4
  import { T as Tracer } from './observability-BhnVLBLS.js';
3
- import { E as EventBus, a as EventName, L as Listener } from './events-B6Q03pTu.js';
4
- import { R as Renderer, C as Container, P as Pipeline, c as ReadonlyPipeline } from './renderer-0A2ZEtca.js';
5
- import { a as PermissionPolicy, S as SecretScrubber } from './secret-scrubber-3TLUkiCV.js';
6
- import { e as ProviderConfig, C as Config } from './config-DXrqb41m.js';
5
+ import { E as EventBus, a as EventName, L as Listener } from './events-BHIQs4o1.js';
6
+ import { a as PermissionPolicy, S as SecretScrubber } from './secret-scrubber-CgG2tV2B.js';
7
+ import { l as ProviderConfig, a as Config } from './config-D2qvAxVd.js';
7
8
  import { W as WireFamily } from './models-registry-Y2xbog0E.js';
8
- import { L as Logger } from './logger-BMQgxvdy.js';
9
9
 
10
+ /**
11
+ * A function that wraps (decorates) an existing tool. Receives the
12
+ * original tool and returns a modified version — typically the same
13
+ * tool with a wrapped `execute` / `executeStream`, or with modified
14
+ * metadata (description, permission).
15
+ *
16
+ * Use `ToolRegistry.wrap()` to apply; the wrapper is called immediately
17
+ * and the result replaces the registered tool. Multiple wraps stack —
18
+ * each wrapper receives the output of the previous.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * registry.wrap('read', (original) => ({
23
+ * ...original,
24
+ * async execute(input, ctx, opts) {
25
+ * console.log('read called');
26
+ * return original.execute(input, ctx, opts);
27
+ * }
28
+ * }));
29
+ * ```
30
+ */
31
+ type ToolWrapper = (tool: Tool) => Tool;
10
32
  declare class ToolRegistry {
11
33
  private readonly tools;
12
34
  register(tool: Tool, owner?: string): void;
@@ -16,6 +38,17 @@ declare class ToolRegistry {
16
38
  * scenarios where duplicate registration may be intentional.
17
39
  */
18
40
  tryRegister(tool: Tool, owner?: string): boolean;
41
+ /**
42
+ * Bulk-register multiple tools at once. Each tool that conflicts with an
43
+ * existing registration is silently skipped — use `registerAllOrThrow`
44
+ * if you want it to throw on conflicts.
45
+ */
46
+ registerAll(tools: Tool[], owner?: string): void;
47
+ /**
48
+ * Bulk-register and throw on the first conflict. Use when you need
49
+ * strict registration (e.g. at boot time).
50
+ */
51
+ registerAllOrThrow(tools: Tool[], owner?: string): void;
19
52
  /**
20
53
  * Register a tool as a default. If the tool name is already registered,
21
54
  * this is a no-op — the existing registration (from core or another
@@ -28,9 +61,27 @@ declare class ToolRegistry {
28
61
  * Plugins use this to replace built-in tools with custom implementations.
29
62
  */
30
63
  override(name: string, tool: Tool, owner?: string): void;
64
+ /**
65
+ * Wrap (decorate) an existing tool. The wrapper receives the current
66
+ * tool and must return a new tool — typically the same tool with a
67
+ * wrapped `execute` or `executeStream`. Throws if the tool is not
68
+ * registered.
69
+ *
70
+ * Multiple wraps stack: each wrapper gets the output of the previous.
71
+ *
72
+ * @example
73
+ * registry.wrap('bash', (t) => ({ ...t, permission: 'confirm' }));
74
+ */
75
+ wrap(name: string, wrapper: ToolWrapper, owner?: string): void;
31
76
  get(name: string): Tool | undefined;
32
77
  ownerOf(name: string): string | undefined;
33
78
  list(): Tool[];
79
+ /**
80
+ * Group tools by their `category` field. Tools without a category
81
+ * are placed under the key `""` (empty string). Returns a Map of
82
+ * category → tools, sorted by registration order within each category.
83
+ */
84
+ listByCategory(): Map<string, Tool[]>;
34
85
  listWithOwner(): {
35
86
  tool: Tool;
36
87
  owner: string;
@@ -96,6 +147,224 @@ interface ToolConfirmPendingResult {
96
147
  }
97
148
  type ToolExecutorStrategy = 'parallel' | 'sequential' | 'smart';
98
149
 
150
+ /**
151
+ * A contributor that injects additional TextBlocks into the system prompt.
152
+ *
153
+ * Contributors are called on every `build()` in registration order.
154
+ * Their output is inserted after the core blocks (identity, tool usage,
155
+ * environment) but before the mode and plan blocks. This lets plugins
156
+ * inject ephemeral context — current state, recent events, plugin-specific
157
+ * instructions — without replacing the entire system prompt builder.
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * api.extensions.registerSystemPromptContributor(async (ctx) => {
162
+ * return [{ type: 'text', text: '## My Plugin Context\n...' }];
163
+ * });
164
+ * ```
165
+ */
166
+ type SystemPromptContributor = (ctx: BuildContext) => Promise<TextBlock[]>;
167
+
168
+ /**
169
+ * Extension points for the Agent lifecycle.
170
+ *
171
+ * Each extension point is a hook that gets called at a specific phase.
172
+ * Extensions are always optional and failures are isolated — a failing
173
+ * extension never aborts the agent run.
174
+ *
175
+ * Plugins register extensions via `PluginAPI.extensions`, not by
176
+ * directly importing this module. The Agent calls the registry in
177
+ * order at each phase.
178
+ */
179
+
180
+ /**
181
+ * Called before Agent.run() begins the main iteration loop.
182
+ * Returns `false` or throws to prevent the run from starting.
183
+ */
184
+ type BeforeRunHook = (ctx: Context, input: UserInputPayload) => void | Promise<void>;
185
+ /**
186
+ * Called after Agent.run() completes (or fails/aborts).
187
+ * Receives the final RunResult, always called regardless of outcome.
188
+ */
189
+ type AfterRunHook = (ctx: Context, result: RunResult) => void | Promise<void>;
190
+ /**
191
+ * Called right before each iteration of the agent loop.
192
+ * The context is live (messages, signal, etc.) and can be inspected.
193
+ * Modifications to ctx (e.g. ctx.messages, ctx.model) take effect
194
+ * for the upcoming iteration.
195
+ */
196
+ type BeforeIterationHook = (ctx: Context, iterationIndex: number) => void | Promise<void>;
197
+ /**
198
+ * Called after each iteration completes (tool results appended,
199
+ * compaction done, but before the next loop iteration check).
200
+ */
201
+ type AfterIterationHook = (ctx: Context, iterationIndex: number) => void | Promise<void>;
202
+ /**
203
+ * Called when the agent encounters an error during the provider call
204
+ * or tool execution phase. The hook can return a modified context
205
+ * or signal that recovery should be attempted.
206
+ *
207
+ * Return `{ action: 'retry', model?: string }` to retry the turn
208
+ * (possibly with a different model).
209
+ * Return `{ action: 'fail' }` to propagate the error.
210
+ * Return `{ action: 'continue' }` to skip and continue the loop.
211
+ */
212
+ type OnErrorHook = (ctx: Context, err: unknown, phase: 'provider' | 'tool' | 'agent', iterationIndex: number) => {
213
+ action: 'retry';
214
+ model?: string;
215
+ } | {
216
+ action: 'fail';
217
+ } | {
218
+ action: 'continue';
219
+ } | void | Promise<{
220
+ action: 'retry';
221
+ model?: string;
222
+ } | {
223
+ action: 'fail';
224
+ } | {
225
+ action: 'continue';
226
+ } | void>;
227
+ /**
228
+ * The default provider runner function signature — what the Agent's
229
+ * built-in provider runner looks like. Extensions that wrap the provider
230
+ * runner receive this as the `inner` parameter they can delegate to.
231
+ */
232
+ type ProviderRunnerFn = (ctx: Context, request: Request) => Promise<Response>;
233
+ /**
234
+ * Wrap or replace the provider call in the agent loop.
235
+ *
236
+ * The `inner` function is the default provider runner (with retries).
237
+ * The extension can call it, modify the request/response, add caching,
238
+ * or bypass it entirely.
239
+ */
240
+ type ProviderRunnerWrapper = (ctx: Context, request: Request, inner: ProviderRunnerFn) => Promise<Response>;
241
+ /**
242
+ * Called before a batch of tools is executed. Can modify or reject
243
+ * the tool list. Return the (possibly filtered/modified) tool uses.
244
+ */
245
+ type BeforeToolExecutionHook = (ctx: Context, toolUses: ToolUseBlock[]) => ToolUseBlock[] | Promise<ToolUseBlock[]>;
246
+ /**
247
+ * Called after a batch of tools has been executed and results
248
+ * are available. The extension can inspect or transform results
249
+ * before they're appended to context.
250
+ */
251
+ type AfterToolExecutionHook = (ctx: Context, outputs: ToolExecutionOutput[]) => void | Promise<void>;
252
+ /**
253
+ * An extension registered by a plugin or the host application.
254
+ *
255
+ * Every hook is optional — implement only the phases you need.
256
+ * Hooks are called in registration order. A hook failure is
257
+ * caught, logged, and does not prevent subsequent hooks from running.
258
+ *
259
+ * @example
260
+ * ```ts
261
+ * const myExt: AgentExtension = {
262
+ * name: 'my-plugin-ext',
263
+ * beforeIteration: async (ctx, idx) => {
264
+ * console.log('Starting iteration', idx);
265
+ * },
266
+ * };
267
+ * api.extensions.register(myExt);
268
+ * ```
269
+ */
270
+ interface AgentExtension {
271
+ /** Unique name for this extension. Used in diagnostics and logging. */
272
+ name: string;
273
+ /** Optional owner tag (plugin name or host identifier). */
274
+ owner?: string;
275
+ beforeRun?: BeforeRunHook;
276
+ afterRun?: AfterRunHook;
277
+ beforeIteration?: BeforeIterationHook;
278
+ afterIteration?: AfterIterationHook;
279
+ onError?: OnErrorHook;
280
+ wrapProviderRunner?: ProviderRunnerWrapper;
281
+ beforeToolExecution?: BeforeToolExecutionHook;
282
+ afterToolExecution?: AfterToolExecutionHook;
283
+ }
284
+
285
+ /**
286
+ * ExtensionRegistry — manages AgentExtension registrations.
287
+ *
288
+ * Extensions are called in registration order at each lifecycle phase.
289
+ * Each extension hook failure is caught and logged independently so
290
+ * one bad extension can't take down the agent.
291
+ */
292
+
293
+ declare class ExtensionRegistry {
294
+ private readonly extensions;
295
+ private readonly promptContributors;
296
+ private log;
297
+ setLogger(log: Logger): void;
298
+ /**
299
+ * Register a system prompt contributor. Returns an unregister function.
300
+ * Contributors are called on every system prompt build in registration
301
+ * order. Their output blocks are inserted after the core environment
302
+ * block, before the mode and plan blocks.
303
+ */
304
+ registerSystemPromptContributor(c: SystemPromptContributor): () => void;
305
+ /**
306
+ * Build all registered system prompt contributions.
307
+ * Failures are caught and logged — one bad contributor doesn't
308
+ * break the prompt assembly.
309
+ */
310
+ buildSystemPromptContributions(ctx: Parameters<SystemPromptContributor>[0]): Promise<TextBlock[]>;
311
+ /**
312
+ * Returns the live array of contributors (readonly snapshot for
313
+ * passing to DefaultSystemPromptBuilder at build time).
314
+ */
315
+ listSystemPromptContributors(): readonly SystemPromptContributor[];
316
+ /**
317
+ * Register an extension. Duplicate names are rejected.
318
+ * Returns an unregister function.
319
+ */
320
+ register(ext: AgentExtension): () => void;
321
+ /**
322
+ * Register an extension, silently replacing any previous registration
323
+ * with the same name. Use this when overriding a default extension.
324
+ */
325
+ registerOrReplace(ext: AgentExtension): () => void;
326
+ /**
327
+ * Unregister an extension by name. Returns true if found.
328
+ */
329
+ unregister(name: string): boolean;
330
+ /**
331
+ * List registered extension names in order.
332
+ */
333
+ list(): readonly string[];
334
+ /**
335
+ * Check if an extension with the given name is registered.
336
+ */
337
+ has(name: string): boolean;
338
+ /**
339
+ * Remove all registered extensions and contributors.
340
+ */
341
+ clear(): void;
342
+ runBeforeRun(...args: Parameters<BeforeRunHook>): Promise<void>;
343
+ runAfterRun(...args: Parameters<AfterRunHook>): Promise<void>;
344
+ runBeforeIteration(...args: Parameters<BeforeIterationHook>): Promise<void>;
345
+ runAfterIteration(...args: Parameters<AfterIterationHook>): Promise<void>;
346
+ /**
347
+ * Run onError hooks in order. The first hook that returns a non-void
348
+ * result wins; subsequent hooks are skipped.
349
+ */
350
+ runOnError(...args: Parameters<OnErrorHook>): Promise<{
351
+ action: 'retry';
352
+ model?: string;
353
+ } | {
354
+ action: 'fail';
355
+ } | {
356
+ action: 'continue';
357
+ } | void>;
358
+ /**
359
+ * Build a composed provider runner. Extensions with `wrapProviderRunner`
360
+ * form a middleware-style chain: the innermost extension wraps the
361
+ * default runner, each subsequent wrapper wraps the previous.
362
+ */
363
+ wrapProviderRunner(inner: ProviderRunnerFn): ProviderRunnerFn;
364
+ runBeforeToolExecution(...args: Parameters<BeforeToolExecutionHook>): Promise<Parameters<BeforeToolExecutionHook>[1]>;
365
+ runAfterToolExecution(...args: Parameters<AfterToolExecutionHook>): Promise<void>;
366
+ }
367
+
99
368
  /**
100
369
  * Factory for constructing a Provider instance. The `family` field
101
370
  * declares the wire protocol so callers can route without inspecting
@@ -124,6 +393,10 @@ declare class ProviderRegistry {
124
393
  * runtime overrides (e.g. from plugins or CLI flags).
125
394
  */
126
395
  register(f: ProviderFactory$1): void;
396
+ /**
397
+ * Bulk-register multiple provider factories at once.
398
+ */
399
+ registerAll(factories: ProviderFactory$1[]): void;
127
400
  /**
128
401
  * Override an existing factory. Throws if no factory is registered
129
402
  * for the given type. Use this to safely replace a provider at runtime
@@ -188,6 +461,14 @@ interface AgentInit {
188
461
  * Default is `NoopTracer` (zero overhead).
189
462
  */
190
463
  tracer?: Tracer | undefined;
464
+ /**
465
+ * Optional extension registry. Plugins and host applications register
466
+ * extensions here to hook into the agent lifecycle (beforeRun, afterRun,
467
+ * beforeIteration, onError, wrapProviderRunner, etc.).
468
+ * When not provided, the agent creates an empty registry internally —
469
+ * no overhead, zero breakage.
470
+ */
471
+ extensions?: ExtensionRegistry | undefined;
191
472
  }
192
473
  interface AgentPipelines {
193
474
  request: Pipeline<Request>;
@@ -227,6 +508,7 @@ declare class Agent {
227
508
  private readonly toolExecutor;
228
509
  private readonly autoExtendLimit;
229
510
  private readonly tracer;
511
+ readonly extensions: ExtensionRegistry;
230
512
  constructor(init: AgentInit);
231
513
  private get logger();
232
514
  private get retry();
@@ -238,10 +520,6 @@ declare class Agent {
238
520
  use(plugin: Plugin, api: PluginAPI): Promise<void>;
239
521
  run(userInput: AgentInput, opts?: RunOptions): Promise<RunResult>;
240
522
  private runInner;
241
- /**
242
- * Normalize user input and emit through userInput pipeline + session append.
243
- */
244
- private normalizeAndEmitUserInput;
245
523
  /**
246
524
  * Check if iteration limit has been reached and request extension if needed.
247
525
  * Returns the new effective limit (possibly extended) and a RunResult if
@@ -316,6 +594,8 @@ interface SlashCommand {
316
594
  interface ToolRegistryView {
317
595
  register(t: Tool): void;
318
596
  unregister(name: string): void;
597
+ /** Wrap (decorate) an existing tool. The wrapper gets the current tool and returns the decorated version. */
598
+ wrap(name: string, wrapper: ToolWrapper): void;
319
599
  get(name: string): Tool | undefined;
320
600
  list(): Tool[];
321
601
  }
@@ -347,6 +627,31 @@ interface SlashCommandRegistryView {
347
627
  get(name: string): SlashCommand | undefined;
348
628
  list(): SlashCommand[];
349
629
  }
630
+ /**
631
+ * Read-only view of the session writer. Plugins can append custom events
632
+ * to the JSONL session log and read the transcript path.
633
+ *
634
+ * The `append` method accepts any JSON-serializable payload — custom
635
+ * event types are persisted verbatim next to the built-in events.
636
+ */
637
+ interface SessionWriterView {
638
+ readonly transcriptPath?: string;
639
+ append(event: Record<string, unknown> & {
640
+ type: string;
641
+ ts: string;
642
+ }): Promise<void>;
643
+ }
644
+ /**
645
+ * Metrics sink scoped to a plugin. The host auto-prefixes metric names
646
+ * with `plugin.<pluginName>.` so plugins don't need to namespace
647
+ * manually. Plugins call counter/histogram/gauge directly; the values
648
+ * flow to the host's MetricsSink (Prometheus, OTLP, or noop).
649
+ */
650
+ interface MetricsSinkView {
651
+ counter(name: string, value?: number, labels?: Record<string, string>): void;
652
+ histogram(name: string, value: number, labels?: Record<string, string>): void;
653
+ gauge(name: string, value: number, labels?: Record<string, string>): void;
654
+ }
350
655
  interface PluginPipelines {
351
656
  request: ReadonlyPipeline<Request>;
352
657
  response: ReadonlyPipeline<Response>;
@@ -368,6 +673,18 @@ interface PluginAPI {
368
673
  providers: ProviderRegistryView;
369
674
  mcp: MCPRegistryView;
370
675
  slashCommands: SlashCommandRegistryView;
676
+ /** Live session writer — plugins can append custom events here. */
677
+ session: SessionWriterView;
678
+ /** Scoped metrics sink — counters/histograms/gauges auto-namespaced under `plugin.<name>.` */
679
+ metrics: MetricsSinkView;
680
+ /** Registry for agent lifecycle extensions — hooks like beforeRun, beforeIteration, onError, etc. */
681
+ extensions: ExtensionRegistry;
682
+ /**
683
+ * Register a system prompt contributor. Plugins call this to inject
684
+ * ephemeral TextBlocks into the system prompt on every build.
685
+ * Returns an unregister function.
686
+ */
687
+ registerSystemPromptContributor(c: SystemPromptContributor): () => void;
371
688
  config: Config;
372
689
  log: Logger;
373
690
  /**
@@ -376,6 +693,28 @@ interface PluginAPI {
376
693
  * comes first.
377
694
  */
378
695
  onEvent<K extends EventName>(event: K, handler: Listener<K>): () => void;
696
+ /**
697
+ * Subscribe to all events matching a glob-style pattern.
698
+ * `'tool.*'` matches all tool events. `'*'` matches everything.
699
+ * Returns an unsubscribe function.
700
+ */
701
+ onPattern(pattern: string, handler: (event: string, payload: unknown) => void): () => void;
702
+ /**
703
+ * Emit a custom event on the agent's EventBus. Use for inter-plugin
704
+ * communication or to surface plugin-specific state to the host.
705
+ *
706
+ * Custom events use a `pluginName:eventName` convention to avoid
707
+ * collisions with built-in events (e.g. `my-plugin:cache_hit`).
708
+ * The payload is passed through to all subscribers.
709
+ */
710
+ emitCustom(event: string, payload: unknown): void;
711
+ /**
712
+ * Register a callback that fires when the configuration changes at
713
+ * runtime (e.g. via `/config` slash command or programmatic update).
714
+ * The handler receives the new and previous config snapshots.
715
+ * Returns an unsubscribe function.
716
+ */
717
+ onConfigChange(handler: (next: Readonly<Config>, prev: Readonly<Config>) => void): () => void;
379
718
  }
380
719
  /**
381
720
  * Capability declaration — informs the host which subsystems a plugin
@@ -440,8 +779,26 @@ interface Plugin {
440
779
  /** Optional plugin dependencies — silently skipped if absent. */
441
780
  optionalDeps?: (string | PluginDependency)[];
442
781
  conflictsWith?: string[];
782
+ /**
783
+ * Default configuration values, deep-merged under the plugin's options
784
+ * key before `configSchema` validation. User-provided values take
785
+ * precedence over defaults — this is a fallback, not an override.
786
+ *
787
+ * @example
788
+ * defaultConfig: { ttl: 3600, maxSize: 100 }
789
+ */
790
+ defaultConfig?: Record<string, unknown>;
443
791
  setup(api: PluginAPI): void | Promise<void>;
444
792
  teardown?(api: PluginAPI): void | Promise<void>;
793
+ /**
794
+ * Optional health check. Called by the host (e.g. `/diag plugins` slash
795
+ * command or health endpoint) to surface plugin status. Return
796
+ * `{ ok: false, message: '...' }` when the plugin is degraded.
797
+ */
798
+ health?(): Promise<{
799
+ ok: boolean;
800
+ message?: string;
801
+ }>;
445
802
  }
446
803
 
447
- export { Agent as A, DEFAULT_MAX_ITERATIONS as D, type MCPRegistryView as M, type Plugin as P, type RunResult as R, type SlashCommand as S, type ToolRegistryView as T, type UserInputPayload as U, type PluginAPI as a, type PluginCapabilities as b, type PluginDependency as c, type PluginPipelines as d, type ProviderFactory as e, type ProviderRegistryView as f, type SlashCommandRegistryView as g, type ToolExecutorOptions as h, type ToolExecutorStrategy as i, type ToolBatchResult as j, ToolRegistry as k, ProviderRegistry as l, type AgentInit as m, type AgentInput as n, type AgentPipelines as o, type ProviderFactory$1 as p, createDefaultPipelines as q };
804
+ export { type AfterIterationHook as A, type BeforeIterationHook as B, type ToolWrapper as C, DEFAULT_MAX_ITERATIONS as D, ExtensionRegistry as E, createDefaultPipelines as F, type ProviderRunnerFn as G, type MCPRegistryView as M, type OnErrorHook as O, type Plugin as P, type RunResult as R, type SessionWriterView as S, type ToolRegistryView as T, type UserInputPayload as U, type MetricsSinkView as a, type PluginAPI as b, type PluginCapabilities as c, type PluginDependency as d, type PluginPipelines as e, type ProviderFactory as f, type ProviderRegistryView as g, type SlashCommand as h, type SlashCommandRegistryView as i, type SystemPromptContributor as j, type ToolExecutorOptions as k, type ToolExecutorStrategy as l, type ToolBatchResult as m, ToolRegistry as n, ProviderRegistry as o, type AfterRunHook as p, type AfterToolExecutionHook as q, Agent as r, type AgentExtension as s, type AgentInit as t, type AgentInput as u, type AgentPipelines as v, type BeforeRunHook as w, type BeforeToolExecutionHook as x, type ProviderFactory$1 as y, type ProviderRunnerWrapper as z };