@zapier/kitcore 0.0.0 → 0.4.0

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.
@@ -0,0 +1,2907 @@
1
+ import { z } from 'zod';
2
+
3
+ declare module "zod" {
4
+ interface GlobalMeta {
5
+ internal?: boolean;
6
+ deprecated?: boolean;
7
+ valueHint?: string;
8
+ }
9
+ }
10
+
11
+ /**
12
+ * Pagination shapes used by the plugin framework.
13
+ */
14
+ /**
15
+ * Single page of a paginated SDK list result. Returned from the page-level
16
+ * promise and yielded from the page-level async iterable.
17
+ */
18
+ interface SdkPage<T = unknown> {
19
+ data: T[];
20
+ nextCursor?: string;
21
+ }
22
+ /**
23
+ * Return type of every paginated SDK method. The same value is both:
24
+ *
25
+ * - a Promise that resolves to the first page (`SdkPage<TItem>`), and
26
+ * - an AsyncIterable that yields each page in turn,
27
+ *
28
+ * with an `.items()` method that returns an AsyncIterable over individual
29
+ * items across all pages. Named so paginated plugin signatures serialize
30
+ * as `PaginatedSdkResult<AppItem>` in `.d.ts` rather than expanding the
31
+ * full triple-intersection at every callsite.
32
+ *
33
+ * The faces share one underlying cursor, so a result is consumed once:
34
+ *
35
+ * - `await` / `.then()` read the buffered first page without starting the
36
+ * stream, so awaiting is a repeatable peek and you can still iterate the
37
+ * result afterward.
38
+ * - The page-iterable and `.items()` are two views over one page stream, so
39
+ * consuming either drains the other: the second view yields nothing (it
40
+ * does not replay page 1). To read a result more than once, call the
41
+ * method again for a fresh result.
42
+ */
43
+ interface PaginatedSdkResult<TItem> extends Promise<SdkPage<TItem>>, AsyncIterable<SdkPage<TItem>> {
44
+ items(): AsyncIterable<TItem>;
45
+ }
46
+ type PaginatedSdkFunction<TOptions, TItem> = (options: TOptions) => PaginatedSdkResult<TItem>;
47
+
48
+ interface FormattedItem {
49
+ title: string;
50
+ /**
51
+ * Secondary identifying context shown dimmed after the title (ids, keys,
52
+ * slugs, ...). A dumb visual string a renderer shows verbatim, never
53
+ * structured data it has to interpret; the same role as a prompt choice's
54
+ * `hint`. An array is joined with ", ". Structured fields live on the
55
+ * response / `outputSchema`, not here, so the renderer stays dumb.
56
+ */
57
+ hint?: string | string[];
58
+ /** @deprecated Use `hint` (the renderer no longer interprets ids). */
59
+ id?: string;
60
+ /** @deprecated Use `hint`. */
61
+ key?: string;
62
+ /** @deprecated Use `hint`. */
63
+ keys?: string[];
64
+ description?: string;
65
+ /** If provided, the renderer shows this raw (verbatim) instead of `details`. */
66
+ raw?: unknown;
67
+ details: Array<{
68
+ label?: string;
69
+ text: string;
70
+ style: "normal" | "dim" | "accent" | "warning" | "success";
71
+ }>;
72
+ }
73
+ interface OutputFormatter<TSdk, TItem = unknown, TParams = Record<string, unknown>, TContext = unknown> {
74
+ fetch?: (sdk: TSdk, params: TParams, item: TItem, context: TContext | undefined) => Promise<TContext>;
75
+ format: (item: TItem, context?: TContext) => FormattedItem;
76
+ }
77
+ declare function getOutputSchema(inputSchema: z.ZodType): z.ZodType | undefined;
78
+ declare function withOutputSchema<T extends z.ZodType>(inputSchema: T, outputSchema: z.ZodType): T & {
79
+ _def: T["_def"] & {
80
+ outputSchema: z.ZodType;
81
+ };
82
+ };
83
+ /** A selectable option in a prompt. `label` is the display text; `value` is
84
+ * what the resolver returns when picked. */
85
+ interface PromptConfigChoice {
86
+ label: string;
87
+ value: unknown;
88
+ /**
89
+ * Optional secondary info shown after the label. The CLI wraps it in
90
+ * dimmed parens; an array is joined with ", ". Use for keys, ids, or
91
+ * other context that's useful but shouldn't compete visually with
92
+ * the primary label.
93
+ */
94
+ hint?: string | string[];
95
+ }
96
+ /**
97
+ * The pre-rename choice shape, kept so existing resolvers keep compiling while
98
+ * they migrate to {@link PromptConfigChoice}.
99
+ * @deprecated Use {@link PromptConfigChoice} with `label` instead of `name`.
100
+ */
101
+ interface DeprecatedPromptConfigChoice {
102
+ /** @deprecated Use `label` instead. */
103
+ name: string;
104
+ value: unknown;
105
+ hint?: string | string[];
106
+ }
107
+ interface PromptConfig {
108
+ type: "list" | "checkbox" | "confirm";
109
+ /**
110
+ * The answer key. The framework supplies it from the resolver's attachment
111
+ * (the param the resolver resolves), so authors should omit it; a provided
112
+ * value is overwritten.
113
+ * @deprecated Omit; the framework supplies the param key.
114
+ */
115
+ name?: string;
116
+ message: string;
117
+ choices?: Array<PromptConfigChoice | DeprecatedPromptConfigChoice>;
118
+ default?: unknown;
119
+ /** Informational, non-selectable lines shown with the prompt (e.g. "enable X
120
+ * to see more"). A host renders them dimmed, after the choices. The framework
121
+ * stays agnostic about their content; the resolver composes the text. */
122
+ notes?: string[];
123
+ filter?: (value: unknown) => unknown;
124
+ /**
125
+ * Return `true` for valid; a string for a custom invalid message; or
126
+ * `false` for invalid with a generic fallback message ("X: invalid
127
+ * value."). Prefer returning a string so users see something specific.
128
+ */
129
+ validate?: (value: unknown) => boolean | string;
130
+ }
131
+ /** A PromptConfig narrowed to single-select list mode. */
132
+ type ListPromptConfig = PromptConfig & {
133
+ type: "list";
134
+ };
135
+ /**
136
+ * The prompt config the NEW-model resolvers (`defineResolver`) return. It omits
137
+ * three fields the resolution controller does not honor, so authors can't
138
+ * supply a silent no-op:
139
+ * - `name` — the framework supplies the answer key (always was overwritten).
140
+ * - `default`— no resolver uses it; the controller has no preselect concept.
141
+ * - `filter` — no resolver uses it; transform values in `listItems` instead.
142
+ * (The legacy `SchemaParameterResolver` still honors `default`/`filter`, so the
143
+ * full `PromptConfig` stays for that path.)
144
+ */
145
+ type ResolverPromptConfig = Omit<PromptConfig, "name" | "default" | "filter">;
146
+ interface Resolver$1 {
147
+ type: string;
148
+ depends?: readonly string[] | string[];
149
+ }
150
+ interface StaticResolver$1 extends Resolver$1 {
151
+ type: "static";
152
+ inputType?: "text" | "password" | "email";
153
+ placeholder?: string;
154
+ }
155
+ /**
156
+ * A resolver that always resolves to a fixed value, never prompts. Use to
157
+ * pin an implicit parameter that downstream resolvers or SDK calls require
158
+ * but the user shouldn't have to provide. Triggers, for example, are always
159
+ * `actionType: "read"` from the SDK's perspective; createTriggerInbox
160
+ * declares `actionType: { type: "constant", value: "read" }` so the
161
+ * standard `actionKeyResolver` and `inputsResolver` (which depend on
162
+ * `actionType`) work without any pinned variants.
163
+ *
164
+ * Constants attached to keys that aren't in the schema are seeded into
165
+ * `resolvedParams` upfront, so dependent resolvers find them in context
166
+ * without the key appearing in the user-facing surface (TS option type,
167
+ * CLI flags, generated docs).
168
+ */
169
+ interface ConstantResolver$1 extends Resolver$1 {
170
+ type: "constant";
171
+ value: unknown;
172
+ }
173
+ /**
174
+ * Fields shared by both variants of {@link DynamicResolver}.
175
+ */
176
+ interface DynamicResolverBase<TSdk, TItem, TParams> extends Resolver$1 {
177
+ type: "dynamic";
178
+ prompt: (items: TItem[], params: TParams) => PromptConfig;
179
+ /** Capabilities that expand results. The parameter resolver shows a hint for any that aren't enabled. */
180
+ requireCapabilities?: string[];
181
+ /**
182
+ * Optional hook called before fetch/prompt. If it returns a non-null object,
183
+ * resolvedValue is used directly and fetch/prompt are skipped entirely. Return
184
+ * null to fall through to the normal resolution flow. Implementations should
185
+ * catch their own errors and return null on failure rather than throwing, so
186
+ * that a transient API error does not block the CLI entirely.
187
+ */
188
+ tryResolveWithoutPrompt?: (sdk: TSdk, params: TParams) => Promise<{
189
+ resolvedValue: unknown;
190
+ } | null>;
191
+ }
192
+ /**
193
+ * The classic dynamic-resolver variant: `fetch` returns a list of items
194
+ * that the CLI renders as a search-filterable dropdown. The user picks one.
195
+ */
196
+ interface DynamicListResolver<TSdk, TItem, TParams> extends DynamicResolverBase<TSdk, TItem, TParams> {
197
+ /** Explicitly absent on the list variant; set `inputType: "search"` to opt into the search variant. */
198
+ inputType?: never;
199
+ /** Only meaningful for the search variant; set to `never` here so TS catches misuse. */
200
+ placeholder?: never;
201
+ fetch: (sdk: TSdk, resolvedParams: TParams) => PromiseLike<TItem[] | {
202
+ data: TItem[];
203
+ nextCursor?: string;
204
+ } | AsyncIterable<{
205
+ data: TItem[];
206
+ nextCursor?: string;
207
+ }>>;
208
+ }
209
+ /**
210
+ * The search-input variant: the CLI prompts the user for free-form text
211
+ * first, then calls `fetch` with `{ ...resolvedParams, search }`.
212
+ *
213
+ * `fetch` can short-circuit by returning a primitive (`string | number`),
214
+ * which the CLI treats as an exact match — no dropdown is rendered. Any
215
+ * other return (array, page, async iterable) is rendered as the normal
216
+ * search-filterable dropdown.
217
+ *
218
+ * The `search` key is injected by the CLI at call time; it isn't part of
219
+ * `TParams` because callers that invoke `fetch` directly (outside the CLI)
220
+ * are responsible for passing it themselves. Search-mode resolvers should
221
+ * type `TParams` as `{ search?: string; ...otherDeps }` to make this
222
+ * explicit.
223
+ */
224
+ interface DynamicSearchResolver<TSdk, TItem, TParams> extends Omit<DynamicResolverBase<TSdk, TItem, TParams>, "prompt"> {
225
+ inputType: "search";
226
+ /**
227
+ * Hint text appended to the search prompt's message. NOT used as
228
+ * inquirer's `default` value, because inquirer prefills `default` as
229
+ * editable text that the user has to delete before typing.
230
+ */
231
+ placeholder?: string;
232
+ /**
233
+ * Search-mode always renders a single-select @inquirer/search dropdown,
234
+ * so `prompt` must return a list-typed PromptConfig. Checkbox/confirm
235
+ * configs would be silently ignored at runtime; the type narrows so
236
+ * misuse fails at compile time.
237
+ *
238
+ * Note: a primitive return from `fetch` (string | number) is treated
239
+ * as an exact match and short-circuits without running this prompt or
240
+ * the resolver's validate/filter. Canonicalize inside `fetch` if the
241
+ * exact-match path needs normalization.
242
+ */
243
+ prompt: (items: TItem[], params: TParams) => ListPromptConfig;
244
+ fetch: (sdk: TSdk, resolvedParams: TParams) => PromiseLike<string | number | TItem[] | {
245
+ data: TItem[];
246
+ nextCursor?: string;
247
+ } | AsyncIterable<{
248
+ data: TItem[];
249
+ nextCursor?: string;
250
+ }>>;
251
+ }
252
+ /**
253
+ * A dynamic resolver: either a classic list (`inputType` absent) or a
254
+ * search-input variant (`inputType: "search"`). The discriminator is the
255
+ * `inputType` field; TS narrows to the right variant when you check it.
256
+ */
257
+ type DynamicResolver$1<TSdk, TItem = unknown, TParams = Record<string, unknown>> = DynamicListResolver<TSdk, TItem, TParams> | DynamicSearchResolver<TSdk, TItem, TParams>;
258
+ interface ResolverFieldItem {
259
+ type: string;
260
+ key: string;
261
+ title?: string;
262
+ is_required?: boolean;
263
+ value_type?: string;
264
+ choices?: Array<{
265
+ label: string;
266
+ value: string;
267
+ }>;
268
+ fields?: ResolverFieldItem[];
269
+ resolver?: ResolverMetadata<any, any, any>;
270
+ }
271
+ interface FieldsResolver<TSdk, TParams = Record<string, unknown>, TResult = Record<string, unknown>> extends Resolver$1 {
272
+ type: "fields";
273
+ fetch: (sdk: TSdk, resolvedParams: TParams) => Promise<ResolverFieldItem[]>;
274
+ transform?: (value: Record<string, unknown>) => TResult;
275
+ }
276
+ interface ArrayResolver$1<TSdk, TParams = Record<string, unknown>> extends Resolver$1 {
277
+ type: "array";
278
+ fetch: (sdk: TSdk, resolvedParams: TParams) => Promise<ResolverMetadata<TSdk, unknown, TParams>>;
279
+ minItems?: number;
280
+ maxItems?: number;
281
+ }
282
+ type ResolverMetadata<TSdk, TItem = unknown, TParams = Record<string, unknown>> = StaticResolver$1 | ConstantResolver$1 | DynamicResolver$1<TSdk, TItem, TParams> | FieldsResolver<TSdk, TParams> | ArrayResolver$1<TSdk, TParams>;
283
+ /**
284
+ * Extract the SDK shape a resolver requires by inferring it from the resolver's
285
+ * `fetch` callback. Static and Constant resolvers have no fetch and produce
286
+ * `unknown`, meaning they impose no requirement on the plugin's SDK.
287
+ */
288
+ type RequiredSdkOf<R> = R extends {
289
+ fetch: (sdk: infer S, ...args: any[]) => any;
290
+ } ? S : unknown;
291
+ /**
292
+ * Per-entry resolver-slot validator. For each key, if the plugin's `TSdk`
293
+ * satisfies the resolver's required SDK, the entry passes through unchanged;
294
+ * otherwise the slot widens to `ResolverMetadata<TSdk, any, any>`, so TS
295
+ * surfaces the mismatch at the specific offending key rather than at the
296
+ * whole `resolvers` object.
297
+ *
298
+ * Pair with `NoInfer<TSdk>` at the call site to prevent TS from inferring
299
+ * `TSdk` from a resolver entry (which would silently accommodate the
300
+ * mismatch). With `NoInfer`, the only inference site for `TSdk` is the
301
+ * `sdk` argument, and each resolver is then checked against it.
302
+ */
303
+ type ValidResolvers<TSdk, R> = {
304
+ [K in keyof R]: TSdk extends RequiredSdkOf<R[K]> ? R[K] : ResolverMetadata<TSdk, any, any>;
305
+ };
306
+ interface ResolverConfig<TSdk, TItem = unknown, TParams = Record<string, unknown>> {
307
+ resolver: ResolverMetadata<TSdk, TItem, TParams>;
308
+ }
309
+ declare function withResolver<T extends z.ZodType, TSdk, TItem = unknown, TParams = Record<string, unknown>>(schema: T, config: ResolverConfig<TSdk, TItem, TParams>): T;
310
+ declare function getSchemaDescription(schema: z.ZodSchema): string | undefined;
311
+ declare function getFieldDescriptions(schema: z.ZodObject<z.ZodRawShape>): Record<string, string>;
312
+ interface PositionalMetadata {
313
+ positionalMeta: {
314
+ positional: true;
315
+ };
316
+ }
317
+ declare function withPositional<T extends z.ZodType>(schema: T): T & {
318
+ _def: T["_def"] & PositionalMetadata;
319
+ };
320
+ declare function isPositional(schema: z.ZodType): boolean;
321
+ declare function openEnum<const T extends readonly [string, ...string[]]>(values: T, description: string): z.ZodUnion<readonly [z.ZodEnum<{ [k_1 in T[number]]: k_1; } extends infer T_1 ? { [k in keyof T_1]: { [k_1 in T[number]]: k_1; }[k]; } : never>, z.ZodString]>;
322
+
323
+ /**
324
+ * Method-call lifecycle hooks. Plugins contribute `onMethodStart` and/or
325
+ * `onMethodEnd` on their context; `buildHooks` composes contributions across
326
+ * plugins so multiple observers can coexist. Composition is right-additive
327
+ * (newer plugins fire after earlier ones); only opt-in methods built through
328
+ * `createPluginMethod` / `createPaginatedPluginMethod` trigger the hooks.
329
+ */
330
+ interface OnMethodStartContext {
331
+ methodName: string;
332
+ args: unknown[];
333
+ isPaginated: boolean;
334
+ /**
335
+ * Depth of this method invocation in the SDK call tree. 0 = outermost
336
+ * (user-initiated) call; 1+ = called from inside another SDK method.
337
+ * Observers can use this to ignore nested calls if they only want
338
+ * top-level events.
339
+ */
340
+ depth: number;
341
+ }
342
+ type OnMethodStart = (ctx: OnMethodStartContext) => void;
343
+ interface OnMethodEndContext {
344
+ methodName: string;
345
+ args: unknown[];
346
+ isPaginated: boolean;
347
+ depth: number;
348
+ durationMs: number;
349
+ error?: Error;
350
+ }
351
+ type OnMethodEnd = (ctx: OnMethodEndContext) => void;
352
+ interface MethodHooks {
353
+ onMethodStart?: OnMethodStart;
354
+ onMethodEnd?: OnMethodEnd;
355
+ }
356
+
357
+ /**
358
+ * Descriptive metadata a leaf carries for the registry / CLI / MCP / docs:
359
+ * description, categories, type, formatter, resolvers, etc.
360
+ * Reuses the shipped `PluginMeta` minus `inputSchema`, which is a first-class
361
+ * descriptor field (it also drives `input` typing and runtime validation).
362
+ */
363
+ type LeafMeta = Omit<PluginMeta, "inputSchema">;
364
+ /**
365
+ * The descriptive registry fields a `defineMethod` / `defineProperty` author
366
+ * sets directly on the config (hoisted, not nested under a `meta` wrapper).
367
+ * The impl folds whichever are present back into the stored `LeafMeta`. This is
368
+ * the strict, explicit subset of `PluginMeta` (no `[key: string]: any` escape
369
+ * hatch, no `inputSchema` / `formatter` / `resolvers` — those are first-class
370
+ * config fields of their own).
371
+ */
372
+ interface LeafMetaFields {
373
+ description?: string;
374
+ categories?: (string | CategoryDefinition)[];
375
+ type?: "list" | "item" | "create" | "update" | "delete" | "function";
376
+ itemType?: string;
377
+ returnType?: string;
378
+ outputSchema?: z.ZodSchema;
379
+ inputParameters?: Array<{
380
+ name: string;
381
+ schema: z.ZodSchema;
382
+ }>;
383
+ packages?: string[];
384
+ experimental?: boolean;
385
+ confirm?: "create-secret" | "delete";
386
+ deprecation?: FunctionDeprecation;
387
+ aliases?: Record<string, string>;
388
+ supportsJsonOutput?: boolean;
389
+ }
390
+ type AnyMethodPlugin = MethodPlugin<string, any, any, readonly string[]>;
391
+ type AnyPropertyPlugin = PropertyPlugin<string, any>;
392
+ /** A leaf plugin: a method (callable) or a property (value). */
393
+ type AnyLeafPlugin = AnyMethodPlugin | AnyPropertyPlugin;
394
+ /**
395
+ * How a module declares its imports: an array. Each element binds under its own
396
+ * name (a leaf under its name, a module under each of its export names); a
397
+ * `selectExports(...)` element contributes its chosen bindings. To rename or
398
+ * subset, wrap an element in `selectExports`; there is no alias-map form.
399
+ */
400
+ type ImportsInput = readonly AnyPlugin[];
401
+ /** A resolved import edge: the local binding name and the plugin id it reads
402
+ * from `context.plugins` (id, not identity, so a swap stays transparent). */
403
+ interface ImportBinding {
404
+ binding: string;
405
+ id: string;
406
+ }
407
+ /**
408
+ * Collapse a union to an intersection. Turns the per-dependency
409
+ * `{ name: signature }` union into one `imports` object type.
410
+ */
411
+ type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
412
+ /**
413
+ * A method's callable signature. A method with no declared input infers
414
+ * `TInput = unknown`; make its input optional so it is callable with no
415
+ * argument. An input whose properties are all optional (e.g. a `list` method
416
+ * whose only input is the framework's `cursor` / `pageSize` / `maxItems`) is
417
+ * also callable with no argument. A real required input keeps the arg required.
418
+ */
419
+ type MethodCall<TInput, TOutput> = [unknown] extends [TInput] ? (input?: TInput) => TOutput : {} extends TInput ? (input?: TInput) => TOutput : (input: TInput) => TOutput;
420
+ /**
421
+ * Project the canonical input through an ordered list of key names into a
422
+ * positional argument tuple, preserving trailing-optionality: a key that is
423
+ * optional in `TInput` becomes an optional argument (so `fetch(url)` is legal
424
+ * when `init` is optional). A name that is not a key of `TInput` is an error.
425
+ */
426
+ type PositionalArgs<TInput, TNames extends readonly PropertyKey[]> = TNames extends readonly [
427
+ infer Head extends keyof TInput,
428
+ ...infer Tail extends readonly (keyof TInput)[]
429
+ ] ? {} extends Pick<TInput, Head> ? [arg?: TInput[Head], ...PositionalArgs<TInput, Tail>] : [arg: TInput[Head], ...PositionalArgs<TInput, Tail>] : [];
430
+ /**
431
+ * The public call signature of a method on the surface and in `imports`. With
432
+ * no positional projection it is the canonical single-object `MethodCall`; with
433
+ * one it is the positional signature derived from the input. Middleware does
434
+ * NOT use this (its bag carries one canonical `input`); see `MiddlewareMap`.
435
+ */
436
+ type SurfaceCall<TInput, TOutput, TPositional extends readonly string[]> = TPositional extends readonly [] ? MethodCall<TInput, TOutput> : (...args: PositionalArgs<TInput, TPositional>) => TOutput;
437
+ /**
438
+ * The bindings one array-form dependency contributes to `imports`: a leaf under
439
+ * its own name (method callable or property value), an aggregate under each of
440
+ * its export names.
441
+ */
442
+ type BindingsOf<TDep> = TDep extends MethodPlugin<infer TName, infer TInput, infer TOutput, infer TPositional> ? {
443
+ [P in TName]: SurfaceCall<TInput, TOutput, TPositional>;
444
+ } : TDep extends PropertyPlugin<infer TName, infer TValue> ? {
445
+ [P in TName]: TValue;
446
+ } : TDep extends AggregatePlugin<string, infer TExports> ? {
447
+ [K in keyof TExports]: ExportSurface<TExports[K]>;
448
+ } : never;
449
+ /**
450
+ * The `imports` a body receives. Each element contributes its bindings
451
+ * (`BindingsOf`); empty imports yield an empty object.
452
+ */
453
+ type ImportsOf<TImports extends ImportsInput> = TImports extends readonly [] ? Record<never, never> : UnionToIntersection<{
454
+ [K in keyof TImports]: BindingsOf<TImports[K]>;
455
+ }[number]>;
456
+ /**
457
+ * The bag a method body receives. `imports` is the dependency-narrowed reach;
458
+ * `state` is the plugin's private constructor result (undefined when none);
459
+ * `input` is the canonical call argument.
460
+ */
461
+ interface MethodRunBag<TImports, TInput, TState = unknown> {
462
+ imports: TImports;
463
+ state: TState;
464
+ input: TInput;
465
+ }
466
+ /** Shared plumbing for the method attachments: each declares its own
467
+ * dependencies. Resolvers and formatters are otherwise separate concepts. */
468
+ interface MethodAttachment {
469
+ imports: readonly AnyPlugin[];
470
+ /** Binding-name to plugin-id edges, normalized from `imports`; what the
471
+ * narrowed bag captured at materialization is built from. */
472
+ importBindings: readonly ImportBinding[];
473
+ }
474
+ /**
475
+ * A resolver's kind, the discriminant of the {@link Resolver} union. Scalars
476
+ * (`dynamic` / `static` / `constant`) resolve one value; `info` resolves none
477
+ * (display-only); `object` / `array` compose nested resolvers. Names borrow
478
+ * JSON Schema's structural vocabulary (`object`/`array`/`properties`/`items`),
479
+ * but a resolver carries behavior (fetch/prompt), not validation.
480
+ */
481
+ type ResolverType = "dynamic" | "static" | "constant" | "info" | "object" | "array";
482
+ /**
483
+ * A reference from a field (or array `items`) to a reusable resolver in the
484
+ * nearest `definitions` block. `input` are merged into the referenced
485
+ * resolver's `input` (e.g. the field key a shared choices-fetcher needs).
486
+ * Used when a fetch-built field needs an import-bearing resolver, which can't
487
+ * be inlined at fetch time (its imports bind at materialization).
488
+ */
489
+ interface ResolverRef {
490
+ ref: string;
491
+ input?: Record<string, unknown>;
492
+ }
493
+ /**
494
+ * One member of an object resolver's `properties` (literal or fetch-built): the
495
+ * resolver for the value plus its per-occurrence meta. `required` / `valueType`
496
+ * live here, not on the resolver, because the same resolver can be required in
497
+ * one object and optional in another, and a fetch-built field (no schema) has
498
+ * nowhere else to carry them.
499
+ */
500
+ interface Field {
501
+ resolver: Resolver | ResolverRef;
502
+ label?: string;
503
+ required?: boolean;
504
+ valueType?: string;
505
+ }
506
+ /** Shared gates for resolvers that resolve a value: the attachment plumbing
507
+ * plus the param-dataflow prerequisite. (`info` skips these.) */
508
+ interface ResolverBase extends MethodAttachment {
509
+ /** Sibling parameters that must resolve before this resolver runs (it reads
510
+ * their values from `input`). The param-dataflow prerequisite, distinct from
511
+ * `imports`' SDK-capability graph. */
512
+ requireParameters?: readonly string[];
513
+ }
514
+ /** List candidate items and prompt the user to pick one. */
515
+ interface DynamicResolver extends ResolverBase {
516
+ type: "dynamic";
517
+ inputType?: "text" | "password" | "email" | "search";
518
+ placeholder?: string;
519
+ /** Compute side-context once, before `listItems`, with the narrowed `imports`
520
+ * bag (no items yet — it runs pre-fetch so it can shape the fetch). The result
521
+ * flows into `listItems` and `prompt` as `context`. Use it to resolve, in one
522
+ * place, anything both the fetch and the render need (e.g. a capability gate:
523
+ * compute `includeShared` here, gate the fetch in `listItems`, surface a
524
+ * `notes` hint in `prompt`). May run more than once across re-asks, so keep it
525
+ * cheap/idempotent. */
526
+ getContext?: (bag: {
527
+ imports: Record<string, unknown>;
528
+ input: Record<string, unknown>;
529
+ }) => PromiseLike<unknown>;
530
+ /** Produce the candidate list. Behaves like an SDK list method: returns a
531
+ * paginated result (await for the first page + `nextCursor`, or iterate pages),
532
+ * never a bare array. `cursor` is the stateless re-entry hook for "load more":
533
+ * an in-process host iterates the result; a distributed host awaits one page,
534
+ * carries `nextCursor`, and calls again with `cursor`. */
535
+ listItems?: (bag: {
536
+ imports: Record<string, unknown>;
537
+ input: Record<string, unknown>;
538
+ /** The value `getContext` returned, if any. */
539
+ context?: unknown;
540
+ /** Free-text term injected by the CLI for search-mode resolvers. A separate
541
+ * key, not part of `input`, so it never collides with a method parameter
542
+ * also named `search`. */
543
+ search?: string;
544
+ cursor?: string;
545
+ }) => ListItemsResult<unknown>;
546
+ prompt?: (bag: {
547
+ items: unknown[];
548
+ input: Record<string, unknown>;
549
+ /** The value `getContext` returned, if any. */
550
+ context?: unknown;
551
+ }) => ResolverPromptConfig;
552
+ /** Resolve with no user input at all (e.g. a configured default), skipping the
553
+ * prompt. Runs before prompting; used always in non-interactive mode and as a
554
+ * "can we skip asking?" check otherwise. Returns null to fall through to a prompt. */
555
+ tryResolveWithoutPrompt?: (bag: {
556
+ imports: Record<string, unknown>;
557
+ input: Record<string, unknown>;
558
+ }) => Promise<{
559
+ resolvedValue: unknown;
560
+ } | null>;
561
+ /** Search-mode exact match: the user typed `search`; if it already names a
562
+ * valid value (e.g. validated via the API), return it to skip the picker.
563
+ * Distinct from `tryResolveWithoutPrompt` (no input) — this is interactive,
564
+ * mid-prompt, with the typed term. Returns null to fall through to `listItems`. */
565
+ tryResolveFromSearch?: (bag: {
566
+ imports: Record<string, unknown>;
567
+ input: Record<string, unknown>;
568
+ search?: string;
569
+ }) => Promise<{
570
+ resolvedValue: unknown;
571
+ } | null>;
572
+ }
573
+ /** Free-text input, no candidate list. */
574
+ interface StaticResolver extends ResolverBase {
575
+ type: "static";
576
+ inputType?: "text" | "password" | "email" | "search";
577
+ placeholder?: string;
578
+ }
579
+ /** A fixed value, no prompt. */
580
+ interface ConstantResolver extends ResolverBase {
581
+ type: "constant";
582
+ value: unknown;
583
+ }
584
+ /** Display-only text; resolves no value (its key is skipped in the result). */
585
+ interface InfoResolver extends MethodAttachment {
586
+ type: "info";
587
+ text: string;
588
+ }
589
+ /** A keyed object. `properties` are known up front; `getProperties` builds them
590
+ * when the key set is dynamic (re-invoked as `input` grow, for depends-on
591
+ * fields). Returns the property map raw (no envelope: nothing to paginate).
592
+ * `definitions` holds reusable resolvers reached by `{ ref }` from built fields
593
+ * that need an import. */
594
+ interface ObjectResolver extends ResolverBase {
595
+ type: "object";
596
+ properties?: Record<string, Field>;
597
+ getProperties?: (bag: {
598
+ imports: Record<string, unknown>;
599
+ input: Record<string, unknown>;
600
+ }) => PromiseLike<Record<string, Field>>;
601
+ definitions?: Record<string, Resolver>;
602
+ }
603
+ /** A homogeneous list: each element resolves through `items`. */
604
+ interface ArrayResolver extends ResolverBase {
605
+ type: "array";
606
+ items: Resolver | ResolverRef;
607
+ minItems?: number;
608
+ maxItems?: number;
609
+ /** Coarse value type of each element, so a free-text item answer coerces
610
+ * (e.g. `"5"` → `5` for `z.array(z.number())`) the way object fields do via
611
+ * `Field.valueType`. `items` is a bare resolver with no `valueType` slot of
612
+ * its own, so the element type rides here. */
613
+ itemValueType?: string;
614
+ definitions?: Record<string, Resolver>;
615
+ }
616
+ /**
617
+ * An input resolver descriptor (produced by `defineResolver`, attached to a
618
+ * method parameter). A discriminated union on `type`; composites (`object` /
619
+ * `array`) recurse. Callbacks take a narrowed `imports` bag; the materializer
620
+ * captures it and produces a {@link BoundResolver}. Stored loosely (the precise
621
+ * `imports` / item / param types live on the `defineResolver` config), like
622
+ * `MethodPlugin.run`.
623
+ */
624
+ type Resolver = DynamicResolver | StaticResolver | ConstantResolver | InfoResolver | ObjectResolver | ArrayResolver;
625
+ /**
626
+ * An output formatter descriptor (produced by `defineFormatter`, attached to a
627
+ * method's output). `getContext` reaches the narrowed `imports` bag; the
628
+ * materializer captures it and produces a {@link BoundFormatter}. Stored
629
+ * loosely, like {@link Resolver}. Both callbacks receive the method's `input`
630
+ * (the formatter runs post-execution, so the input is complete, unlike a
631
+ * resolver's partial `input`).
632
+ */
633
+ interface Formatter extends MethodAttachment {
634
+ getContext?: (bag: {
635
+ imports: Record<string, unknown>;
636
+ items: unknown[];
637
+ input: Record<string, unknown>;
638
+ context?: unknown;
639
+ }) => Promise<unknown>;
640
+ format: (bag: {
641
+ item: unknown;
642
+ input: Record<string, unknown>;
643
+ context?: unknown;
644
+ }) => FormattedItem;
645
+ }
646
+ /** What a dynamic resolver's `listItems` yields: an SDK list-method result
647
+ * (`await` for the first page + `nextCursor`, or iterate pages in-process), or a
648
+ * plain page / promise of one. No bare array and no scalar: it behaves like any
649
+ * other list method, and exact-match short-circuits live on `tryResolveFromSearch`. */
650
+ type ListItemsResult<TItem> = PaginatedSdkResult<TItem> | SdkPage<TItem> | Promise<SdkPage<TItem>>;
651
+ /** A bound object resolver's literal property: its resolver is already bound
652
+ * (or a `{ ref }` the CLI resolves against `definitions` at runtime). */
653
+ interface BoundField {
654
+ resolver: BoundResolver | ResolverRef;
655
+ label?: string;
656
+ required?: boolean;
657
+ valueType?: string;
658
+ }
659
+ /**
660
+ * The runtime resolver `defineResolver` binds to: its imports are already
661
+ * captured, so the CLI calls these with input (and `search`) only, no sdk.
662
+ * `prompt` stays pure (no SDK reach).
663
+ *
664
+ * Carries every kind's fields on one loose interface, discriminated by `type`.
665
+ * The CLI rewrite (the consumer) narrows this into per-kind shapes; until then
666
+ * a single shape keeps the binder simple. `listItems` produces the candidate
667
+ * list for `dynamic`; `getProperties` builds the (unbound) property map for
668
+ * `object`. `properties` / `definitions` are bound; `items` is bound (or a ref).
669
+ */
670
+ interface BoundResolver {
671
+ type: ResolverType;
672
+ /** Sibling parameters that must resolve before this resolver runs (it reads
673
+ * their values from `input`). The param-dataflow prerequisite, distinct from
674
+ * `imports`' SDK-capability graph. */
675
+ requireParameters?: readonly string[];
676
+ inputType?: "text" | "password" | "email" | "search";
677
+ placeholder?: string;
678
+ value?: unknown;
679
+ text?: string;
680
+ properties?: Record<string, BoundField>;
681
+ definitions?: Record<string, BoundResolver>;
682
+ items?: BoundResolver | ResolverRef;
683
+ minItems?: number;
684
+ maxItems?: number;
685
+ /** For an array: the element's coarse value type, used to coerce a free-text
686
+ * item answer before validation (see {@link ArrayResolver.itemValueType}). */
687
+ itemValueType?: string;
688
+ getContext?: (bag: {
689
+ input: Record<string, unknown>;
690
+ }) => PromiseLike<unknown>;
691
+ listItems?: (bag: {
692
+ input: Record<string, unknown>;
693
+ context?: unknown;
694
+ search?: string;
695
+ cursor?: string;
696
+ }) => ListItemsResult<unknown>;
697
+ getProperties?: (bag: {
698
+ input: Record<string, unknown>;
699
+ }) => PromiseLike<Record<string, Field>>;
700
+ prompt?: (bag: {
701
+ items: unknown[];
702
+ input: Record<string, unknown>;
703
+ context?: unknown;
704
+ }) => ResolverPromptConfig;
705
+ tryResolveWithoutPrompt?: (bag: {
706
+ input: Record<string, unknown>;
707
+ }) => Promise<{
708
+ resolvedValue: unknown;
709
+ } | null>;
710
+ tryResolveFromSearch?: (bag: {
711
+ input: Record<string, unknown>;
712
+ search?: string;
713
+ }) => Promise<{
714
+ resolvedValue: unknown;
715
+ } | null>;
716
+ }
717
+ /**
718
+ * The runtime formatter `defineFormatter` binds to: `getContext` runs once per
719
+ * rendered batch (imports captured, no sdk) to build shared context; `format`
720
+ * is pure and synchronous, turning one item + context into a `FormattedItem`.
721
+ */
722
+ interface BoundFormatter<TItem = unknown, TInput = Record<string, unknown>, TContext = unknown> {
723
+ getContext?: (bag: {
724
+ items: TItem[];
725
+ input: TInput;
726
+ context?: TContext;
727
+ }) => Promise<TContext>;
728
+ format: (bag: {
729
+ item: TItem;
730
+ input: TInput;
731
+ context?: TContext;
732
+ }) => FormattedItem;
733
+ }
734
+ /**
735
+ * A leaf plugin that is a single function: it IS the method. `pluginType` is
736
+ * the node-kind discriminant; `name` is its identity and default
737
+ * binding name. `imports` are the other plugins it depends on. The stored
738
+ * `run` is loosely typed for `imports` (the precise type lives on the
739
+ * `defineMethod` authoring surface, like the shipped definePlugin).
740
+ */
741
+ interface MethodPlugin<TName extends string = string, TInput = unknown, TOutput = unknown, TPositional extends readonly string[] = readonly []> {
742
+ pluginType: "method";
743
+ name: TName;
744
+ namespace?: string;
745
+ /** `namespace/name`, or bare `name`. The `context.plugins` key. */
746
+ id: string;
747
+ /** True for a `declareMethod` stand-in: a typed reference with no real
748
+ * implementation. A real plugin under the same id satisfies it. */
749
+ standIn?: boolean;
750
+ imports: readonly AnyPlugin[];
751
+ /** Binding-name to plugin-id edges, normalized from `imports`;
752
+ * what the `imports` bag is built from. */
753
+ importBindings: readonly ImportBinding[];
754
+ /** Optional per-materialization constructor: runs once at createSdk
755
+ * (dependencies first), may side-effect, and returns the method's private
756
+ * state (delivered to `run` as `bag.state`). */
757
+ setup?: (bag: {
758
+ imports: Record<string, unknown>;
759
+ }) => unknown;
760
+ /** Validates `input` before `run` and drives the authoring `input` type. */
761
+ inputSchema?: z.ZodType;
762
+ /** Descriptive metadata for the registry / CLI / MCP / docs (carry-only at
763
+ * runtime). */
764
+ meta?: LeafMeta;
765
+ /** Per-parameter input resolvers (method attachments). Reached for
766
+ * materialization and bound into the entry at createSdk; a reachability-only
767
+ * edge whose imports never enter this method's `importBindings`. */
768
+ resolvers?: Record<string, Resolver>;
769
+ /** Output formatter (method attachment). Bound into the entry at createSdk. */
770
+ formatter?: Formatter;
771
+ run: (bag: MethodRunBag<any, TInput, any>) => TOutput;
772
+ /** How `run`'s result is shaped into the public surface (see Output in the
773
+ * design doc). Omitted is "raw". Stored loosely; the precise per-mode typing
774
+ * lives on the `defineMethod` overloads. */
775
+ output?: OutputConfig;
776
+ /** Positional projection (see Output): ordered keys of the canonical input
777
+ * that the public surface and imports take as positional arguments. The
778
+ * framework packs them back into `{ input }` before validation, middleware,
779
+ * and `run`, so internals stay canonical. The runtime reads this loose field;
780
+ * the precise names ride the `TPositional` type param for surface typing. */
781
+ positional?: readonly string[];
782
+ /**
783
+ * Phantom: carries the positional names as a tuple type so `BindingsOf` /
784
+ * `ExportSurface` can render the positional signature. Never present at
785
+ * runtime; the loose `positional` field above is the runtime carrier.
786
+ * @internal
787
+ */
788
+ readonly [POSITIONAL_NAMES]?: TPositional;
789
+ }
790
+ /** Phantom-only key (see `MethodPlugin`); never set at runtime. */
791
+ declare const POSITIONAL_NAMES: unique symbol;
792
+ /** A method's output mode: raw passthrough, a `{ data }` item envelope, or a
793
+ * paginated list. */
794
+ type OutputMode = "raw" | "item" | "list";
795
+ /** The authoring value for `output`: a bare mode string, or the object form
796
+ * (which carries list options). */
797
+ type OutputConfig = OutputMode | {
798
+ type: "raw";
799
+ } | {
800
+ type: "item";
801
+ } | {
802
+ type: "list";
803
+ adaptPage?: (response: any) => SdkPage<any>;
804
+ defaultPageSize?: number;
805
+ };
806
+ /** Normalized output config: always the object form with a resolved `type`. */
807
+ interface NormalizedOutput {
808
+ type: OutputMode;
809
+ adaptPage?: (response: any) => SdkPage<any>;
810
+ defaultPageSize?: number;
811
+ }
812
+ /** Framework-injected page controls a list method's `run` receives. */
813
+ type PageFetchInput = {
814
+ cursor?: string;
815
+ pageSize?: number;
816
+ };
817
+ /** Page controls a list method's public caller may pass. */
818
+ type PaginatedCallInput = PageFetchInput & {
819
+ maxItems?: number;
820
+ };
821
+ /**
822
+ * A response whose only own keys are `data` / `nextCursor`. Gates the
823
+ * list-standard overload: a raw envelope with extra keys is not a `StrictPage`
824
+ * and falls through to the adapted overload, where `adaptPage` is required.
825
+ */
826
+ type StrictPage$1<TResponse> = SdkPage<unknown> & {
827
+ [K in Exclude<keyof TResponse, keyof SdkPage<unknown>>]?: never;
828
+ };
829
+ /** Item type sourced from a page-ish response. */
830
+ type ItemOf$1<TResponse> = TResponse extends SdkPage<infer TItem> ? TItem : TResponse extends {
831
+ data: readonly (infer TItem)[];
832
+ } ? TItem : never;
833
+ /**
834
+ * A leaf plugin that is a single value (not a function). `value` is a static
835
+ * constant; `get({ imports })` computes the value from imports. Like a
836
+ * method's `setup`, `get` runs eagerly at createSdk (dependencies first), so a
837
+ * module-level value is built on import. An imported/surfaced property yields
838
+ * the value, not a callable.
839
+ */
840
+ interface PropertyPlugin<TName extends string = string, TValue = unknown> {
841
+ pluginType: "property";
842
+ name: TName;
843
+ namespace?: string;
844
+ /** `namespace/name`, or bare `name`. The `context.plugins` key. */
845
+ id: string;
846
+ /** True for a `declareProperty` stand-in: a typed reference with no value. A
847
+ * real property under the same id satisfies it. */
848
+ standIn?: boolean;
849
+ imports: readonly AnyPlugin[];
850
+ /** Binding-name to plugin-id edges, normalized from `imports`;
851
+ * what the `imports` bag is built from. */
852
+ importBindings: readonly ImportBinding[];
853
+ /** Optional once-eager constructor (the property twin of a method's `setup`):
854
+ * runs once at createSdk (dependencies first), may side-effect, and returns the
855
+ * private state delivered to `get` as `bag.state`. */
856
+ setup?: (bag: {
857
+ imports: Record<string, unknown>;
858
+ }) => unknown;
859
+ value?: TValue;
860
+ /** A live getter: computes the value from imports and `setup` state on each
861
+ * read (not once). The stored shape is loose; the precise typing lives on the
862
+ * `defineProperty` overloads. */
863
+ get?: (bag: {
864
+ imports: Record<string, unknown>;
865
+ state: unknown;
866
+ }) => TValue;
867
+ /** Descriptive metadata for the registry / CLI / MCP / docs (carry-only). */
868
+ meta?: LeafMeta;
869
+ /** A built-in whose value is the live `SdkContext`, injected at
870
+ * materialization. Reserved for kitcore's own plugins;
871
+ * authors use `value` / `get`. */
872
+ privileged?: boolean;
873
+ }
874
+ /**
875
+ * A middleware function wrapping one of the aggregate's imported methods.
876
+ * `next` invokes the next layer (an inner wrap, ultimately the core method);
877
+ * `imports` is the middleware plugin's own dependency reach; `input` is the
878
+ * canonical call argument. It must preserve the target's contract; the
879
+ * `MiddlewareMap` typing on `definePlugin` enforces that statically.
880
+ */
881
+ type MiddlewareFn = (bag: {
882
+ imports: any;
883
+ next: (input: any) => any;
884
+ input: any;
885
+ }) => any;
886
+ /**
887
+ * The authoring type for an aggregate's `middleware`: a map
888
+ * whose keys are the method bindings among `imports` (you can only wrap a
889
+ * method you import) and whose values are contract-preserving wraps. `next` and
890
+ * `input` take the target's input and the wrap must return the target's output,
891
+ * so a wrap that changes the public signature, or that targets a non-imported /
892
+ * non-method binding, does not compile.
893
+ */
894
+ type MiddlewareMap<TImports> = {
895
+ [K in keyof TImports as TImports[K] extends (input: any) => any ? K : never]?: TImports[K] extends (input: infer TInput) => infer TOutput ? (bag: {
896
+ imports: TImports;
897
+ next: (input: TInput) => TOutput;
898
+ input: TInput;
899
+ }) => TOutput : never;
900
+ };
901
+ /** The export record one array element contributes: a leaf under its own name,
902
+ * a module under each of its export bindings. */
903
+ type ElementExports<E> = E extends MethodPlugin<infer N, any, any, any> ? {
904
+ [K in N]: E;
905
+ } : E extends PropertyPlugin<infer N, any> ? {
906
+ [K in N]: E;
907
+ } : E extends AggregatePlugin<string, infer TE> ? TE : never;
908
+ /**
909
+ * The canonical export record an aggregate stores: each array element's
910
+ * bindings merged, so every downstream consumer sees a `Record<binding, leaf>`.
911
+ */
912
+ type ArrayExports<T extends readonly (AnyLeafPlugin | AnyAggregatePlugin)[]> = T extends readonly [] ? Record<never, never> : UnionToIntersection<{
913
+ [I in keyof T]: ElementExports<T[I]>;
914
+ }[number]>;
915
+ interface AggregatePlugin<TName extends string = string, TExports extends Record<string, AnyLeafPlugin> = Record<string, AnyLeafPlugin>> {
916
+ pluginType: "aggregate";
917
+ name: TName;
918
+ namespace?: string;
919
+ /** `namespace/name`, or bare `name`. The `context.plugins` key. */
920
+ id: string;
921
+ /** True for a `declarePlugin` stand-in: a typed reference to a whole module
922
+ * with no implementation. A real aggregate under the same id satisfies it. */
923
+ standIn?: boolean;
924
+ imports: readonly AnyPlugin[];
925
+ /** Binding-name to plugin-id edges, normalized from `imports`; what a
926
+ * middleware wrap's `imports` is built from, and how a middleware target
927
+ * binding resolves to a method id. */
928
+ importBindings: readonly ImportBinding[];
929
+ exports: TExports;
930
+ middleware?: Record<string, MiddlewareFn>;
931
+ }
932
+ type AnyAggregatePlugin = AggregatePlugin<string, Record<string, any>>;
933
+ /**
934
+ * A legacy bridge plugin: wraps an old function plugin
935
+ * (`(sdk) => provides`) so it materializes inside the new graph. At
936
+ * materialization it runs `run` against a live compat view, merges the
937
+ * returned context contributions into the shared `SdkContext`, and synthesizes
938
+ * a `context.plugins` entry per root key. `TSurface` is the surfaced shape (the
939
+ * provides minus `context`). This is the single shape `createPluginStack()
940
+ * .toPlugin()` emits; there is no separate interim definition format.
941
+ */
942
+ interface LegacyPlugin<TSurface = Record<string, unknown>> {
943
+ pluginType: "legacy";
944
+ name: string;
945
+ namespace?: string;
946
+ /** `namespace/name`, or bare `name`. The `context.plugins` key. */
947
+ id: string;
948
+ imports: readonly AnyPlugin[];
949
+ importBindings: readonly ImportBinding[];
950
+ run: (sdk: any) => PluginProvides;
951
+ /** Type-only carrier for the surfaced shape; never set at runtime. */
952
+ readonly __surface?: TSurface;
953
+ }
954
+ type AnyLegacyPlugin = LegacyPlugin<any>;
955
+ type AnyPlugin = AnyLeafPlugin | AnyAggregatePlugin | AnyLegacyPlugin;
956
+ /**
957
+ * A transitional root that merges a legacy function-plugin stack with the
958
+ * module-model plugins migrated off it (see Migration order). At `createSdk` it
959
+ * lifts and runs the legacy stack (like `fromFunctionPlugin`), materializes the
960
+ * module-model `plugin`, and surfaces the union: the legacy stack's methods plus
961
+ * the module plugin's exports. The migrated plugins live in one `plugin`
962
+ * aggregate, so each migration only edits that aggregate's exports, not the
963
+ * heads. Deleted once every plugin is module-model.
964
+ */
965
+ interface LegacyMergePlugin<TProvides extends PluginProvides = PluginProvides, TPlugin extends AnyPlugin = AnyPlugin> {
966
+ pluginType: "legacy-merge";
967
+ name: string;
968
+ namespace?: string;
969
+ id: string;
970
+ /** The lifted legacy stack (one node). */
971
+ legacy: LegacyPlugin<TProvides & {
972
+ getRegistry: (options?: {
973
+ package?: string;
974
+ }) => RegistryResult;
975
+ }>;
976
+ /** The module-model plugins migrated off the legacy stack. */
977
+ plugin: TPlugin;
978
+ }
979
+ /** One middleware layer on a method's chain: the wrap and its owning aggregate
980
+ * (whose `imports` the wrap receives, built live at call time). */
981
+ interface MiddlewareWrap {
982
+ run: MiddlewareFn;
983
+ owner: AnyAggregatePlugin;
984
+ }
985
+ /** A materialized method: a stable callable `value` that folds `chain` around
986
+ * the core at call time. The chain is ordered dependents-outermost; it is
987
+ * mutable so post-seal `addPlugin` middleware can append. */
988
+ interface MethodEntry {
989
+ pluginType: "method";
990
+ name: string;
991
+ value: (input: any) => any;
992
+ chain: MiddlewareWrap[];
993
+ /** Carried from the descriptor for the registry / CLI / MCP / docs. */
994
+ inputSchema?: z.ZodType;
995
+ meta?: LeafMeta;
996
+ /** Resolved output mode; the registry derives presentation from it. */
997
+ output?: NormalizedOutput;
998
+ /** Positional input projection (see Output): ordered canonical-input keys the
999
+ * public callable / imports take as positional args. */
1000
+ positional?: readonly string[];
1001
+ /** Bound input resolvers (their imports captured at materialization), keyed by
1002
+ * param name. The CLI calls these with input only, no sdk. */
1003
+ resolvers?: Record<string, BoundResolver>;
1004
+ /** Bound output formatter (imports captured at materialization). */
1005
+ formatter?: BoundFormatter;
1006
+ }
1007
+ /** A materialized property: a static `value`, or a live `getValue` thunk that
1008
+ * re-derives the value per read (consumers install it as a getter on the surface
1009
+ * and on `imports`). Exactly one of `value` / `getValue` is set. */
1010
+ interface PropertyEntry {
1011
+ pluginType: "property";
1012
+ name: string;
1013
+ value?: any;
1014
+ getValue?: () => any;
1015
+ /** Carried from the descriptor for the registry / CLI / MCP / docs. */
1016
+ meta?: LeafMeta;
1017
+ }
1018
+ /** A materialized aggregate: its resolved export bindings to child values
1019
+ * (a method's callable or a property's value). */
1020
+ interface AggregateEntry {
1021
+ pluginType: "aggregate";
1022
+ name: string;
1023
+ exports: Record<string, any>;
1024
+ }
1025
+ /** An entry in `context.plugins`. The `value`
1026
+ * of a method entry is its callable; of a property entry, its value. */
1027
+ type PluginEntry = MethodEntry | PropertyEntry | AggregateEntry;
1028
+ /**
1029
+ * The materialization substrate: every reachable plugin keyed by
1030
+ * id, plus the legacy-compat surface used during migration. The
1031
+ * compat fields let adapted function plugins read/write `context` exactly as
1032
+ * they do on the shipped stack: `meta` is the per-method registry source, `hooks`
1033
+ * the composed lifecycle hooks, and the index signature covers arbitrary legacy
1034
+ * fields a function plugin contributes (`api`, `options`, `manifest` helpers,
1035
+ * ...). A pure module-model SDK leaves `meta`/`hooks` empty and uses entry-level
1036
+ * metadata instead.
1037
+ */
1038
+ interface SdkContext {
1039
+ plugins: Record<string, PluginEntry>;
1040
+ meta: Record<string, PluginMeta>;
1041
+ hooks: MethodHooks;
1042
+ /** The SDK surface: each callable/value binding name mapped to the leaf plugin
1043
+ * id it resolves to. This is what the consumer actually calls (the root's
1044
+ * re-exports plus `addPlugin` additions), so the registry reports entries by
1045
+ * binding (with meta from the leaf) rather than dumping `plugins` by id. An
1046
+ * aliased re-export (`{ hi: greet }`) appears here as `hi -> "greet"`. */
1047
+ surface: Record<string, string>;
1048
+ [key: string]: any;
1049
+ }
1050
+ /** The surfaced shape of one re-exported child: a method's callable or a
1051
+ * property's value. */
1052
+ type ExportSurface<TChild extends AnyLeafPlugin> = TChild extends MethodPlugin<any, infer TInput, infer TOutput, infer TPositional> ? SurfaceCall<TInput, TOutput, TPositional> : TChild extends PropertyPlugin<any, infer TValue> ? TValue : never;
1053
+ /**
1054
+ * The framework-owned access an SDK carries beyond its string surface: the
1055
+ * legacy `context` string key (back-compat, narrows away later). The off-surface
1056
+ * `[CONTEXT]` symbol is attached at runtime (reach it via `getContext`) but kept
1057
+ * out of this type so it never leaks into a consumer's emitted declarations.
1058
+ */
1059
+ type SdkInternals = {
1060
+ context: SdkContext;
1061
+ };
1062
+ /**
1063
+ * The materialized SDK for a leaf root: the root's callable (method) or value
1064
+ * (property) under its name, plus framework access.
1065
+ */
1066
+ type Sdk$1<TName extends string, TInput, TOutput, TPositional extends readonly string[] = readonly []> = {
1067
+ [K in TName]: SurfaceCall<TInput, TOutput, TPositional>;
1068
+ } & SdkInternals;
1069
+ /** The materialized SDK for a property root: the value under its name. */
1070
+ type PropertySdk<TName extends string, TValue> = {
1071
+ [K in TName]: TValue;
1072
+ } & SdkInternals;
1073
+ /**
1074
+ * The materialized SDK for an aggregate root: each export binding becomes a
1075
+ * surface entry, typed from the re-exported child (callable for a method,
1076
+ * value for a property).
1077
+ */
1078
+ type AggregateSdk<TExports extends Record<string, AnyLeafPlugin>> = {
1079
+ [K in keyof TExports]: ExportSurface<TExports[K]>;
1080
+ } & SdkInternals;
1081
+ /**
1082
+ * The surface a plugin adds to an SDK when passed to `addPlugin`: a method
1083
+ * under its name, a property's value, an aggregate's export bindings, or a
1084
+ * legacy function plugin's root provides (minus `context`).
1085
+ */
1086
+ type AddedSurface<P> = P extends MethodPlugin<infer TName, infer TInput, infer TOutput, infer TPositional> ? {
1087
+ [K in TName]: SurfaceCall<TInput, TOutput, TPositional>;
1088
+ } : P extends PropertyPlugin<infer TName, infer TValue> ? {
1089
+ [K in TName]: TValue;
1090
+ } : P extends AggregatePlugin<string, infer TExports> ? {
1091
+ [K in keyof TExports]: ExportSurface<TExports[K]>;
1092
+ } : P extends (sdk: any) => infer TProvides ? TProvides extends PluginProvides ? Omit<TProvides, "context"> : Record<never, never> : Record<never, never>;
1093
+ /** `T` when it is a specific string literal, else `never`. Used on a stand-in's
1094
+ * `name` so the id is always captured as a literal: a widened `string` (or the
1095
+ * stale `declareMethod<TInput, TOutput>(...)` call shape, where the contract
1096
+ * lands in the name slot) is rejected at the call rather than silently
1097
+ * weakening the requirements ledger. */
1098
+ type LiteralString<T extends string> = string extends T ? never : T;
1099
+ declare const REQUIRES: unique symbol;
1100
+ declare const PROVIDES: unique symbol;
1101
+ /** Phantom carriers for the requirements ledger; never present at runtime. */
1102
+ interface PluginSummary<TRequires extends string = never, TProvides extends string = never> {
1103
+ /** Declaration ids the plugin's subgraph still needs. @internal */
1104
+ readonly [REQUIRES]?: TRequires;
1105
+ /** Ids the plugin and its subgraph provide. @internal */
1106
+ readonly [PROVIDES]?: TProvides;
1107
+ }
1108
+ /** The declaration ids a plugin still needs (reads the phantom carrier). */
1109
+ type RequiresOf<P> = P extends {
1110
+ readonly [REQUIRES]?: infer R;
1111
+ } ? Extract<R, string> : never;
1112
+ /** The ids a plugin and its subgraph provide (reads the phantom carrier). */
1113
+ type ProvidesOf$1<P> = P extends {
1114
+ readonly [PROVIDES]?: infer R;
1115
+ } ? Extract<R, string> : never;
1116
+ /** Union the requires / provides across an inline imports or exports tuple. */
1117
+ type RequiresIn<T extends readonly unknown[]> = RequiresOf<T[number]>;
1118
+ type ProvidesIn<T extends readonly unknown[]> = ProvidesOf$1<T[number]>;
1119
+ /**
1120
+ * Reject an `imports` / `exports` value whose type widened to a non-tuple
1121
+ * `Plugin[]`: a literal tuple has a literal `length`, a widened array has
1122
+ * `length: number`. Identity in the good (tuple) case, so `T & StaticList<T>`
1123
+ * infers `T` unchanged; an error brand in the bad case, which the passed array
1124
+ * is not assignable to.
1125
+ */
1126
+ type StaticList<T extends readonly unknown[]> = number extends T["length"] ? {
1127
+ readonly __kitcoreError: "must be a fixed inline list of plugins, not a widened Plugin[]; declare them inline so the dependency graph stays statically known";
1128
+ } : T;
1129
+ /** A leaf provides its own name plus whatever its imports provide. */
1130
+ type LeafProvides<TName extends string, TImports extends readonly unknown[]> = TName | ProvidesIn<TImports>;
1131
+ /** A leaf requires its imports' requirements, minus what it provides. */
1132
+ type LeafRequires<TName extends string, TImports extends readonly unknown[]> = Exclude<RequiresIn<TImports>, LeafProvides<TName, TImports>>;
1133
+ /** An aggregate provides its own name plus its imports' and exports' provides. */
1134
+ type AggregateProvides<TName extends string, TImports extends readonly unknown[], TExports extends readonly unknown[]> = TName | ProvidesIn<TImports> | ProvidesIn<TExports>;
1135
+ /** An aggregate requires its imports' and exports' requirements, minus provides. */
1136
+ type AggregateRequires<TName extends string, TImports extends readonly unknown[], TExports extends readonly unknown[]> = Exclude<RequiresIn<TImports> | RequiresIn<TExports>, AggregateProvides<TName, TImports, TExports>>;
1137
+ /** A plugin's id as a type: `namespace/name`, or bare `name` when the namespace
1138
+ * is empty. The ledger keys on this (matching runtime id resolution), not the
1139
+ * bare name, so same-named plugins in different namespaces stay distinct. */
1140
+ type IdOf<TNamespace extends string, TName extends string> = TNamespace extends "" ? TName : `${TNamespace}/${TName}`;
1141
+ /** The binding name of an id: its last `/`-separated segment. The inverse view
1142
+ * of `IdOf`, used by `declare*` to derive the bare binding from a full id. */
1143
+ type LastSegment<TId extends string> = TId extends `${string}/${infer Rest}` ? LastSegment<Rest> : TId;
1144
+ /** The `PluginSummary` a leaf carries, keyed on its full id. */
1145
+ type LeafSummary<TNamespace extends string, TName extends string, TImports extends readonly unknown[]> = PluginSummary<LeafRequires<IdOf<TNamespace, TName>, TImports>, LeafProvides<IdOf<TNamespace, TName>, TImports>>;
1146
+ /** The `PluginSummary` an aggregate carries, keyed on its full id. */
1147
+ type AggregateSummary<TNamespace extends string, TName extends string, TImports extends readonly unknown[], TExports extends readonly unknown[]> = PluginSummary<AggregateRequires<IdOf<TNamespace, TName>, TImports, TExports>, AggregateProvides<IdOf<TNamespace, TName>, TImports, TExports>>;
1148
+ /** Surfaced by `createSdk` when reachable declarations have no provider. */
1149
+ interface MissingDependencies<TIds extends string> {
1150
+ readonly __kitcoreError: "Missing concrete provider(s) for required declaration id(s)";
1151
+ readonly missing: TIds;
1152
+ }
1153
+ /**
1154
+ * `unknown` when every reachable declaration is provided, otherwise a
1155
+ * `MissingDependencies` brand. `createSdk` takes `root: P & CompletenessOf<P>`,
1156
+ * so a complete root infers `P` unchanged (intersect `unknown`) while an
1157
+ * incomplete one fails to assign (the argument lacks `missing`).
1158
+ */
1159
+ type CompletenessOf<P> = [
1160
+ Exclude<RequiresOf<P>, ProvidesOf$1<P>>
1161
+ ] extends [never] ? unknown : MissingDependencies<Exclude<RequiresOf<P>, ProvidesOf$1<P>>>;
1162
+ /** Recover the materialized SDK type for a checked root (the summary that
1163
+ * rides on the `define*` return is transparent to these). */
1164
+ type MethodSdkOf<P> = P extends MethodPlugin<infer TName, infer TInput, infer TOutput, infer TPos> ? Sdk$1<TName, TInput, TOutput, TPos> : never;
1165
+ type PropertySdkOf<P> = P extends PropertyPlugin<infer TName, infer TValue> ? PropertySdk<TName, TValue> : never;
1166
+ type AggregateSdkOf<P> = P extends AggregatePlugin<string, infer TExports> ? AggregateSdk<TExports> : never;
1167
+
1168
+ /**
1169
+ * Declaration for a registry category (a bucket grouping related functions).
1170
+ * Plugins reference categories in their `meta.categories` field, as either a
1171
+ * bare key (auto-derive title and plural) or this object (override either).
1172
+ *
1173
+ * Examples (with auto-derive rules):
1174
+ * - `{ key: "app" }` → title "App", plural "Apps"
1175
+ * - `{ key: "client-credentials" }` → title "Client Credentials", plural "Client Credentials"
1176
+ * - `{ key: "utility" }` → title "Utility", plural "Utilities"
1177
+ * - `{ key: "http", title: "HTTP Request" }` → plural "HTTP Requests"
1178
+ */
1179
+ interface CategoryDefinition {
1180
+ key: string;
1181
+ /** Display title for the category. Auto-derived from `key` if omitted. */
1182
+ title?: string;
1183
+ /** Plural form of `title`. Auto-derived from the resolved title if omitted. */
1184
+ titlePlural?: string;
1185
+ }
1186
+ interface FunctionRegistryEntry<TSdk = any> {
1187
+ name: string;
1188
+ /**
1189
+ * Human-readable description of the function. Surfaced wherever the
1190
+ * registry is consumed (command help, tool/RPC descriptions, generated
1191
+ * documentation). Prefer providing this directly rather than relying
1192
+ * solely on inputSchema.describe().
1193
+ */
1194
+ description?: string;
1195
+ type?: "list" | "item" | "create" | "update" | "delete" | "function";
1196
+ itemType?: string;
1197
+ returnType?: string;
1198
+ inputSchema?: z.ZodSchema;
1199
+ inputParameters?: Array<{
1200
+ name: string;
1201
+ schema: z.ZodSchema;
1202
+ }>;
1203
+ outputSchema?: z.ZodSchema;
1204
+ /**
1205
+ * Ordered input keys the public surface projects onto positional arguments
1206
+ * (the method's `positional` declaration). Absent when the method takes only
1207
+ * the canonical single bag. Lifted off the materialized method entry by the
1208
+ * surface builder, like `boundResolvers` — a runtime projection, not
1209
+ * descriptive meta.
1210
+ */
1211
+ positional?: readonly string[];
1212
+ categories: string[];
1213
+ resolvers?: Record<string, ResolverMetadata<TSdk, any, any>>;
1214
+ /**
1215
+ * Per-parameter bound resolvers from the new model (imports already captured,
1216
+ * called with `input` only, no sdk). Parallel to the legacy `resolvers` field
1217
+ * and `formatter`: the surface builder lifts these off the materialized method
1218
+ * entry. Additive bridge — populated for migrated `defineMethod` plugins; the
1219
+ * legacy `resolvers` field above stays the source for unmigrated ones.
1220
+ */
1221
+ boundResolvers?: Record<string, BoundResolver>;
1222
+ packages?: string[];
1223
+ /**
1224
+ * True if the plugin is registered only in the experimental SDK
1225
+ * factory. See `PluginMeta.experimental`.
1226
+ */
1227
+ experimental?: boolean;
1228
+ /** Confirmation prompt type - prompts user before executing */
1229
+ confirm?: "create-secret" | "delete";
1230
+ /**
1231
+ * Optional deprecation metadata for commands.
1232
+ */
1233
+ deprecation?: FunctionDeprecation;
1234
+ /**
1235
+ * Short aliases for parameter names (e.g., { request: "X", header: "H" }).
1236
+ * Consumers that render the function as a flag-style command surface use
1237
+ * these as short forms.
1238
+ */
1239
+ aliases?: Record<string, string>;
1240
+ /**
1241
+ * Output formatter, normalized to the bound runtime shape (its imports/sdk
1242
+ * already captured), so consumers call `getContext`/`format` with no sdk.
1243
+ * The surface builder produces this from the method entry — `entry.formatter`
1244
+ * for a migrated plugin, or the legacy `meta.formatter` adapted — so vintage
1245
+ * is invisible here.
1246
+ */
1247
+ formatter?: BoundFormatter;
1248
+ /** Defaults to true. Set to false to suppress --json (e.g. login/logout/init). */
1249
+ supportsJsonOutput: boolean;
1250
+ }
1251
+ interface FunctionDeprecation {
1252
+ /** User-facing deprecation message for why/how to migrate */
1253
+ message: string;
1254
+ }
1255
+ interface RegistryResult<TSdk = any> {
1256
+ functions: FunctionRegistryEntry<TSdk>[];
1257
+ categories: {
1258
+ key: string;
1259
+ title: string;
1260
+ titlePlural: string;
1261
+ functions: string[];
1262
+ }[];
1263
+ }
1264
+
1265
+ /**
1266
+ * ------------------------------
1267
+ * Plugin Type System
1268
+ * ------------------------------
1269
+ *
1270
+ * Plugins receive the sdk as a positional parameter. sdk.context holds shared
1271
+ * internal state (api client, event emission, meta, options, etc.). SDK methods
1272
+ * live at the root, context nests under .context.
1273
+ *
1274
+ * A plugin is (sdk) => partialSdk. `createPluginStack()` accumulates plugins
1275
+ * and materializes a built `Sdk` via `.toSdk()`; `addPlugin(sdk, plugin)`
1276
+ * extends an already-built SDK in place with one more plugin.
1277
+ */
1278
+
1279
+ interface PluginProvides extends Record<string, any> {
1280
+ context?: {
1281
+ meta?: Record<string, PluginMeta<any>>;
1282
+ hooks?: MethodHooks;
1283
+ [key: string]: any;
1284
+ };
1285
+ }
1286
+ interface PluginMeta<TSdk = unknown> {
1287
+ /**
1288
+ * Human-readable description of the plugin function. Used by the CLI (help text),
1289
+ * MCP (tool description), and README generators. When omitted, falls back to
1290
+ * the inputSchema's `.describe()` value or a generic placeholder.
1291
+ */
1292
+ description?: string;
1293
+ /**
1294
+ * Buckets this function belongs to in `getRegistry()` output. Each entry is
1295
+ * either a bare key (`"app"`) for auto-derived titles or a {@link CategoryDefinition}
1296
+ * object to override the title or plural. Only one plugin needs to supply
1297
+ * the object form per category key; object refs win over string refs, so
1298
+ * other plugins in the same bucket can stay on bare strings.
1299
+ */
1300
+ categories?: (string | CategoryDefinition)[];
1301
+ type?: "list" | "item" | "create" | "update" | "delete" | "function";
1302
+ itemType?: string;
1303
+ returnType?: string;
1304
+ inputSchema?: z.ZodSchema;
1305
+ outputSchema?: z.ZodSchema;
1306
+ /**
1307
+ * Item formatter that the registry hands to the CLI/MCP renderer. The
1308
+ * `sdk` param on `fetch` is typed to the plugin's own declared SDK
1309
+ * surface (`TRequires & TProvides`); reaching into another plugin's
1310
+ * method requires adding it to `TRequires` explicitly.
1311
+ */
1312
+ formatter?: OutputFormatter<TSdk, any, any, any>;
1313
+ /**
1314
+ * Per-parameter resolver metadata. Same `TSdk` surfaces in each
1315
+ * resolver's `fetch`/`tryResolveWithoutPrompt` callbacks.
1316
+ */
1317
+ resolvers?: Record<string, ResolverMetadata<TSdk, any, any>>;
1318
+ /** Confirmation prompt type - prompts user before executing */
1319
+ confirm?: "create-secret" | "delete";
1320
+ /**
1321
+ * Marks this plugin as experimental — wrappers can keep it out of
1322
+ * their stable build (typically by gating it behind an
1323
+ * `experimental` subpath import) and the registry can badge it in
1324
+ * generated docs / CLI help. No runtime capability check.
1325
+ */
1326
+ experimental?: boolean;
1327
+ [key: string]: any;
1328
+ }
1329
+ /**
1330
+ * Plugin interface — 2 type params:
1331
+ *
1332
+ * TSdk = what this plugin needs (the SDK shape including context)
1333
+ * TProvides = what this plugin returns (a partial SDK shape)
1334
+ *
1335
+ * The sdk param always includes context.meta, even if TSdk doesn't declare it.
1336
+ */
1337
+ interface Plugin<TSdk = {}, TProvides extends PluginProvides = PluginProvides> {
1338
+ (sdk: TSdk & {
1339
+ context: {
1340
+ meta: Record<string, PluginMeta<any>>;
1341
+ hooks: MethodHooks;
1342
+ };
1343
+ }): TProvides;
1344
+ }
1345
+ /**
1346
+ * A built SDK. Carries the plugins' contributions plus the
1347
+ * `getRegistry` accessor over `context.meta`. No `addPlugin` method
1348
+ * on the shape: extension after build goes through the top-level
1349
+ * `addPlugin(sdk, plugin)` function, which mutates the sdk in place
1350
+ * and narrows the caller's binding via TypeScript's assertion
1351
+ * functions.
1352
+ */
1353
+ type Sdk<T = {
1354
+ context: {
1355
+ meta: Record<string, PluginMeta<any>>;
1356
+ hooks: MethodHooks;
1357
+ };
1358
+ }> = T & {
1359
+ getRegistry(options?: {
1360
+ package?: string;
1361
+ }): RegistryResult<T>;
1362
+ };
1363
+
1364
+ /**
1365
+ * ------------------------------
1366
+ * Plugin authoring helpers
1367
+ * ------------------------------
1368
+ *
1369
+ * - `createPluginMethod` / `createPaginatedPluginMethod`: per-method
1370
+ * primitives that sit inside a `definePlugin` callback and build the
1371
+ *
1372
+ * { [name]: wrappedFn, context: { meta: { [name]: meta } } }
1373
+ *
1374
+ * fragment a plugin returns for a single method, wiring up
1375
+ * `createFunction` / `createPaginatedFunction`, the method-call hooks,
1376
+ * and the doubled `name` (function key + meta key) in one place.
1377
+ *
1378
+ * Two method helpers (rather than one with a `paginated: true` discriminant)
1379
+ * because the handler signature changes shape across pagination, and
1380
+ * discriminated unions on optional booleans produce noisy TS errors.
1381
+ */
1382
+
1383
+ /**
1384
+ * Method-level meta fields. Mirrors `PluginMeta` minus `inputSchema`, which is
1385
+ * passed at the top level alongside the handler and merged into the meta by
1386
+ * the helpers themselves.
1387
+ */
1388
+ type MethodMeta<TSdk> = Omit<PluginMeta<TSdk>, "inputSchema">;
1389
+ /**
1390
+ * The plugin's own method signature, synthesized from the method config.
1391
+ * Mixed into the resolver-side SDK so a resolver may freely reference the
1392
+ * host plugin's own method (e.g. `appKeyResolver` calling `sdk.getApp`)
1393
+ * without forcing the plugin to declare a circular dependency on itself.
1394
+ *
1395
+ * Uses `any` for options and return: we only need to assert the method
1396
+ * exists on `sdk`, not pin its full signature. Using `TInput`/`TResult`
1397
+ * here would create a circular inference (TSdk depends on TInput/TResult
1398
+ * via the resolvers slot, TInput/TResult are inferred from the handler
1399
+ * which depends on TSdk), and TS resolves the cycle by widening to
1400
+ * `unknown`. With `any`, the resolver check still verifies the method's
1401
+ * presence on the SDK; signature precision for self is the plugin
1402
+ * author's responsibility.
1403
+ *
1404
+ * Not mixed into the handler's `sdk`: handlers run against the SDK that
1405
+ * existed when the plugin was added to the stack (closure-captured), so
1406
+ * self-method access there would be a lie at runtime.
1407
+ */
1408
+ type SelfMethod<TName extends string> = {
1409
+ [K in TName]: (options?: any) => any;
1410
+ };
1411
+ interface PluginMethodConfig<TSdk, TInput, TResult, TName extends string, TResolvers> extends Omit<MethodMeta<TSdk>, "resolvers"> {
1412
+ name: TName;
1413
+ /**
1414
+ * Schema for runtime input validation; drives the handler's `options`
1415
+ * type. For plugins that accept deprecated parameter aliases this is a
1416
+ * `z.union([CanonicalSchema, DeprecatedSchema])` — the registry
1417
+ * unwraps unions and exposes only the first variant (canonical) to
1418
+ * documentation and downstream consumer surfaces.
1419
+ */
1420
+ inputSchema?: z.ZodSchema<TInput>;
1421
+ handler: (args: {
1422
+ sdk: TSdk;
1423
+ options: TInput;
1424
+ }) => Promise<TResult>;
1425
+ /**
1426
+ * Per-parameter resolvers. Each entry's `TSdk` requirement is checked
1427
+ * against the plugin's own `TSdk` (plus the plugin's own method via
1428
+ * {@link SelfMethod}) using {@link ValidResolvers}; mismatches surface
1429
+ * at the offending key. `NoInfer` pins `TSdk` to the `sdk` argument so
1430
+ * resolver entries don't widen the inferred `TSdk`.
1431
+ */
1432
+ resolvers?: ValidResolvers<NoInfer<TSdk & SelfMethod<TName>>, TResolvers> & TResolvers;
1433
+ }
1434
+ type PluginMethodReturn<TName extends string, TInput, TResult> = {
1435
+ [K in TName]: (options?: TInput) => Promise<TResult>;
1436
+ } & {
1437
+ context: {
1438
+ meta: {
1439
+ [K in TName]: PluginMeta;
1440
+ };
1441
+ };
1442
+ };
1443
+ /**
1444
+ * Build the method fragment for a non-paginated SDK method. Used inside a
1445
+ * `definePlugin(...)` callback:
1446
+ *
1447
+ * export const getProfilePlugin = definePlugin(
1448
+ * (sdk: ApiPluginProvides & EventEmissionProvides) =>
1449
+ * createPluginMethod(sdk, {
1450
+ * name: "getProfile",
1451
+ * categories: ["account"],
1452
+ * inputSchema: GetProfileSchema,
1453
+ * handler: async ({ sdk }) => { ... },
1454
+ * }),
1455
+ * );
1456
+ */
1457
+ declare function createPluginMethod<const TName extends string, TSdk extends {
1458
+ context: unknown;
1459
+ }, TInput, TResult, const TResolvers extends Record<string, ResolverMetadata<any, any, any>> = {}>(sdk: TSdk, config: PluginMethodConfig<TSdk, TInput, TResult, TName, TResolvers>): PluginMethodReturn<TName, TInput, TResult>;
1460
+ interface PaginatedPluginMethodConfigBase<TSdk, TInput, TName extends string, TResolvers> extends Omit<MethodMeta<TSdk>, "resolvers"> {
1461
+ name: TName;
1462
+ /** Same semantics as `createPluginMethod`'s `inputSchema`. */
1463
+ inputSchema?: z.ZodSchema<TInput>;
1464
+ /**
1465
+ * Optional default page size when the caller doesn't pass one. Mirrors
1466
+ * `createPaginatedFunction`'s `defaultPageSize` arg.
1467
+ */
1468
+ defaultPageSize?: number;
1469
+ /** See {@link PluginMethodConfig.resolvers}. */
1470
+ resolvers?: ValidResolvers<NoInfer<TSdk & SelfMethod<TName>>, TResolvers> & TResolvers;
1471
+ }
1472
+ /**
1473
+ * A page whose *only* own keys are `data` / `nextCursor`. Used to constrain
1474
+ * the Standard overload: a raw envelope with extra keys (a JSON:API
1475
+ * `links`/`meta`, a top-level `next`, etc.) is NOT a `StrictPage`, so it falls
1476
+ * through to the Adapted overload and `adaptPage` becomes required. Each excess
1477
+ * key is mapped to `?: never`, which a real value (e.g. `links: {...}`) can't
1478
+ * satisfy — that's what a plain `SdkPage` assignability check (which allows
1479
+ * excess keys structurally) misses.
1480
+ */
1481
+ type StrictPage<TResponse> = SdkPage<unknown> & {
1482
+ [K in Exclude<keyof TResponse, keyof SdkPage<unknown>>]?: never;
1483
+ };
1484
+ /**
1485
+ * Config for a paginated method whose handler already returns a clean page
1486
+ * (`{ data, nextCursor? }` and nothing else — see `StrictPage`, enforced on
1487
+ * the overload). No `adaptPage` needed; `TItem` is sourced from the handler's
1488
+ * `data`. Interface extension keeps this a single flattened object type (not
1489
+ * an intersection), preserving clean inference of the `resolvers` /
1490
+ * `TResolvers` slot.
1491
+ */
1492
+ interface PaginatedPluginMethodConfigStandard<TSdk, TInput, TResponse, TName extends string, TResolvers> extends PaginatedPluginMethodConfigBase<TSdk, TInput, TName, TResolvers> {
1493
+ handler: (args: {
1494
+ sdk: TSdk;
1495
+ options: TInput & {
1496
+ cursor?: string;
1497
+ pageSize?: number;
1498
+ };
1499
+ }) => Promise<TResponse>;
1500
+ /** No adapter: the handler already returns a page. */
1501
+ adaptPage?: undefined;
1502
+ }
1503
+ /**
1504
+ * Config for a paginated method whose handler returns a raw upstream shape
1505
+ * (`TResponse`, e.g. a JSON:API `links.next` envelope). `adaptPage` is required
1506
+ * to translate it into a page. `TItem` is sourced from `TResponse` (`ItemOf`),
1507
+ * not the adapter — the adapter is item-agnostic (relocates the cursor; items
1508
+ * are finalized in the handler's `data`), hence `NoInfer`, so a generic adapter
1509
+ * (e.g. `<T>(r) => SdkPage<T>`) doesn't collapse `TItem` to `unknown`.
1510
+ */
1511
+ interface PaginatedPluginMethodConfigAdapted<TSdk, TInput, TResponse, TItem, TName extends string, TResolvers> extends PaginatedPluginMethodConfigBase<TSdk, TInput, TName, TResolvers> {
1512
+ handler: (args: {
1513
+ sdk: TSdk;
1514
+ options: TInput & {
1515
+ cursor?: string;
1516
+ pageSize?: number;
1517
+ };
1518
+ }) => Promise<TResponse>;
1519
+ adaptPage: (response: TResponse) => SdkPage<NoInfer<TItem>>;
1520
+ }
1521
+ type ItemOf<TResponse> = TResponse extends SdkPage<infer TItem> ? TItem : TResponse extends {
1522
+ data: readonly (infer TItem)[];
1523
+ } ? TItem : never;
1524
+ type PaginatedPluginMethodReturn<TName extends string, TInput, TItem> = {
1525
+ [K in TName]: (options?: TInput & {
1526
+ cursor?: string;
1527
+ pageSize?: number;
1528
+ maxItems?: number;
1529
+ }) => PaginatedSdkResult<TItem>;
1530
+ } & {
1531
+ context: {
1532
+ meta: {
1533
+ [K in TName]: PluginMeta;
1534
+ };
1535
+ };
1536
+ };
1537
+ /**
1538
+ * Paginated variant of `createPluginMethod`. Two overloads enforce the
1539
+ * response contract at compile time:
1540
+ *
1541
+ * - **Standard** — the handler returns a strict `SdkPage<TItem>`
1542
+ * (`{ data, nextCursor? }` and nothing else); no `adaptPage`.
1543
+ * - **Adapted** — the handler returns a raw upstream shape and `adaptPage` is
1544
+ * *required* to translate it.
1545
+ *
1546
+ * A handler that returns neither a page-like shape nor pairs a raw shape with
1547
+ * `adaptPage` matches no overload and is a compile error.
1548
+ *
1549
+ * createPaginatedPluginMethod(sdk, {
1550
+ * name: "listThings",
1551
+ * inputSchema: ListThingsSchema,
1552
+ * adaptPage: (res) => ({ data: res.items, nextCursor: res.next }),
1553
+ * handler: ({ sdk, options }) => sdk.context.api.get("/things", { ... }),
1554
+ * });
1555
+ */
1556
+ declare function createPaginatedPluginMethod<const TName extends string, TSdk extends {
1557
+ context: unknown;
1558
+ }, TInput, TResponse extends StrictPage<TResponse>, TItem = ItemOf<TResponse>, const TResolvers extends Record<string, ResolverMetadata<any, any, any>> = {}>(sdk: TSdk, config: PaginatedPluginMethodConfigStandard<TSdk, TInput, TResponse, TName, TResolvers>): PaginatedPluginMethodReturn<TName, TInput, TItem>;
1559
+ declare function createPaginatedPluginMethod<const TName extends string, TSdk extends {
1560
+ context: unknown;
1561
+ }, TInput, TResponse, TItem = ItemOf<TResponse>, const TResolvers extends Record<string, ResolverMetadata<any, any, any>> = {}>(sdk: TSdk, config: PaginatedPluginMethodConfigAdapted<TSdk, TInput, TResponse, TItem, TName, TResolvers>): PaginatedPluginMethodReturn<TName, TInput, TItem>;
1562
+ /**
1563
+ * Maps a tuple of plugins to a tuple of their TSdk requirement types.
1564
+ *
1565
+ * SdkRequirementsOf<[Plugin<{ api }, _>, Plugin<{ options }, _>]>
1566
+ * = [{ api }, { options }]
1567
+ */
1568
+ type SdkRequirementsOf<T extends readonly Plugin<any, any>[]> = {
1569
+ [K in keyof T]: T[K] extends Plugin<infer Sdk, any> ? Sdk : never;
1570
+ };
1571
+ /**
1572
+ * Maps a tuple of plugins to a tuple of their TProvides output types.
1573
+ *
1574
+ * ProvidesOf<[Plugin<_, { hello }>, Plugin<_, { goodbye }>]>
1575
+ * = [{ hello }, { goodbye }]
1576
+ */
1577
+ type ProvidesOf<T extends readonly Plugin<any, any>[]> = {
1578
+ [K in keyof T]: T[K] extends Plugin<any, infer Provides> ? Provides : never;
1579
+ };
1580
+ /**
1581
+ * Intersects every member of a tuple into a single combined type. The
1582
+ * result is an object that has every property of every member at once.
1583
+ *
1584
+ * IntersectAll<[{ api }, { options }]> = { api } & { options }
1585
+ * IntersectAll<[]> = {}
1586
+ *
1587
+ * Walks recursively: head & IntersectAll<tail>, base case is the empty
1588
+ * tuple. Why intersection (`&`) and not union (`|`): the composed plugin
1589
+ * must require ALL of the sub-plugins' needs at once — an SDK that has
1590
+ * both `api` AND `options` — not "either api or options."
1591
+ */
1592
+ type IntersectAll<T extends readonly unknown[]> = T extends readonly [
1593
+ infer Head,
1594
+ ...infer Tail
1595
+ ] ? Head & IntersectAll<Tail> : {};
1596
+ /**
1597
+ * The TSdk a composed plugin requires: every sub-plugin's TSdk requirement,
1598
+ * all at once. Composing a plugin that needs `{ api }` with one that needs
1599
+ * `{ options }` yields a composed plugin that needs `{ api } & { options }`.
1600
+ */
1601
+ type ComposeSdk<T extends readonly Plugin<any, any>[]> = IntersectAll<SdkRequirementsOf<T>>;
1602
+ /**
1603
+ * What a composed plugin provides: every sub-plugin's TProvides combined.
1604
+ * Composing a plugin that provides `{ hello }` with one that provides
1605
+ * `{ goodbye }` yields `{ hello } & { goodbye }`.
1606
+ */
1607
+ type ComposeProvides<T extends readonly Plugin<any, any>[]> = IntersectAll<ProvidesOf<T>>;
1608
+ /**
1609
+ * @deprecated Use {@link createPluginStack} instead. It carries the same
1610
+ * collision-detection and hook-composition behavior and supports
1611
+ * per-step `{ override: true }` for intentional duplicates. Migration
1612
+ * (note the stack emits a definition, not a bare function):
1613
+ *
1614
+ * composePlugins(a, b, c)
1615
+ * // →
1616
+ * createPluginStack().use(a).use(b).use(c).toPlugin({ name: "bundle" })
1617
+ *
1618
+ * Bundles N plugins into a single plugin so a consumer can call
1619
+ * `.use(combined)` once on a stack. Bag mode: sub-plugins must not
1620
+ * depend on each other; TSdk on sub-plugins is the intersection of
1621
+ * every sub-plugin's requirements (so the type system never exposes
1622
+ * one sub-plugin's contributions to another).
1623
+ */
1624
+ declare function composePlugins<const Ts extends readonly Plugin<any, any>[]>(...plugins: Ts): Plugin<ComposeSdk<Ts>, ComposeProvides<Ts>>;
1625
+ /**
1626
+ * A typed builder that accumulates plugins into an immutable linked list.
1627
+ * Each `.use` returns a new stack instance (cons-style); the original
1628
+ * stack stays usable for branching. Call `toPlugin()` to collapse the
1629
+ * accumulated chain into a single `Plugin<TRequires, TProvides>`.
1630
+ *
1631
+ * Type params: `TRequires` is the external surface declared on
1632
+ * `createPluginStack<TRequires>()` (what the outer sdk will provide);
1633
+ * `TProvides` accumulates every registration's provides.
1634
+ */
1635
+ interface PluginStack<TRequires, TProvides extends PluginProvides> {
1636
+ /**
1637
+ * Register a bare plugin function. Its required surface is constrained
1638
+ * to `TRequires & TProvides` (the external requirements plus everything
1639
+ * provided by earlier `.use` calls), so registration order is enforced
1640
+ * per step: a plugin that reads a dependency at construction can only be
1641
+ * registered after a plugin that provides it. This stack collapses to a
1642
+ * single function plugin and runs its entries in registration order, so
1643
+ * the type-level order matches the runtime order.
1644
+ *
1645
+ * `{ override: true }` lets a registration replace an earlier root/meta
1646
+ * key it would otherwise collide with.
1647
+ */
1648
+ use<TNewProvides extends PluginProvides>(plugin: Plugin<TRequires & TProvides, TNewProvides>, options?: {
1649
+ override?: boolean;
1650
+ }): PluginStack<TRequires, TProvides & TNewProvides>;
1651
+ /**
1652
+ * Collapse the accumulated registrations into a single bare function
1653
+ * plugin. Its TSdk is `TRequires` (the declared external surface);
1654
+ * in-stack inter-plugin dependencies are resolved when its setup runs.
1655
+ * A head lifts it into the module model with `fromFunctionPlugin`.
1656
+ */
1657
+ toPlugin(): Plugin<TRequires, TProvides>;
1658
+ /**
1659
+ * Build the stack into a sealed, ready-to-use SDK. Eagerly applies the
1660
+ * resolved order: each plugin runs once during `toSdk`, contributions
1661
+ * merge into a single accumulator, and the result is wrapped as an
1662
+ * `Sdk<TRequires & TProvides>`. The returned SDK has `context` and
1663
+ * `getRegistry`, but no plugin-registration method.
1664
+ * To extend a built SDK, use the top-level {@link addPlugin}.
1665
+ */
1666
+ toSdk(): Sdk<TRequires & TProvides>;
1667
+ }
1668
+ /**
1669
+ * Create an empty plugin stack. Pass a type parameter to declare external
1670
+ * SDK requirements that every plugin in the stack can rely on:
1671
+ *
1672
+ * const tablesPlugin = createPluginStack<FetchPluginProvides>()
1673
+ * .use(apiPlugin)
1674
+ * .use(listTablesPlugin)
1675
+ * .use(getTablePlugin)
1676
+ * .toPlugin({ name: "tables" });
1677
+ *
1678
+ * const sdk = createPluginStack()
1679
+ * .use(fetchPlugin) // provides FetchPluginProvides
1680
+ * .use(tablesPlugin) // PluginDefinition<FetchPluginProvides, ...>
1681
+ * .toSdk();
1682
+ *
1683
+ * The stack itself is immutable: calling `.use` returns a new stack
1684
+ * without mutating the original, so you can branch off a base stack for
1685
+ * different consumers. Until the stack materializes, no plugin functions
1686
+ * run.
1687
+ */
1688
+ declare function createPluginStack<TRequires = object>(): PluginStack<TRequires, {
1689
+ context: {
1690
+ meta: Record<string, PluginMeta>;
1691
+ hooks: MethodHooks;
1692
+ };
1693
+ }>;
1694
+
1695
+ /**
1696
+ * Define a method leaf. The plugin IS the function; `createSdk` (or a
1697
+ * dependent's `imports`) binds it under its bare `name`. `imports` is typed
1698
+ * from the declared `imports` array. `namespace` sets the plugin's id
1699
+ * (`namespace/name`).
1700
+ *
1701
+ * The `output` mode shapes `run`'s result into the public surface and drives
1702
+ * the overload that types the call: raw (default, passthrough), `item`
1703
+ * (`run` returns `T`, surfaced as `Promise<{ data: T }>`), or `list` (`run`
1704
+ * returns one `SdkPage`, surfaced as `PaginatedSdkResult`). See Output.
1705
+ */
1706
+ declare function defineMethod<const TName extends string, TInput, TOutput, const TPositional extends readonly (keyof TInput & string)[] = readonly [], const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
1707
+ name: TName;
1708
+ namespace?: TNamespace;
1709
+ imports?: TImports & StaticList<TImports>;
1710
+ /** Validates `input` and drives its type: when given, `input` is the schema's
1711
+ * output and no `run` annotation is needed. */
1712
+ inputSchema?: z.ZodType<TInput>;
1713
+ resolvers?: Record<string, Resolver>;
1714
+ formatter?: Formatter;
1715
+ output?: "raw" | {
1716
+ type: "raw";
1717
+ };
1718
+ positional?: TPositional;
1719
+ setup?: (bag: {
1720
+ imports: ImportsOf<TImports>;
1721
+ }) => TState;
1722
+ run: (bag: MethodRunBag<ImportsOf<TImports>, TInput, TState>) => TOutput;
1723
+ } & LeafMetaFields): MethodPlugin<TName, TInput, TOutput, TPositional> & LeafSummary<TNamespace, TName, TImports>;
1724
+ declare function defineMethod<const TName extends string, TInput, TData, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
1725
+ name: TName;
1726
+ namespace?: TNamespace;
1727
+ imports?: TImports & StaticList<TImports>;
1728
+ inputSchema?: z.ZodType<TInput>;
1729
+ resolvers?: Record<string, Resolver>;
1730
+ formatter?: Formatter;
1731
+ output: "item" | {
1732
+ type: "item";
1733
+ };
1734
+ setup?: (bag: {
1735
+ imports: ImportsOf<TImports>;
1736
+ }) => TState;
1737
+ run: (bag: MethodRunBag<ImportsOf<TImports>, TInput, TState>) => TData;
1738
+ } & LeafMetaFields): MethodPlugin<TName, TInput, Promise<{
1739
+ data: Awaited<TData>;
1740
+ }>> & LeafSummary<TNamespace, TName, TImports>;
1741
+ declare function defineMethod<const TName extends string, TInput, TResponse extends StrictPage$1<TResponse>, TItem = ItemOf$1<TResponse>, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
1742
+ name: TName;
1743
+ namespace?: TNamespace;
1744
+ imports?: TImports & StaticList<TImports>;
1745
+ inputSchema?: z.ZodType<TInput>;
1746
+ resolvers?: Record<string, Resolver>;
1747
+ formatter?: Formatter;
1748
+ output: "list" | {
1749
+ type: "list";
1750
+ adaptPage?: undefined;
1751
+ defaultPageSize?: number;
1752
+ };
1753
+ setup?: (bag: {
1754
+ imports: ImportsOf<TImports>;
1755
+ }) => TState;
1756
+ run: (bag: MethodRunBag<ImportsOf<TImports>, TInput & PageFetchInput, TState>) => TResponse | Promise<TResponse>;
1757
+ } & LeafMetaFields): MethodPlugin<TName, TInput & PaginatedCallInput, PaginatedSdkResult<TItem>> & LeafSummary<TNamespace, TName, TImports>;
1758
+ declare function defineMethod<const TName extends string, TInput, TResponse, TItem, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
1759
+ name: TName;
1760
+ namespace?: TNamespace;
1761
+ imports?: TImports & StaticList<TImports>;
1762
+ inputSchema?: z.ZodType<TInput>;
1763
+ resolvers?: Record<string, Resolver>;
1764
+ formatter?: Formatter;
1765
+ output: {
1766
+ type: "list";
1767
+ adaptPage: (response: TResponse) => SdkPage<TItem>;
1768
+ defaultPageSize?: number;
1769
+ };
1770
+ setup?: (bag: {
1771
+ imports: ImportsOf<TImports>;
1772
+ }) => TState;
1773
+ run: (bag: MethodRunBag<ImportsOf<TImports>, TInput & PageFetchInput, TState>) => TResponse | Promise<TResponse>;
1774
+ } & LeafMetaFields): MethodPlugin<TName, TInput & PaginatedCallInput, PaginatedSdkResult<TItem>> & LeafSummary<TNamespace, TName, TImports>;
1775
+ /**
1776
+ * Define an input resolver: a method attachment for one of its parameters. Like
1777
+ * `defineMethod` it declares its own `imports`, and its callbacks receive a
1778
+ * narrowed `imports` bag, NOT the whole SDK. The graph reaches its imports
1779
+ * (materialize + dedup) but they never enter the host method's run-bag, so a
1780
+ * resolver may even import its own host method. At createSdk the imports are
1781
+ * captured, so the CLI later calls `listItems(input)` / `tryResolveWithoutPrompt
1782
+ * (input)` with no sdk argument.
1783
+ *
1784
+ * The `type` selects the kind (a {@link Resolver} union member); the config
1785
+ * narrows to it. `requireParameters` names sibling parameters that must resolve
1786
+ * first (it reads their values from `input`), independent of `imports` (the
1787
+ * SDK-capability graph). `object` / `array` resolvers compose nested resolvers;
1788
+ * an import-bearing resolver reached from a built field lives in `definitions`
1789
+ * (reached by `{ ref }`), since it can't be inlined when the field set is built
1790
+ * dynamically.
1791
+ */
1792
+ declare function defineResolver<const TImports extends ImportsInput = readonly [], TItem = unknown, TInput = Record<string, unknown>, TContext = unknown>(config: {
1793
+ type?: "dynamic";
1794
+ imports?: TImports & StaticList<TImports>;
1795
+ requireParameters?: readonly string[];
1796
+ inputType?: "text" | "password" | "email" | "search";
1797
+ placeholder?: string;
1798
+ /** Compute side-context once, before `listItems` (pre-fetch, no items yet),
1799
+ * with the narrowed `imports`. Its result flows into `listItems` and `prompt`
1800
+ * as `context`, so one place resolves what both the fetch and the render need
1801
+ * (e.g. a capability gate). May re-run across re-asks; keep it cheap. */
1802
+ getContext?: (bag: {
1803
+ imports: ImportsOf<TImports>;
1804
+ input: TInput;
1805
+ }) => PromiseLike<TContext>;
1806
+ /** Produce the candidate list. Behaves like an SDK list method (returns a page
1807
+ * / paginated result, never a bare array). `cursor` is the stateless "load
1808
+ * more" re-entry hook. */
1809
+ listItems?: (bag: {
1810
+ imports: ImportsOf<TImports>;
1811
+ input: TInput;
1812
+ /** The value `getContext` returned, if any. */
1813
+ context?: TContext;
1814
+ /** Free-text term the CLI injects for search-mode resolvers; a separate key
1815
+ * from `input`, so it never collides with a parameter named `search`. */
1816
+ search?: string;
1817
+ cursor?: string;
1818
+ }) => ListItemsResult<TItem>;
1819
+ prompt?: (bag: {
1820
+ items: TItem[];
1821
+ input: TInput;
1822
+ /** The value `getContext` returned, if any. */
1823
+ context?: TContext;
1824
+ }) => ResolverPromptConfig;
1825
+ /** Resolve with no user input (e.g. a configured default), skipping the prompt. */
1826
+ tryResolveWithoutPrompt?: (bag: {
1827
+ imports: ImportsOf<TImports>;
1828
+ input: TInput;
1829
+ }) => Promise<{
1830
+ resolvedValue: unknown;
1831
+ } | null>;
1832
+ /** Search-mode exact match: the typed `search` already names a valid value, so
1833
+ * return it and skip the picker. Returns null to fall through to `listItems`. */
1834
+ tryResolveFromSearch?: (bag: {
1835
+ imports: ImportsOf<TImports>;
1836
+ input: TInput;
1837
+ search?: string;
1838
+ }) => Promise<{
1839
+ resolvedValue: unknown;
1840
+ } | null>;
1841
+ }): DynamicResolver;
1842
+ declare function defineResolver(config: {
1843
+ type: "static";
1844
+ requireParameters?: readonly string[];
1845
+ inputType?: "text" | "password" | "email" | "search";
1846
+ placeholder?: string;
1847
+ }): StaticResolver;
1848
+ declare function defineResolver(config: {
1849
+ type: "constant";
1850
+ value: unknown;
1851
+ requireParameters?: readonly string[];
1852
+ }): ConstantResolver;
1853
+ declare function defineResolver(config: {
1854
+ type: "info";
1855
+ text: string;
1856
+ }): InfoResolver;
1857
+ declare function defineResolver<const TImports extends ImportsInput = readonly [], TInput = Record<string, unknown>>(config: {
1858
+ type: "object";
1859
+ imports?: TImports & StaticList<TImports>;
1860
+ requireParameters?: readonly string[];
1861
+ properties?: Record<string, Field>;
1862
+ /** Build the property map when the key set is dynamic (re-invoked as `input`
1863
+ * grow). Returns the map raw, no envelope. */
1864
+ getProperties?: (bag: {
1865
+ imports: ImportsOf<TImports>;
1866
+ input: TInput;
1867
+ }) => PromiseLike<Record<string, Field>>;
1868
+ definitions?: Record<string, Resolver>;
1869
+ }): ObjectResolver;
1870
+ declare function defineResolver(config: {
1871
+ type: "array";
1872
+ requireParameters?: readonly string[];
1873
+ items: Resolver | ResolverRef;
1874
+ minItems?: number;
1875
+ maxItems?: number;
1876
+ /** Coarse value type of each element, so a free-text item answer coerces
1877
+ * (e.g. `"5"` → `5`) like object fields do via `Field.valueType`. */
1878
+ itemValueType?: string;
1879
+ definitions?: Record<string, Resolver>;
1880
+ }): ArrayResolver;
1881
+ /**
1882
+ * Define an output formatter: a method attachment for its output. `getContext`
1883
+ * runs once per rendered page with the narrowed `imports` bag (no sdk); it
1884
+ * receives the items on the page and the context accumulated from prior pages,
1885
+ * and returns the (possibly extended) context — so page-independent context
1886
+ * (e.g. field labels) is fetched once, while per-item context grows as pages
1887
+ * arrive. `format` is pure and synchronous, turning one item + context into a
1888
+ * `FormattedItem`. Anything needing SDK data belongs in `getContext`, not
1889
+ * `format`. Both callbacks get the method's `input` (complete, since the
1890
+ * formatter runs after the method).
1891
+ */
1892
+ declare function defineFormatter<const TImports extends ImportsInput = readonly [], TItem = unknown, TInput = Record<string, unknown>, TContext = unknown>(config: {
1893
+ imports?: TImports & StaticList<TImports>;
1894
+ getContext?: (bag: {
1895
+ imports: ImportsOf<TImports>;
1896
+ items: TItem[];
1897
+ input: TInput;
1898
+ context?: TContext;
1899
+ }) => Promise<TContext>;
1900
+ format: (bag: {
1901
+ item: TItem;
1902
+ input: TInput;
1903
+ context?: TContext;
1904
+ }) => FormattedItem;
1905
+ }): Formatter;
1906
+ /**
1907
+ * Declare a stand-in for a method registered elsewhere (a configured factory
1908
+ * plugin, or just a different module). You reference it by `id` (`namespace/name`,
1909
+ * or a bare name); the binding is the id's last segment, and resolution by id
1910
+ * binds the real implementation at materialization (constraints 3-4). Its `run`
1911
+ * throws, since a stand-in must never be the implementation.
1912
+ */
1913
+ declare function declareMethod<const TId extends string, TInput = unknown, TOutput = unknown>(config: {
1914
+ id: LiteralString<TId>;
1915
+ }): MethodPlugin<LastSegment<TId>, TInput, TOutput> & PluginSummary<TId, never>;
1916
+ /**
1917
+ * Define a property leaf. Either a static `value` or a computed `get` (eager,
1918
+ * dependencies first, like `setup`). `createSdk`, a dependent's `imports`, or
1919
+ * an aggregate's re-export binds it under its bare `name` and yields the value.
1920
+ */
1921
+ declare function defineProperty<const TName extends string, TValue, const TNamespace extends string = "">(config: {
1922
+ name: TName;
1923
+ namespace?: TNamespace;
1924
+ value: TValue;
1925
+ } & LeafMetaFields): PropertyPlugin<TName, TValue> & PluginSummary<never, IdOf<TNamespace, TName>>;
1926
+ declare function defineProperty<const TName extends string, TValue, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
1927
+ name: TName;
1928
+ namespace?: TNamespace;
1929
+ imports?: TImports & StaticList<TImports>;
1930
+ setup?: (bag: {
1931
+ imports: ImportsOf<TImports>;
1932
+ }) => TState;
1933
+ get: (bag: {
1934
+ imports: ImportsOf<TImports>;
1935
+ state: TState;
1936
+ }) => TValue;
1937
+ } & LeafMetaFields): PropertyPlugin<TName, TValue> & LeafSummary<TNamespace, TName, TImports>;
1938
+ /**
1939
+ * Declare a stand-in for a property registered elsewhere (a configured factory
1940
+ * plugin, e.g. the api client built from options). Carries only a name and a
1941
+ * provides type; dependents reference it for typing, and resolution by id binds
1942
+ * the real property at materialization (constraints 3-4, the property twin of
1943
+ * `declareMethod`). A stand-in left with no real implementation is a missing
1944
+ * dependency (a runtime error from `createSdk`).
1945
+ */
1946
+ declare function declareProperty<const TId extends string, TValue = unknown>(config: {
1947
+ id: LiteralString<TId>;
1948
+ }): PropertyPlugin<LastSegment<TId>, TValue> & PluginSummary<TId, never>;
1949
+ /**
1950
+ * Declare a stand-in for a whole aggregate (module) registered elsewhere: the
1951
+ * aggregate twin of `declareMethod` / `declareProperty`. `exports` is an array
1952
+ * of leaf stand-ins describing the module's surface, so dependents that import
1953
+ * it get typed bindings; resolution by id binds the real aggregate at
1954
+ * materialization, and a stand-in left with no implementation is a missing
1955
+ * dependency. Use it to depend on a module abstractly and provide the concrete
1956
+ * one at the composition root (the tree-shakeable / swappable shape).
1957
+ */
1958
+ declare function declarePlugin<const TId extends string, const TExports extends readonly AnyLeafPlugin[] = readonly []>(config: {
1959
+ id: LiteralString<TId>;
1960
+ exports?: TExports & StaticList<TExports>;
1961
+ }): AggregatePlugin<LastSegment<TId>, ArrayExports<TExports>> & PluginSummary<TId, never>;
1962
+ /**
1963
+ * Define a plugin. Two forms, one function:
1964
+ *
1965
+ * - **Object form** — a module that re-exports child plugins and may wrap
1966
+ * imported methods with `middleware`. `exports` mirrors `imports`: an
1967
+ * array where a leaf binds under its own name (`[greet]` binds "greet"), a
1968
+ * module spreads its bindings, and `selectExports(dep, { hi: "greet" })`
1969
+ * subsets/renames. It is optional, so a pure-middleware module can omit it.
1970
+ * Re-exporting implies a dependency on the child. A middleware key names the
1971
+ * target's binding, a direct dependency.
1972
+ * - **Function form** — the legacy function-plugin identity wrapper: it returns
1973
+ * the function unchanged but constrains its return to `PluginProvides` and
1974
+ * preserves the narrow inferred shape, so callers derive `*PluginProvides`
1975
+ * via `ReturnType<typeof plugin>`. This is how the existing ~90 plugins are
1976
+ * written; they run on the module model through the legacy bridge.
1977
+ */
1978
+ declare function definePlugin<TSdk, TProvides extends PluginProvides>(fn: (sdk: TSdk & {
1979
+ context: {
1980
+ meta: Record<string, PluginMeta>;
1981
+ };
1982
+ }) => TProvides): (sdk: TSdk & {
1983
+ context: {
1984
+ meta: Record<string, PluginMeta>;
1985
+ };
1986
+ }) => TProvides;
1987
+ declare function definePlugin<const TName extends string, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", const TExports extends readonly (AnyLeafPlugin | AnyAggregatePlugin)[] = readonly []>(config: {
1988
+ name: TName;
1989
+ namespace?: TNamespace;
1990
+ imports?: TImports & StaticList<TImports>;
1991
+ exports?: TExports & StaticList<TExports>;
1992
+ middleware?: MiddlewareMap<ImportsOf<TImports>>;
1993
+ }): AggregatePlugin<TName, ArrayExports<TExports>> & AggregateSummary<TNamespace, TName, TImports, TExports>;
1994
+
1995
+ /**
1996
+ * A `selectExports` spec: a bare export name to keep (`"getApp"`), or a rename
1997
+ * map whose key is the resulting binding and value the source export name
1998
+ * (`{ getUser: "getProfile" }` is `export { getProfile as getUser }`).
1999
+ */
2000
+ type SelectSpec<TExports> = (keyof TExports & string) | {
2001
+ [newName: string]: keyof TExports & string;
2002
+ };
2003
+ /** The export record one spec contributes: a kept name maps to its own leaf; a
2004
+ * rename map keys each new name to the leaf at the source name. */
2005
+ type ResolveSpec<TExports extends Record<string, AnyLeafPlugin>, S> = S extends string | number ? S extends keyof TExports ? {
2006
+ [K in S]: TExports[S];
2007
+ } : never : {
2008
+ [K in keyof S]: S[K] extends keyof TExports ? TExports[S[K]] : never;
2009
+ };
2010
+ /** Ensure the computed export record satisfies the `AggregatePlugin` constraint
2011
+ * (an empty/degenerate selection collapses to a bare exports record). */
2012
+ type AsExports<T> = T extends Record<string, AnyLeafPlugin> ? T : Record<string, AnyLeafPlugin>;
2013
+ /**
2014
+ * Select (and optionally rename) a subset of a module's exports, the ES
2015
+ * `{ a, b, c as d }` clause. Works the same in `imports` (import) and
2016
+ * `exports` (re-export): each spec is a bare name to keep or a `{ new: "old" }`
2017
+ * rename map. An unknown source name throws. Returns a re-export descriptor (a
2018
+ * synthetic aggregate over the chosen bindings) that drops straight into either
2019
+ * array; the selected bindings keep the source module's identity.
2020
+ */
2021
+ declare function selectExports<TExports extends Record<string, AnyLeafPlugin>, const TSpecs extends readonly SelectSpec<TExports>[]>(source: AggregatePlugin<string, TExports>, ...specs: TSpecs): AggregatePlugin<string, AsExports<UnionToIntersection<{
2022
+ [I in keyof TSpecs]: ResolveSpec<TExports, TSpecs[I]>;
2023
+ }[number]>>>;
2024
+
2025
+ /**
2026
+ * Lift a legacy function plugin into the module model. The
2027
+ * returned plugin runs `fn` at materialization and surfaces its root methods;
2028
+ * `createPluginStack().toPlugin()` is built on this, and `addPlugin` uses it for
2029
+ * external function plugins. `fn`'s `context` contributions merge into the live
2030
+ * `SdkContext`; its other root keys become the surface.
2031
+ */
2032
+ declare function fromFunctionPlugin<TProvides extends PluginProvides>(fn: (sdk: any) => TProvides, config: {
2033
+ name: string;
2034
+ namespace?: string;
2035
+ }): LegacyPlugin<TProvides & {
2036
+ getRegistry: (options?: {
2037
+ package?: string;
2038
+ }) => RegistryResult;
2039
+ }>;
2040
+ /**
2041
+ * Build a {@link LegacyMergePlugin}: pass the collapsed legacy stack
2042
+ * (`stack.toPlugin()`) as `legacy` and the migrated module-model plugins as
2043
+ * `plugin`. `createSdk(defineLegacyMerge({...}))` surfaces both.
2044
+ */
2045
+ declare function defineLegacyMerge<TProvides extends PluginProvides, const TPlugin extends AnyPlugin>(args: {
2046
+ name: string;
2047
+ namespace?: string;
2048
+ legacy: (sdk: any) => TProvides;
2049
+ plugin: TPlugin;
2050
+ }): LegacyMergePlugin<TProvides, TPlugin>;
2051
+
2052
+ /**
2053
+ * Escape hatch. A built-in privileged plugin whose value is the live
2054
+ * `SdkContext`: the raw plugin graph plus the legacy compat fields. Importing it
2055
+ * (`imports.context`) lets a body reach internals the model otherwise keeps
2056
+ * private.
2057
+ *
2058
+ * Prefer not to depend on this. The `SdkContext` shape is an implementation
2059
+ * detail and may change without notice; import the specific plugins you need,
2060
+ * and use `getRegistryPlugin` for surface introspection. It exists mainly so a
2061
+ * not-yet-migrated plugin can read legacy `context.*` fields during migration.
2062
+ * Its value is injected at materialization, not authored.
2063
+ */
2064
+ declare const dangerousContextPlugin: PropertyPlugin<"context", SdkContext>;
2065
+ /**
2066
+ * A built-in that reports the live SDK surface as the canonical
2067
+ * {@link RegistryResult}. It is just a method depending on `dangerousContextPlugin` (no
2068
+ * new privilege): re-export it to put `getRegistry()` on the SDK surface. Reads
2069
+ * `context.surface` at call time, so it reflects any post-seal `addPlugin`
2070
+ * additions, and produces the same registry shape the heads (CLI / MCP / docs)
2071
+ * consume.
2072
+ */
2073
+ declare const getRegistryPlugin: MethodPlugin<"getRegistry", {
2074
+ package?: string | undefined;
2075
+ } | undefined, RegistryResult<any>, readonly []> & LeafSummary<"kitcore", "getRegistry", readonly [PropertyPlugin<"context", SdkContext>]>;
2076
+
2077
+ /**
2078
+ * The external escape-hatch key for an SDK's context. A Symbol,
2079
+ * not a string, so it stays off the string surface (which is exactly the root's
2080
+ * exports) and is collision-free and clearly internal. It is attached at
2081
+ * runtime but kept OUT of the public SDK type (a `unique symbol` in an exported
2082
+ * type can't be named in a consumer's emitted `.d.ts`); reach it through the
2083
+ * typed `getContext(sdk)` accessor.
2084
+ */
2085
+ declare const CONTEXT: unique symbol;
2086
+ /** The off-surface escape hatch to an SDK's `SdkContext`. */
2087
+ declare function getContext(sdk: unknown): SdkContext;
2088
+ /**
2089
+ * Materialize one plugin into an SDK whose surface is that plugin's exports.
2090
+ * A method root surfaces its callable under its bare name; a property root its
2091
+ * value; an aggregate root its export bindings.
2092
+ */
2093
+ declare function createSdk<P extends AnyMethodPlugin>(root: P & CompletenessOf<P>): MethodSdkOf<P>;
2094
+ declare function createSdk<P extends AnyPropertyPlugin>(root: P & CompletenessOf<P>): PropertySdkOf<P>;
2095
+ declare function createSdk<P extends AnyAggregatePlugin>(root: P & CompletenessOf<P>): AggregateSdkOf<P>;
2096
+ declare function createSdk<TSurface>(root: LegacyPlugin<TSurface>): TSurface & SdkInternals;
2097
+ declare function createSdk<TProvides extends PluginProvides, TPlugin extends AnyPlugin>(root: LegacyMergePlugin<TProvides, TPlugin>): TProvides & {
2098
+ getRegistry: (options?: {
2099
+ package?: string;
2100
+ }) => RegistryResult;
2101
+ } & AddedSurface<TPlugin> & SdkInternals;
2102
+ /**
2103
+ * Extend an already-built SDK in place with one more plugin (the post-seal
2104
+ * extension path). Dispatches on shape: a module-model plugin (`defineMethod` /
2105
+ * `defineProperty` / `definePlugin`) is materialized incrementally into the live
2106
+ * graph; a legacy function plugin runs through the legacy merge. Either way the
2107
+ * caller's `sdk` binding is narrowed to include the addition.
2108
+ */
2109
+ declare function addPlugin<TSdk extends object, P>(sdk: TSdk, plugin: P, options?: {
2110
+ override?: boolean;
2111
+ }): asserts sdk is TSdk & AddedSurface<P>;
2112
+
2113
+ /**
2114
+ * Public types for the resolution engine: the serializable protocol a host
2115
+ * drives (`start` / `step`), the in-process `resolve` sugar's answerer, and the
2116
+ * reflection shapes (`listMethods` / `getMethod` / `listChoices`). The engine
2117
+ * turns a method's partial input into a complete, validated input by resolving
2118
+ * each parameter, interacting with the host only when it must. See the kitcore
2119
+ * README's "Resolving inputs: controllers" section for worked host examples.
2120
+ */
2121
+ /** A candidate value the host renders; the host composes its own display label
2122
+ * from `label`/`hint`. `value` is what flows back in a `choose` action. */
2123
+ interface ControllerChoice {
2124
+ label: string;
2125
+ value: string;
2126
+ hint?: string;
2127
+ }
2128
+ /**
2129
+ * A move the host can make in response to a question, self-described so an agent
2130
+ * can follow it without the type definitions (HATEOAS-lite). `description` says
2131
+ * what it does; `supply` names the single payload field to include when sending
2132
+ * the action (absent = no payload). Enriching an affordance with a full field
2133
+ * schema later is additive and never changes the {@link ControllerAction} it
2134
+ * produces.
2135
+ */
2136
+ interface ControllerAffordance {
2137
+ action: ControllerAction["type"];
2138
+ description: string;
2139
+ supply?: "value" | "term";
2140
+ }
2141
+ /** A question the host renders. Discriminated on `type`; the available moves are
2142
+ * the self-describing `actions` list (single source of truth, no flags). */
2143
+ type ControllerQuestion = {
2144
+ type: "select";
2145
+ message: string;
2146
+ /** What this field is, for an agent that lacks the schema. */
2147
+ description?: string;
2148
+ choices: ControllerChoice[];
2149
+ actions: ControllerAffordance[];
2150
+ /** A multi-select (the resolver's `prompt` returned `type: "checkbox"`);
2151
+ * the `choose` action then carries an array. */
2152
+ multiple?: boolean;
2153
+ /** Informational, non-selectable lines (`PromptConfig.notes`), e.g. a
2154
+ * capability hint. A host renders them dimmed, after the choices. */
2155
+ notes?: string[];
2156
+ } | {
2157
+ type: "input";
2158
+ message: string;
2159
+ description?: string;
2160
+ inputType: "text" | "password" | "email";
2161
+ placeholder?: string;
2162
+ actions: ControllerAffordance[];
2163
+ } | {
2164
+ type: "collection";
2165
+ message: string;
2166
+ description?: string;
2167
+ count: number;
2168
+ min: number;
2169
+ /** Absent when the array is unbounded (no `maxItems`); a finite cap
2170
+ * otherwise. Omitted rather than `Infinity` so the question stays JSON. */
2171
+ max?: number;
2172
+ actions: ControllerAffordance[];
2173
+ };
2174
+ /** The host's response to a question. The wire shape is frozen: a fuller
2175
+ * HATEOAS affordance schema would still produce exactly these. */
2176
+ type ControllerAction = {
2177
+ type: "choose";
2178
+ value: string | string[];
2179
+ } | {
2180
+ type: "search";
2181
+ term: string;
2182
+ } | {
2183
+ type: "more";
2184
+ } | {
2185
+ type: "custom";
2186
+ value: string;
2187
+ } | {
2188
+ type: "skip";
2189
+ } | {
2190
+ type: "add";
2191
+ } | {
2192
+ type: "done";
2193
+ } | {
2194
+ type: "cancel";
2195
+ } | {
2196
+ type: "retry";
2197
+ };
2198
+ /** What `start` / `step` return alongside the next state. `ask` carries a
2199
+ * question to answer; `done` the fully resolved input; `invalid` the validation
2200
+ * issues; `failed` a thrown lookup error plus a question offering retry/cancel. */
2201
+ type ControllerResult = {
2202
+ status: "ask";
2203
+ question: ControllerQuestion;
2204
+ /** The prior answer's validation failure (`PromptConfig.validate`), when
2205
+ * this is a re-ask. About the last transition, not the question itself. */
2206
+ error?: string;
2207
+ } | {
2208
+ status: "done";
2209
+ value: Record<string, unknown>;
2210
+ } | {
2211
+ status: "invalid";
2212
+ issues: ControllerIssue[];
2213
+ } | {
2214
+ status: "failed";
2215
+ error: ControllerError;
2216
+ question: ControllerQuestion;
2217
+ } | {
2218
+ status: "cancelled";
2219
+ };
2220
+ /** A thrown lookup failure, normalized to plain data at the wall. The engine
2221
+ * catches an arbitrary throwable; a raw `Error` loses its message under
2222
+ * `JSON.stringify` (and a circular/custom value can break transport), so a
2223
+ * `failed` result carries this DTO instead, which a remote host can render. */
2224
+ interface ControllerError {
2225
+ name: string;
2226
+ message: string;
2227
+ code?: string;
2228
+ }
2229
+ /** A single validation problem, keyed to the offending parameter when known. */
2230
+ interface ControllerIssue {
2231
+ parameter?: string;
2232
+ message: string;
2233
+ }
2234
+ /**
2235
+ * The serializable, caller-held progress of a resolution. The host carries it
2236
+ * forward and passes it back into the next `step`; it round-trips across a
2237
+ * client/server boundary unchanged (no closures, no live iterators). It carries
2238
+ * the method id, so `step` needs nothing else.
2239
+ */
2240
+ interface ControllerState {
2241
+ method: string;
2242
+ /** The growing input, as a nested tree of *real values only* — objects build
2243
+ * in place (`resolved.inputs.channel`), so a leaf value lives at its {@link ControllerPath}. */
2244
+ resolved: Record<string, unknown>;
2245
+ /** Dotted path-keys the engine is done with: a resolved leaf (value in
2246
+ * `resolved`), a skipped leaf (no value), or a finished array. Objects derive
2247
+ * doneness from their children. The "touched" analog from form libraries. */
2248
+ settled: string[];
2249
+ /** The path of the parameter (or nested field) currently being asked. */
2250
+ current?: ControllerPath;
2251
+ /** Listing progress for the current dynamic leaf (serializable: items +
2252
+ * cursor, never a live iterator). */
2253
+ listing?: ControllerListing;
2254
+ /** Whether the host will prompt. Interactive (the default) always asks;
2255
+ * non-interactive runs `tryResolveWithoutPrompt` to auto-fill what it can
2256
+ * (e.g. configured defaults) before asking for the rest. */
2257
+ interactive: boolean;
2258
+ }
2259
+ /** A location in the input tree: top-level `["app"]`, a nested object field
2260
+ * `["inputs", "channel"]`, or (later) an array item `["records", 0, "id"]`. */
2261
+ type ControllerPath = (string | number)[];
2262
+ /** Accumulated candidate items for the current dynamic parameter, plus the
2263
+ * serializable cursor for "load more" and the active search term. */
2264
+ interface ControllerListing {
2265
+ items: unknown[];
2266
+ cursor?: string;
2267
+ search?: string;
2268
+ /** True when the source reported no further pages. */
2269
+ exhausted: boolean;
2270
+ }
2271
+ /**
2272
+ * The one pluggable seam for the in-process `resolve` sugar. It receives the
2273
+ * same `{ state, result }` pair `start`/`step` return (so an answer callback
2274
+ * sees exactly what a host driving the protocol directly would) and produces
2275
+ * the next action. `result` is a question-bearing result — `ask` (the question
2276
+ * plus any prior-answer `error`) or `failed` (a lookup threw; the question
2277
+ * offers `retry`/`cancel`, `error` is the thrown value). `state` is read-only
2278
+ * context (e.g. an agent can inspect `state.resolved`); mutating it is
2279
+ * unsupported. Modality-agnostic — inquirer/DOM, an LLM agent, an auto-select
2280
+ * policy, or a test script all satisfy it. The `start`/`step` protocol needs no
2281
+ * answer callback.
2282
+ */
2283
+ type ControllerAnswerFn = (turn: {
2284
+ state: ControllerState;
2285
+ result: Extract<ControllerResult, {
2286
+ status: "ask" | "failed";
2287
+ }>;
2288
+ }) => Promise<ControllerAction>;
2289
+ /** Per-parameter metadata for reflection (agents / MCP / docs / previews). The
2290
+ * static, no-I/O view, complementing the in-the-moment `question`. */
2291
+ interface ControllerParameterDescription {
2292
+ required: boolean;
2293
+ /** True when values come from a fetch (`listItems`) rather than a static set. */
2294
+ dynamic: boolean;
2295
+ /** True when the resolver accepts a free-text search term. */
2296
+ searchable?: boolean;
2297
+ /** The field's serialized type (`z.toJSONSchema` of its input schema). Absent
2298
+ * for a dynamically-shaped field (`getProperties`) with no static schema, or
2299
+ * when the schema can't be represented as JSON Schema. zod never crosses the
2300
+ * wall; this is its plain-data projection. */
2301
+ schema?: Record<string, unknown>;
2302
+ /** Statically known labeled values, when the parameter is a fixed enum. Richer
2303
+ * than `schema.enum` (carries label/hint), so kept alongside `schema`. */
2304
+ choices?: ControllerChoice[];
2305
+ /** Sibling parameters this one depends on (`requireParameters`). A form host
2306
+ * reads this to know which fields are independent (render together) and which
2307
+ * to re-fetch when a dependency changes. */
2308
+ requireParameters?: readonly string[];
2309
+ }
2310
+ /** A method's lightweight index entry: enough to render a menu or tool list
2311
+ * without the full per-parameter detail. The list face of {@link Controller}. */
2312
+ interface ControllerMethodSummary {
2313
+ name: string;
2314
+ description?: string;
2315
+ categories?: string[];
2316
+ }
2317
+ /** A method's full static contract, serialized: its parameters as a named bag
2318
+ * (mirroring the canonical single-object input), the positional projection if
2319
+ * the surface declares one, and the output type. All plain JSON — the
2320
+ * serializable projection of the registry entry, never its live zod. */
2321
+ interface ControllerMethodDescription {
2322
+ name: string;
2323
+ description?: string;
2324
+ categories?: string[];
2325
+ /** Keyed by parameter name (the input bag's shape), not an ordered array:
2326
+ * named-first, since MCP/web/agent hosts fill named slots. Order, when it
2327
+ * matters, lives in `positional`. */
2328
+ parameters: Record<string, ControllerParameterDescription>;
2329
+ /** Ordered input keys the public surface takes as positional args, when the
2330
+ * method declares a positional projection. Absent for a pure single-bag call. */
2331
+ positional?: readonly string[];
2332
+ /** The output type (`z.toJSONSchema` of the output schema), when known. */
2333
+ output?: Record<string, unknown>;
2334
+ }
2335
+ /**
2336
+ * Drives parameter resolution over a built SDK, reading its registry for the
2337
+ * method's input schema and bound resolvers. Created from an SDK with
2338
+ * `createController(sdk)`; transport-agnostic, so a remote implementation
2339
+ * (browser → server) satisfies the same interface.
2340
+ */
2341
+ interface Controller {
2342
+ /** In-process sugar: loop `start`/`step` against an answer callback, return
2343
+ * the resolved input (ready to pass to the SDK method). Throws on cancel. */
2344
+ resolve(opts: {
2345
+ method: string;
2346
+ input?: Record<string, unknown>;
2347
+ answer: ControllerAnswerFn;
2348
+ /** Defaults to true. Pass false for an agent/headless answer callback that
2349
+ * wants configured defaults auto-filled (`tryResolveWithoutPrompt`) rather
2350
+ * than prompted. */
2351
+ interactive?: boolean;
2352
+ }): Promise<Record<string, unknown>>;
2353
+ /** Start resolving: seed from `input`, auto-resolve what needs no interaction,
2354
+ * return the first result (an `ask`, or `done`). */
2355
+ start(opts: {
2356
+ method: string;
2357
+ input?: Record<string, unknown>;
2358
+ /** Defaults to true (always prompt). Pass false for headless/agent hosts to
2359
+ * auto-fill via `tryResolveWithoutPrompt` before asking. */
2360
+ interactive?: boolean;
2361
+ }): Promise<{
2362
+ state: ControllerState;
2363
+ result: ControllerResult;
2364
+ }>;
2365
+ /** Advance with the user's action; return the next state and result. */
2366
+ step(opts: {
2367
+ state: ControllerState;
2368
+ action: ControllerAction;
2369
+ }): Promise<{
2370
+ state: ControllerState;
2371
+ result: ControllerResult;
2372
+ }>;
2373
+ /** Reflection (list): the lightweight index of every method (no I/O). The
2374
+ * `nextCursor` slot mirrors `listChoices` and leaves room for paging a future
2375
+ * dynamic/large method set; unpaged today. */
2376
+ listMethods(): {
2377
+ data: ControllerMethodSummary[];
2378
+ nextCursor?: string;
2379
+ };
2380
+ /** Reflection (item): one method's full static contract, serialized (no I/O).
2381
+ * Named `getMethod` to mirror the SDK's `getApp`/`listApps` resource pair;
2382
+ * returns the method's *description*, not the callable. */
2383
+ getMethod(opts: {
2384
+ method: string;
2385
+ }): {
2386
+ data: ControllerMethodDescription;
2387
+ };
2388
+ /** Reflection: enumerate legal values for one dynamic parameter. */
2389
+ listChoices(opts: {
2390
+ method: string;
2391
+ parameter: string;
2392
+ input?: Record<string, unknown>;
2393
+ search?: string;
2394
+ cursor?: string;
2395
+ }): Promise<{
2396
+ data: ControllerChoice[];
2397
+ nextCursor?: string;
2398
+ }>;
2399
+ }
2400
+
2401
+ /** The slice of a built SDK the driver needs: its registry accessor. */
2402
+ interface ControllerSdk {
2403
+ getRegistry: (options?: {
2404
+ package?: string;
2405
+ }) => RegistryResult;
2406
+ }
2407
+ /**
2408
+ * Build a {@link Controller} over a built SDK. Reads `sdk.getRegistry()`
2409
+ * at call time (so post-build `addPlugin` additions are visible) to find each
2410
+ * method's canonical input schema and bound resolvers, then drives the engine.
2411
+ * The SDK surface itself is untouched; this is a sibling layer.
2412
+ */
2413
+ declare function createController(sdk: ControllerSdk): Controller;
2414
+
2415
+ /**
2416
+ * Generic utility functions for creating SDK-method wrappers.
2417
+ *
2418
+ * Both `createFunction` and `createPaginatedFunction` accept the SDK
2419
+ * as a parameter and read framework state (`hooks`, `core.adaptError`)
2420
+ * live from `sdk.context.*` at method-invocation time. Plugins registered
2421
+ * after a method is built still observe and configure it; ordering of
2422
+ * plugin registration doesn't change runtime semantics. (Pagination's
2423
+ * `adaptPage` is passed in per method, not read from context.)
2424
+ */
2425
+
2426
+ /**
2427
+ * Minimal SDK shape the function wrappers accept. The wrappers only
2428
+ * touch `context.hooks` and `context.core.*`, but we keep `context`
2429
+ * typed as `unknown` so any kitcore-built SDK (whose context type
2430
+ * widens unpredictably as plugins layer on) flows through without
2431
+ * upstream type narrowing. Each read inside is asserted at the use
2432
+ * site against the small slice we actually need.
2433
+ */
2434
+ type FunctionSdk = {
2435
+ context: unknown;
2436
+ };
2437
+ /**
2438
+ * Wrap a core async function with input validation, error normalization,
2439
+ * and method-call lifecycle hooks. Hooks and `adaptError` are read live
2440
+ * from `sdk.context.*` at every invocation, so a plugin registered
2441
+ * after this method is built still observes and configures it.
2442
+ *
2443
+ * @param coreFn - the underlying async function to wrap
2444
+ * @param options.sdk - the SDK (or sub-SDK view) providing `context.hooks`
2445
+ * and `context.core`
2446
+ * @param options.schema - optional Zod schema for input validation
2447
+ */
2448
+ declare function createFunction<TOptions, TResult, TSchemaOptions extends TOptions = TOptions>(coreFn: (options: TOptions) => Promise<TResult>, options: {
2449
+ sdk: FunctionSdk;
2450
+ schema?: z.ZodSchema<TSchemaOptions>;
2451
+ name?: string;
2452
+ }): (callOptions?: TOptions) => Promise<TResult>;
2453
+ /**
2454
+ * Higher-order function that creates a paginated function that wraps
2455
+ * results in `SdkPage<TItem>`.
2456
+ *
2457
+ * @param coreFn - Function that returns T directly or throws errors
2458
+ * @returns A function that normalizes errors and wraps results in `SdkPage`
2459
+ */
2460
+ /**
2461
+ * Extract the item type from a page handler's return shape. The handler
2462
+ * may return a flat `{ data: TItem[] }` (or single `data: TItem`), a bare
2463
+ * array, or anything else; in all cases the wrapper normalizes to
2464
+ * `SdkPage<TItem>` and this resolves the right `TItem`.
2465
+ */
2466
+ type ItemType<TResult> = TResult extends {
2467
+ data: infer TData;
2468
+ } ? TData extends readonly (infer TItem)[] ? TItem : TData : TResult extends readonly (infer TItem)[] ? TItem : TResult;
2469
+ declare function createPaginatedFunction<TUserOptions, TResponse, TItem = ItemType<TResponse>>(coreFn: (options: TUserOptions & {
2470
+ cursor?: string;
2471
+ pageSize?: number;
2472
+ }) => Promise<TResponse>, options: {
2473
+ sdk: FunctionSdk;
2474
+ schema?: z.ZodSchema<TUserOptions>;
2475
+ name?: string;
2476
+ defaultPageSize?: number;
2477
+ /**
2478
+ * Translate the handler's raw `TResponse` into `SdkPage<TItem>`. `TItem`
2479
+ * is wrapped in `NoInfer`: it is sourced from `TResponse` (via the
2480
+ * `ItemType` default), not from this adapter, which is item-agnostic (it
2481
+ * relocates the cursor; items are finalized in the handler's `data`).
2482
+ * Without `NoInfer`, a generic adapter (e.g. `<T>(r) => SdkPage<T>`)
2483
+ * would collapse `TItem` to `unknown`.
2484
+ */
2485
+ adaptPage?: (response: TResponse) => SdkPage<NoInfer<TItem>>;
2486
+ }): (options?: TUserOptions & {
2487
+ cursor?: string;
2488
+ pageSize?: number;
2489
+ maxItems?: number;
2490
+ }) => PaginatedSdkResult<TItem>;
2491
+
2492
+ /**
2493
+ * Core error machinery.
2494
+ *
2495
+ * kitcore constructs errors at two internal throw sites: input
2496
+ * validation (`utils/validation.ts`) and non-Error normalization
2497
+ * (`utils/function-utils.ts`'s `normalizeError`). Heads supply a
2498
+ * `adaptError` factory via `createCorePlugin` to map kitcore's abstract
2499
+ * `CoreErrorCode` values onto their own branded error classes; if
2500
+ * no factory is supplied, kitcore falls back to constructing a plain
2501
+ * `CoreError`. Either way, every kitcore-thrown error is brand-stamped
2502
+ * with `CORE_ERROR_SYMBOL` and `coreCode` (non-enumerable),
2503
+ * so consumers can recognize core errors via `isCoreError`
2504
+ * without knowing the head's class identity.
2505
+ */
2506
+ /**
2507
+ * Cross-package brand for kitcore-constructed errors. `Symbol.for(key)`
2508
+ * reads from the engine-global registry, so the same value resolves
2509
+ * across realms and across multiple copies of kitcore (e.g. when one
2510
+ * package bundles kitcore and another installs it standalone). Use
2511
+ * `isCoreError` for cross-package checks.
2512
+ */
2513
+ declare const CORE_ERROR_SYMBOL: unique symbol;
2514
+ /**
2515
+ * Abstract codes for the errors kitcore can produce. Heads receive these
2516
+ * via `AdaptErrorOptions.code` and map them onto their own named
2517
+ * error classes (e.g. `VALIDATION_ERROR` → the head's branded
2518
+ * `<Prefix>ValidationError`).
2519
+ */
2520
+ declare const CoreErrorCode: {
2521
+ readonly Validation: "VALIDATION_ERROR";
2522
+ readonly Unknown: "UNKNOWN_ERROR";
2523
+ };
2524
+ type CoreErrorCode = (typeof CoreErrorCode)[keyof typeof CoreErrorCode];
2525
+ /**
2526
+ * Standard error envelope. kitcore doesn't generate these
2527
+ * itself; heads set `errors?: CoreApiError[]` on their error constructor
2528
+ * options when surfacing structured upstream failures.
2529
+ */
2530
+ interface CoreApiError {
2531
+ status: number;
2532
+ code: string;
2533
+ title: string;
2534
+ detail: string;
2535
+ source?: unknown;
2536
+ meta?: unknown;
2537
+ }
2538
+ /**
2539
+ * Base options for the default `CoreError` fallback. Heads' own error
2540
+ * classes typically accept a richer options bag.
2541
+ */
2542
+ interface CoreErrorOptions {
2543
+ statusCode?: number;
2544
+ errors?: CoreApiError[];
2545
+ cause?: unknown;
2546
+ response?: unknown;
2547
+ }
2548
+ /**
2549
+ * What `adaptError` factories receive. `code` is the abstract error
2550
+ * code; `details` carries type-specific extras (validation issues for
2551
+ * `VALIDATION_ERROR`, etc.).
2552
+ */
2553
+ interface AdaptErrorOptions {
2554
+ code: CoreErrorCode;
2555
+ message: string;
2556
+ cause?: unknown;
2557
+ details?: unknown;
2558
+ }
2559
+ type AdaptError = (options: AdaptErrorOptions) => Error;
2560
+ /**
2561
+ * Default error class kitcore constructs when no `adaptError` is
2562
+ * supplied. Heads typically provide their own branded classes via
2563
+ * `adaptError` and never see this. Exported so the rare head-less
2564
+ * caller (tests, scratch scripts) can recognize the fallback.
2565
+ */
2566
+ declare class CoreError extends Error {
2567
+ readonly name: string;
2568
+ statusCode?: number;
2569
+ errors?: CoreApiError[];
2570
+ cause?: unknown;
2571
+ response?: unknown;
2572
+ constructor(message: string, options?: CoreErrorOptions);
2573
+ }
2574
+ /**
2575
+ * Construct a core error, optionally via a head-supplied factory.
2576
+ * Stamps the core brand and the abstract `coreCode` on the
2577
+ * returned instance (non-enumerable, so they don't pollute JSON
2578
+ * serialization). The `instanceof <HeadErrorClass>` check on the
2579
+ * result works as expected; `isCoreError` is the cross-package
2580
+ * recognizer that survives bundled/standalone splits.
2581
+ */
2582
+ declare function createCoreError(options: AdaptErrorOptions, adaptError?: AdaptError): Error;
2583
+ /**
2584
+ * Cross-package-safe check that `value` was produced by kitcore's
2585
+ * error construction path (i.e. through `createCoreError`). Use
2586
+ * this in code that needs to distinguish "kitcore threw this" from
2587
+ * "a handler threw an unrelated `Error` subclass" — `instanceof` checks
2588
+ * on specific head classes also work, but `isCoreError` is the
2589
+ * neutral recognizer.
2590
+ */
2591
+ declare function isCoreError(value: unknown): boolean;
2592
+ /**
2593
+ * Abstract `CoreErrorCode` for an error produced via
2594
+ * `createCoreError`. Returns `undefined` for non-kitcore values.
2595
+ */
2596
+ declare function getCoreErrorCode(value: unknown): CoreErrorCode | undefined;
2597
+ /**
2598
+ * `cause` field accessor that doesn't trip the type system. Same as
2599
+ * `(value as { cause?: unknown }).cause` for kitcore-produced errors;
2600
+ * returns `undefined` for non-kitcore values.
2601
+ */
2602
+ declare function getCoreErrorCause(value: unknown): unknown;
2603
+
2604
+ /**
2605
+ * ------------------------------
2606
+ * Core configuration plugin
2607
+ * ------------------------------
2608
+ *
2609
+ * `createCorePlugin` is how a head supplies kitcore-level behavior knobs
2610
+ * (`adaptError` for branded errors, future entries similarly). The plugin
2611
+ * writes to `context.core`; kitcore reads from that path at every method
2612
+ * invocation. Consumers configure through this factory's typed `CoreOptions`,
2613
+ * never by touching the context path.
2614
+ *
2615
+ * createPluginStack()
2616
+ * .use(createCorePlugin({ adaptError: myAdaptError }))
2617
+ * .use(listAppsPlugin);
2618
+ *
2619
+ * Installing this plugin is optional. Kitcore reads `context.core.*`
2620
+ * with optional chaining, so an SDK without `createCorePlugin`
2621
+ * installed just falls back to kitcore's built-in behavior.
2622
+ *
2623
+ * Note: pagination shaping is NOT configured here. Each paginated method
2624
+ * declares its own `adaptPage` on `createPaginatedPluginMethod`, so the
2625
+ * adapter travels with the plugin (and stays type-checked) rather than
2626
+ * relying on an ambient SDK-wide default.
2627
+ */
2628
+
2629
+ /**
2630
+ * Head-supplied configuration for kitcore-managed behavior. All fields are
2631
+ * optional; absent fields fall back to kitcore's built-in behavior.
2632
+ */
2633
+ interface CoreOptions {
2634
+ /**
2635
+ * Construct the head's branded error class for kitcore-thrown errors
2636
+ * (validation failures, non-Error normalization). Receives the
2637
+ * abstract `CoreErrorCode`, message, optional cause, and
2638
+ * type-specific details; returns the head's `Error` subclass. The
2639
+ * returned instance is automatically brand-stamped via
2640
+ * `createCoreError` so `isCoreError(err)` still recognizes
2641
+ * it across package boundaries. If absent, kitcore throws a plain
2642
+ * `CoreError`.
2643
+ */
2644
+ adaptError?: AdaptError;
2645
+ }
2646
+ /**
2647
+ * Register kitcore-level configuration. Writes the options to
2648
+ * `context.core` internally; consumers never reference the path.
2649
+ *
2650
+ * Reads of `context.core.adaptError` are
2651
+ * live: kitcore's method wrappers consult them at every invocation,
2652
+ * not at registration time. A `createCorePlugin` registered after a
2653
+ * method plugin still applies to that method's subsequent calls.
2654
+ */
2655
+ declare function createCorePlugin(options: CoreOptions): Plugin<object, {
2656
+ context: {
2657
+ core: CoreOptions;
2658
+ };
2659
+ }>;
2660
+
2661
+ /**
2662
+ * Per-invocation scope for SDK method calls. Each top-level SDK method call
2663
+ * runs in its own AsyncLocalStorage scope (via `runInMethodScope`), isolating
2664
+ * its depth counter and any plugin-specific state from concurrent calls.
2665
+ *
2666
+ * The toolkit reserves the `depth` field; anything else on the scope is
2667
+ * opaque key/value storage that plugins can use (e.g. eventEmission stores
2668
+ * its `MethodMetadata` under its own key).
2669
+ */
2670
+ /**
2671
+ * The per-call scope object held in ALS. Toolkit owns `depth`; everything
2672
+ * else is open for plugin-specific use.
2673
+ */
2674
+ interface MethodScope {
2675
+ depth: number;
2676
+ [key: string]: unknown;
2677
+ }
2678
+ /**
2679
+ * Read the current scope object, or `undefined` if no scope is active or
2680
+ * AsyncLocalStorage isn't available. Plugins use this to read/write their
2681
+ * own scoped state under their own key.
2682
+ */
2683
+ declare function getCurrentScope(): MethodScope | undefined;
2684
+ /**
2685
+ * Current depth of the SDK method-call stack. 0 = outermost call,
2686
+ * 1+ = invoked from inside another SDK method. Returns 0 when no scope
2687
+ * is active (e.g. raw callers outside the framework).
2688
+ */
2689
+ declare function getCurrentDepth(): number;
2690
+ /**
2691
+ * True when the current call is nested inside another SDK method.
2692
+ * Preserves the legacy "no store = nested" fallback used by browser
2693
+ * builds to suppress hook firing when async_hooks isn't available.
2694
+ */
2695
+ declare function isNestedMethodCall(): boolean;
2696
+ /**
2697
+ * Run `fn` inside a new method scope. Nested invocations see an incremented
2698
+ * `depth`. When no scope store is available (e.g. browsers without
2699
+ * async_hooks), `fn` is called directly with no scope tracking.
2700
+ */
2701
+ declare function runInMethodScope<T>(fn: () => T): T;
2702
+ declare const runWithTelemetryContext: typeof runInMethodScope;
2703
+ declare const isTelemetryNested: typeof isNestedMethodCall;
2704
+
2705
+ /**
2706
+ * A typed wrapper around a single `AsyncLocalStorage` instance. Centralizes the
2707
+ * `node:async_hooks` plumbing (bundler-safe static import, browser fallback) so
2708
+ * consumers don't each hand-roll it and drift apart.
2709
+ *
2710
+ * The wrapper holds no merge or depth policy: `run` simply activates `store`
2711
+ * for the duration of `fn`, and `get` returns whatever is active. Consumers
2712
+ * layer their own semantics (e.g. depth counting, parent merging) on top.
2713
+ */
2714
+ interface AsyncContext<T> {
2715
+ /** Run `fn` with `store` active. Returns whatever `fn` returns; `fn`'s errors propagate. */
2716
+ run<R>(store: T, fn: () => R): R;
2717
+ /** The active store, or `undefined` if no scope is active or ALS is unavailable. */
2718
+ get(): T | undefined;
2719
+ /**
2720
+ * `false` only where `node:async_hooks` could not be loaded (e.g. browsers),
2721
+ * leaving the context inert. Lets callers distinguish "ALS unavailable" from
2722
+ * the also-`undefined` "ALS available but no active scope".
2723
+ */
2724
+ readonly available: boolean;
2725
+ }
2726
+ /** Create an isolated {@link AsyncContext} backed by one `AsyncLocalStorage`. */
2727
+ declare function createAsyncContext<T>(): AsyncContext<T>;
2728
+
2729
+ /**
2730
+ * Deferred form: bind a schema (and `adaptError`) once, get a reusable
2731
+ * validator. Its input is `unknown` so it can validate values wider than the
2732
+ * schema's own type (e.g. paginated options that carry cursor / pageSize
2733
+ * alongside the schema-typed fields).
2734
+ */
2735
+ declare function createValidator<TSchema extends z.ZodSchema>(schema: TSchema, { adaptError }?: {
2736
+ adaptError?: AdaptError;
2737
+ }): (input: unknown) => z.infer<TSchema>;
2738
+ /**
2739
+ * Eager form: validate `options` now and return the parsed value. The
2740
+ * `TSchemaOptions extends TOptions` generics let the call site check that the
2741
+ * value being validated matches the schema's type, which `createValidator`
2742
+ * (input `unknown`) can't.
2743
+ */
2744
+ declare const validateOptions: <TOptions, TSchemaOptions extends TOptions>(schema: z.ZodSchema<TSchemaOptions>, options: TOptions, { adaptError }?: {
2745
+ adaptError?: AdaptError;
2746
+ }) => TSchemaOptions;
2747
+
2748
+ /**
2749
+ * Translates a paginated handler's raw response into a normalized
2750
+ * `SdkPage<TItem>`. Supplied per method as the `adaptPage` on
2751
+ * `createPaginatedPluginMethod` (and forwarded to `createPaginatedFunction`).
2752
+ */
2753
+ type AdaptPage<TResponse = unknown, TItem = unknown> = (response: TResponse) => SdkPage<TItem>;
2754
+ type TPageOptions<TOptions> = TOptions extends undefined ? {
2755
+ cursor?: string;
2756
+ maxItems?: number;
2757
+ pageSize?: number;
2758
+ } : TOptions & {
2759
+ cursor?: string;
2760
+ maxItems?: number;
2761
+ pageSize?: number;
2762
+ };
2763
+ declare function decodeIncomingCursor(incoming?: string): {
2764
+ offset: number;
2765
+ cursor: string | undefined;
2766
+ };
2767
+ declare function createPrefixedCursor(prefix: string, cursor: string | undefined): string;
2768
+ declare function splitPrefixedCursor(cursor: string | undefined, prefixes?: string[]): [string | undefined, string | undefined];
2769
+ /**
2770
+ * Utility for paginating through API endpoints that return cursor-based pages.
2771
+ * Accepts and yields SDK-encoded cursor envelopes. Any incoming cursor is decoded
2772
+ * before being passed to the page function; all outgoing cursors are encoded.
2773
+ *
2774
+ * @param pageFunction - Function that fetches a single page with {data, nextCursor} structure
2775
+ * @param pageOptions - Options to pass to the page function (cursor will be managed automatically)
2776
+ * @returns Async iterator that yields pages with encoded cursors
2777
+ */
2778
+ declare function paginateMaxItems<TOptions, TPage extends {
2779
+ data: any[];
2780
+ nextCursor?: string;
2781
+ }>(pageFunction: (options: TOptions & {
2782
+ cursor?: string;
2783
+ maxItems?: number;
2784
+ pageSize?: number;
2785
+ }) => Promise<TPage>, pageOptions?: TPageOptions<TOptions>): AsyncIterableIterator<TPage>;
2786
+ declare function paginateBuffered<TOptions, TPage extends {
2787
+ data: any[];
2788
+ nextCursor?: string;
2789
+ }>(pageFunction: (options: TOptions & {
2790
+ cursor?: string;
2791
+ maxItems?: number;
2792
+ pageSize?: number;
2793
+ }) => Promise<TPage>, pageOptions?: TPageOptions<TOptions>): AsyncIterableIterator<TPage>;
2794
+ declare const paginate: typeof paginateBuffered;
2795
+ interface PaginatedResult<TItem> {
2796
+ data: TItem[];
2797
+ nextCursor?: string;
2798
+ }
2799
+ type PaginatedSource<TItem> = () => PromiseLike<PaginatedResult<TItem>> & AsyncIterable<PaginatedResult<TItem>>;
2800
+ /**
2801
+ * Concatenate multiple paginated SDK results into a single paginated stream.
2802
+ * Each source is a function returning a dual Promise+AsyncIterable (as SDK
2803
+ * paginated methods return). Sources are drained in order.
2804
+ *
2805
+ * The optional `dedupe` key extractor filters items from source N against
2806
+ * all items seen in sources 0 through N-1.
2807
+ *
2808
+ * Uses paginateBuffered internally to normalize page sizes across source
2809
+ * boundaries — e.g. if the first source only has 2 items, they'll be
2810
+ * buffered with items from the next source into a full page.
2811
+ *
2812
+ * Returns the same dual Promise+AsyncIterable shape that resolvers expect.
2813
+ */
2814
+ declare function concatPaginated<TItem>({ sources, dedupe, pageSize, }: {
2815
+ sources: PaginatedSource<TItem>[];
2816
+ dedupe?: (item: TItem) => string;
2817
+ pageSize?: number;
2818
+ }): PromiseLike<PaginatedResult<TItem>> & AsyncIterable<PaginatedResult<TItem>>;
2819
+ /**
2820
+ * Strip the PromiseLike from an async iterable, returning a plain
2821
+ * AsyncIterable. This prevents async functions from unwrapping the
2822
+ * iterable (since async only unwraps PromiseLike, not AsyncIterable).
2823
+ */
2824
+ declare function toIterable<T>(source: AsyncIterable<T>): AsyncIterable<T>;
2825
+
2826
+ /**
2827
+ * Generic string utilities used by the plugin framework.
2828
+ */
2829
+ /**
2830
+ * Converts a string to title case, handling various input formats:
2831
+ * - camelCase: "firstName" → "First Name"
2832
+ * - snake_case: "first_name" → "First Name"
2833
+ * - kebab-case: "first-name" → "First Name"
2834
+ * - mixed formats: "first_name-value" → "First Name Value"
2835
+ */
2836
+ declare function toTitleCase(input: string): string;
2837
+ /**
2838
+ * Converts a string to snake_case, handling various input formats:
2839
+ * - camelCase: "firstName" → "first_name"
2840
+ * - kebab-case: "first-name" → "first_name"
2841
+ * - title case: "First Name" → "first_name"
2842
+ * - mixed formats: "first-Name Value" → "first_name_value"
2843
+ * - starts with number: "123abc" → "_123abc"
2844
+ */
2845
+ declare function toSnakeCase(input: string): string;
2846
+
2847
+ interface DeprecationLogger {
2848
+ logDeprecation(message: string): void;
2849
+ resetDeprecationWarnings(): void;
2850
+ }
2851
+ /**
2852
+ * Create a package-tagged deprecation logger. Each logger tracks its own
2853
+ * once-per-process message Set, so package heads can keep independent warning
2854
+ * channels while sharing the implementation.
2855
+ */
2856
+ declare function createDeprecationLogger(tag: string): DeprecationLogger;
2857
+
2858
+ /**
2859
+ * Core signal machinery.
2860
+ *
2861
+ * Signals are intentional control-flow throws — not failures. They're the
2862
+ * sibling of {@link CoreError}: where an error means "something went wrong," a
2863
+ * signal means "stop and do this on purpose." The first (and currently only)
2864
+ * one is {@link CoreCancelledSignal}, thrown by `Controller.resolve` when the
2865
+ * host cancels resolution (its answer callback returned `{ type: "cancel" }`).
2866
+ *
2867
+ * Like errors, every signal is brand-stamped with {@link CORE_SIGNAL_SYMBOL} so
2868
+ * a consumer can recognize one via {@link isCoreSignal} without sharing class
2869
+ * identity — important across the bundled-vs-standalone kitcore boundary.
2870
+ */
2871
+ /**
2872
+ * Cross-package brand for kitcore signals. `Symbol.for(key)` reads the
2873
+ * engine-global registry, so the same value resolves across realms and across
2874
+ * multiple copies of kitcore. Use {@link isCoreSignal} for cross-package checks.
2875
+ */
2876
+ declare const CORE_SIGNAL_SYMBOL: unique symbol;
2877
+ /**
2878
+ * Base class for kitcore signals. A signal is intentional control flow, not an
2879
+ * error, so it does NOT extend any error hierarchy that failure-handling code
2880
+ * sweeps up via `instanceof CoreError`. Subclasses declare a stable `name` and
2881
+ * `code`. (Mirrors the head convention, e.g. zapier-sdk's `ZapierSignal`.)
2882
+ */
2883
+ declare abstract class CoreSignal extends Error {
2884
+ abstract readonly name: string;
2885
+ abstract readonly code: string;
2886
+ constructor(message?: string);
2887
+ }
2888
+ /**
2889
+ * Cross-package-safe check that `value` is a kitcore signal (an intentional
2890
+ * control-flow throw), as opposed to a real error. Survives the
2891
+ * bundled/standalone kitcore split, where `instanceof CoreSignal` may not.
2892
+ */
2893
+ declare function isCoreSignal(value: unknown): boolean;
2894
+ /**
2895
+ * Thrown by `Controller.resolve` when the host cancels resolution (the answer
2896
+ * callback returned `{ type: "cancel" }`). The lower-level `start`/`step`
2897
+ * protocol instead returns a `{ status: "cancelled" }` result, so a host
2898
+ * driving it directly never sees this throw; `resolve` raises it because its
2899
+ * contract is "the resolved input, or nothing."
2900
+ */
2901
+ declare class CoreCancelledSignal extends CoreSignal {
2902
+ readonly name = "CoreCancelledSignal";
2903
+ readonly code: "CANCELLED";
2904
+ constructor(message?: string);
2905
+ }
2906
+
2907
+ export { type AdaptError, type AdaptErrorOptions, type AdaptPage, type AggregatePlugin, type ArrayResolver$1 as ArrayResolver, type AsyncContext, type BoundFormatter, type BoundResolver, CONTEXT, CORE_ERROR_SYMBOL, CORE_SIGNAL_SYMBOL, type CategoryDefinition, type ConstantResolver$1 as ConstantResolver, type Controller, type ControllerAction, type ControllerAffordance, type ControllerAnswerFn, type ControllerChoice, type ControllerError, type ControllerIssue, type ControllerListing, type ControllerMethodDescription, type ControllerMethodSummary, type ControllerParameterDescription, type ControllerPath, type ControllerQuestion, type ControllerResult, type ControllerSdk, type ControllerState, type CoreApiError, CoreCancelledSignal, CoreError, CoreErrorCode, type CoreErrorOptions, type CoreOptions, CoreSignal, type DeprecatedPromptConfigChoice, type DeprecationLogger, type DynamicListResolver, type DynamicResolver$1 as DynamicResolver, type DynamicSearchResolver, type FieldsResolver, type FormattedItem, type Formatter, type FunctionDeprecation, type FunctionRegistryEntry, type LeafMeta, type LegacyMergePlugin, type LegacyPlugin, type ListItemsResult, type ListPromptConfig, type MethodAttachment, type MethodHooks, type MethodPlugin, type MethodScope, type OnMethodEnd, type OnMethodEndContext, type OnMethodStart, type OnMethodStartContext, type OutputFormatter, type PaginatedSdkFunction, type PaginatedSdkResult, type Plugin, type PluginMeta, type PluginProvides, type PluginStack, type PluginSummary, type PositionalMetadata, type PromptConfig, type PromptConfigChoice, type PropertyPlugin, type RegistryResult, type RequiredSdkOf, type Resolver$1 as Resolver, type ResolverConfig, type ResolverFieldItem, type ResolverMetadata, type ResolverPromptConfig, type ResolverType, type Sdk, type SdkContext, type SdkPage, type StaticResolver$1 as StaticResolver, type ValidResolvers, addPlugin, composePlugins, concatPaginated, createAsyncContext, createController, createCoreError, createCorePlugin, createDeprecationLogger, createFunction, createPaginatedFunction, createPaginatedPluginMethod, createPluginMethod, createPluginStack, createPrefixedCursor, createSdk, createValidator, dangerousContextPlugin, declareMethod, declarePlugin, declareProperty, decodeIncomingCursor, defineFormatter, defineLegacyMerge, defineMethod, definePlugin, defineProperty, defineResolver, fromFunctionPlugin, getContext, getCoreErrorCause, getCoreErrorCode, getCurrentDepth, getCurrentScope, getFieldDescriptions, getOutputSchema, getRegistryPlugin, getSchemaDescription, isCoreError, isCoreSignal, isNestedMethodCall, isPositional, isTelemetryNested, openEnum, paginate, paginateBuffered, paginateMaxItems, runInMethodScope, runWithTelemetryContext, selectExports, splitPrefixedCursor, toIterable, toSnakeCase, toTitleCase, validateOptions, withOutputSchema, withPositional, withResolver };