@zapier/kitcore 0.0.0 → 0.5.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,3646 @@
1
+ // src/registry.ts
2
+ import { z } from "zod";
3
+
4
+ // src/utils/string-utils.ts
5
+ function toTitleCase(input) {
6
+ return input.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_\-]+/g, " ").replace(/\s+/g, " ").trim().split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
7
+ }
8
+ function toSnakeCase(input) {
9
+ let result = input.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[\s\-]+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase();
10
+ if (/^[0-9]/.test(result)) {
11
+ result = "_" + result;
12
+ }
13
+ return result;
14
+ }
15
+ function pluralize(word) {
16
+ if (/s$/i.test(word)) return word;
17
+ if (/[bcdfghjklmnpqrstvwxz]y$/i.test(word)) {
18
+ return word.slice(0, -1) + "ies";
19
+ }
20
+ return word + "s";
21
+ }
22
+ function pluralizeLastWord(title) {
23
+ const words = title.split(" ");
24
+ return [...words.slice(0, -1), pluralize(words[words.length - 1])].join(" ");
25
+ }
26
+
27
+ // src/registry.ts
28
+ function resolveCategoryDefinition(ref) {
29
+ const def = typeof ref === "string" ? { key: ref } : ref;
30
+ const title = def.title ?? toTitleCase(def.key);
31
+ return {
32
+ key: def.key,
33
+ title,
34
+ titlePlural: def.titlePlural ?? pluralizeLastWord(title)
35
+ };
36
+ }
37
+ function canonicalInputSchema(schema) {
38
+ if (schema instanceof z.ZodUnion) {
39
+ return schema.options[0];
40
+ }
41
+ return schema;
42
+ }
43
+ function buildRegistry({
44
+ sdk,
45
+ meta,
46
+ formatters,
47
+ boundResolvers,
48
+ positional,
49
+ packageFilter
50
+ }) {
51
+ const definitionsByKey = /* @__PURE__ */ new Map();
52
+ const objectDeclaredKeys = /* @__PURE__ */ new Set();
53
+ for (const m of Object.values(meta)) {
54
+ for (const ref of m.categories ?? []) {
55
+ const key2 = typeof ref === "string" ? ref : ref.key;
56
+ if (typeof ref === "object") {
57
+ objectDeclaredKeys.add(key2);
58
+ definitionsByKey.set(key2, resolveCategoryDefinition(ref));
59
+ } else if (!objectDeclaredKeys.has(key2)) {
60
+ definitionsByKey.set(key2, resolveCategoryDefinition(ref));
61
+ }
62
+ }
63
+ }
64
+ if (!definitionsByKey.has("other")) {
65
+ definitionsByKey.set("other", resolveCategoryDefinition("other"));
66
+ }
67
+ const knownCategories = Array.from(definitionsByKey.keys());
68
+ const functions = Object.keys(meta).filter((key2) => {
69
+ const property = sdk[key2];
70
+ if (typeof property === "function") return true;
71
+ const [rootKey] = key2.split(".");
72
+ const rootProperty = sdk[rootKey];
73
+ return typeof rootProperty === "object" && rootProperty !== null;
74
+ }).map((key2) => {
75
+ const m = meta[key2];
76
+ return {
77
+ name: key2,
78
+ description: m.description,
79
+ type: m.type,
80
+ itemType: m.itemType,
81
+ returnType: m.returnType,
82
+ inputSchema: canonicalInputSchema(m.inputSchema),
83
+ inputParameters: m.inputParameters,
84
+ outputSchema: m.outputSchema,
85
+ positional: positional?.[key2],
86
+ categories: (m.categories ?? []).map(
87
+ (c) => typeof c === "string" ? c : c.key
88
+ ),
89
+ resolvers: m.resolvers,
90
+ boundResolvers: boundResolvers?.[key2],
91
+ formatter: formatters?.[key2],
92
+ experimental: m.experimental,
93
+ packages: m.packages,
94
+ confirm: m.confirm ?? (m.type === "delete" ? "delete" : void 0),
95
+ deprecation: m.deprecation,
96
+ aliases: m.aliases,
97
+ supportsJsonOutput: m.supportsJsonOutput ?? true
98
+ };
99
+ }).sort((a, b) => a.name.localeCompare(b.name));
100
+ const filteredFunctions = packageFilter ? functions.filter((f) => !f.packages || f.packages.includes(packageFilter)) : functions;
101
+ const filteredCategories = knownCategories.slice().sort((a, b) => {
102
+ if (a === "other") return 1;
103
+ if (b === "other") return -1;
104
+ return definitionsByKey.get(a).title.localeCompare(definitionsByKey.get(b).title);
105
+ }).map((categoryKey) => {
106
+ const categoryFunctions = filteredFunctions.filter(
107
+ (f) => f.categories.includes(categoryKey) || categoryKey === "other" && !f.categories.some((c) => knownCategories.includes(c))
108
+ ).map((f) => f.name).sort();
109
+ const def = definitionsByKey.get(categoryKey);
110
+ return {
111
+ key: categoryKey,
112
+ title: def.title,
113
+ titlePlural: def.titlePlural,
114
+ functions: categoryFunctions
115
+ };
116
+ }).filter((category) => category.functions.length > 0);
117
+ return { functions: filteredFunctions, categories: filteredCategories };
118
+ }
119
+
120
+ // src/utils/build-hooks.ts
121
+ function composeVoid(existing, added) {
122
+ if (!existing) return added;
123
+ if (!added) return existing;
124
+ return (ctx) => {
125
+ existing(ctx);
126
+ added(ctx);
127
+ };
128
+ }
129
+ function buildHooks(existing, added) {
130
+ const result = {};
131
+ const start2 = composeVoid(existing.onMethodStart, added.onMethodStart);
132
+ if (start2) result.onMethodStart = start2;
133
+ const end = composeVoid(existing.onMethodEnd, added.onMethodEnd);
134
+ if (end) result.onMethodEnd = end;
135
+ return result;
136
+ }
137
+
138
+ // src/utils/logging.ts
139
+ function createDeprecationLogger(tag) {
140
+ const loggedDeprecations = /* @__PURE__ */ new Set();
141
+ return {
142
+ logDeprecation(message) {
143
+ if (loggedDeprecations.has(message)) return;
144
+ loggedDeprecations.add(message);
145
+ console.warn(`[${tag}] Deprecation: ${message}`);
146
+ },
147
+ resetDeprecationWarnings() {
148
+ loggedDeprecations.clear();
149
+ }
150
+ };
151
+ }
152
+ var { logDeprecation, resetDeprecationWarnings } = createDeprecationLogger("core");
153
+
154
+ // src/types/errors.ts
155
+ var CORE_ERROR_SYMBOL = Symbol.for("kitcore.error");
156
+ var CoreErrorCode = {
157
+ Validation: "VALIDATION_ERROR",
158
+ Unknown: "UNKNOWN_ERROR"
159
+ };
160
+ var CoreError = class extends Error {
161
+ constructor(message, options = {}) {
162
+ super(message);
163
+ this.name = "CoreError";
164
+ if (options.statusCode !== void 0) this.statusCode = options.statusCode;
165
+ if (options.errors !== void 0) this.errors = options.errors;
166
+ if (options.cause !== void 0) this.cause = options.cause;
167
+ if (options.response !== void 0) this.response = options.response;
168
+ Object.setPrototypeOf(this, new.target.prototype);
169
+ }
170
+ };
171
+ function createCoreError(options, adaptError) {
172
+ const error = adaptError?.(options) ?? new CoreError(options.message, { cause: options.cause });
173
+ Object.defineProperty(error, CORE_ERROR_SYMBOL, {
174
+ value: true,
175
+ enumerable: false,
176
+ configurable: true,
177
+ writable: false
178
+ });
179
+ Object.defineProperty(error, "coreCode", {
180
+ value: options.code,
181
+ enumerable: false,
182
+ configurable: true,
183
+ writable: false
184
+ });
185
+ return error;
186
+ }
187
+ function isCoreError(value) {
188
+ return Boolean(
189
+ value && typeof value === "object" && value[CORE_ERROR_SYMBOL] === true
190
+ );
191
+ }
192
+ function getCoreErrorCode(value) {
193
+ if (!isCoreError(value)) return void 0;
194
+ return value.coreCode;
195
+ }
196
+ function getCoreErrorCause(value) {
197
+ if (!isCoreError(value)) return void 0;
198
+ return value.cause;
199
+ }
200
+
201
+ // src/utils/pagination-utils.ts
202
+ var CURSOR_VERSION = 1;
203
+ var CURSOR_SOURCE = {
204
+ API: "api",
205
+ SDK: "sdk"
206
+ };
207
+ function encodeBase64(str) {
208
+ return btoa(
209
+ Array.from(
210
+ new TextEncoder().encode(str),
211
+ (b) => String.fromCharCode(b)
212
+ ).join("")
213
+ );
214
+ }
215
+ function decodeBase64(str) {
216
+ return new TextDecoder().decode(
217
+ Uint8Array.from(atob(str), (c) => c.charCodeAt(0))
218
+ );
219
+ }
220
+ function encodeApiCursor(cursor) {
221
+ const envelope = {
222
+ v: CURSOR_VERSION,
223
+ source: CURSOR_SOURCE.API,
224
+ cursor
225
+ };
226
+ return encodeBase64(JSON.stringify(envelope));
227
+ }
228
+ function encodeSdkCursor(offset, cursor) {
229
+ const envelope = {
230
+ v: CURSOR_VERSION,
231
+ source: CURSOR_SOURCE.SDK,
232
+ cursor,
233
+ offset
234
+ };
235
+ return encodeBase64(JSON.stringify(envelope));
236
+ }
237
+ function decodeIncomingCursor(incoming) {
238
+ if (!incoming) {
239
+ return { offset: 0, cursor: void 0 };
240
+ }
241
+ try {
242
+ const decoded = decodeBase64(incoming);
243
+ const envelope = JSON.parse(decoded);
244
+ if (envelope.v !== CURSOR_VERSION) {
245
+ return { offset: 0, cursor: incoming };
246
+ }
247
+ if (envelope.source === CURSOR_SOURCE.SDK) {
248
+ return { offset: envelope.offset ?? 0, cursor: envelope.cursor };
249
+ }
250
+ if (envelope.source === CURSOR_SOURCE.API) {
251
+ return { offset: 0, cursor: envelope.cursor };
252
+ }
253
+ return { offset: 0, cursor: incoming };
254
+ } catch {
255
+ return { offset: 0, cursor: incoming };
256
+ }
257
+ }
258
+ function createPrefixedCursor(prefix, cursor) {
259
+ if (!cursor) {
260
+ return `${prefix}::`;
261
+ }
262
+ return `${prefix}::${cursor}`;
263
+ }
264
+ function splitPrefixedCursor(cursor, prefixes) {
265
+ if (!cursor) {
266
+ return [void 0, void 0];
267
+ }
268
+ const [prefix, ...rest] = cursor.split("::");
269
+ if (prefixes && !prefixes.includes(prefix)) {
270
+ return [void 0, cursor];
271
+ }
272
+ cursor = rest.join("::");
273
+ if (!cursor) {
274
+ return [prefix, void 0];
275
+ }
276
+ return [prefix, cursor];
277
+ }
278
+ async function* paginateMaxItemsWithUnencodedCursor(pageFunction, pageOptions) {
279
+ let cursor = pageOptions?.cursor;
280
+ let totalItemsYielded = 0;
281
+ const maxItems = pageOptions?.maxItems;
282
+ const pageSize = pageOptions?.pageSize;
283
+ do {
284
+ const options = {
285
+ ...pageOptions || {},
286
+ cursor,
287
+ pageSize: maxItems !== void 0 && pageSize !== void 0 ? Math.min(pageSize, maxItems) : pageSize
288
+ };
289
+ const page = await pageFunction(options);
290
+ if (maxItems !== void 0) {
291
+ const remainingItems = maxItems - totalItemsYielded;
292
+ if (page.data.length >= remainingItems) {
293
+ yield {
294
+ ...page,
295
+ data: page.data.slice(0, remainingItems),
296
+ nextCursor: void 0
297
+ };
298
+ break;
299
+ }
300
+ }
301
+ yield page;
302
+ totalItemsYielded += page.data.length;
303
+ cursor = page.nextCursor;
304
+ } while (cursor);
305
+ }
306
+ async function* paginateMaxItems(pageFunction, pageOptions) {
307
+ const { cursor } = decodeIncomingCursor(pageOptions?.cursor);
308
+ const options = {
309
+ ...pageOptions || {},
310
+ cursor
311
+ };
312
+ for await (const page of paginateMaxItemsWithUnencodedCursor(
313
+ pageFunction,
314
+ options
315
+ )) {
316
+ yield {
317
+ ...page,
318
+ nextCursor: page.nextCursor ? encodeApiCursor(page.nextCursor) : void 0
319
+ };
320
+ }
321
+ }
322
+ async function* paginateBuffered(pageFunction, pageOptions) {
323
+ const pageSize = pageOptions?.pageSize;
324
+ const { offset: cursorOffset, cursor: initialCursor } = decodeIncomingCursor(
325
+ pageOptions?.cursor
326
+ );
327
+ const requestedMaxItems = pageOptions?.maxItems;
328
+ const options = {
329
+ ...pageOptions || {},
330
+ cursor: initialCursor,
331
+ // SDK cursors can carry an offset into a raw backend page. Since maxItems
332
+ // is expected to be relative to the resumed position, we add that offset
333
+ // so raw pagination still yields enough items after offset slicing.
334
+ maxItems: requestedMaxItems !== void 0 && cursorOffset > 0 ? requestedMaxItems + cursorOffset : requestedMaxItems
335
+ };
336
+ if (!pageSize) {
337
+ for await (const page of paginateMaxItemsWithUnencodedCursor(
338
+ pageFunction,
339
+ options
340
+ )) {
341
+ yield {
342
+ ...page,
343
+ nextCursor: page.nextCursor ? encodeApiCursor(page.nextCursor) : void 0
344
+ };
345
+ }
346
+ return;
347
+ }
348
+ let bufferedPages = [];
349
+ let isFirstPage = true;
350
+ let rawCursor;
351
+ for await (let page of paginateMaxItemsWithUnencodedCursor(
352
+ pageFunction,
353
+ options
354
+ )) {
355
+ const nextRawCursor = page.nextCursor;
356
+ if (isFirstPage) {
357
+ isFirstPage = false;
358
+ if (cursorOffset) {
359
+ page = {
360
+ ...page,
361
+ data: page.data.slice(cursorOffset)
362
+ };
363
+ }
364
+ }
365
+ const bufferedLength = bufferedPages.reduce(
366
+ (acc, p) => acc + p.data.length,
367
+ 0
368
+ );
369
+ if (bufferedLength + page.data.length < pageSize) {
370
+ bufferedPages.push(page);
371
+ rawCursor = nextRawCursor;
372
+ continue;
373
+ }
374
+ const bufferedItems = bufferedPages.map((p) => p.data).flat();
375
+ const allItems = [...bufferedItems, ...page.data];
376
+ const pageItems = allItems.slice(0, pageSize);
377
+ const remainingItems = allItems.slice(pageItems.length);
378
+ if (remainingItems.length === 0) {
379
+ yield {
380
+ ...page,
381
+ data: pageItems,
382
+ nextCursor: nextRawCursor ? encodeApiCursor(nextRawCursor) : void 0
383
+ };
384
+ bufferedPages = [];
385
+ rawCursor = nextRawCursor;
386
+ continue;
387
+ }
388
+ yield {
389
+ ...page,
390
+ data: pageItems,
391
+ nextCursor: encodeSdkCursor(
392
+ page.data.length - remainingItems.length,
393
+ rawCursor
394
+ )
395
+ };
396
+ while (remainingItems.length > pageSize) {
397
+ const chunkItems = remainingItems.splice(0, pageSize);
398
+ yield {
399
+ ...page,
400
+ data: chunkItems,
401
+ nextCursor: encodeSdkCursor(
402
+ page.data.length - remainingItems.length,
403
+ rawCursor
404
+ )
405
+ };
406
+ }
407
+ bufferedPages = [
408
+ {
409
+ ...page,
410
+ data: remainingItems
411
+ }
412
+ ];
413
+ rawCursor = nextRawCursor;
414
+ }
415
+ if (bufferedPages.length > 0) {
416
+ const lastBufferedPage = bufferedPages.slice(-1)[0];
417
+ const bufferedItems = bufferedPages.map((p) => p.data).flat();
418
+ yield {
419
+ ...lastBufferedPage,
420
+ data: bufferedItems
421
+ };
422
+ }
423
+ }
424
+ var paginate = paginateBuffered;
425
+ function concatPaginated({
426
+ sources,
427
+ dedupe,
428
+ pageSize = 100
429
+ }) {
430
+ if (sources.length === 0) {
431
+ const empty = { data: [] };
432
+ return Object.assign(Promise.resolve(empty), {
433
+ [Symbol.asyncIterator]: async function* () {
434
+ yield empty;
435
+ }
436
+ });
437
+ }
438
+ let sourceIndex = 0;
439
+ let currentIterator = null;
440
+ const seen = /* @__PURE__ */ new Set();
441
+ const pageFunction = async (_options) => {
442
+ while (sourceIndex < sources.length) {
443
+ if (!currentIterator) {
444
+ const result = sources[sourceIndex]();
445
+ currentIterator = result[Symbol.asyncIterator]();
446
+ }
447
+ const next = await currentIterator.next();
448
+ if (next.done) {
449
+ sourceIndex++;
450
+ currentIterator = null;
451
+ continue;
452
+ }
453
+ let items = next.value.data;
454
+ if (dedupe) {
455
+ if (sourceIndex > 0) {
456
+ items = items.filter((item) => !seen.has(dedupe(item)));
457
+ }
458
+ for (const item of items) {
459
+ seen.add(dedupe(item));
460
+ }
461
+ }
462
+ const hasMoreInSource = next.value.nextCursor != null;
463
+ const hasMoreSources = sourceIndex < sources.length - 1;
464
+ return {
465
+ data: items,
466
+ nextCursor: hasMoreInSource || hasMoreSources ? "__has_more__" : void 0
467
+ };
468
+ }
469
+ return { data: [] };
470
+ };
471
+ const iterator = paginateBuffered(pageFunction, { pageSize });
472
+ const firstPagePromise = iterator.next().then((result) => {
473
+ if (result.done) {
474
+ return { data: [] };
475
+ }
476
+ return result.value;
477
+ });
478
+ return Object.assign(firstPagePromise, {
479
+ [Symbol.asyncIterator]: async function* () {
480
+ yield await firstPagePromise;
481
+ for await (const page of { [Symbol.asyncIterator]: () => iterator }) {
482
+ yield page;
483
+ }
484
+ }
485
+ });
486
+ }
487
+ function toIterable(source) {
488
+ return { [Symbol.asyncIterator]: () => source[Symbol.asyncIterator]() };
489
+ }
490
+
491
+ // src/utils/validation.ts
492
+ var parseOrThrow = (schema, input, { adaptError } = {}) => {
493
+ const result = schema.safeParse(input);
494
+ if (!result.success) {
495
+ const errorMessages = result.error.issues.map((issue) => {
496
+ const path = issue.path.length > 0 ? issue.path.join(".") : "input";
497
+ return `${path}: ${issue.message}`;
498
+ });
499
+ throw createCoreError(
500
+ {
501
+ code: CoreErrorCode.Validation,
502
+ message: `Validation failed:
503
+ ${errorMessages.join("\n ")}`,
504
+ details: {
505
+ zodErrors: result.error.issues,
506
+ input
507
+ }
508
+ },
509
+ adaptError
510
+ );
511
+ }
512
+ return result.data;
513
+ };
514
+ function createValidator(schema, { adaptError } = {}) {
515
+ return function validateFn(input) {
516
+ return parseOrThrow(schema, input, { adaptError });
517
+ };
518
+ }
519
+ var validateOptions = (schema, options, { adaptError } = {}) => parseOrThrow(schema, options, { adaptError });
520
+
521
+ // src/utils/async-context.ts
522
+ import {
523
+ AsyncLocalStorage
524
+ } from "async_hooks";
525
+ function createAsyncContext() {
526
+ let store = null;
527
+ try {
528
+ store = new AsyncLocalStorage();
529
+ } catch {
530
+ store = null;
531
+ }
532
+ return {
533
+ available: store !== null,
534
+ run(value, fn) {
535
+ return store ? store.run(value, fn) : fn();
536
+ },
537
+ get() {
538
+ return store?.getStore();
539
+ }
540
+ };
541
+ }
542
+
543
+ // src/utils/method-scope.ts
544
+ var scope = createAsyncContext();
545
+ function getCurrentScope() {
546
+ return scope.get();
547
+ }
548
+ function getCurrentDepth() {
549
+ return getCurrentScope()?.depth ?? 0;
550
+ }
551
+ function isNestedMethodCall() {
552
+ if (!scope.available) return true;
553
+ const store = scope.get();
554
+ return store !== void 0 && store.depth > 0;
555
+ }
556
+ var observerReentrancy = 0;
557
+ function runIsolatedObserver(fn) {
558
+ observerReentrancy++;
559
+ try {
560
+ fn();
561
+ } catch {
562
+ } finally {
563
+ observerReentrancy--;
564
+ }
565
+ }
566
+ function isInsideObserver() {
567
+ return observerReentrancy > 0;
568
+ }
569
+ function runInMethodScope(fn) {
570
+ if (!scope.available) return fn();
571
+ const currentDepth = scope.get()?.depth ?? -1;
572
+ return scope.run({ depth: currentDepth + 1 }, fn);
573
+ }
574
+ var runWithTelemetryContext = runInMethodScope;
575
+ var isTelemetryNested = isNestedMethodCall;
576
+
577
+ // src/utils/core-options.ts
578
+ function defaultLogDeprecation({
579
+ methodName,
580
+ deprecation
581
+ }) {
582
+ logDeprecation(`${methodName}() is deprecated. ${deprecation.message}`);
583
+ }
584
+ var CORE_OPTIONS_ID = "kitcore/coreOptions";
585
+
586
+ // src/utils/function-utils.ts
587
+ function resolveCoreOptions(context) {
588
+ const entry = context.plugins?.[CORE_OPTIONS_ID];
589
+ if (entry) {
590
+ return entry.getValue ? entry.getValue() : entry.value;
591
+ }
592
+ return context.core;
593
+ }
594
+ var INTERNAL_CALL = Symbol("kitcore.internalCall");
595
+ function signalDeprecation(context, methodName, getDeprecation) {
596
+ if (isInsideObserver()) return;
597
+ const deprecation = getDeprecation?.();
598
+ if (!deprecation?.message) return;
599
+ const warning = {
600
+ type: "deprecation",
601
+ methodName,
602
+ deprecation
603
+ };
604
+ const handler = resolveCoreOptions(context)?.logDeprecation ?? defaultLogDeprecation;
605
+ runIsolatedObserver(() => handler(warning));
606
+ }
607
+ function normalizeError(error, adaptError) {
608
+ if (error instanceof Error) return error;
609
+ const message = typeof error === "object" && error !== null && "message" in error && typeof error.message === "string" ? error.message : String(error);
610
+ return createCoreError(
611
+ {
612
+ code: CoreErrorCode.Unknown,
613
+ message,
614
+ cause: error
615
+ },
616
+ adaptError
617
+ );
618
+ }
619
+ function createFunction(coreFn, options) {
620
+ const { sdk, schema, name, getDeprecation } = options;
621
+ const functionName = name || coreFn.name;
622
+ const namedFunctions = {
623
+ [functionName]: async function(callOptions) {
624
+ if (arguments[1] !== INTERNAL_CALL) {
625
+ signalDeprecation(sdk.context, functionName, getDeprecation);
626
+ }
627
+ return runInMethodScope(async () => {
628
+ const startTime = Date.now();
629
+ const normalizedOptions = callOptions ?? {};
630
+ const args = [normalizedOptions];
631
+ const depth = getCurrentDepth();
632
+ const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
633
+ const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
634
+ hooks?.onMethodStart?.({
635
+ methodName: functionName,
636
+ args,
637
+ isPaginated: false,
638
+ depth
639
+ });
640
+ try {
641
+ let result;
642
+ if (schema) {
643
+ const validatedOptions = validateOptions(
644
+ schema,
645
+ normalizedOptions,
646
+ {
647
+ adaptError
648
+ }
649
+ );
650
+ result = await coreFn({
651
+ ...normalizedOptions,
652
+ ...validatedOptions
653
+ });
654
+ } else {
655
+ result = await coreFn(normalizedOptions);
656
+ }
657
+ hooks?.onMethodEnd?.({
658
+ methodName: functionName,
659
+ args,
660
+ isPaginated: false,
661
+ depth,
662
+ durationMs: Date.now() - startTime
663
+ });
664
+ return result;
665
+ } catch (error) {
666
+ const normalizedError = normalizeError(error, adaptError);
667
+ hooks?.onMethodEnd?.({
668
+ methodName: functionName,
669
+ args,
670
+ isPaginated: false,
671
+ depth,
672
+ durationMs: Date.now() - startTime,
673
+ error: normalizedError
674
+ });
675
+ throw normalizedError;
676
+ }
677
+ });
678
+ }
679
+ };
680
+ return namedFunctions[functionName];
681
+ }
682
+ function createRawFunction(coreFn, options) {
683
+ const { sdk, name, schema, positional, getDeprecation } = options;
684
+ return function(rawInput) {
685
+ if (arguments[1] !== INTERNAL_CALL) {
686
+ signalDeprecation(sdk.context, name, getDeprecation);
687
+ }
688
+ return runInMethodScope(() => {
689
+ const startTime = Date.now();
690
+ const depth = getCurrentDepth();
691
+ const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
692
+ const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
693
+ const input = schema ? rawInput ?? {} : rawInput;
694
+ const record = input;
695
+ const args = positional ? positional.filter((key2) => record?.[key2] !== void 0).map((key2) => record?.[key2]) : [input];
696
+ hooks?.onMethodStart?.({
697
+ methodName: name,
698
+ args,
699
+ isPaginated: false,
700
+ depth
701
+ });
702
+ const fireEnd = (error) => {
703
+ hooks?.onMethodEnd?.({
704
+ methodName: name,
705
+ args,
706
+ isPaginated: false,
707
+ depth,
708
+ durationMs: Date.now() - startTime,
709
+ ...error ? { error } : {}
710
+ });
711
+ };
712
+ try {
713
+ const parsed = schema ? validateOptions(schema, input, { adaptError }) : input;
714
+ const result = coreFn(parsed);
715
+ if (result !== null && typeof result === "object" && typeof result.then === "function") {
716
+ return result.then(
717
+ (value) => {
718
+ fireEnd();
719
+ return value;
720
+ },
721
+ (error) => {
722
+ fireEnd(
723
+ error instanceof Error ? error : new Error(String(error))
724
+ );
725
+ throw error;
726
+ }
727
+ );
728
+ }
729
+ fireEnd();
730
+ return result;
731
+ } catch (error) {
732
+ fireEnd(error instanceof Error ? error : new Error(String(error)));
733
+ throw error;
734
+ }
735
+ });
736
+ };
737
+ }
738
+ function isSdkPage(value) {
739
+ if (typeof value !== "object" || value === null) return false;
740
+ const page = value;
741
+ if (!Array.isArray(page.data)) return false;
742
+ if (page.nextCursor !== void 0 && typeof page.nextCursor !== "string") {
743
+ return false;
744
+ }
745
+ return Object.keys(page).every((k) => k === "data" || k === "nextCursor");
746
+ }
747
+ function createPageFunction(coreFn, {
748
+ sdk,
749
+ adaptPage
750
+ }) {
751
+ const functionName = coreFn.name + "Page";
752
+ const namedFunctions = {
753
+ [functionName]: async function(options) {
754
+ try {
755
+ const response = await coreFn(options);
756
+ const page = adaptPage ? adaptPage(response) : response;
757
+ if (!isSdkPage(page)) {
758
+ throw new Error(
759
+ `${functionName}: paginated result must be exactly { data: TItem[], nextCursor? } (produced by the handler or its \`adaptPage\`); got keys [${page && typeof page === "object" ? Object.keys(page).join(", ") : typeof page}]. If the handler returns a raw shape, set \`adaptPage\` to translate it; if \`adaptPage\` already runs, it must return only \`data\`/\`nextCursor\`.`
760
+ );
761
+ }
762
+ return page;
763
+ } catch (error) {
764
+ throw normalizeError(
765
+ error,
766
+ resolveCoreOptions(sdk.context)?.adaptError
767
+ );
768
+ }
769
+ }
770
+ };
771
+ return namedFunctions[functionName];
772
+ }
773
+ function createPaginatedFunction(coreFn, options) {
774
+ const { sdk, schema, name, defaultPageSize, adaptPage, getDeprecation } = options;
775
+ const pageFunction = createPageFunction(coreFn, { sdk, adaptPage });
776
+ const functionName = name || coreFn.name;
777
+ const namedFunctions = {
778
+ [functionName]: function(callOptions) {
779
+ if (arguments[1] !== INTERNAL_CALL) {
780
+ signalDeprecation(sdk.context, functionName, getDeprecation);
781
+ }
782
+ return runInMethodScope(() => {
783
+ const startTime = Date.now();
784
+ const normalizedOptions = callOptions ?? {};
785
+ const args = [normalizedOptions];
786
+ const depth = getCurrentDepth();
787
+ const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
788
+ const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
789
+ hooks?.onMethodStart?.({
790
+ methodName: functionName,
791
+ args,
792
+ isPaginated: true,
793
+ depth
794
+ });
795
+ try {
796
+ const validatedOptions = {
797
+ ...normalizedOptions,
798
+ ...schema ? createValidator(schema, { adaptError })(normalizedOptions) : normalizedOptions
799
+ };
800
+ const pageSize = validatedOptions.pageSize ?? defaultPageSize;
801
+ const optimizedOptions = {
802
+ ...validatedOptions,
803
+ pageSize
804
+ };
805
+ const iterator = paginate(pageFunction, optimizedOptions);
806
+ const firstPagePromise = iterator.next().then((result) => {
807
+ if (result.done) {
808
+ throw new Error("Paginate should always iterate at least once");
809
+ }
810
+ return result.value;
811
+ });
812
+ if (hooks?.onMethodEnd) {
813
+ firstPagePromise.then(() => {
814
+ hooks.onMethodEnd({
815
+ methodName: functionName,
816
+ args,
817
+ isPaginated: true,
818
+ depth,
819
+ durationMs: Date.now() - startTime
820
+ });
821
+ }).catch((error) => {
822
+ hooks.onMethodEnd({
823
+ methodName: functionName,
824
+ args,
825
+ isPaginated: true,
826
+ depth,
827
+ durationMs: Date.now() - startTime,
828
+ error: error instanceof Error ? error : new Error(String(error))
829
+ });
830
+ });
831
+ }
832
+ const pageStream = async function* () {
833
+ yield await firstPagePromise;
834
+ for await (const page of iterator) {
835
+ yield page;
836
+ }
837
+ }();
838
+ return Object.assign(firstPagePromise, {
839
+ [Symbol.asyncIterator]() {
840
+ return pageStream;
841
+ },
842
+ items: function() {
843
+ return {
844
+ [Symbol.asyncIterator]: async function* () {
845
+ for await (const page of pageStream) {
846
+ for (const item of page.data) {
847
+ yield item;
848
+ }
849
+ }
850
+ }
851
+ };
852
+ }
853
+ });
854
+ } catch (error) {
855
+ const normalizedError = normalizeError(error, adaptError);
856
+ hooks?.onMethodEnd?.({
857
+ methodName: functionName,
858
+ args,
859
+ isPaginated: true,
860
+ depth,
861
+ durationMs: Date.now() - startTime,
862
+ error: normalizedError
863
+ });
864
+ throw normalizedError;
865
+ }
866
+ });
867
+ }
868
+ };
869
+ return namedFunctions[functionName];
870
+ }
871
+
872
+ // src/utils/plugin-utils.ts
873
+ function createPluginMethod(sdk, config) {
874
+ logDeprecation(
875
+ "createPluginMethod() is deprecated. Author methods with defineMethod instead."
876
+ );
877
+ const { name, inputSchema, handler, ...metaFields } = config;
878
+ const namedHandlers = {
879
+ [name]: async function(options) {
880
+ return handler({ sdk, options });
881
+ }
882
+ };
883
+ const wrappedFn = createFunction(namedHandlers[name], {
884
+ sdk,
885
+ schema: inputSchema
886
+ });
887
+ return {
888
+ [name]: wrappedFn,
889
+ context: {
890
+ meta: {
891
+ [name]: {
892
+ ...metaFields,
893
+ ...inputSchema ? { inputSchema } : {}
894
+ }
895
+ }
896
+ }
897
+ };
898
+ }
899
+ function createPaginatedPluginMethod(sdk, config) {
900
+ logDeprecation(
901
+ 'createPaginatedPluginMethod() is deprecated. Author list methods with defineMethod output "list" instead.'
902
+ );
903
+ const {
904
+ name,
905
+ inputSchema,
906
+ handler,
907
+ adaptPage,
908
+ defaultPageSize,
909
+ ...metaFields
910
+ } = config;
911
+ const namedHandlers = {
912
+ [name]: function(options) {
913
+ return handler({ sdk, options });
914
+ }
915
+ };
916
+ const wrappedFn = createPaginatedFunction(namedHandlers[name], {
917
+ sdk,
918
+ schema: inputSchema,
919
+ name,
920
+ defaultPageSize,
921
+ adaptPage
922
+ });
923
+ return {
924
+ [name]: wrappedFn,
925
+ context: {
926
+ meta: {
927
+ [name]: {
928
+ ...metaFields,
929
+ ...inputSchema ? { inputSchema } : {}
930
+ }
931
+ }
932
+ }
933
+ };
934
+ }
935
+ function splitPluginContribution(result) {
936
+ const { context, ...rootKeys } = result;
937
+ const { meta, hooks, ...contextRest } = context ?? {};
938
+ return {
939
+ rootKeys,
940
+ meta: meta ?? {},
941
+ hooks: hooks ?? {},
942
+ contextRest
943
+ };
944
+ }
945
+ var RESERVED_ROOT_KEYS = /* @__PURE__ */ new Set([
946
+ "context",
947
+ "getRegistry"
948
+ ]);
949
+ function hasOwn(obj, key2) {
950
+ return Object.prototype.hasOwnProperty.call(obj, key2);
951
+ }
952
+ function setOwn(target, key2, value) {
953
+ Object.defineProperty(target, key2, {
954
+ value,
955
+ enumerable: true,
956
+ configurable: true,
957
+ writable: true
958
+ });
959
+ }
960
+ function checkCollisions(target, source, kind, callerLabel, override) {
961
+ if (kind === "root key") {
962
+ checkRootKeyCollisions(target, Object.keys(source), override, callerLabel);
963
+ return;
964
+ }
965
+ for (const key2 of Object.keys(source)) {
966
+ if (!override && hasOwn(target, key2)) {
967
+ throw new Error(
968
+ `${callerLabel}: duplicate ${kind} "${key2}". If the override is intentional, pass { override: true } in the options.`
969
+ );
970
+ }
971
+ }
972
+ }
973
+ function checkRootKeyCollisions(target, keys, override, callerLabel) {
974
+ for (const key2 of keys) {
975
+ if (RESERVED_ROOT_KEYS.has(key2)) {
976
+ throw new Error(
977
+ `${callerLabel}: plugin attempted to register reserved root key "${key2}". The SDK uses this key for its own accessor; rename the plugin's method.`
978
+ );
979
+ }
980
+ if (!override && hasOwn(target, key2)) {
981
+ throw new Error(
982
+ `${callerLabel}: duplicate root key "${key2}". If the override is intentional, pass { override: true } in the options.`
983
+ );
984
+ }
985
+ }
986
+ }
987
+ function applyOwnProperties(target, source) {
988
+ for (const key2 of Object.keys(source)) {
989
+ setOwn(target, key2, source[key2]);
990
+ }
991
+ }
992
+ function createPluginAccumulator(initialProperties = {}, initialContext = {}) {
993
+ const initialMeta = initialContext.meta ?? {};
994
+ const initialHooks = initialContext.hooks ?? {};
995
+ const context = {
996
+ ...initialContext,
997
+ meta: { ...initialMeta },
998
+ hooks: { ...initialHooks }
999
+ };
1000
+ const view = { ...initialProperties, context };
1001
+ return { view, context };
1002
+ }
1003
+ function mergeContribution(propertiesTarget, contextTarget, contribution, options) {
1004
+ checkCollisions(
1005
+ propertiesTarget,
1006
+ contribution.rootKeys,
1007
+ "root key",
1008
+ options.callerLabel,
1009
+ options.override
1010
+ );
1011
+ checkCollisions(
1012
+ contextTarget.meta,
1013
+ contribution.meta,
1014
+ "context.meta key",
1015
+ options.callerLabel,
1016
+ options.override
1017
+ );
1018
+ checkCollisions(
1019
+ contextTarget,
1020
+ contribution.contextRest,
1021
+ "context key",
1022
+ options.callerLabel,
1023
+ options.override
1024
+ );
1025
+ applyOwnProperties(propertiesTarget, contribution.rootKeys);
1026
+ applyOwnProperties(contextTarget.meta, contribution.meta);
1027
+ applyOwnProperties(contextTarget, contribution.contextRest);
1028
+ contextTarget.hooks = buildHooks(contextTarget.hooks, contribution.hooks);
1029
+ }
1030
+ function applyPluginContribution(acc, contribution, options) {
1031
+ mergeContribution(acc.view, acc.context, contribution, options);
1032
+ }
1033
+ function wrapAsSdk(properties, context) {
1034
+ const sdk = {
1035
+ ...properties,
1036
+ context,
1037
+ getRegistry(qopts) {
1038
+ return buildRegistry({
1039
+ sdk,
1040
+ meta: context.meta,
1041
+ packageFilter: qopts?.package
1042
+ });
1043
+ }
1044
+ };
1045
+ return sdk;
1046
+ }
1047
+ function wrapAccumulatorAsSdk(acc) {
1048
+ const { context: _ctx, ...rootKeys } = acc.view;
1049
+ return wrapAsSdk(
1050
+ rootKeys,
1051
+ acc.context
1052
+ );
1053
+ }
1054
+ function applyPluginToSdk(sdk, plugin, options) {
1055
+ const context = sdk.context;
1056
+ const contribution = splitPluginContribution(
1057
+ plugin(sdk)
1058
+ );
1059
+ mergeContribution(sdk, context, contribution, {
1060
+ callerLabel: "addPlugin",
1061
+ override: options.override === true
1062
+ });
1063
+ return contribution;
1064
+ }
1065
+ function resolveStack(head) {
1066
+ const entries = [];
1067
+ let node = head;
1068
+ while (node) {
1069
+ entries.unshift({ apply: node.entry, override: node.override });
1070
+ node = node.prev;
1071
+ }
1072
+ return entries;
1073
+ }
1074
+ function composeStackHooks(hooks) {
1075
+ let composed = {};
1076
+ for (const h of hooks) composed = buildHooks(composed, h);
1077
+ return composed;
1078
+ }
1079
+ function collapseStackEntries(entries, callerLabel) {
1080
+ return (outerSdk) => {
1081
+ const { context: outerContext, ...outerProperties } = outerSdk ?? {};
1082
+ const viewAcc = createPluginAccumulator(outerProperties, outerContext);
1083
+ const contribsAcc = createPluginAccumulator();
1084
+ const hooks = [];
1085
+ for (const { apply, override } of entries) {
1086
+ const contribution = splitPluginContribution(
1087
+ apply(viewAcc.view)
1088
+ );
1089
+ const hookless = { ...contribution, hooks: {} };
1090
+ applyPluginContribution(viewAcc, hookless, { callerLabel, override });
1091
+ applyPluginContribution(contribsAcc, hookless, { callerLabel, override });
1092
+ hooks.push(contribution.hooks);
1093
+ }
1094
+ const stackHooks = composeStackHooks(hooks);
1095
+ viewAcc.context.hooks = buildHooks(viewAcc.context.hooks, stackHooks);
1096
+ contribsAcc.context.hooks = stackHooks;
1097
+ const { context: _ignored, ...contributedRoot } = contribsAcc.view;
1098
+ return {
1099
+ ...contributedRoot,
1100
+ context: contribsAcc.context
1101
+ };
1102
+ };
1103
+ }
1104
+ function buildStackAccumulator(head, callerLabel) {
1105
+ const entries = resolveStack(head);
1106
+ const acc = createPluginAccumulator();
1107
+ const hooks = [];
1108
+ for (const { apply, override } of entries) {
1109
+ const contribution = splitPluginContribution(
1110
+ apply(acc.view)
1111
+ );
1112
+ applyPluginContribution(
1113
+ acc,
1114
+ { ...contribution, hooks: {} },
1115
+ { callerLabel, override }
1116
+ );
1117
+ hooks.push(contribution.hooks);
1118
+ }
1119
+ acc.context.hooks = composeStackHooks(hooks);
1120
+ return acc;
1121
+ }
1122
+ function composePlugins(...plugins) {
1123
+ logDeprecation(
1124
+ "composePlugins(...) is deprecated. Use createPluginStack().use(a).use(b).use(c).toPlugin({ name }) instead. The stack carries the same collision-detection and hook-composition behavior and supports per-step { override: true } for intentional duplicates."
1125
+ );
1126
+ let head = null;
1127
+ for (const plugin of plugins) {
1128
+ head = { entry: plugin, override: false, prev: head };
1129
+ }
1130
+ const entries = resolveStack(head);
1131
+ return collapseStackEntries(entries, "composePlugins");
1132
+ }
1133
+ function createPluginStack() {
1134
+ logDeprecation(
1135
+ "createPluginStack() is deprecated. Compose with definePlugin and build with createSdk instead."
1136
+ );
1137
+ return buildPluginStack(null, "createPluginStack");
1138
+ }
1139
+ function buildPluginStack(head, callerLabel) {
1140
+ const stack = {
1141
+ use(plugin, options) {
1142
+ const next = {
1143
+ entry: plugin,
1144
+ override: options?.override === true,
1145
+ prev: head
1146
+ };
1147
+ return buildPluginStack(next, callerLabel);
1148
+ },
1149
+ toPlugin() {
1150
+ const entries = resolveStack(head);
1151
+ return collapseStackEntries(entries, callerLabel);
1152
+ },
1153
+ toSdk() {
1154
+ return wrapAccumulatorAsSdk(
1155
+ buildStackAccumulator(head, callerLabel)
1156
+ );
1157
+ }
1158
+ };
1159
+ return stack;
1160
+ }
1161
+
1162
+ // src/model/shared.ts
1163
+ function parseId(id) {
1164
+ const at = id.lastIndexOf("/");
1165
+ return at === -1 ? { name: id, namespace: void 0 } : { name: id.slice(at + 1), namespace: id.slice(0, at) };
1166
+ }
1167
+ function makeId(name, namespace, kind = "leaf") {
1168
+ validateName(name, kind);
1169
+ if (namespace !== void 0) validateNamespace(namespace);
1170
+ return namespace ? `${namespace}/${name}` : name;
1171
+ }
1172
+ var NAME_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
1173
+ var SEGMENT_RE = /^@?[A-Za-z0-9._-]+$/;
1174
+ function validateName(name, kind) {
1175
+ if (name === "") throw new Error("Plugin name must not be empty.");
1176
+ if (kind === "leaf") {
1177
+ if (!NAME_RE.test(name)) {
1178
+ throw new Error(
1179
+ `Plugin name "${name}" must be a valid JS identifier (it is the binding name).`
1180
+ );
1181
+ }
1182
+ } else if (!SEGMENT_RE.test(name)) {
1183
+ throw new Error(
1184
+ `Plugin name "${name}" must be package-like (letters, digits, ".", "_", "-", optional leading "@") with no "/".`
1185
+ );
1186
+ }
1187
+ }
1188
+ function validateNamespace(namespace) {
1189
+ if (namespace === "") throw new Error("Plugin namespace must not be empty.");
1190
+ for (const segment of namespace.split("/")) {
1191
+ if (!SEGMENT_RE.test(segment)) {
1192
+ throw new Error(
1193
+ `Plugin namespace "${namespace}" is invalid: each "/"-separated segment must be package-like (letters, digits, ".", "_", "-", optional leading "@").`
1194
+ );
1195
+ }
1196
+ }
1197
+ }
1198
+
1199
+ // src/model/types.ts
1200
+ var LEAF_META_KEYS = [
1201
+ "description",
1202
+ "categories",
1203
+ "type",
1204
+ "itemType",
1205
+ "returnType",
1206
+ "outputSchema",
1207
+ "inputParameters",
1208
+ "packages",
1209
+ "experimental",
1210
+ "confirm",
1211
+ "deprecation",
1212
+ "aliases",
1213
+ "supportsJsonOutput"
1214
+ ];
1215
+
1216
+ // src/model/define.ts
1217
+ function normalizeImports(deps) {
1218
+ if (!deps) return { plugins: [], bindings: [] };
1219
+ const seen = /* @__PURE__ */ new Map();
1220
+ const bindings = [];
1221
+ const add = (binding, id, optional) => {
1222
+ const priorId = seen.get(binding);
1223
+ if (priorId !== void 0 && priorId !== id) {
1224
+ throw new Error(
1225
+ `Import binding "${binding}" is declared twice. Two different plugins ("${priorId}" and "${id}") bind the same name; wrap one in selectExports to rename it.`
1226
+ );
1227
+ }
1228
+ if (priorId === void 0) {
1229
+ seen.set(binding, id);
1230
+ bindings.push(optional ? { binding, id, optional } : { binding, id });
1231
+ }
1232
+ };
1233
+ for (const plugin of deps) {
1234
+ if (plugin.pluginType === "aggregate") {
1235
+ for (const [binding, child] of Object.entries(plugin.exports)) {
1236
+ add(binding, child.id);
1237
+ }
1238
+ } else if (plugin.pluginType === "hook") {
1239
+ } else {
1240
+ add(plugin.name, plugin.id, plugin.optional);
1241
+ }
1242
+ }
1243
+ return { plugins: deps, bindings };
1244
+ }
1245
+ function collectLeafMeta(config) {
1246
+ let meta;
1247
+ for (const key2 of LEAF_META_KEYS) {
1248
+ if (config[key2] !== void 0) (meta ?? (meta = {}))[key2] = config[key2];
1249
+ }
1250
+ return meta;
1251
+ }
1252
+ function formatDynamicMemberName(path) {
1253
+ return path.map((seg) => typeof seg === "string" ? seg : `{${seg.param}}`).join(".");
1254
+ }
1255
+ function collectDynamicMembers(members) {
1256
+ if (!members?.length) return void 0;
1257
+ return members.map((member) => {
1258
+ const root = member.path[0];
1259
+ if (typeof root !== "string") {
1260
+ throw new Error(
1261
+ "defineProperty: a dynamicMember path must start with a literal segment (the owning binding), not a { param }."
1262
+ );
1263
+ }
1264
+ const leaf = collectLeafMeta(member) ?? {};
1265
+ return {
1266
+ name: formatDynamicMemberName(member.path),
1267
+ rootBinding: root,
1268
+ meta: member.inputSchema ? { ...leaf, inputSchema: member.inputSchema } : leaf
1269
+ };
1270
+ });
1271
+ }
1272
+ function defineMethod(config) {
1273
+ const deps = normalizeImports(config.imports);
1274
+ return {
1275
+ pluginType: "method",
1276
+ name: config.name,
1277
+ namespace: config.namespace,
1278
+ id: makeId(config.name, config.namespace),
1279
+ imports: deps.plugins,
1280
+ importBindings: deps.bindings,
1281
+ inputSchema: config.inputSchema,
1282
+ skipInputValidation: config.skipInputValidation,
1283
+ meta: collectLeafMeta(config),
1284
+ resolvers: config.resolvers,
1285
+ formatter: config.formatter,
1286
+ output: config.output,
1287
+ positional: config.positional,
1288
+ setup: config.setup,
1289
+ dispose: config.dispose,
1290
+ run: config.run
1291
+ };
1292
+ }
1293
+ function defineMethodOverride(config) {
1294
+ const { target, namespace, ...rest } = config;
1295
+ return {
1296
+ pluginType: "method-override",
1297
+ name: `override:${target}`,
1298
+ id: namespace ? `${namespace}/override:${target}` : `override:${target}`,
1299
+ target,
1300
+ imports: [],
1301
+ importBindings: [],
1302
+ meta: collectLeafMeta(rest)
1303
+ };
1304
+ }
1305
+ function defineResolver(config) {
1306
+ const deps = normalizeImports(config.imports);
1307
+ const base = { imports: deps.plugins, importBindings: deps.bindings };
1308
+ const gates = {
1309
+ requireParameters: config.requireParameters
1310
+ };
1311
+ switch (config.type) {
1312
+ case "static":
1313
+ return {
1314
+ ...base,
1315
+ ...gates,
1316
+ type: "static",
1317
+ inputType: config.inputType,
1318
+ placeholder: config.placeholder
1319
+ };
1320
+ case "constant":
1321
+ return { ...base, ...gates, type: "constant", value: config.value };
1322
+ case "info":
1323
+ return { ...base, type: "info", text: config.text ?? "" };
1324
+ case "object":
1325
+ return {
1326
+ ...base,
1327
+ ...gates,
1328
+ type: "object",
1329
+ properties: config.properties,
1330
+ definitions: config.definitions,
1331
+ getProperties: config.getProperties
1332
+ };
1333
+ case "array":
1334
+ return {
1335
+ ...base,
1336
+ ...gates,
1337
+ type: "array",
1338
+ items: config.items,
1339
+ minItems: config.minItems,
1340
+ maxItems: config.maxItems,
1341
+ itemValueType: config.itemValueType,
1342
+ definitions: config.definitions
1343
+ };
1344
+ default:
1345
+ return {
1346
+ ...base,
1347
+ ...gates,
1348
+ type: "dynamic",
1349
+ inputType: config.inputType,
1350
+ placeholder: config.placeholder,
1351
+ getContext: config.getContext,
1352
+ listItems: config.listItems,
1353
+ prompt: config.prompt,
1354
+ tryResolveWithoutPrompt: config.tryResolveWithoutPrompt,
1355
+ tryResolveFromSearch: config.tryResolveFromSearch
1356
+ };
1357
+ }
1358
+ }
1359
+ function defineFormatter(config) {
1360
+ const deps = normalizeImports(config.imports);
1361
+ return {
1362
+ imports: deps.plugins,
1363
+ importBindings: deps.bindings,
1364
+ getContext: config.getContext,
1365
+ format: config.format
1366
+ };
1367
+ }
1368
+ function declareMethod(config) {
1369
+ const { name, namespace } = parseId(config.id);
1370
+ const id = makeId(name, namespace);
1371
+ return {
1372
+ pluginType: "method",
1373
+ name,
1374
+ namespace,
1375
+ id,
1376
+ standIn: true,
1377
+ imports: [],
1378
+ importBindings: [],
1379
+ run: () => {
1380
+ throw new Error(
1381
+ `Plugin "${id}" is a stand-in (declareMethod) with no implementation. Register the real plugin under this id.`
1382
+ );
1383
+ }
1384
+ };
1385
+ }
1386
+ function defineProperty(config) {
1387
+ const deps = normalizeImports(config.imports);
1388
+ return {
1389
+ pluginType: "property",
1390
+ name: config.name,
1391
+ namespace: config.namespace,
1392
+ id: makeId(config.name, config.namespace),
1393
+ imports: deps.plugins,
1394
+ importBindings: deps.bindings,
1395
+ setup: config.setup,
1396
+ dispose: config.dispose,
1397
+ value: config.value,
1398
+ get: config.get,
1399
+ meta: collectLeafMeta(config),
1400
+ dynamicMembers: collectDynamicMembers(config.dynamicMembers)
1401
+ };
1402
+ }
1403
+ function declareProperty(config) {
1404
+ const { name, namespace } = parseId(config.id);
1405
+ return {
1406
+ pluginType: "property",
1407
+ name,
1408
+ namespace,
1409
+ id: makeId(name, namespace),
1410
+ standIn: true,
1411
+ imports: [],
1412
+ importBindings: []
1413
+ };
1414
+ }
1415
+ function declareOptionalProperty(config) {
1416
+ const { name, namespace } = parseId(config.id);
1417
+ return {
1418
+ pluginType: "property",
1419
+ name,
1420
+ namespace,
1421
+ id: makeId(name, namespace),
1422
+ standIn: true,
1423
+ optional: true,
1424
+ imports: [],
1425
+ importBindings: []
1426
+ // Requires nothing (phantom carrier `<never, never>`): a consumer that
1427
+ // imports it still passes `createSdk`'s completeness check unprovided. The
1428
+ // import binding is still typed `TValue | undefined` from the descriptor.
1429
+ };
1430
+ }
1431
+ function defineHook(config) {
1432
+ const deps = normalizeImports(config.imports);
1433
+ return {
1434
+ pluginType: "hook",
1435
+ name: config.name,
1436
+ namespace: config.namespace,
1437
+ id: makeId(config.name, config.namespace),
1438
+ imports: deps.plugins,
1439
+ importBindings: deps.bindings,
1440
+ setup: config.setup,
1441
+ dispose: config.dispose,
1442
+ wrap: config.wrap,
1443
+ observe: config.observe
1444
+ };
1445
+ }
1446
+ function declarePlugin(config) {
1447
+ const { name, namespace } = parseId(config.id);
1448
+ return {
1449
+ pluginType: "aggregate",
1450
+ name,
1451
+ namespace,
1452
+ id: makeId(name, namespace, "aggregate"),
1453
+ standIn: true,
1454
+ imports: [],
1455
+ importBindings: [],
1456
+ exports: normalizeExports(config.exports)
1457
+ };
1458
+ }
1459
+ function definePlugin(fnOrConfig) {
1460
+ if (typeof fnOrConfig === "function") {
1461
+ logDeprecation(
1462
+ "definePlugin(fn) (the function form) is deprecated. Author plugins with defineMethod/defineProperty/definePlugin({ ... }) instead."
1463
+ );
1464
+ return fnOrConfig;
1465
+ }
1466
+ const config = fnOrConfig;
1467
+ const deps = normalizeImports(config.imports);
1468
+ return {
1469
+ pluginType: "aggregate",
1470
+ name: config.name,
1471
+ namespace: config.namespace,
1472
+ id: makeId(config.name, config.namespace, "aggregate"),
1473
+ // A re-export synthetic (`selectExports` / `omitExports`) is flattened by
1474
+ // `normalizeExports` into bare bindings, which drops its own `imports:
1475
+ // [source]`. That edge is how `omitExports` keeps an omitted (unbound) leaf
1476
+ // materialized + addressable by id, so preserve every exported aggregate's
1477
+ // imports as extra reachability edges here (bindings unaffected).
1478
+ imports: [...deps.plugins, ...exportedAggregateImports(config.exports)],
1479
+ importBindings: deps.bindings,
1480
+ exports: normalizeExports(config.exports)
1481
+ };
1482
+ }
1483
+ function exportedAggregateImports(exports) {
1484
+ if (!exports) return [];
1485
+ const out = [];
1486
+ for (const element of exports) {
1487
+ if (element.pluginType === "aggregate") out.push(...element.imports);
1488
+ }
1489
+ return out;
1490
+ }
1491
+ function normalizeExports(exports) {
1492
+ if (!exports) return {};
1493
+ const out = {};
1494
+ const add = (binding, leaf) => {
1495
+ const existing = out[binding];
1496
+ if (existing && existing.id !== leaf.id) {
1497
+ throw new Error(
1498
+ `definePlugin: duplicate export binding "${binding}". Two different plugins ("${existing.id}" and "${leaf.id}") bind the same name; wrap one in selectExports to rename it.`
1499
+ );
1500
+ }
1501
+ out[binding] = leaf;
1502
+ };
1503
+ for (const element of exports) {
1504
+ if (element.pluginType === "aggregate") {
1505
+ for (const [binding, child] of Object.entries(element.exports)) {
1506
+ add(binding, child);
1507
+ }
1508
+ } else {
1509
+ add(element.name, element);
1510
+ }
1511
+ }
1512
+ return out;
1513
+ }
1514
+
1515
+ // src/model/exports.ts
1516
+ var selectSeq = 0;
1517
+ function selectExports(source, ...specs) {
1518
+ const selected = {};
1519
+ const pick = (binding, fromName) => {
1520
+ const child = source.exports[fromName];
1521
+ if (!child) {
1522
+ throw new Error(
1523
+ `selectExports: "${source.id}" has no export "${fromName}".`
1524
+ );
1525
+ }
1526
+ selected[binding] = child;
1527
+ };
1528
+ for (const spec of specs) {
1529
+ if (typeof spec === "string") {
1530
+ pick(spec, spec);
1531
+ } else {
1532
+ for (const [newName, fromName] of Object.entries(spec)) {
1533
+ pick(newName, fromName);
1534
+ }
1535
+ }
1536
+ }
1537
+ const id = `${source.id}#select:${selectSeq++}`;
1538
+ return {
1539
+ pluginType: "aggregate",
1540
+ name: makeId(`select`, source.name, "aggregate"),
1541
+ id,
1542
+ // Depend on the source so it is materialized; the selected bindings resolve
1543
+ // to the source's own leaves (kept identity).
1544
+ imports: [source],
1545
+ importBindings: [],
1546
+ exports: selected
1547
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1548
+ };
1549
+ }
1550
+ function omitExports(source, omit) {
1551
+ const omitSet = new Set(omit);
1552
+ for (const name of omit) {
1553
+ if (!(name in source.exports)) {
1554
+ throw new Error(`omitExports: "${source.id}" has no export "${name}".`);
1555
+ }
1556
+ }
1557
+ const kept = {};
1558
+ for (const [binding, child] of Object.entries(source.exports)) {
1559
+ if (!omitSet.has(binding)) kept[binding] = child;
1560
+ }
1561
+ return {
1562
+ pluginType: "aggregate",
1563
+ name: makeId(`omit`, source.name, "aggregate"),
1564
+ id: `${source.id}#omit:${selectSeq++}`,
1565
+ imports: [source],
1566
+ importBindings: [],
1567
+ exports: kept
1568
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1569
+ };
1570
+ }
1571
+
1572
+ // src/model/legacy.ts
1573
+ function fromFunctionPlugin(fn, config) {
1574
+ logDeprecation(
1575
+ "fromFunctionPlugin() is deprecated. Author plugins with defineMethod/definePlugin instead."
1576
+ );
1577
+ return {
1578
+ pluginType: "legacy",
1579
+ name: config.name,
1580
+ namespace: config.namespace,
1581
+ id: makeId(config.name, config.namespace, "aggregate"),
1582
+ imports: [],
1583
+ importBindings: [],
1584
+ run: fn
1585
+ };
1586
+ }
1587
+ function defineLegacyMerge(args) {
1588
+ logDeprecation(
1589
+ "defineLegacyMerge() is deprecated. Build directly with createSdk(root, { configuration }) instead."
1590
+ );
1591
+ return {
1592
+ pluginType: "legacy-merge",
1593
+ name: args.name,
1594
+ namespace: args.namespace,
1595
+ id: makeId(args.name, args.namespace, "aggregate"),
1596
+ legacy: fromFunctionPlugin(args.legacy, {
1597
+ name: args.name,
1598
+ namespace: args.namespace
1599
+ }),
1600
+ plugin: args.plugin
1601
+ };
1602
+ }
1603
+ function legacyGraphEntry(name, value, pluginMeta) {
1604
+ const { inputSchema, ...rest } = pluginMeta ?? {};
1605
+ const meta = Object.keys(rest).length ? rest : void 0;
1606
+ if (typeof value === "function") {
1607
+ return {
1608
+ pluginType: "method",
1609
+ name,
1610
+ value,
1611
+ chain: [],
1612
+ ...inputSchema ? { inputSchema } : {},
1613
+ ...meta ? { meta } : {}
1614
+ };
1615
+ }
1616
+ return { pluginType: "property", name, value, ...meta ? { meta } : {} };
1617
+ }
1618
+
1619
+ // src/model/builtins.ts
1620
+ import { z as z2 } from "zod";
1621
+
1622
+ // src/model/registry-support.ts
1623
+ function adaptLegacyFormatter(legacy, sdk) {
1624
+ const legacyFetch = legacy.fetch;
1625
+ return {
1626
+ getContext: legacyFetch ? async ({ items, input, context }) => {
1627
+ let ctx = context;
1628
+ for (const item of items) {
1629
+ ctx = await legacyFetch(sdk, input, item, ctx);
1630
+ }
1631
+ return ctx;
1632
+ } : void 0,
1633
+ format: ({ item, context }) => legacy.format(item, context)
1634
+ };
1635
+ }
1636
+ function normalizeFormatter(entry, sdk) {
1637
+ if (entry.pluginType !== "method") return void 0;
1638
+ if (entry.formatter) return entry.formatter;
1639
+ const legacy = entry.meta?.formatter;
1640
+ return legacy ? adaptLegacyFormatter(legacy, sdk) : void 0;
1641
+ }
1642
+ function normalizeBoundResolvers(entry) {
1643
+ if (entry.pluginType !== "method") return void 0;
1644
+ return entry.resolvers;
1645
+ }
1646
+ function methodPositional(entry) {
1647
+ if (entry.pluginType !== "method") return void 0;
1648
+ return entry.positional;
1649
+ }
1650
+ function pluginEntryMeta(entry) {
1651
+ if (entry.pluginType === "method" && entry.meta) {
1652
+ return entry.inputSchema ? { ...entry.meta, inputSchema: entry.inputSchema } : entry.meta;
1653
+ }
1654
+ if (entry.pluginType === "property" && entry.meta) return entry.meta;
1655
+ return void 0;
1656
+ }
1657
+ function foldDynamicMembers(entry, surfaceBindings, meta) {
1658
+ if (entry.pluginType !== "property" || !entry.dynamicMembers) return;
1659
+ for (const member of entry.dynamicMembers) {
1660
+ if (!surfaceBindings.has(member.rootBinding)) {
1661
+ throw new Error(
1662
+ `dynamicMember "${member.name}": its root "${member.rootBinding}" is not a surfaced member. A dynamic member's path must start with a real binding.`
1663
+ );
1664
+ }
1665
+ meta[member.name] = member.meta;
1666
+ }
1667
+ }
1668
+ function collectSurfaceProjection(context, formatterSdk) {
1669
+ const meta = {};
1670
+ const entries = {};
1671
+ for (const [binding, id] of Object.entries(context.surface)) {
1672
+ const entry = context.plugins[id];
1673
+ if (!entry || entry.pluginType === "aggregate") continue;
1674
+ entries[binding] = entry;
1675
+ const m = pluginEntryMeta(entry);
1676
+ if (m) meta[binding] = m;
1677
+ }
1678
+ const surfaceBindings = new Set(Object.keys(context.surface));
1679
+ for (const entry of Object.values(entries)) {
1680
+ foldDynamicMembers(entry, surfaceBindings, meta);
1681
+ }
1682
+ const formatters = {};
1683
+ const boundResolvers = {};
1684
+ const positional = {};
1685
+ for (const [binding, entry] of Object.entries(entries)) {
1686
+ const f = normalizeFormatter(entry, formatterSdk);
1687
+ if (f) formatters[binding] = f;
1688
+ const r = normalizeBoundResolvers(entry);
1689
+ if (r) boundResolvers[binding] = r;
1690
+ const p = methodPositional(entry);
1691
+ if (p) positional[binding] = p;
1692
+ }
1693
+ return { meta, formatters, boundResolvers, positional };
1694
+ }
1695
+ function buildSurfaceRegistry(context, packageFilter) {
1696
+ const surface = {};
1697
+ for (const [binding, id] of Object.entries(context.surface)) {
1698
+ const entry = context.plugins[id];
1699
+ if (!entry || entry.pluginType === "aggregate") continue;
1700
+ surface[binding] = entry.pluginType === "property" && entry.getValue ? entry.getValue() : entry.value;
1701
+ }
1702
+ return buildRegistry({
1703
+ sdk: surface,
1704
+ ...collectSurfaceProjection(context, surface),
1705
+ packageFilter
1706
+ });
1707
+ }
1708
+
1709
+ // src/model/builtins.ts
1710
+ var coreOptionsPluginRef = declareOptionalProperty({ id: CORE_OPTIONS_ID });
1711
+ var dangerousContextPlugin = {
1712
+ pluginType: "property",
1713
+ name: "context",
1714
+ namespace: "kitcore",
1715
+ id: "kitcore/context",
1716
+ imports: [],
1717
+ importBindings: [],
1718
+ privileged: true
1719
+ };
1720
+ var getRegistryPlugin = defineMethod({
1721
+ name: "getRegistry",
1722
+ namespace: "kitcore",
1723
+ imports: [dangerousContextPlugin],
1724
+ inputSchema: z2.object({ package: z2.string().optional() }).optional(),
1725
+ run: ({ imports, input }) => buildSurfaceRegistry(imports.context, input?.package)
1726
+ });
1727
+
1728
+ // src/model/materialize.ts
1729
+ var FRAMEWORK_CONFIGURATION_IDS = /* @__PURE__ */ new Set([
1730
+ CORE_OPTIONS_ID
1731
+ ]);
1732
+ function normalizeOutput(output) {
1733
+ if (output === void 0) return { type: "raw" };
1734
+ if (typeof output === "string") return { type: output };
1735
+ return output;
1736
+ }
1737
+ var CONTEXT = Symbol.for("kitcore.context");
1738
+ function getContext(sdk) {
1739
+ return sdk[CONTEXT];
1740
+ }
1741
+ function isResolverRef(value) {
1742
+ return "ref" in value;
1743
+ }
1744
+ function nestedResolvers(resolver) {
1745
+ const out = [];
1746
+ if (resolver.type === "object") {
1747
+ for (const field of Object.values(resolver.properties ?? {})) {
1748
+ if (!isResolverRef(field.resolver)) out.push(field.resolver);
1749
+ }
1750
+ out.push(...Object.values(resolver.definitions ?? {}));
1751
+ } else if (resolver.type === "array") {
1752
+ if (!isResolverRef(resolver.items)) out.push(resolver.items);
1753
+ out.push(...Object.values(resolver.definitions ?? {}));
1754
+ }
1755
+ return out;
1756
+ }
1757
+ function resolverImportEdges(resolver) {
1758
+ const out = [...resolver.imports];
1759
+ for (const child of nestedResolvers(resolver)) {
1760
+ out.push(...resolverImportEdges(child));
1761
+ }
1762
+ return out;
1763
+ }
1764
+ function methodAttachmentEdges(plugin) {
1765
+ const out = [];
1766
+ if (plugin.resolvers) {
1767
+ for (const resolver of Object.values(plugin.resolvers)) {
1768
+ out.push(...resolverImportEdges(resolver));
1769
+ }
1770
+ }
1771
+ if (plugin.formatter) out.push(...plugin.formatter.imports);
1772
+ return out;
1773
+ }
1774
+ function edgesOf(plugin) {
1775
+ if (plugin.pluginType === "aggregate") {
1776
+ return [...Object.values(plugin.exports), ...plugin.imports];
1777
+ }
1778
+ if (plugin.pluginType === "method") {
1779
+ return [...plugin.imports, ...methodAttachmentEdges(plugin)];
1780
+ }
1781
+ return plugin.imports;
1782
+ }
1783
+ function isStandIn(plugin) {
1784
+ return (plugin.pluginType === "method" || plugin.pluginType === "property" || plugin.pluginType === "aggregate") && plugin.standIn === true;
1785
+ }
1786
+ function topoOrder(descriptors) {
1787
+ const order = [];
1788
+ const visited = /* @__PURE__ */ new Set();
1789
+ const visit = (id) => {
1790
+ if (visited.has(id)) return;
1791
+ visited.add(id);
1792
+ const descriptor = descriptors.get(id);
1793
+ if (descriptor) for (const edge of edgesOf(descriptor)) visit(edge.id);
1794
+ order.push(id);
1795
+ };
1796
+ for (const id of descriptors.keys()) visit(id);
1797
+ return order;
1798
+ }
1799
+ function collectPlugins(root, materialized = /* @__PURE__ */ new Set(), configuration) {
1800
+ const byId = /* @__PURE__ */ new Map();
1801
+ const visit = (plugin) => {
1802
+ if (materialized.has(plugin.id)) return;
1803
+ const existing = byId.get(plugin.id);
1804
+ if (existing === plugin) return;
1805
+ if (existing) {
1806
+ const bothReal = !isStandIn(existing) && !isStandIn(plugin);
1807
+ if (bothReal) {
1808
+ throw new Error(
1809
+ `createSdk: duplicate plugin id "${plugin.id}". Two different plugins registered under the same id.`
1810
+ );
1811
+ }
1812
+ if (isStandIn(existing) && !isStandIn(plugin)) {
1813
+ byId.set(plugin.id, plugin);
1814
+ for (const edge of edgesOf(plugin)) visit(edge);
1815
+ }
1816
+ return;
1817
+ }
1818
+ byId.set(plugin.id, plugin);
1819
+ for (const edge of edgesOf(plugin)) visit(edge);
1820
+ };
1821
+ visit(root);
1822
+ if (configuration) {
1823
+ for (const [id, value] of Object.entries(configuration)) {
1824
+ const existing = byId.get(id);
1825
+ if (!existing) {
1826
+ if (FRAMEWORK_CONFIGURATION_IDS.has(id)) {
1827
+ const { name, namespace } = parseId(id);
1828
+ byId.set(id, {
1829
+ pluginType: "property",
1830
+ name,
1831
+ namespace,
1832
+ id,
1833
+ imports: [],
1834
+ importBindings: [],
1835
+ value
1836
+ });
1837
+ continue;
1838
+ }
1839
+ throw new Error(
1840
+ `createSdk: configuration id "${id}" matches no plugin in the graph. An injected value must satisfy a property stand-in reachable from the root.`
1841
+ );
1842
+ }
1843
+ if (existing.pluginType !== "property") {
1844
+ throw new Error(
1845
+ `createSdk: configuration id "${id}" resolves to a "${existing.pluginType}" plugin; only property values can be injected.`
1846
+ );
1847
+ }
1848
+ if (!isStandIn(existing)) {
1849
+ throw new Error(
1850
+ `createSdk: configuration id "${id}" collides with a registered provider. A property is either injected or provided by a plugin, not both.`
1851
+ );
1852
+ }
1853
+ byId.set(id, {
1854
+ pluginType: "property",
1855
+ name: existing.name,
1856
+ namespace: existing.namespace,
1857
+ id,
1858
+ imports: [],
1859
+ importBindings: [],
1860
+ value
1861
+ });
1862
+ }
1863
+ }
1864
+ for (const [id, plugin] of byId) {
1865
+ if (isStandIn(plugin)) {
1866
+ if ("optional" in plugin && plugin.optional) continue;
1867
+ throw new Error(
1868
+ `createSdk: missing dependency "${id}". A plugin depends on it (via a stand-in) but no implementation was registered.`
1869
+ );
1870
+ }
1871
+ }
1872
+ return byId;
1873
+ }
1874
+ function bindValue(target, key2, entry, callType = "surface") {
1875
+ if (entry.pluginType === "property" && entry.getValue) {
1876
+ Object.defineProperty(target, key2, {
1877
+ get: entry.getValue,
1878
+ enumerable: true,
1879
+ configurable: true
1880
+ });
1881
+ } else {
1882
+ const value = callType === "internal" && entry.pluginType === "method" ? entry.internalValue ?? entry.value : entry.value;
1883
+ Object.defineProperty(target, key2, {
1884
+ value,
1885
+ writable: true,
1886
+ enumerable: true,
1887
+ configurable: true
1888
+ });
1889
+ }
1890
+ }
1891
+ function buildSurface(context, ...maps) {
1892
+ const sdk = {};
1893
+ for (const map of maps) {
1894
+ Object.defineProperties(sdk, Object.getOwnPropertyDescriptors(map));
1895
+ }
1896
+ sdk.context = context;
1897
+ sdk[CONTEXT] = context;
1898
+ return sdk;
1899
+ }
1900
+ function buildImports(plugins, importBindings) {
1901
+ const imports = {};
1902
+ for (const { binding, id, optional } of importBindings) {
1903
+ const entry = plugins[id];
1904
+ if (!entry && optional) {
1905
+ Object.defineProperty(imports, binding, {
1906
+ value: void 0,
1907
+ writable: true,
1908
+ enumerable: true,
1909
+ configurable: true
1910
+ });
1911
+ continue;
1912
+ }
1913
+ bindValue(imports, binding, entry, "internal");
1914
+ }
1915
+ return imports;
1916
+ }
1917
+ function mirrorLegacyRootKeys(context, rootKeys, meta) {
1918
+ const exports = {};
1919
+ for (const [name, value] of Object.entries(rootKeys)) {
1920
+ context.plugins[name] = legacyGraphEntry(name, value, meta[name]);
1921
+ exports[name] = value;
1922
+ }
1923
+ return exports;
1924
+ }
1925
+ function recordExportSurface(context, exports) {
1926
+ for (const [binding, child] of Object.entries(exports)) {
1927
+ context.surface[binding] = child.id;
1928
+ }
1929
+ }
1930
+ function materialize(descriptors, context) {
1931
+ const states = /* @__PURE__ */ new Map();
1932
+ runLegacyPass(descriptors, context);
1933
+ buildMethodEntries(descriptors, context, states);
1934
+ buildEagerArtifacts(descriptors, context, states);
1935
+ bindAttachments(descriptors, context);
1936
+ resolveAggregates(descriptors, context);
1937
+ assembleMiddleware(descriptors, context, states);
1938
+ assembleHooks(descriptors, context, states);
1939
+ applyMethodOverrides(descriptors, context);
1940
+ return context.plugins;
1941
+ }
1942
+ function applyMethodOverride(context, override) {
1943
+ const entry = context.plugins[override.target];
1944
+ if (!entry) {
1945
+ throw new Error(
1946
+ `defineMethodOverride: no method "${override.target}" to override. Include the target method in the SDK build.`
1947
+ );
1948
+ }
1949
+ if (entry.pluginType !== "method") {
1950
+ throw new Error(
1951
+ `defineMethodOverride: "${override.target}" is a ${entry.pluginType}, not a method; only methods can be overridden.`
1952
+ );
1953
+ }
1954
+ entry.meta = { ...entry.meta, ...override.meta };
1955
+ }
1956
+ function applyMethodOverrides(descriptors, context) {
1957
+ for (const descriptor of descriptors.values()) {
1958
+ if (descriptor.pluginType !== "method-override") continue;
1959
+ applyMethodOverride(context, descriptor);
1960
+ }
1961
+ }
1962
+ function bindResolver(resolver, plugins) {
1963
+ switch (resolver.type) {
1964
+ case "static":
1965
+ return {
1966
+ type: "static",
1967
+ requireParameters: resolver.requireParameters,
1968
+ inputType: resolver.inputType,
1969
+ placeholder: resolver.placeholder
1970
+ };
1971
+ case "constant":
1972
+ return {
1973
+ type: "constant",
1974
+ value: resolver.value,
1975
+ requireParameters: resolver.requireParameters
1976
+ };
1977
+ case "info":
1978
+ return { type: "info", text: resolver.text };
1979
+ case "object": {
1980
+ const imports = buildImports(plugins, resolver.importBindings);
1981
+ const bound = {
1982
+ type: "object",
1983
+ requireParameters: resolver.requireParameters
1984
+ };
1985
+ if (resolver.properties)
1986
+ bound.properties = bindFields(resolver.properties, plugins);
1987
+ if (resolver.definitions)
1988
+ bound.definitions = bindDefinitions(resolver.definitions, plugins);
1989
+ const { getProperties } = resolver;
1990
+ if (getProperties)
1991
+ bound.getProperties = ({ input }) => getProperties({ imports, input });
1992
+ return bound;
1993
+ }
1994
+ case "array": {
1995
+ const bound = {
1996
+ type: "array",
1997
+ requireParameters: resolver.requireParameters,
1998
+ minItems: resolver.minItems,
1999
+ maxItems: resolver.maxItems,
2000
+ itemValueType: resolver.itemValueType,
2001
+ items: isResolverRef(resolver.items) ? resolver.items : bindResolver(resolver.items, plugins)
2002
+ };
2003
+ if (resolver.definitions)
2004
+ bound.definitions = bindDefinitions(resolver.definitions, plugins);
2005
+ return bound;
2006
+ }
2007
+ case "dynamic": {
2008
+ const imports = buildImports(plugins, resolver.importBindings);
2009
+ const {
2010
+ getContext: getContext2,
2011
+ listItems,
2012
+ tryResolveWithoutPrompt,
2013
+ tryResolveFromSearch
2014
+ } = resolver;
2015
+ const bound = {
2016
+ type: "dynamic",
2017
+ requireParameters: resolver.requireParameters,
2018
+ inputType: resolver.inputType,
2019
+ placeholder: resolver.placeholder,
2020
+ prompt: resolver.prompt,
2021
+ listItems: ({ input, context, search, cursor }) => listItems({ imports, input, context, search, cursor })
2022
+ };
2023
+ if (getContext2)
2024
+ bound.getContext = ({ input }) => getContext2({ imports, input });
2025
+ if (tryResolveWithoutPrompt) {
2026
+ bound.tryResolveWithoutPrompt = ({ input }) => tryResolveWithoutPrompt({ imports, input });
2027
+ }
2028
+ if (tryResolveFromSearch) {
2029
+ bound.tryResolveFromSearch = ({ input, search }) => tryResolveFromSearch({ imports, input, search });
2030
+ }
2031
+ return bound;
2032
+ }
2033
+ default: {
2034
+ const unhandled = resolver;
2035
+ throw new Error(
2036
+ `unhandled resolver kind: ${unhandled.type}`
2037
+ );
2038
+ }
2039
+ }
2040
+ }
2041
+ function bindFields(fields, plugins) {
2042
+ const out = {};
2043
+ for (const [key2, field] of Object.entries(fields)) {
2044
+ out[key2] = {
2045
+ ...field,
2046
+ resolver: isResolverRef(field.resolver) ? field.resolver : bindResolver(field.resolver, plugins)
2047
+ };
2048
+ }
2049
+ return out;
2050
+ }
2051
+ function bindDefinitions(definitions, plugins) {
2052
+ const out = {};
2053
+ for (const [key2, def] of Object.entries(definitions)) {
2054
+ out[key2] = bindResolver(def, plugins);
2055
+ }
2056
+ return out;
2057
+ }
2058
+ function bindFormatter(formatter, plugins) {
2059
+ const imports = buildImports(plugins, formatter.importBindings);
2060
+ const bound = { format: formatter.format };
2061
+ const { getContext: getContext2 } = formatter;
2062
+ if (getContext2)
2063
+ bound.getContext = ({ items, input, context }) => getContext2({ imports, items, input, context });
2064
+ return bound;
2065
+ }
2066
+ function bindAttachments(descriptors, context) {
2067
+ const plugins = context.plugins;
2068
+ for (const [id, descriptor] of descriptors) {
2069
+ if (descriptor.pluginType !== "method") continue;
2070
+ const entry = plugins[id];
2071
+ if (!entry || entry.pluginType !== "method") continue;
2072
+ if (descriptor.resolvers) {
2073
+ const bound = {};
2074
+ for (const [param, resolver] of Object.entries(descriptor.resolvers)) {
2075
+ bound[param] = bindResolver(resolver, plugins);
2076
+ }
2077
+ entry.resolvers = bound;
2078
+ }
2079
+ if (descriptor.formatter) {
2080
+ entry.formatter = bindFormatter(descriptor.formatter, plugins);
2081
+ }
2082
+ }
2083
+ }
2084
+ function runLegacyPass(descriptors, context) {
2085
+ const plugins = context.plugins;
2086
+ const compatView = new Proxy(
2087
+ {},
2088
+ {
2089
+ get: (_target, prop) => {
2090
+ if (prop === "context") return context;
2091
+ const entry = plugins[prop];
2092
+ return entry?.value;
2093
+ }
2094
+ }
2095
+ );
2096
+ for (const id of topoOrder(descriptors)) {
2097
+ const descriptor = descriptors.get(id);
2098
+ if (!descriptor || descriptor.pluginType !== "legacy") continue;
2099
+ const { rootKeys, meta, hooks, contextRest } = splitPluginContribution(
2100
+ descriptor.run(compatView)
2101
+ );
2102
+ Object.assign(context.meta, meta);
2103
+ Object.assign(context, contextRest);
2104
+ context.hooks = buildHooks(context.hooks, hooks);
2105
+ const exports = mirrorLegacyRootKeys(context, rootKeys, meta);
2106
+ if (!("getRegistry" in exports)) {
2107
+ let getRegistry2 = function(options) {
2108
+ const sdk = this ?? exports;
2109
+ const projection = collectSurfaceProjection(context, sdk);
2110
+ Object.assign(projection.meta, context.meta);
2111
+ return buildRegistry({
2112
+ sdk,
2113
+ ...projection,
2114
+ packageFilter: options?.package
2115
+ });
2116
+ };
2117
+ var getRegistry = getRegistry2;
2118
+ exports.getRegistry = getRegistry2;
2119
+ plugins.getRegistry = {
2120
+ pluginType: "method",
2121
+ name: "getRegistry",
2122
+ value: getRegistry2,
2123
+ chain: []
2124
+ };
2125
+ }
2126
+ plugins[id] = { pluginType: "aggregate", name: descriptor.name, exports };
2127
+ }
2128
+ }
2129
+ function buildMethodEntries(descriptors, context, states) {
2130
+ const plugins = context.plugins;
2131
+ for (const [id, descriptor] of descriptors) {
2132
+ if (descriptor.pluginType !== "method") continue;
2133
+ const out = normalizeOutput(descriptor.output);
2134
+ const entry = {
2135
+ pluginType: "method",
2136
+ name: descriptor.name,
2137
+ chain: [],
2138
+ inputSchema: descriptor.inputSchema,
2139
+ // Derive the presentation type from the output mode when the author did
2140
+ // not set one; an explicit meta.type (e.g. "create") still wins.
2141
+ meta: out.type === "raw" || descriptor.meta?.type ? descriptor.meta : { ...descriptor.meta, type: out.type },
2142
+ output: out,
2143
+ // Replaced below; never called.
2144
+ value: () => void 0
2145
+ };
2146
+ const callRun = (input) => descriptor.run({
2147
+ imports: buildImports(plugins, descriptor.importBindings),
2148
+ state: states.get(id),
2149
+ input
2150
+ });
2151
+ const fold = (coreFn) => (input) => {
2152
+ let next = coreFn;
2153
+ for (const wrap of entry.chain) {
2154
+ const inner = next;
2155
+ next = (i) => wrap.run({
2156
+ imports: buildImports(plugins, wrap.owner.importBindings),
2157
+ next: inner,
2158
+ input: i,
2159
+ // Overwritten by the chain item's own closure with the owning
2160
+ // hook's setup state.
2161
+ state: void 0
2162
+ });
2163
+ }
2164
+ return next(input);
2165
+ };
2166
+ const sdk = { context };
2167
+ if (out.type === "list") {
2168
+ entry.value = createPaginatedFunction(
2169
+ fold(callRun),
2170
+ {
2171
+ sdk,
2172
+ schema: descriptor.inputSchema,
2173
+ name: descriptor.name,
2174
+ defaultPageSize: out.defaultPageSize,
2175
+ adaptPage: out.adaptPage,
2176
+ getDeprecation: () => entry.meta?.deprecation
2177
+ }
2178
+ );
2179
+ } else if (out.type === "item") {
2180
+ const itemCore = async (input) => ({
2181
+ data: await callRun(input)
2182
+ });
2183
+ entry.value = createFunction(
2184
+ fold(itemCore),
2185
+ {
2186
+ sdk,
2187
+ schema: descriptor.inputSchema,
2188
+ name: descriptor.name,
2189
+ getDeprecation: () => entry.meta?.deprecation
2190
+ }
2191
+ );
2192
+ } else {
2193
+ entry.value = createRawFunction(
2194
+ (input) => fold(callRun)(input),
2195
+ {
2196
+ sdk,
2197
+ name: descriptor.name,
2198
+ schema: descriptor.skipInputValidation ? void 0 : descriptor.inputSchema,
2199
+ positional: descriptor.positional,
2200
+ // The boundary reads the deprecation LIVE off the entry, so a
2201
+ // deprecation merged after build (defineMethodOverride, addPlugin)
2202
+ // fires too.
2203
+ getDeprecation: () => entry.meta?.deprecation
2204
+ }
2205
+ );
2206
+ }
2207
+ const canonicalValue = entry.value;
2208
+ if (descriptor.positional) {
2209
+ const names = descriptor.positional;
2210
+ const pack = (args) => {
2211
+ const packed = {};
2212
+ names.forEach((name, i) => {
2213
+ if (i < args.length) packed[name] = args[i];
2214
+ });
2215
+ return packed;
2216
+ };
2217
+ entry.value = (...args) => canonicalValue(pack(args));
2218
+ entry.internalValue = (...args) => canonicalValue(pack(args), INTERNAL_CALL);
2219
+ entry.positional = names;
2220
+ } else {
2221
+ entry.internalValue = (input) => canonicalValue(input, INTERNAL_CALL);
2222
+ }
2223
+ plugins[id] = entry;
2224
+ }
2225
+ }
2226
+ function buildEagerArtifacts(descriptors, context, states) {
2227
+ const plugins = context.plugins;
2228
+ const built = /* @__PURE__ */ new Set();
2229
+ const building = /* @__PURE__ */ new Set();
2230
+ const ensureBuilt = (id) => {
2231
+ if (built.has(id)) return;
2232
+ const descriptor = descriptors.get(id);
2233
+ if (!descriptor || descriptor.pluginType === "aggregate" || descriptor.pluginType === "legacy" || descriptor.pluginType === "method-override" || isStandIn(descriptor)) {
2234
+ built.add(id);
2235
+ return;
2236
+ }
2237
+ if (building.has(id)) {
2238
+ throw new Error(`createSdk: dependency cycle at "${id}".`);
2239
+ }
2240
+ building.add(id);
2241
+ for (const { id: depId } of descriptor.importBindings) ensureBuilt(depId);
2242
+ const recordDisposer = () => {
2243
+ const dispose = descriptor.dispose;
2244
+ if (!dispose) return;
2245
+ context.disposers?.push({
2246
+ id,
2247
+ dispose: (input) => dispose({
2248
+ imports: buildImports(plugins, descriptor.importBindings),
2249
+ state: states.get(id),
2250
+ input
2251
+ })
2252
+ });
2253
+ };
2254
+ if (descriptor.pluginType === "hook") {
2255
+ states.set(
2256
+ id,
2257
+ descriptor.setup ? descriptor.setup({
2258
+ imports: buildImports(plugins, descriptor.importBindings)
2259
+ }) : void 0
2260
+ );
2261
+ recordDisposer();
2262
+ building.delete(id);
2263
+ built.add(id);
2264
+ return;
2265
+ }
2266
+ if (descriptor.pluginType === "method") {
2267
+ states.set(
2268
+ id,
2269
+ descriptor.setup ? descriptor.setup({
2270
+ imports: buildImports(plugins, descriptor.importBindings)
2271
+ }) : void 0
2272
+ );
2273
+ } else {
2274
+ states.set(
2275
+ id,
2276
+ descriptor.setup ? descriptor.setup({
2277
+ imports: buildImports(plugins, descriptor.importBindings)
2278
+ }) : void 0
2279
+ );
2280
+ if (descriptor.privileged) {
2281
+ plugins[id] = {
2282
+ pluginType: "property",
2283
+ name: descriptor.name,
2284
+ value: context,
2285
+ meta: descriptor.meta,
2286
+ dynamicMembers: descriptor.dynamicMembers
2287
+ };
2288
+ } else if (descriptor.get) {
2289
+ const get = descriptor.get;
2290
+ const importBindings = descriptor.importBindings;
2291
+ plugins[id] = {
2292
+ pluginType: "property",
2293
+ name: descriptor.name,
2294
+ getValue: () => get({
2295
+ imports: buildImports(plugins, importBindings),
2296
+ state: states.get(id)
2297
+ }),
2298
+ meta: descriptor.meta,
2299
+ dynamicMembers: descriptor.dynamicMembers
2300
+ };
2301
+ } else {
2302
+ plugins[id] = {
2303
+ pluginType: "property",
2304
+ name: descriptor.name,
2305
+ value: descriptor.value,
2306
+ meta: descriptor.meta,
2307
+ dynamicMembers: descriptor.dynamicMembers
2308
+ };
2309
+ }
2310
+ }
2311
+ recordDisposer();
2312
+ building.delete(id);
2313
+ built.add(id);
2314
+ };
2315
+ for (const id of descriptors.keys()) ensureBuilt(id);
2316
+ }
2317
+ function resolvePlugin(sdk, ref) {
2318
+ const entry = getContext(sdk).plugins[ref.id];
2319
+ if (!entry) {
2320
+ if (ref.optional) {
2321
+ return void 0;
2322
+ }
2323
+ throw new Error(
2324
+ `resolvePlugin: plugin "${ref.id}" is not materialized on the SDK.`
2325
+ );
2326
+ }
2327
+ if (entry.pluginType === "property" && entry.getValue) {
2328
+ return entry.getValue();
2329
+ }
2330
+ if (entry.pluginType === "method" && entry.internalValue) {
2331
+ return entry.internalValue;
2332
+ }
2333
+ return entry.value;
2334
+ }
2335
+ var CoreDisposeError = class extends Error {
2336
+ constructor(errors) {
2337
+ super(`disposeSdk: ${errors.length} dispose callback(s) failed.`);
2338
+ this.name = "CoreDisposeError";
2339
+ this.errors = errors;
2340
+ Object.setPrototypeOf(this, new.target.prototype);
2341
+ }
2342
+ };
2343
+ function disposeSdk(sdk, input) {
2344
+ const context = getContext(sdk);
2345
+ if (context.disposed) return context.disposed;
2346
+ const disposers = context.disposers ?? [];
2347
+ context.disposed = (async () => {
2348
+ const errors = [];
2349
+ for (let i = disposers.length - 1; i >= 0; i--) {
2350
+ try {
2351
+ await disposers[i].dispose(input);
2352
+ } catch (error) {
2353
+ errors.push(error);
2354
+ }
2355
+ }
2356
+ if (errors.length > 0) throw new CoreDisposeError(errors);
2357
+ })();
2358
+ return context.disposed;
2359
+ }
2360
+ function resolveAggregates(descriptors, context) {
2361
+ const plugins = context.plugins;
2362
+ for (const [id, descriptor] of descriptors) {
2363
+ if (descriptor.pluginType !== "aggregate") continue;
2364
+ const exports = {};
2365
+ for (const [binding, child] of Object.entries(descriptor.exports)) {
2366
+ bindValue(exports, binding, plugins[child.id]);
2367
+ }
2368
+ plugins[id] = { pluginType: "aggregate", name: descriptor.name, exports };
2369
+ }
2370
+ }
2371
+ function assembleMiddleware(descriptors, context, states) {
2372
+ const plugins = context.plugins;
2373
+ for (const id of topoOrder(descriptors)) {
2374
+ const descriptor = descriptors.get(id);
2375
+ if (!descriptor || descriptor.pluginType !== "hook" || !descriptor.wrap) {
2376
+ continue;
2377
+ }
2378
+ for (const [targetBinding, fn] of Object.entries(descriptor.wrap)) {
2379
+ const edge = descriptor.importBindings.find(
2380
+ (b) => b.binding === targetBinding
2381
+ );
2382
+ if (!edge) {
2383
+ throw new Error(
2384
+ `createSdk: wrap target "${targetBinding}" in hook "${id}" is not a direct dependency. A wrap target must be a declared import of the wrapping hook.`
2385
+ );
2386
+ }
2387
+ const target = plugins[edge.id];
2388
+ if (!target || target.pluginType !== "method") {
2389
+ throw new Error(
2390
+ `createSdk: wrap target "${targetBinding}" in hook "${id}" does not resolve to a method.`
2391
+ );
2392
+ }
2393
+ if (target.output?.type === "list") {
2394
+ throw new Error(
2395
+ `createSdk: wrap target "${targetBinding}" in hook "${id}" resolves to a list-output method, which does not support wrapping yet.`
2396
+ );
2397
+ }
2398
+ target.chain.push({
2399
+ run: (bag) => fn({ ...bag, state: states.get(id) }),
2400
+ owner: descriptor
2401
+ });
2402
+ }
2403
+ }
2404
+ }
2405
+ function assembleHooks(descriptors, context, states) {
2406
+ const plugins = context.plugins;
2407
+ for (const id of topoOrder(descriptors)) {
2408
+ const descriptor = descriptors.get(id);
2409
+ if (!descriptor || descriptor.pluginType !== "hook" || !descriptor.observe) {
2410
+ continue;
2411
+ }
2412
+ const { observe } = descriptor;
2413
+ const imports = buildImports(plugins, descriptor.importBindings);
2414
+ const state = states.get(id);
2415
+ const contributed = {};
2416
+ if (observe.onMethodStart) {
2417
+ const onStart = observe.onMethodStart;
2418
+ contributed.onMethodStart = (input) => {
2419
+ runIsolatedObserver(() => onStart({ imports, input, state }));
2420
+ };
2421
+ }
2422
+ if (observe.onMethodEnd) {
2423
+ const onEnd = observe.onMethodEnd;
2424
+ contributed.onMethodEnd = (input) => {
2425
+ runIsolatedObserver(() => onEnd({ imports, input, state }));
2426
+ };
2427
+ }
2428
+ context.hooks = buildHooks(context.hooks, contributed);
2429
+ }
2430
+ }
2431
+ function createSdk(root, options) {
2432
+ const context = {
2433
+ plugins: {},
2434
+ meta: {},
2435
+ hooks: {},
2436
+ surface: {},
2437
+ disposers: []
2438
+ };
2439
+ if (root.pluginType === "legacy-merge") {
2440
+ const { legacy, plugin } = root;
2441
+ const collectRoot = {
2442
+ pluginType: "aggregate",
2443
+ name: root.name,
2444
+ id: `${root.id}:merge`,
2445
+ imports: [legacy, plugin],
2446
+ importBindings: [],
2447
+ exports: {}
2448
+ };
2449
+ const plugins2 = materialize(
2450
+ collectPlugins(collectRoot, void 0, options?.configuration),
2451
+ context
2452
+ );
2453
+ const legacyExports = plugins2[legacy.id].exports;
2454
+ let pluginSurface;
2455
+ if (plugin.pluginType === "aggregate") {
2456
+ pluginSurface = plugins2[plugin.id].exports;
2457
+ } else {
2458
+ pluginSurface = {};
2459
+ bindValue(pluginSurface, plugin.name, plugins2[plugin.id]);
2460
+ }
2461
+ for (const key2 of Object.keys(legacyExports)) context.surface[key2] = key2;
2462
+ if (plugin.pluginType === "aggregate") {
2463
+ recordExportSurface(context, plugin.exports);
2464
+ } else {
2465
+ context.surface[plugin.name] = plugin.id;
2466
+ }
2467
+ return buildSurface(context, legacyExports, pluginSurface);
2468
+ }
2469
+ const plugins = materialize(
2470
+ collectPlugins(root, void 0, options?.configuration),
2471
+ context
2472
+ );
2473
+ if (root.pluginType === "method" || root.pluginType === "property") {
2474
+ context.surface[root.name] = root.id;
2475
+ const sdk = buildSurface(context);
2476
+ bindValue(sdk, root.name, plugins[root.id]);
2477
+ return sdk;
2478
+ }
2479
+ if (root.pluginType === "aggregate")
2480
+ recordExportSurface(context, root.exports);
2481
+ return buildSurface(context, plugins[root.id].exports);
2482
+ }
2483
+ function addModelPlugin(sdk, plugin, options = {}) {
2484
+ const override = options.override === true;
2485
+ const context = getContext(sdk);
2486
+ const surfaceKeys = plugin.pluginType === "aggregate" ? Object.keys(plugin.exports) : plugin.pluginType === "hook" ? [] : [plugin.name];
2487
+ checkRootKeyCollisions(sdk, surfaceKeys, override, "addPlugin");
2488
+ const materialized = new Set(Object.keys(context.plugins));
2489
+ if (override && materialized.has(plugin.id)) {
2490
+ throw new Error(
2491
+ `addPlugin: cannot override already-materialized plugin "${plugin.id}" on the incremental path. Rebuild the SDK with the replacement via createSdk.`
2492
+ );
2493
+ }
2494
+ materialize(collectPlugins(plugin, materialized), context);
2495
+ if (plugin.pluginType === "hook") return;
2496
+ const entry = context.plugins[plugin.id];
2497
+ if (entry.pluginType === "aggregate") {
2498
+ Object.defineProperties(
2499
+ sdk,
2500
+ Object.getOwnPropertyDescriptors(entry.exports)
2501
+ );
2502
+ for (const [binding, child] of Object.entries(
2503
+ plugin.exports
2504
+ )) {
2505
+ context.surface[binding] = child.id;
2506
+ }
2507
+ } else {
2508
+ bindValue(sdk, plugin.name, entry);
2509
+ context.surface[plugin.name] = plugin.id;
2510
+ }
2511
+ }
2512
+ function addPlugin(sdk, plugin, options) {
2513
+ if (typeof plugin === "function") {
2514
+ const record = sdk;
2515
+ const contribution = applyPluginToSdk(
2516
+ record,
2517
+ plugin,
2518
+ options ?? {}
2519
+ );
2520
+ const context = record[CONTEXT];
2521
+ if (context) {
2522
+ mirrorLegacyRootKeys(context, contribution.rootKeys, contribution.meta);
2523
+ for (const name of Object.keys(contribution.rootKeys)) {
2524
+ context.surface[name] = name;
2525
+ }
2526
+ }
2527
+ return;
2528
+ }
2529
+ if (plugin.pluginType === "method-override") {
2530
+ applyMethodOverride(
2531
+ getContext(sdk),
2532
+ plugin
2533
+ );
2534
+ return;
2535
+ }
2536
+ addModelPlugin(
2537
+ sdk,
2538
+ plugin,
2539
+ options ?? {}
2540
+ );
2541
+ }
2542
+
2543
+ // src/model/resolution/controller.ts
2544
+ import { z as z4 } from "zod";
2545
+
2546
+ // src/types/signals.ts
2547
+ var CORE_SIGNAL_SYMBOL = Symbol.for("kitcore.signal");
2548
+ var CoreSignal = class extends Error {
2549
+ constructor(message) {
2550
+ super(message);
2551
+ Object.setPrototypeOf(this, new.target.prototype);
2552
+ Object.defineProperty(this, CORE_SIGNAL_SYMBOL, {
2553
+ value: true,
2554
+ enumerable: false,
2555
+ configurable: true,
2556
+ writable: false
2557
+ });
2558
+ }
2559
+ };
2560
+ function isCoreSignal(value) {
2561
+ return Boolean(
2562
+ value && typeof value === "object" && value[CORE_SIGNAL_SYMBOL] === true
2563
+ );
2564
+ }
2565
+ var CoreCancelledSignal = class extends CoreSignal {
2566
+ constructor(message = "resolution cancelled") {
2567
+ super(message);
2568
+ this.name = "CoreCancelledSignal";
2569
+ this.code = "CANCELLED";
2570
+ }
2571
+ };
2572
+
2573
+ // src/model/resolution/plan.ts
2574
+ import { z as z3 } from "zod";
2575
+ function unwrap(schema) {
2576
+ let inner = schema;
2577
+ let required = true;
2578
+ for (; ; ) {
2579
+ if (inner instanceof z3.ZodOptional) {
2580
+ required = false;
2581
+ inner = inner._zod.def.innerType;
2582
+ } else if (inner instanceof z3.ZodDefault) {
2583
+ required = false;
2584
+ inner = inner._zod.def.innerType;
2585
+ } else if (inner instanceof z3.ZodNullable) {
2586
+ inner = inner._zod.def.innerType;
2587
+ } else {
2588
+ break;
2589
+ }
2590
+ }
2591
+ return { inner, required };
2592
+ }
2593
+ function valueTypeOf(inner) {
2594
+ if (inner instanceof z3.ZodString) return "string";
2595
+ if (inner instanceof z3.ZodNumber) return "number";
2596
+ if (inner instanceof z3.ZodBoolean) return "boolean";
2597
+ if (inner instanceof z3.ZodEnum) return "string";
2598
+ if (inner instanceof z3.ZodArray) return "array";
2599
+ if (inner instanceof z3.ZodObject) return "object";
2600
+ return void 0;
2601
+ }
2602
+ function staticChoicesOf(inner) {
2603
+ if (inner instanceof z3.ZodEnum) {
2604
+ const values = inner.options;
2605
+ return values.map((value) => ({ label: value, value }));
2606
+ }
2607
+ return void 0;
2608
+ }
2609
+ function objectShape(schema) {
2610
+ const { inner } = schema ? unwrap(schema) : { inner: void 0 };
2611
+ if (inner instanceof z3.ZodObject) {
2612
+ return inner.shape;
2613
+ }
2614
+ return void 0;
2615
+ }
2616
+ function topoOrder2(specs) {
2617
+ const byName = new Map(specs.map((s) => [s.name, s]));
2618
+ const placed = /* @__PURE__ */ new Set();
2619
+ const ordered = [];
2620
+ const isReady = (spec) => spec.requires.every((r) => !byName.has(r) || placed.has(r));
2621
+ for (; ; ) {
2622
+ const next = specs.find((s) => !placed.has(s.name) && isReady(s));
2623
+ if (!next) break;
2624
+ ordered.push(next);
2625
+ placed.add(next.name);
2626
+ }
2627
+ for (const spec of specs) if (!placed.has(spec.name)) ordered.push(spec);
2628
+ return ordered;
2629
+ }
2630
+ function planParameters(entry) {
2631
+ const shape = objectShape(entry.inputSchema);
2632
+ const resolvers = entry.boundResolvers ?? {};
2633
+ const names = shape ? [
2634
+ ...Object.keys(shape),
2635
+ ...Object.keys(resolvers).filter(
2636
+ (name) => !(name in shape) && resolvers[name].type === "constant"
2637
+ )
2638
+ ] : Object.keys(resolvers);
2639
+ const specs = names.map((name) => {
2640
+ const field = shape?.[name];
2641
+ const { inner, required } = field ? unwrap(field) : { inner: void 0, required: false };
2642
+ const resolver = resolvers[name];
2643
+ return {
2644
+ name,
2645
+ required,
2646
+ valueType: inner ? valueTypeOf(inner) : void 0,
2647
+ staticChoices: inner ? staticChoicesOf(inner) : void 0,
2648
+ resolver,
2649
+ requires: resolver?.requireParameters ?? []
2650
+ };
2651
+ });
2652
+ const declared = shape ? specs.filter((s) => s.name in shape) : specs;
2653
+ const scan = [
2654
+ ...shape ? specs.filter((s) => !(s.name in shape)) : [],
2655
+ ...declared.filter((s) => s.required),
2656
+ ...declared.filter((s) => !s.required)
2657
+ ];
2658
+ return { parameters: topoOrder2(scan) };
2659
+ }
2660
+
2661
+ // src/model/resolution/engine.ts
2662
+ function getAtPath(root, path) {
2663
+ let node = root;
2664
+ for (const seg of path) {
2665
+ if (node == null || typeof node !== "object") return void 0;
2666
+ node = node[seg];
2667
+ }
2668
+ return node;
2669
+ }
2670
+ function setAtPath(root, path, value) {
2671
+ let node = root;
2672
+ for (let i = 0; i < path.length - 1; i++) {
2673
+ const seg = path[i];
2674
+ if (node[seg] == null || typeof node[seg] !== "object") node[seg] = {};
2675
+ node = node[seg];
2676
+ }
2677
+ node[path[path.length - 1]] = value;
2678
+ }
2679
+ var key = (path) => path.join(".");
2680
+ function isSettled(state, path) {
2681
+ return state.settled.includes(key(path));
2682
+ }
2683
+ function remember(state, k) {
2684
+ if (!state.settled.includes(k)) state.settled.push(k);
2685
+ }
2686
+ function settle(state, path) {
2687
+ remember(state, key(path));
2688
+ }
2689
+ function clone(state) {
2690
+ return JSON.parse(JSON.stringify(state));
2691
+ }
2692
+ function coerce(leaf, raw) {
2693
+ if (typeof raw !== "string") return raw;
2694
+ if (leaf.valueType === "number") {
2695
+ const n = Number(raw);
2696
+ return raw.trim() !== "" && !Number.isNaN(n) ? n : raw;
2697
+ }
2698
+ if (leaf.valueType === "boolean") {
2699
+ if (raw === "true") return true;
2700
+ if (raw === "false") return false;
2701
+ }
2702
+ return raw;
2703
+ }
2704
+ async function validationError(leaf, value, state) {
2705
+ if (leaf.resolver?.type !== "dynamic") return null;
2706
+ const context = await resolveContext(leaf, state.resolved);
2707
+ const config = leaf.resolver.prompt?.({
2708
+ items: state.listing?.items ?? [],
2709
+ input: mergeInput(state.resolved, leaf.extraInput),
2710
+ context
2711
+ });
2712
+ if (!config?.validate) return null;
2713
+ const verdict = config.validate(value);
2714
+ if (verdict === true) return null;
2715
+ return typeof verdict === "string" ? verdict : `${leaf.name}: invalid value`;
2716
+ }
2717
+ function isRef(r) {
2718
+ return typeof r === "object" && r !== null && "ref" in r;
2719
+ }
2720
+ function toLeaf(name, field, definitions) {
2721
+ let resolver;
2722
+ let extraInput;
2723
+ if (isRef(field.resolver)) {
2724
+ resolver = definitions?.[field.resolver.ref];
2725
+ extraInput = field.resolver.input;
2726
+ } else {
2727
+ resolver = field.resolver;
2728
+ }
2729
+ return {
2730
+ name,
2731
+ required: field.required ?? false,
2732
+ label: field.label,
2733
+ resolver,
2734
+ extraInput,
2735
+ // Carry the field's value type so nested answers coerce (number/boolean)
2736
+ // the same way top-level params do. Without this a nested `z.number()`
2737
+ // field's typed answer stays a string and fails final validation.
2738
+ valueType: field.valueType,
2739
+ requires: resolver?.requireParameters ?? []
2740
+ };
2741
+ }
2742
+ async function objectChildren(resolver, input) {
2743
+ if (resolver.properties) {
2744
+ return Object.entries(resolver.properties).map(
2745
+ ([name, field]) => toLeaf(name, field, resolver.definitions)
2746
+ );
2747
+ }
2748
+ if (!resolver.getProperties) return [];
2749
+ const fields = await resolver.getProperties({ input });
2750
+ return Object.entries(fields).map(([name, field]) => {
2751
+ if (!isRef(field.resolver) && (field.resolver.imports?.length ?? 0) > 0) {
2752
+ throw new Error(
2753
+ `dynamic object field "${name}" inlines an import-bearing resolver; use { ref } into the object's definitions so its imports bind`
2754
+ );
2755
+ }
2756
+ return toLeaf(name, field, resolver.definitions);
2757
+ });
2758
+ }
2759
+ function arrayItem(resolver) {
2760
+ const items = resolver.items;
2761
+ const valueType = resolver.itemValueType;
2762
+ if (isRef(items)) {
2763
+ return {
2764
+ name: "",
2765
+ required: true,
2766
+ resolver: resolver.definitions?.[items.ref],
2767
+ extraInput: items.input,
2768
+ valueType,
2769
+ requires: []
2770
+ };
2771
+ }
2772
+ return {
2773
+ name: "",
2774
+ required: true,
2775
+ resolver: items,
2776
+ valueType,
2777
+ requires: []
2778
+ };
2779
+ }
2780
+ function autoSettles(resolver) {
2781
+ return resolver.type === "constant" || resolver.type === "info";
2782
+ }
2783
+ function mergeInput(input, extra) {
2784
+ return extra ? { ...input, ...extra } : input;
2785
+ }
2786
+ async function childrenAt(ctx, path, resolved) {
2787
+ if (path.length === 0) return ctx.parameters;
2788
+ const leaf = await leafAt(ctx, path, resolved);
2789
+ if (!leaf?.resolver || leaf.resolver.type !== "object") return [];
2790
+ return objectChildren(leaf.resolver, mergeInput(resolved, leaf.extraInput));
2791
+ }
2792
+ async function leafAt(ctx, path, resolved) {
2793
+ let children = ctx.parameters;
2794
+ let leaf;
2795
+ for (let i = 0; i < path.length; i++) {
2796
+ const seg = path[i];
2797
+ if (typeof seg === "number") {
2798
+ if (leaf?.resolver?.type !== "array") return void 0;
2799
+ leaf = arrayItem(leaf.resolver);
2800
+ } else {
2801
+ leaf = children.find((c) => c.name === seg);
2802
+ if (!leaf) return void 0;
2803
+ }
2804
+ if (i < path.length - 1 && typeof path[i + 1] === "string") {
2805
+ if (leaf?.resolver?.type !== "object") return void 0;
2806
+ children = await objectChildren(
2807
+ leaf.resolver,
2808
+ mergeInput(resolved, leaf.extraInput)
2809
+ );
2810
+ }
2811
+ }
2812
+ return leaf;
2813
+ }
2814
+ async function arrayInfoAt(ctx, path, resolved) {
2815
+ const leaf = await leafAt(ctx, path, resolved);
2816
+ const resolver = leaf?.resolver;
2817
+ if (resolver?.type !== "array") {
2818
+ throw new Error(`expected an array resolver at "${key(path)}"`);
2819
+ }
2820
+ return {
2821
+ min: resolver.minItems ?? 0,
2822
+ max: resolver.maxItems ?? Infinity,
2823
+ item: { ...arrayItem(resolver), name: String(path[path.length - 1]) }
2824
+ };
2825
+ }
2826
+ async function firstPage(result) {
2827
+ const page = await result;
2828
+ return {
2829
+ data: Array.isArray(page?.data) ? page.data : [],
2830
+ nextCursor: page?.nextCursor
2831
+ };
2832
+ }
2833
+ async function resolveContext(leaf, input) {
2834
+ if (leaf.resolver?.type !== "dynamic") return void 0;
2835
+ return leaf.resolver.getContext?.({
2836
+ input: mergeInput(input, leaf.extraInput)
2837
+ });
2838
+ }
2839
+ async function fetchListing(leaf, input, opts = {}) {
2840
+ const page = await firstPage(
2841
+ leaf.resolver?.type === "dynamic" ? leaf.resolver.listItems({
2842
+ input: mergeInput(input, leaf.extraInput),
2843
+ context: opts.context,
2844
+ search: opts.search,
2845
+ cursor: opts.cursor
2846
+ }) : void 0
2847
+ );
2848
+ return {
2849
+ items: [...opts.priorItems ?? [], ...page.data],
2850
+ cursor: page.nextCursor,
2851
+ search: opts.search,
2852
+ exhausted: page.nextCursor == null
2853
+ };
2854
+ }
2855
+
2856
+ // src/model/resolution/questions.ts
2857
+ function toChoice(c) {
2858
+ const label = "label" in c ? c.label : c.name;
2859
+ const hint = Array.isArray(c.hint) ? c.hint.join(", ") : c.hint;
2860
+ return { label, value: String(c.value), hint };
2861
+ }
2862
+ var AFFORDANCE = {
2863
+ choose: { action: "choose", description: "Pick one of the listed options" },
2864
+ custom: {
2865
+ action: "custom",
2866
+ description: "Provide a value directly",
2867
+ supply: "value"
2868
+ },
2869
+ search: {
2870
+ action: "search",
2871
+ description: "Filter the options by a search term",
2872
+ supply: "term"
2873
+ },
2874
+ more: { action: "more", description: "Load more options" },
2875
+ skip: { action: "skip", description: "Omit this optional parameter" },
2876
+ add: { action: "add", description: "Add another item" },
2877
+ done: { action: "done", description: "Finish the list" },
2878
+ retry: { action: "retry", description: "Retry loading the options" },
2879
+ cancel: { action: "cancel", description: "Cancel resolution" }
2880
+ };
2881
+ function selectActions(leaf, listing, multiple) {
2882
+ const searchMode = leaf.resolver?.type === "dynamic" && leaf.resolver.inputType === "search";
2883
+ if (searchMode && listing.search === void 0 && listing.items.length === 0) {
2884
+ const actions2 = multiple ? [AFFORDANCE.search] : [AFFORDANCE.search, AFFORDANCE.custom];
2885
+ if (!leaf.required) actions2.push(AFFORDANCE.skip);
2886
+ return actions2;
2887
+ }
2888
+ const actions = multiple ? [AFFORDANCE.choose] : [AFFORDANCE.choose, AFFORDANCE.custom];
2889
+ if (searchMode) actions.push(AFFORDANCE.search);
2890
+ if (listing.cursor) actions.push(AFFORDANCE.more);
2891
+ if (!leaf.required) actions.push(AFFORDANCE.skip);
2892
+ return actions;
2893
+ }
2894
+ function labeledMessage(leaf) {
2895
+ if (!leaf.label) return void 0;
2896
+ return `${leaf.label} (${leaf.required ? "required" : "optional"}):`;
2897
+ }
2898
+ function selectQuestion(leaf, input, listing, context) {
2899
+ const resolver = leaf.resolver?.type === "dynamic" ? leaf.resolver : void 0;
2900
+ const config = resolver?.prompt?.({
2901
+ items: listing.items,
2902
+ input: mergeInput(input, leaf.extraInput),
2903
+ context
2904
+ });
2905
+ const multiple = config?.type === "checkbox";
2906
+ return {
2907
+ type: "select",
2908
+ // A labeled field's title beats the resolver's message: per-field
2909
+ // resolvers are shared across fields (one choices-fetcher for every
2910
+ // field), so only the leaf knows which field is being asked.
2911
+ message: labeledMessage(leaf) ?? config?.message ?? `Select ${leaf.name}:`,
2912
+ choices: (config?.choices ?? []).map(toChoice),
2913
+ ...multiple ? { multiple: true } : {},
2914
+ ...config?.notes?.length ? { notes: config.notes } : {},
2915
+ ...listing.search !== void 0 ? { search: listing.search } : {},
2916
+ ...resolver?.placeholder ? { placeholder: resolver.placeholder } : {},
2917
+ actions: selectActions(leaf, listing, multiple)
2918
+ };
2919
+ }
2920
+ function toControllerError(error) {
2921
+ if (error instanceof Error) {
2922
+ const code = error.code;
2923
+ return {
2924
+ name: error.name,
2925
+ message: error.message,
2926
+ ...typeof code === "string" ? { code } : {}
2927
+ };
2928
+ }
2929
+ return { name: "Error", message: String(error) };
2930
+ }
2931
+ function failedResult(state, name, error) {
2932
+ return {
2933
+ state,
2934
+ result: {
2935
+ status: "failed",
2936
+ error: toControllerError(error),
2937
+ question: {
2938
+ type: "select",
2939
+ message: `Could not load options for ${name}.`,
2940
+ choices: [],
2941
+ actions: [AFFORDANCE.retry, AFFORDANCE.cancel]
2942
+ }
2943
+ }
2944
+ };
2945
+ }
2946
+ async function buildQuestion(leaf, input) {
2947
+ const optional = !leaf.required;
2948
+ const resolver = leaf.resolver;
2949
+ if (resolver?.type === "dynamic") {
2950
+ const context = await resolveContext(leaf, input);
2951
+ if (resolver.inputType === "search") {
2952
+ const listing2 = {
2953
+ items: [],
2954
+ cursor: void 0,
2955
+ search: void 0,
2956
+ exhausted: true
2957
+ };
2958
+ return {
2959
+ question: selectQuestion(leaf, input, listing2, context),
2960
+ listing: listing2
2961
+ };
2962
+ }
2963
+ const listing = await fetchListing(leaf, input, { context });
2964
+ return {
2965
+ question: selectQuestion(leaf, input, listing, context),
2966
+ listing
2967
+ };
2968
+ }
2969
+ if (leaf.staticChoices) {
2970
+ const actions2 = [AFFORDANCE.choose];
2971
+ if (optional) actions2.push(AFFORDANCE.skip);
2972
+ return {
2973
+ question: {
2974
+ type: "select",
2975
+ message: `Select ${leaf.name}:`,
2976
+ choices: leaf.staticChoices,
2977
+ actions: actions2
2978
+ }
2979
+ };
2980
+ }
2981
+ const textSource = resolver?.type === "static" ? resolver : void 0;
2982
+ const inputType = textSource?.inputType && textSource.inputType !== "search" ? textSource.inputType : "text";
2983
+ const actions = [AFFORDANCE.custom];
2984
+ if (optional) actions.push(AFFORDANCE.skip);
2985
+ return {
2986
+ question: {
2987
+ type: "input",
2988
+ // The optional marker makes Enter-to-pass discoverable on a bare
2989
+ // parameter; a labeled field carries its marker via labeledMessage.
2990
+ message: labeledMessage(leaf) ?? `Enter ${leaf.name}${optional ? " (optional)" : ""}:`,
2991
+ inputType,
2992
+ placeholder: textSource?.placeholder,
2993
+ actions
2994
+ }
2995
+ };
2996
+ }
2997
+ function collectionQuestion(t) {
2998
+ const actions = [AFFORDANCE.add];
2999
+ if (t.count >= t.min) actions.push(AFFORDANCE.done);
3000
+ return {
3001
+ type: "collection",
3002
+ message: `Add ${t.path[t.path.length - 1]}[${t.count}]?`,
3003
+ container: "array",
3004
+ count: t.count,
3005
+ min: t.min,
3006
+ // An unbounded array's max is Infinity, which JSON.stringify turns to null;
3007
+ // omit it so the question round-trips across the wall as plain data.
3008
+ ...Number.isFinite(t.max) ? { max: t.max } : {},
3009
+ actions
3010
+ };
3011
+ }
3012
+ function objectGateQuestion(path) {
3013
+ return {
3014
+ type: "collection",
3015
+ message: `Add ${path[path.length - 1]}?`,
3016
+ container: "object",
3017
+ actions: [
3018
+ {
3019
+ action: "add",
3020
+ description: "Provide values for these fields"
3021
+ },
3022
+ { action: "done", description: "Skip these fields" }
3023
+ ]
3024
+ };
3025
+ }
3026
+ function optionalsGateQuestion(pending) {
3027
+ return {
3028
+ type: "collection",
3029
+ // The prompt and its context ride separately so a host renders the info
3030
+ // line above the confirm without composing any text of its own.
3031
+ message: "Would you like to configure optional fields?",
3032
+ description: `There are ${pending.length} optional field(s) available.`,
3033
+ container: "object",
3034
+ // The gated fields' projection, so a smart host can show WHAT `add` would
3035
+ // walk (or render a form section) instead of a blind yes/no.
3036
+ fields: pending.map((leaf) => ({
3037
+ key: leaf.name,
3038
+ ...leaf.label ? { label: leaf.label } : {},
3039
+ ...leaf.valueType ? { valueType: leaf.valueType } : {}
3040
+ })),
3041
+ actions: [
3042
+ { action: "add", description: "Configure the optional fields" },
3043
+ { action: "done", description: "Skip the optional fields" }
3044
+ ]
3045
+ };
3046
+ }
3047
+
3048
+ // src/model/resolution/walk.ts
3049
+ function finalize(ctx, resolved) {
3050
+ if (!ctx.schema) return { status: "done", value: resolved };
3051
+ const parsed = ctx.schema.safeParse(resolved);
3052
+ if (parsed.success) {
3053
+ return { status: "done", value: parsed.data };
3054
+ }
3055
+ const issues = parsed.error.issues.map((i) => ({
3056
+ parameter: i.path.map(String).join(".") || void 0,
3057
+ message: i.message
3058
+ }));
3059
+ return { status: "invalid", issues };
3060
+ }
3061
+ var optionalsMarker = (path) => `${key(path)}?optionals`;
3062
+ async function findInArray(ctx, state, path) {
3063
+ if (isSettled(state, path)) return null;
3064
+ if (getAtPath(state.resolved, path) == null)
3065
+ setAtPath(state.resolved, path, []);
3066
+ if (!state.interactive) {
3067
+ settle(state, path);
3068
+ return null;
3069
+ }
3070
+ const { min, max, item } = await arrayInfoAt(ctx, path, state.resolved);
3071
+ const items = getAtPath(state.resolved, path);
3072
+ const len = items.length;
3073
+ const itemType = item.resolver?.type;
3074
+ if (len > 0 && (itemType === "object" || itemType === "array")) {
3075
+ const itemPath = [...path, len - 1];
3076
+ if (!isSettled(state, itemPath)) {
3077
+ const inner = await findNext(ctx, state, itemPath);
3078
+ if (inner) return inner;
3079
+ }
3080
+ }
3081
+ if (len < min) return descendItem(ctx, state, path, len, item);
3082
+ if (len < max) return { kind: "array", path, count: len, min, max };
3083
+ settle(state, path);
3084
+ return null;
3085
+ }
3086
+ function seedItemSlot(state, itemPath, item) {
3087
+ const type = item.resolver?.type;
3088
+ if (type === "object") {
3089
+ setAtPath(state.resolved, itemPath, {});
3090
+ return "object";
3091
+ }
3092
+ if (type === "array") {
3093
+ setAtPath(state.resolved, itemPath, []);
3094
+ return "array";
3095
+ }
3096
+ return "leaf";
3097
+ }
3098
+ async function descendItem(ctx, state, arrayPath, index, item) {
3099
+ const itemPath = [...arrayPath, index];
3100
+ const kind = seedItemSlot(state, itemPath, item);
3101
+ if (kind === "object") return findNext(ctx, state, itemPath);
3102
+ if (kind === "array") return findInArray(ctx, state, itemPath);
3103
+ return { kind: "leaf", path: itemPath, leaf: item };
3104
+ }
3105
+ async function findNext(ctx, state, path = []) {
3106
+ const container = getAtPath(state.resolved, path) ?? {};
3107
+ const children = await childrenAt(ctx, path, state.resolved);
3108
+ const inObject = path.length > 0;
3109
+ const ordered = inObject ? [
3110
+ ...children.filter((c) => c.required),
3111
+ ...children.filter((c) => !c.required)
3112
+ ] : children;
3113
+ const asksUser = (c) => c.resolver ? !autoSettles(c.resolver) : c.required;
3114
+ const isPendingChild = (c) => container[c.name] === void 0 && !isSettled(state, [...path, c.name]);
3115
+ const hasAskableRequired = children.some((c) => c.required && asksUser(c));
3116
+ for (const leaf of ordered) {
3117
+ const childPath = [...path, leaf.name];
3118
+ if (!leaf.requires.every(
3119
+ (r) => container[r] !== void 0 || getAtPath(state.resolved, [r]) !== void 0 || isSettled(state, [...path, r]) || isSettled(state, [r])
3120
+ )) {
3121
+ continue;
3122
+ }
3123
+ const inArrayItem = path.some((segment) => typeof segment === "number");
3124
+ if (inObject && !inArrayItem && state.interactive && hasAskableRequired && !leaf.required && asksUser(leaf) && isPendingChild(leaf) && !state.settled.includes(optionalsMarker(path)) && !children.some((c) => c.required && asksUser(c) && isPendingChild(c))) {
3125
+ const pending = ordered.filter(
3126
+ (c) => !c.required && asksUser(c) && isPendingChild(c)
3127
+ );
3128
+ return { kind: "optionals", path, pending };
3129
+ }
3130
+ if (leaf.resolver?.type === "object") {
3131
+ if (isSettled(state, childPath)) continue;
3132
+ if (getAtPath(state.resolved, childPath) == null) {
3133
+ if (!leaf.required && !inArrayItem) {
3134
+ if (!state.interactive) {
3135
+ settle(state, childPath);
3136
+ continue;
3137
+ }
3138
+ return { kind: "object", path: childPath, leaf };
3139
+ }
3140
+ setAtPath(state.resolved, childPath, {});
3141
+ }
3142
+ const inner = await findNext(ctx, state, childPath);
3143
+ if (inner) return inner;
3144
+ if (!leaf.required) {
3145
+ const value = getAtPath(state.resolved, childPath);
3146
+ if (value !== null && typeof value === "object" && Object.keys(value).length === 0) {
3147
+ const grandchildren = await childrenAt(
3148
+ ctx,
3149
+ childPath,
3150
+ state.resolved
3151
+ );
3152
+ const pending = grandchildren.some(
3153
+ (c) => value[c.name] === void 0 && !isSettled(state, [...childPath, c.name])
3154
+ );
3155
+ if (!pending) {
3156
+ delete container[leaf.name];
3157
+ settle(state, childPath);
3158
+ }
3159
+ }
3160
+ }
3161
+ continue;
3162
+ }
3163
+ if (leaf.resolver?.type === "array") {
3164
+ const inner = await findInArray(ctx, state, childPath);
3165
+ if (inner) return inner;
3166
+ continue;
3167
+ }
3168
+ if (container[leaf.name] !== void 0 || isSettled(state, childPath))
3169
+ continue;
3170
+ return { kind: "leaf", path: childPath, leaf };
3171
+ }
3172
+ return null;
3173
+ }
3174
+ async function askLeaf(state, path, leaf, opts = {}) {
3175
+ state.current = path;
3176
+ delete state.gate;
3177
+ try {
3178
+ const { question, listing } = await buildQuestion(leaf, state.resolved);
3179
+ state.listing = listing;
3180
+ return {
3181
+ state,
3182
+ result: {
3183
+ status: "ask",
3184
+ question,
3185
+ ...opts.error ? { error: opts.error } : {}
3186
+ }
3187
+ };
3188
+ } catch (error) {
3189
+ state.listing = { items: [], exhausted: false };
3190
+ return failedResult(state, leaf.name, error);
3191
+ }
3192
+ }
3193
+ async function advance(ctx, state) {
3194
+ for (; ; ) {
3195
+ const target = await findNext(ctx, state);
3196
+ if (!target) {
3197
+ delete state.current;
3198
+ delete state.gate;
3199
+ delete state.listing;
3200
+ return { state, result: finalize(ctx, state.resolved) };
3201
+ }
3202
+ if (target.kind === "array") {
3203
+ state.current = target.path;
3204
+ state.gate = "array";
3205
+ delete state.listing;
3206
+ return {
3207
+ state,
3208
+ result: { status: "ask", question: collectionQuestion(target) }
3209
+ };
3210
+ }
3211
+ if (target.kind === "object") {
3212
+ state.current = target.path;
3213
+ state.gate = "entry";
3214
+ delete state.listing;
3215
+ return {
3216
+ state,
3217
+ result: { status: "ask", question: objectGateQuestion(target.path) }
3218
+ };
3219
+ }
3220
+ if (target.kind === "optionals") {
3221
+ state.current = target.path;
3222
+ state.gate = "optionals";
3223
+ delete state.listing;
3224
+ return {
3225
+ state,
3226
+ result: {
3227
+ status: "ask",
3228
+ question: optionalsGateQuestion(target.pending)
3229
+ }
3230
+ };
3231
+ }
3232
+ const { path, leaf } = target;
3233
+ const resolver = leaf.resolver;
3234
+ if (resolver && autoSettles(resolver)) {
3235
+ if (resolver.type === "constant") {
3236
+ setAtPath(state.resolved, path, resolver.value);
3237
+ }
3238
+ settle(state, path);
3239
+ continue;
3240
+ }
3241
+ const auto = resolver?.type === "dynamic" ? await resolver.tryResolveWithoutPrompt?.({
3242
+ input: mergeInput(state.resolved, leaf.extraInput)
3243
+ }) : void 0;
3244
+ if (auto) {
3245
+ if (auto.resolvedValue !== void 0)
3246
+ setAtPath(state.resolved, path, auto.resolvedValue);
3247
+ settle(state, path);
3248
+ continue;
3249
+ }
3250
+ if (!state.interactive) {
3251
+ if (!leaf.required) {
3252
+ settle(state, path);
3253
+ continue;
3254
+ }
3255
+ } else if (!leaf.required && !leaf.resolver) {
3256
+ settle(state, path);
3257
+ continue;
3258
+ }
3259
+ return askLeaf(state, path, leaf);
3260
+ }
3261
+ }
3262
+ async function start(ctx, input = {}, interactive = true) {
3263
+ return advance(ctx, {
3264
+ method: ctx.method,
3265
+ resolved: { ...input },
3266
+ settled: [],
3267
+ interactive
3268
+ });
3269
+ }
3270
+ async function step(ctx, prior, action) {
3271
+ const state = clone(prior);
3272
+ if (action.type === "cancel") {
3273
+ delete state.current;
3274
+ delete state.gate;
3275
+ delete state.listing;
3276
+ return { state, result: { status: "cancelled" } };
3277
+ }
3278
+ const path = state.current;
3279
+ if (!path) throw new Error("step called with no outstanding question");
3280
+ const leaf = await leafAt(ctx, path, state.resolved);
3281
+ if (leaf && (action.type === "search" || action.type === "more" || action.type === "retry")) {
3282
+ return refine(ctx, state, leaf, path, action);
3283
+ }
3284
+ if (action.type === "add" || action.type === "done") {
3285
+ const gate = state.gate;
3286
+ if (!gate) {
3287
+ throw new Error(
3288
+ `action "${action.type}" is not supported here: no container decision is outstanding`
3289
+ );
3290
+ }
3291
+ delete state.current;
3292
+ delete state.gate;
3293
+ delete state.listing;
3294
+ if (action.type === "done") {
3295
+ settle(state, path);
3296
+ return advance(ctx, state);
3297
+ }
3298
+ if (gate === "entry") {
3299
+ setAtPath(state.resolved, path, {});
3300
+ return advance(ctx, state);
3301
+ }
3302
+ if (gate === "optionals") {
3303
+ remember(state, optionalsMarker(path));
3304
+ return advance(ctx, state);
3305
+ }
3306
+ const items = getAtPath(state.resolved, path) ?? [];
3307
+ const { item } = await arrayInfoAt(ctx, path, state.resolved);
3308
+ const itemPath = [...path, items.length];
3309
+ if (seedItemSlot(state, itemPath, item) === "leaf")
3310
+ return askLeaf(state, itemPath, item);
3311
+ return advance(ctx, state);
3312
+ }
3313
+ if (state.gate) {
3314
+ throw new Error(
3315
+ `action "${action.type}" is not supported here: a container decision (${state.gate}) is outstanding`
3316
+ );
3317
+ }
3318
+ switch (action.type) {
3319
+ case "choose":
3320
+ case "custom": {
3321
+ if (leaf) {
3322
+ const error = await validationError(leaf, action.value, state);
3323
+ if (error) {
3324
+ if (state.listing && leaf.resolver?.type === "dynamic") {
3325
+ const context = await resolveContext(leaf, state.resolved);
3326
+ return {
3327
+ state,
3328
+ result: {
3329
+ status: "ask",
3330
+ question: selectQuestion(
3331
+ leaf,
3332
+ state.resolved,
3333
+ state.listing,
3334
+ context
3335
+ ),
3336
+ error
3337
+ }
3338
+ };
3339
+ }
3340
+ return askLeaf(state, path, leaf, { error });
3341
+ }
3342
+ }
3343
+ setAtPath(
3344
+ state.resolved,
3345
+ path,
3346
+ leaf ? coerce(leaf, action.value) : action.value
3347
+ );
3348
+ break;
3349
+ }
3350
+ case "skip":
3351
+ settle(state, path);
3352
+ break;
3353
+ default:
3354
+ throw new Error(`action "${action.type}" is not supported here`);
3355
+ }
3356
+ delete state.current;
3357
+ delete state.listing;
3358
+ return advance(ctx, state);
3359
+ }
3360
+ async function refine(ctx, state, leaf, path, action) {
3361
+ const attempt = action.type === "search" ? { search: action.term, cursor: void 0, priorItems: [] } : {
3362
+ search: state.listing?.search,
3363
+ cursor: state.listing?.cursor,
3364
+ priorItems: state.listing?.items ?? []
3365
+ };
3366
+ try {
3367
+ if (action.type === "search") {
3368
+ const exact = leaf.resolver?.type === "dynamic" ? await leaf.resolver.tryResolveFromSearch?.({
3369
+ input: mergeInput(state.resolved, leaf.extraInput),
3370
+ search: action.term
3371
+ }) : void 0;
3372
+ if (exact) {
3373
+ setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
3374
+ delete state.current;
3375
+ delete state.listing;
3376
+ return advance(ctx, state);
3377
+ }
3378
+ }
3379
+ const context = await resolveContext(leaf, state.resolved);
3380
+ state.listing = await fetchListing(leaf, state.resolved, {
3381
+ ...attempt,
3382
+ context
3383
+ });
3384
+ return {
3385
+ state,
3386
+ result: {
3387
+ status: "ask",
3388
+ question: selectQuestion(leaf, state.resolved, state.listing, context)
3389
+ }
3390
+ };
3391
+ } catch (error) {
3392
+ state.listing = {
3393
+ items: attempt.priorItems,
3394
+ search: attempt.search,
3395
+ cursor: attempt.cursor,
3396
+ exhausted: false
3397
+ };
3398
+ return failedResult(state, leaf.name, error);
3399
+ }
3400
+ }
3401
+
3402
+ // src/model/resolution/controller.ts
3403
+ function toJsonSchema(schema) {
3404
+ if (!schema) return void 0;
3405
+ try {
3406
+ return z4.toJSONSchema(schema);
3407
+ } catch {
3408
+ return void 0;
3409
+ }
3410
+ }
3411
+ function projectSummary(entry) {
3412
+ return {
3413
+ name: entry.name,
3414
+ ...entry.description ? { description: entry.description } : {},
3415
+ ...entry.categories?.length ? { categories: entry.categories } : {}
3416
+ };
3417
+ }
3418
+ function projectMethod(entry) {
3419
+ const inputProperties = toJsonSchema(entry.inputSchema)?.properties;
3420
+ const parameters = {};
3421
+ for (const spec of planParameters(entry).parameters) {
3422
+ const dynamic = spec.resolver?.type === "dynamic" ? spec.resolver : void 0;
3423
+ parameters[spec.name] = {
3424
+ required: spec.required,
3425
+ dynamic: Boolean(dynamic),
3426
+ ...dynamic?.inputType === "search" ? { searchable: true } : {},
3427
+ ...inputProperties?.[spec.name] ? { schema: inputProperties[spec.name] } : {},
3428
+ ...spec.staticChoices ? { choices: spec.staticChoices } : {},
3429
+ ...spec.requires.length ? { requireParameters: spec.requires } : {}
3430
+ };
3431
+ }
3432
+ const output = toJsonSchema(entry.outputSchema);
3433
+ return {
3434
+ name: entry.name,
3435
+ ...entry.description ? { description: entry.description } : {},
3436
+ ...entry.categories?.length ? { categories: entry.categories } : {},
3437
+ parameters,
3438
+ ...entry.positional?.length ? { positional: entry.positional } : {},
3439
+ ...output ? { output } : {}
3440
+ };
3441
+ }
3442
+ function createController(sdk) {
3443
+ function entryFor(method) {
3444
+ const entry = sdk.getRegistry().functions.find((f) => f.name === method);
3445
+ if (!entry) throw new Error(`unknown method "${method}"`);
3446
+ return entry;
3447
+ }
3448
+ function contextFor(method) {
3449
+ const entry = entryFor(method);
3450
+ return {
3451
+ method,
3452
+ schema: entry.inputSchema,
3453
+ parameters: planParameters(entry).parameters
3454
+ };
3455
+ }
3456
+ const start2 = ({ method, input, interactive }) => start(contextFor(method), input, interactive);
3457
+ const step2 = ({ state, action }) => step(contextFor(state.method), state, action);
3458
+ const resolve = async ({
3459
+ method,
3460
+ input,
3461
+ answer,
3462
+ interactive
3463
+ }) => {
3464
+ const ctx = contextFor(method);
3465
+ let { state, result } = await start(ctx, input, interactive);
3466
+ while (result.status === "ask" || result.status === "failed") {
3467
+ const action = await answer({ state, result });
3468
+ ({ state, result } = await step(ctx, state, action));
3469
+ }
3470
+ if (result.status === "done") return result.value;
3471
+ if (result.status === "cancelled") {
3472
+ throw new CoreCancelledSignal(`resolution cancelled for "${method}"`);
3473
+ }
3474
+ const detail = result.issues.map((i) => i.parameter ? `${i.parameter}: ${i.message}` : i.message).join("; ");
3475
+ throw new Error(`invalid input for "${method}": ${detail}`);
3476
+ };
3477
+ const listMethods = () => ({
3478
+ data: sdk.getRegistry().functions.map(projectSummary)
3479
+ });
3480
+ const getMethod = ({ method }) => ({
3481
+ data: projectMethod(entryFor(method))
3482
+ });
3483
+ const listChoices = async ({
3484
+ method,
3485
+ parameter,
3486
+ input = {},
3487
+ search,
3488
+ cursor
3489
+ }) => {
3490
+ const spec = contextFor(method).parameters.find(
3491
+ (p) => p.name === parameter
3492
+ );
3493
+ const dynamic = spec?.resolver?.type === "dynamic" ? spec.resolver : void 0;
3494
+ if (!dynamic) return { data: [] };
3495
+ const context = await dynamic.getContext?.({ input });
3496
+ const page = await firstPage(
3497
+ dynamic.listItems({ input, context, search, cursor })
3498
+ );
3499
+ const config = dynamic.prompt?.({ items: page.data, input, context });
3500
+ const data = (config?.choices ?? []).map(toChoice);
3501
+ return { data, nextCursor: page.nextCursor };
3502
+ };
3503
+ return { resolve, start: start2, step: step2, listMethods, getMethod, listChoices };
3504
+ }
3505
+
3506
+ // src/utils/core-plugin.ts
3507
+ function createCorePlugin(options) {
3508
+ logDeprecation(
3509
+ "createCorePlugin() is deprecated. Inject the options under CORE_OPTIONS_ID via createSdk's configuration instead."
3510
+ );
3511
+ return () => ({
3512
+ context: {
3513
+ core: options
3514
+ }
3515
+ });
3516
+ }
3517
+
3518
+ // src/utils/schema-utils.ts
3519
+ import { z as z5 } from "zod";
3520
+ function getOutputSchema(inputSchema) {
3521
+ return inputSchema._zod.def.outputSchema;
3522
+ }
3523
+ function withOutputSchema(inputSchema, outputSchema) {
3524
+ Object.assign(inputSchema._zod.def, {
3525
+ outputSchema
3526
+ });
3527
+ return inputSchema;
3528
+ }
3529
+ function withResolver(schema, config) {
3530
+ schema._zod.def.resolverMeta = config;
3531
+ return schema;
3532
+ }
3533
+ function getSchemaDescription(schema) {
3534
+ return schema.description;
3535
+ }
3536
+ function getFieldDescriptions(schema) {
3537
+ const descriptions = {};
3538
+ const shape = schema.shape;
3539
+ for (const [key2, fieldSchema] of Object.entries(shape)) {
3540
+ if (fieldSchema instanceof z5.ZodType && fieldSchema.description) {
3541
+ descriptions[key2] = fieldSchema.description;
3542
+ }
3543
+ }
3544
+ return descriptions;
3545
+ }
3546
+ function withPositional(schema) {
3547
+ Object.assign(schema._zod.def, {
3548
+ positionalMeta: { positional: true }
3549
+ });
3550
+ return schema;
3551
+ }
3552
+ function schemaHasPositionalMeta(schema) {
3553
+ return "positionalMeta" in schema._zod.def;
3554
+ }
3555
+ function isPositional(schema) {
3556
+ if (schemaHasPositionalMeta(schema) && schema._zod.def.positionalMeta?.positional) {
3557
+ return true;
3558
+ }
3559
+ if (schema instanceof z5.ZodOptional) {
3560
+ return isPositional(schema._zod.def.innerType);
3561
+ }
3562
+ if (schema instanceof z5.ZodDefault) {
3563
+ return isPositional(schema._zod.def.innerType);
3564
+ }
3565
+ return false;
3566
+ }
3567
+ function openEnum(values, description) {
3568
+ return z5.union([z5.enum(values), z5.string()]).describe(description);
3569
+ }
3570
+ export {
3571
+ CONTEXT,
3572
+ CORE_ERROR_SYMBOL,
3573
+ CORE_OPTIONS_ID,
3574
+ CORE_SIGNAL_SYMBOL,
3575
+ CoreCancelledSignal,
3576
+ CoreDisposeError,
3577
+ CoreError,
3578
+ CoreErrorCode,
3579
+ CoreSignal,
3580
+ addPlugin,
3581
+ composePlugins,
3582
+ concatPaginated,
3583
+ coreOptionsPluginRef,
3584
+ createAsyncContext,
3585
+ createController,
3586
+ createCoreError,
3587
+ createCorePlugin,
3588
+ createDeprecationLogger,
3589
+ createFunction,
3590
+ createPaginatedFunction,
3591
+ createPaginatedPluginMethod,
3592
+ createPluginMethod,
3593
+ createPluginStack,
3594
+ createPrefixedCursor,
3595
+ createSdk,
3596
+ createValidator,
3597
+ dangerousContextPlugin,
3598
+ declareMethod,
3599
+ declareOptionalProperty,
3600
+ declarePlugin,
3601
+ declareProperty,
3602
+ decodeIncomingCursor,
3603
+ defaultLogDeprecation,
3604
+ defineFormatter,
3605
+ defineHook,
3606
+ defineLegacyMerge,
3607
+ defineMethod,
3608
+ defineMethodOverride,
3609
+ definePlugin,
3610
+ defineProperty,
3611
+ defineResolver,
3612
+ disposeSdk,
3613
+ fromFunctionPlugin,
3614
+ getContext,
3615
+ getCoreErrorCause,
3616
+ getCoreErrorCode,
3617
+ getCurrentDepth,
3618
+ getCurrentScope,
3619
+ getFieldDescriptions,
3620
+ getOutputSchema,
3621
+ getRegistryPlugin,
3622
+ getSchemaDescription,
3623
+ isCoreError,
3624
+ isCoreSignal,
3625
+ isNestedMethodCall,
3626
+ isPositional,
3627
+ isTelemetryNested,
3628
+ omitExports,
3629
+ openEnum,
3630
+ paginate,
3631
+ paginateBuffered,
3632
+ paginateMaxItems,
3633
+ resolvePlugin,
3634
+ runInMethodScope,
3635
+ runWithTelemetryContext,
3636
+ selectExports,
3637
+ splitPrefixedCursor,
3638
+ toIterable,
3639
+ toSnakeCase,
3640
+ toTitleCase,
3641
+ validateOptions,
3642
+ withOutputSchema,
3643
+ withPositional,
3644
+ withResolver
3645
+ };
3646
+ //# sourceMappingURL=index.mjs.map