@zapier/kitcore 0.0.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,2962 @@
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
+ function runInMethodScope(fn) {
557
+ if (!scope.available) return fn();
558
+ const currentDepth = scope.get()?.depth ?? -1;
559
+ return scope.run({ depth: currentDepth + 1 }, fn);
560
+ }
561
+ var runWithTelemetryContext = runInMethodScope;
562
+ var isTelemetryNested = isNestedMethodCall;
563
+
564
+ // src/utils/function-utils.ts
565
+ function normalizeError(error, adaptError) {
566
+ if (error instanceof Error) return error;
567
+ const message = typeof error === "object" && error !== null && "message" in error && typeof error.message === "string" ? error.message : String(error);
568
+ return createCoreError(
569
+ {
570
+ code: CoreErrorCode.Unknown,
571
+ message,
572
+ cause: error
573
+ },
574
+ adaptError
575
+ );
576
+ }
577
+ function createFunction(coreFn, options) {
578
+ const { sdk, schema, name } = options;
579
+ const functionName = name || coreFn.name;
580
+ const namedFunctions = {
581
+ [functionName]: async function(callOptions) {
582
+ return runInMethodScope(async () => {
583
+ const startTime = Date.now();
584
+ const normalizedOptions = callOptions ?? {};
585
+ const args = [normalizedOptions];
586
+ const depth = getCurrentDepth();
587
+ const hooks = sdk.context.hooks;
588
+ const adaptError = sdk.context.core?.adaptError;
589
+ hooks?.onMethodStart?.({
590
+ methodName: functionName,
591
+ args,
592
+ isPaginated: false,
593
+ depth
594
+ });
595
+ try {
596
+ let result;
597
+ if (schema) {
598
+ const validatedOptions = validateOptions(
599
+ schema,
600
+ normalizedOptions,
601
+ {
602
+ adaptError
603
+ }
604
+ );
605
+ result = await coreFn({
606
+ ...normalizedOptions,
607
+ ...validatedOptions
608
+ });
609
+ } else {
610
+ result = await coreFn(normalizedOptions);
611
+ }
612
+ hooks?.onMethodEnd?.({
613
+ methodName: functionName,
614
+ args,
615
+ isPaginated: false,
616
+ depth,
617
+ durationMs: Date.now() - startTime
618
+ });
619
+ return result;
620
+ } catch (error) {
621
+ const normalizedError = normalizeError(error, adaptError);
622
+ hooks?.onMethodEnd?.({
623
+ methodName: functionName,
624
+ args,
625
+ isPaginated: false,
626
+ depth,
627
+ durationMs: Date.now() - startTime,
628
+ error: normalizedError
629
+ });
630
+ throw normalizedError;
631
+ }
632
+ });
633
+ }
634
+ };
635
+ return namedFunctions[functionName];
636
+ }
637
+ function isSdkPage(value) {
638
+ if (typeof value !== "object" || value === null) return false;
639
+ const page = value;
640
+ if (!Array.isArray(page.data)) return false;
641
+ if (page.nextCursor !== void 0 && typeof page.nextCursor !== "string") {
642
+ return false;
643
+ }
644
+ return Object.keys(page).every((k) => k === "data" || k === "nextCursor");
645
+ }
646
+ function createPageFunction(coreFn, {
647
+ sdk,
648
+ adaptPage
649
+ }) {
650
+ const functionName = coreFn.name + "Page";
651
+ const namedFunctions = {
652
+ [functionName]: async function(options) {
653
+ try {
654
+ const response = await coreFn(options);
655
+ const page = adaptPage ? adaptPage(response) : response;
656
+ if (!isSdkPage(page)) {
657
+ throw new Error(
658
+ `${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\`.`
659
+ );
660
+ }
661
+ return page;
662
+ } catch (error) {
663
+ throw normalizeError(
664
+ error,
665
+ sdk.context.core?.adaptError
666
+ );
667
+ }
668
+ }
669
+ };
670
+ return namedFunctions[functionName];
671
+ }
672
+ function createPaginatedFunction(coreFn, options) {
673
+ const { sdk, schema, name, defaultPageSize, adaptPage } = options;
674
+ const pageFunction = createPageFunction(coreFn, { sdk, adaptPage });
675
+ const functionName = name || coreFn.name;
676
+ const namedFunctions = {
677
+ [functionName]: function(callOptions) {
678
+ return runInMethodScope(() => {
679
+ const startTime = Date.now();
680
+ const normalizedOptions = callOptions ?? {};
681
+ const args = [normalizedOptions];
682
+ const depth = getCurrentDepth();
683
+ const hooks = sdk.context.hooks;
684
+ const adaptError = sdk.context.core?.adaptError;
685
+ hooks?.onMethodStart?.({
686
+ methodName: functionName,
687
+ args,
688
+ isPaginated: true,
689
+ depth
690
+ });
691
+ const validatedOptions = {
692
+ ...normalizedOptions,
693
+ ...schema ? createValidator(schema, { adaptError })(normalizedOptions) : normalizedOptions
694
+ };
695
+ const pageSize = validatedOptions.pageSize ?? defaultPageSize;
696
+ const optimizedOptions = {
697
+ ...validatedOptions,
698
+ pageSize
699
+ };
700
+ const iterator = paginate(pageFunction, optimizedOptions);
701
+ const firstPagePromise = iterator.next().then((result) => {
702
+ if (result.done) {
703
+ throw new Error("Paginate should always iterate at least once");
704
+ }
705
+ return result.value;
706
+ });
707
+ if (hooks?.onMethodEnd) {
708
+ firstPagePromise.then(() => {
709
+ hooks.onMethodEnd({
710
+ methodName: functionName,
711
+ args,
712
+ isPaginated: true,
713
+ depth,
714
+ durationMs: Date.now() - startTime
715
+ });
716
+ }).catch((error) => {
717
+ hooks.onMethodEnd({
718
+ methodName: functionName,
719
+ args,
720
+ isPaginated: true,
721
+ depth,
722
+ durationMs: Date.now() - startTime,
723
+ error: error instanceof Error ? error : new Error(String(error))
724
+ });
725
+ });
726
+ }
727
+ const pageStream = async function* () {
728
+ yield await firstPagePromise;
729
+ for await (const page of iterator) {
730
+ yield page;
731
+ }
732
+ }();
733
+ return Object.assign(firstPagePromise, {
734
+ [Symbol.asyncIterator]() {
735
+ return pageStream;
736
+ },
737
+ items: function() {
738
+ return {
739
+ [Symbol.asyncIterator]: async function* () {
740
+ for await (const page of pageStream) {
741
+ for (const item of page.data) {
742
+ yield item;
743
+ }
744
+ }
745
+ }
746
+ };
747
+ }
748
+ });
749
+ });
750
+ }
751
+ };
752
+ return namedFunctions[functionName];
753
+ }
754
+
755
+ // src/utils/plugin-utils.ts
756
+ function createPluginMethod(sdk, config) {
757
+ const { name, inputSchema, handler, ...metaFields } = config;
758
+ const namedHandlers = {
759
+ [name]: async function(options) {
760
+ return handler({ sdk, options });
761
+ }
762
+ };
763
+ const wrappedFn = createFunction(namedHandlers[name], {
764
+ sdk,
765
+ schema: inputSchema
766
+ });
767
+ return {
768
+ [name]: wrappedFn,
769
+ context: {
770
+ meta: {
771
+ [name]: {
772
+ ...metaFields,
773
+ ...inputSchema ? { inputSchema } : {}
774
+ }
775
+ }
776
+ }
777
+ };
778
+ }
779
+ function createPaginatedPluginMethod(sdk, config) {
780
+ const {
781
+ name,
782
+ inputSchema,
783
+ handler,
784
+ adaptPage,
785
+ defaultPageSize,
786
+ ...metaFields
787
+ } = config;
788
+ const namedHandlers = {
789
+ [name]: function(options) {
790
+ return handler({ sdk, options });
791
+ }
792
+ };
793
+ const wrappedFn = createPaginatedFunction(namedHandlers[name], {
794
+ sdk,
795
+ schema: inputSchema,
796
+ name,
797
+ defaultPageSize,
798
+ adaptPage
799
+ });
800
+ return {
801
+ [name]: wrappedFn,
802
+ context: {
803
+ meta: {
804
+ [name]: {
805
+ ...metaFields,
806
+ ...inputSchema ? { inputSchema } : {}
807
+ }
808
+ }
809
+ }
810
+ };
811
+ }
812
+ function splitPluginContribution(result) {
813
+ const { context, ...rootKeys } = result;
814
+ const { meta, hooks, ...contextRest } = context ?? {};
815
+ return {
816
+ rootKeys,
817
+ meta: meta ?? {},
818
+ hooks: hooks ?? {},
819
+ contextRest
820
+ };
821
+ }
822
+ var RESERVED_ROOT_KEYS = /* @__PURE__ */ new Set([
823
+ "context",
824
+ "getRegistry"
825
+ ]);
826
+ function hasOwn(obj, key2) {
827
+ return Object.prototype.hasOwnProperty.call(obj, key2);
828
+ }
829
+ function setOwn(target, key2, value) {
830
+ Object.defineProperty(target, key2, {
831
+ value,
832
+ enumerable: true,
833
+ configurable: true,
834
+ writable: true
835
+ });
836
+ }
837
+ function checkCollisions(target, source, kind, callerLabel, override) {
838
+ if (kind === "root key") {
839
+ checkRootKeyCollisions(target, Object.keys(source), override, callerLabel);
840
+ return;
841
+ }
842
+ for (const key2 of Object.keys(source)) {
843
+ if (!override && hasOwn(target, key2)) {
844
+ throw new Error(
845
+ `${callerLabel}: duplicate ${kind} "${key2}". If the override is intentional, pass { override: true } in the options.`
846
+ );
847
+ }
848
+ }
849
+ }
850
+ function checkRootKeyCollisions(target, keys, override, callerLabel) {
851
+ for (const key2 of keys) {
852
+ if (RESERVED_ROOT_KEYS.has(key2)) {
853
+ throw new Error(
854
+ `${callerLabel}: plugin attempted to register reserved root key "${key2}". The SDK uses this key for its own accessor; rename the plugin's method.`
855
+ );
856
+ }
857
+ if (!override && hasOwn(target, key2)) {
858
+ throw new Error(
859
+ `${callerLabel}: duplicate root key "${key2}". If the override is intentional, pass { override: true } in the options.`
860
+ );
861
+ }
862
+ }
863
+ }
864
+ function applyOwnProperties(target, source) {
865
+ for (const key2 of Object.keys(source)) {
866
+ setOwn(target, key2, source[key2]);
867
+ }
868
+ }
869
+ function createPluginAccumulator(initialProperties = {}, initialContext = {}) {
870
+ const initialMeta = initialContext.meta ?? {};
871
+ const initialHooks = initialContext.hooks ?? {};
872
+ const context = {
873
+ ...initialContext,
874
+ meta: { ...initialMeta },
875
+ hooks: { ...initialHooks }
876
+ };
877
+ const view = { ...initialProperties, context };
878
+ return { view, context };
879
+ }
880
+ function mergeContribution(propertiesTarget, contextTarget, contribution, options) {
881
+ checkCollisions(
882
+ propertiesTarget,
883
+ contribution.rootKeys,
884
+ "root key",
885
+ options.callerLabel,
886
+ options.override
887
+ );
888
+ checkCollisions(
889
+ contextTarget.meta,
890
+ contribution.meta,
891
+ "context.meta key",
892
+ options.callerLabel,
893
+ options.override
894
+ );
895
+ checkCollisions(
896
+ contextTarget,
897
+ contribution.contextRest,
898
+ "context key",
899
+ options.callerLabel,
900
+ options.override
901
+ );
902
+ applyOwnProperties(propertiesTarget, contribution.rootKeys);
903
+ applyOwnProperties(contextTarget.meta, contribution.meta);
904
+ applyOwnProperties(contextTarget, contribution.contextRest);
905
+ contextTarget.hooks = buildHooks(contextTarget.hooks, contribution.hooks);
906
+ }
907
+ function applyPluginContribution(acc, contribution, options) {
908
+ mergeContribution(acc.view, acc.context, contribution, options);
909
+ }
910
+ function wrapAsSdk(properties, context) {
911
+ const sdk = {
912
+ ...properties,
913
+ context,
914
+ getRegistry(qopts) {
915
+ return buildRegistry({
916
+ sdk,
917
+ meta: context.meta,
918
+ packageFilter: qopts?.package
919
+ });
920
+ }
921
+ };
922
+ return sdk;
923
+ }
924
+ function wrapAccumulatorAsSdk(acc) {
925
+ const { context: _ctx, ...rootKeys } = acc.view;
926
+ return wrapAsSdk(
927
+ rootKeys,
928
+ acc.context
929
+ );
930
+ }
931
+ function applyPluginToSdk(sdk, plugin, options) {
932
+ const context = sdk.context;
933
+ const contribution = splitPluginContribution(
934
+ plugin(sdk)
935
+ );
936
+ mergeContribution(sdk, context, contribution, {
937
+ callerLabel: "addPlugin",
938
+ override: options.override === true
939
+ });
940
+ return contribution;
941
+ }
942
+ function resolveStack(head) {
943
+ const entries = [];
944
+ let node = head;
945
+ while (node) {
946
+ entries.unshift({ apply: node.entry, override: node.override });
947
+ node = node.prev;
948
+ }
949
+ return entries;
950
+ }
951
+ function composeStackHooks(hooks) {
952
+ let composed = {};
953
+ for (const h of hooks) composed = buildHooks(composed, h);
954
+ return composed;
955
+ }
956
+ function collapseStackEntries(entries, callerLabel) {
957
+ return (outerSdk) => {
958
+ const { context: outerContext, ...outerProperties } = outerSdk ?? {};
959
+ const viewAcc = createPluginAccumulator(outerProperties, outerContext);
960
+ const contribsAcc = createPluginAccumulator();
961
+ const hooks = [];
962
+ for (const { apply, override } of entries) {
963
+ const contribution = splitPluginContribution(
964
+ apply(viewAcc.view)
965
+ );
966
+ const hookless = { ...contribution, hooks: {} };
967
+ applyPluginContribution(viewAcc, hookless, { callerLabel, override });
968
+ applyPluginContribution(contribsAcc, hookless, { callerLabel, override });
969
+ hooks.push(contribution.hooks);
970
+ }
971
+ const stackHooks = composeStackHooks(hooks);
972
+ viewAcc.context.hooks = buildHooks(viewAcc.context.hooks, stackHooks);
973
+ contribsAcc.context.hooks = stackHooks;
974
+ const { context: _ignored, ...contributedRoot } = contribsAcc.view;
975
+ return {
976
+ ...contributedRoot,
977
+ context: contribsAcc.context
978
+ };
979
+ };
980
+ }
981
+ function buildStackAccumulator(head, callerLabel) {
982
+ const entries = resolveStack(head);
983
+ const acc = createPluginAccumulator();
984
+ const hooks = [];
985
+ for (const { apply, override } of entries) {
986
+ const contribution = splitPluginContribution(
987
+ apply(acc.view)
988
+ );
989
+ applyPluginContribution(
990
+ acc,
991
+ { ...contribution, hooks: {} },
992
+ { callerLabel, override }
993
+ );
994
+ hooks.push(contribution.hooks);
995
+ }
996
+ acc.context.hooks = composeStackHooks(hooks);
997
+ return acc;
998
+ }
999
+ function composePlugins(...plugins) {
1000
+ logDeprecation(
1001
+ "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."
1002
+ );
1003
+ let head = null;
1004
+ for (const plugin of plugins) {
1005
+ head = { entry: plugin, override: false, prev: head };
1006
+ }
1007
+ const entries = resolveStack(head);
1008
+ return collapseStackEntries(entries, "composePlugins");
1009
+ }
1010
+ function createPluginStack() {
1011
+ return buildPluginStack(null, "createPluginStack");
1012
+ }
1013
+ function buildPluginStack(head, callerLabel) {
1014
+ const stack = {
1015
+ use(plugin, options) {
1016
+ const next = {
1017
+ entry: plugin,
1018
+ override: options?.override === true,
1019
+ prev: head
1020
+ };
1021
+ return buildPluginStack(next, callerLabel);
1022
+ },
1023
+ toPlugin() {
1024
+ const entries = resolveStack(head);
1025
+ return collapseStackEntries(entries, callerLabel);
1026
+ },
1027
+ toSdk() {
1028
+ return wrapAccumulatorAsSdk(
1029
+ buildStackAccumulator(head, callerLabel)
1030
+ );
1031
+ }
1032
+ };
1033
+ return stack;
1034
+ }
1035
+
1036
+ // src/model/shared.ts
1037
+ function parseId(id) {
1038
+ const at = id.lastIndexOf("/");
1039
+ return at === -1 ? { name: id, namespace: void 0 } : { name: id.slice(at + 1), namespace: id.slice(0, at) };
1040
+ }
1041
+ function makeId(name, namespace, kind = "leaf") {
1042
+ validateName(name, kind);
1043
+ if (namespace !== void 0) validateNamespace(namespace);
1044
+ return namespace ? `${namespace}/${name}` : name;
1045
+ }
1046
+ var NAME_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
1047
+ var SEGMENT_RE = /^@?[A-Za-z0-9._-]+$/;
1048
+ function validateName(name, kind) {
1049
+ if (name === "") throw new Error("Plugin name must not be empty.");
1050
+ if (kind === "leaf") {
1051
+ if (!NAME_RE.test(name)) {
1052
+ throw new Error(
1053
+ `Plugin name "${name}" must be a valid JS identifier (it is the binding name).`
1054
+ );
1055
+ }
1056
+ } else if (!SEGMENT_RE.test(name)) {
1057
+ throw new Error(
1058
+ `Plugin name "${name}" must be package-like (letters, digits, ".", "_", "-", optional leading "@") with no "/".`
1059
+ );
1060
+ }
1061
+ }
1062
+ function validateNamespace(namespace) {
1063
+ if (namespace === "") throw new Error("Plugin namespace must not be empty.");
1064
+ for (const segment of namespace.split("/")) {
1065
+ if (!SEGMENT_RE.test(segment)) {
1066
+ throw new Error(
1067
+ `Plugin namespace "${namespace}" is invalid: each "/"-separated segment must be package-like (letters, digits, ".", "_", "-", optional leading "@").`
1068
+ );
1069
+ }
1070
+ }
1071
+ }
1072
+
1073
+ // src/model/types.ts
1074
+ var LEAF_META_KEYS = [
1075
+ "description",
1076
+ "categories",
1077
+ "type",
1078
+ "itemType",
1079
+ "returnType",
1080
+ "outputSchema",
1081
+ "inputParameters",
1082
+ "packages",
1083
+ "experimental",
1084
+ "confirm",
1085
+ "deprecation",
1086
+ "aliases",
1087
+ "supportsJsonOutput"
1088
+ ];
1089
+
1090
+ // src/model/define.ts
1091
+ function normalizeImports(deps) {
1092
+ if (!deps) return { plugins: [], bindings: [] };
1093
+ const seen = /* @__PURE__ */ new Map();
1094
+ const bindings = [];
1095
+ const add = (binding, id) => {
1096
+ const priorId = seen.get(binding);
1097
+ if (priorId !== void 0 && priorId !== id) {
1098
+ throw new Error(
1099
+ `Import binding "${binding}" is declared twice. Two different plugins ("${priorId}" and "${id}") bind the same name; wrap one in selectExports to rename it.`
1100
+ );
1101
+ }
1102
+ if (priorId === void 0) {
1103
+ seen.set(binding, id);
1104
+ bindings.push({ binding, id });
1105
+ }
1106
+ };
1107
+ for (const plugin of deps) {
1108
+ if (plugin.pluginType === "aggregate") {
1109
+ for (const [binding, child] of Object.entries(plugin.exports)) {
1110
+ add(binding, child.id);
1111
+ }
1112
+ } else {
1113
+ add(plugin.name, plugin.id);
1114
+ }
1115
+ }
1116
+ return { plugins: deps, bindings };
1117
+ }
1118
+ function collectLeafMeta(config) {
1119
+ let meta;
1120
+ for (const key2 of LEAF_META_KEYS) {
1121
+ if (config[key2] !== void 0) (meta ?? (meta = {}))[key2] = config[key2];
1122
+ }
1123
+ return meta;
1124
+ }
1125
+ function defineMethod(config) {
1126
+ const deps = normalizeImports(config.imports);
1127
+ return {
1128
+ pluginType: "method",
1129
+ name: config.name,
1130
+ namespace: config.namespace,
1131
+ id: makeId(config.name, config.namespace),
1132
+ imports: deps.plugins,
1133
+ importBindings: deps.bindings,
1134
+ inputSchema: config.inputSchema,
1135
+ meta: collectLeafMeta(config),
1136
+ resolvers: config.resolvers,
1137
+ formatter: config.formatter,
1138
+ output: config.output,
1139
+ positional: config.positional,
1140
+ setup: config.setup,
1141
+ run: config.run
1142
+ };
1143
+ }
1144
+ function defineResolver(config) {
1145
+ const deps = normalizeImports(config.imports);
1146
+ const base = { imports: deps.plugins, importBindings: deps.bindings };
1147
+ const gates = {
1148
+ requireParameters: config.requireParameters
1149
+ };
1150
+ switch (config.type) {
1151
+ case "static":
1152
+ return {
1153
+ ...base,
1154
+ ...gates,
1155
+ type: "static",
1156
+ inputType: config.inputType,
1157
+ placeholder: config.placeholder
1158
+ };
1159
+ case "constant":
1160
+ return { ...base, ...gates, type: "constant", value: config.value };
1161
+ case "info":
1162
+ return { ...base, type: "info", text: config.text ?? "" };
1163
+ case "object":
1164
+ return {
1165
+ ...base,
1166
+ ...gates,
1167
+ type: "object",
1168
+ properties: config.properties,
1169
+ definitions: config.definitions,
1170
+ getProperties: config.getProperties
1171
+ };
1172
+ case "array":
1173
+ return {
1174
+ ...base,
1175
+ ...gates,
1176
+ type: "array",
1177
+ items: config.items,
1178
+ minItems: config.minItems,
1179
+ maxItems: config.maxItems,
1180
+ itemValueType: config.itemValueType,
1181
+ definitions: config.definitions
1182
+ };
1183
+ default:
1184
+ return {
1185
+ ...base,
1186
+ ...gates,
1187
+ type: "dynamic",
1188
+ inputType: config.inputType,
1189
+ placeholder: config.placeholder,
1190
+ getContext: config.getContext,
1191
+ listItems: config.listItems,
1192
+ prompt: config.prompt,
1193
+ tryResolveWithoutPrompt: config.tryResolveWithoutPrompt,
1194
+ tryResolveFromSearch: config.tryResolveFromSearch
1195
+ };
1196
+ }
1197
+ }
1198
+ function defineFormatter(config) {
1199
+ const deps = normalizeImports(config.imports);
1200
+ return {
1201
+ imports: deps.plugins,
1202
+ importBindings: deps.bindings,
1203
+ getContext: config.getContext,
1204
+ format: config.format
1205
+ };
1206
+ }
1207
+ function declareMethod(config) {
1208
+ const { name, namespace } = parseId(config.id);
1209
+ const id = makeId(name, namespace);
1210
+ return {
1211
+ pluginType: "method",
1212
+ name,
1213
+ namespace,
1214
+ id,
1215
+ standIn: true,
1216
+ imports: [],
1217
+ importBindings: [],
1218
+ run: () => {
1219
+ throw new Error(
1220
+ `Plugin "${id}" is a stand-in (declareMethod) with no implementation. Register the real plugin under this id.`
1221
+ );
1222
+ }
1223
+ };
1224
+ }
1225
+ function defineProperty(config) {
1226
+ const deps = normalizeImports(config.imports);
1227
+ return {
1228
+ pluginType: "property",
1229
+ name: config.name,
1230
+ namespace: config.namespace,
1231
+ id: makeId(config.name, config.namespace),
1232
+ imports: deps.plugins,
1233
+ importBindings: deps.bindings,
1234
+ setup: config.setup,
1235
+ value: config.value,
1236
+ get: config.get,
1237
+ meta: collectLeafMeta(config)
1238
+ };
1239
+ }
1240
+ function declareProperty(config) {
1241
+ const { name, namespace } = parseId(config.id);
1242
+ return {
1243
+ pluginType: "property",
1244
+ name,
1245
+ namespace,
1246
+ id: makeId(name, namespace),
1247
+ standIn: true,
1248
+ imports: [],
1249
+ importBindings: []
1250
+ };
1251
+ }
1252
+ function declarePlugin(config) {
1253
+ const { name, namespace } = parseId(config.id);
1254
+ return {
1255
+ pluginType: "aggregate",
1256
+ name,
1257
+ namespace,
1258
+ id: makeId(name, namespace, "aggregate"),
1259
+ standIn: true,
1260
+ imports: [],
1261
+ importBindings: [],
1262
+ exports: normalizeExports(config.exports)
1263
+ };
1264
+ }
1265
+ function definePlugin(fnOrConfig) {
1266
+ if (typeof fnOrConfig === "function") return fnOrConfig;
1267
+ const config = fnOrConfig;
1268
+ const deps = normalizeImports(config.imports);
1269
+ return {
1270
+ pluginType: "aggregate",
1271
+ name: config.name,
1272
+ namespace: config.namespace,
1273
+ id: makeId(config.name, config.namespace, "aggregate"),
1274
+ imports: deps.plugins,
1275
+ importBindings: deps.bindings,
1276
+ exports: normalizeExports(config.exports),
1277
+ middleware: config.middleware
1278
+ };
1279
+ }
1280
+ function normalizeExports(exports) {
1281
+ if (!exports) return {};
1282
+ const out = {};
1283
+ const add = (binding, leaf) => {
1284
+ const existing = out[binding];
1285
+ if (existing && existing.id !== leaf.id) {
1286
+ throw new Error(
1287
+ `definePlugin: duplicate export binding "${binding}". Two different plugins ("${existing.id}" and "${leaf.id}") bind the same name; wrap one in selectExports to rename it.`
1288
+ );
1289
+ }
1290
+ out[binding] = leaf;
1291
+ };
1292
+ for (const element of exports) {
1293
+ if (element.pluginType === "aggregate") {
1294
+ for (const [binding, child] of Object.entries(element.exports)) {
1295
+ add(binding, child);
1296
+ }
1297
+ } else {
1298
+ add(element.name, element);
1299
+ }
1300
+ }
1301
+ return out;
1302
+ }
1303
+
1304
+ // src/model/exports.ts
1305
+ var selectSeq = 0;
1306
+ function selectExports(source, ...specs) {
1307
+ const selected = {};
1308
+ const pick = (binding, fromName) => {
1309
+ const child = source.exports[fromName];
1310
+ if (!child) {
1311
+ throw new Error(
1312
+ `selectExports: "${source.id}" has no export "${fromName}".`
1313
+ );
1314
+ }
1315
+ selected[binding] = child;
1316
+ };
1317
+ for (const spec of specs) {
1318
+ if (typeof spec === "string") {
1319
+ pick(spec, spec);
1320
+ } else {
1321
+ for (const [newName, fromName] of Object.entries(spec)) {
1322
+ pick(newName, fromName);
1323
+ }
1324
+ }
1325
+ }
1326
+ const id = `${source.id}#select:${selectSeq++}`;
1327
+ return {
1328
+ pluginType: "aggregate",
1329
+ name: makeId(`select`, source.name, "aggregate"),
1330
+ id,
1331
+ // Depend on the source so it is materialized; the selected bindings resolve
1332
+ // to the source's own leaves (kept identity).
1333
+ imports: [source],
1334
+ importBindings: [],
1335
+ exports: selected
1336
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1337
+ };
1338
+ }
1339
+
1340
+ // src/model/legacy.ts
1341
+ function fromFunctionPlugin(fn, config) {
1342
+ return {
1343
+ pluginType: "legacy",
1344
+ name: config.name,
1345
+ namespace: config.namespace,
1346
+ id: makeId(config.name, config.namespace, "aggregate"),
1347
+ imports: [],
1348
+ importBindings: [],
1349
+ run: fn
1350
+ };
1351
+ }
1352
+ function defineLegacyMerge(args) {
1353
+ return {
1354
+ pluginType: "legacy-merge",
1355
+ name: args.name,
1356
+ namespace: args.namespace,
1357
+ id: makeId(args.name, args.namespace, "aggregate"),
1358
+ legacy: fromFunctionPlugin(args.legacy, {
1359
+ name: args.name,
1360
+ namespace: args.namespace
1361
+ }),
1362
+ plugin: args.plugin
1363
+ };
1364
+ }
1365
+ function legacyGraphEntry(name, value, pluginMeta) {
1366
+ const { inputSchema, ...rest } = pluginMeta ?? {};
1367
+ const meta = Object.keys(rest).length ? rest : void 0;
1368
+ if (typeof value === "function") {
1369
+ return {
1370
+ pluginType: "method",
1371
+ name,
1372
+ value,
1373
+ chain: [],
1374
+ ...inputSchema ? { inputSchema } : {},
1375
+ ...meta ? { meta } : {}
1376
+ };
1377
+ }
1378
+ return { pluginType: "property", name, value, ...meta ? { meta } : {} };
1379
+ }
1380
+
1381
+ // src/model/builtins.ts
1382
+ import { z as z2 } from "zod";
1383
+
1384
+ // src/model/registry-support.ts
1385
+ function adaptLegacyFormatter(legacy, sdk) {
1386
+ const legacyFetch = legacy.fetch;
1387
+ return {
1388
+ getContext: legacyFetch ? async ({ items, input, context }) => {
1389
+ let ctx = context;
1390
+ for (const item of items) {
1391
+ ctx = await legacyFetch(sdk, input, item, ctx);
1392
+ }
1393
+ return ctx;
1394
+ } : void 0,
1395
+ format: ({ item, context }) => legacy.format(item, context)
1396
+ };
1397
+ }
1398
+ function normalizeFormatter(entry, sdk) {
1399
+ if (entry.pluginType !== "method") return void 0;
1400
+ if (entry.formatter) return entry.formatter;
1401
+ const legacy = entry.meta?.formatter;
1402
+ return legacy ? adaptLegacyFormatter(legacy, sdk) : void 0;
1403
+ }
1404
+ function normalizeBoundResolvers(entry) {
1405
+ if (entry.pluginType !== "method") return void 0;
1406
+ return entry.resolvers;
1407
+ }
1408
+ function methodPositional(entry) {
1409
+ if (entry.pluginType !== "method") return void 0;
1410
+ return entry.positional;
1411
+ }
1412
+ function pluginEntryMeta(entry) {
1413
+ if (entry.pluginType === "method" && entry.meta) {
1414
+ return entry.inputSchema ? { ...entry.meta, inputSchema: entry.inputSchema } : entry.meta;
1415
+ }
1416
+ if (entry.pluginType === "property" && entry.meta) return entry.meta;
1417
+ return void 0;
1418
+ }
1419
+ function buildSurfaceRegistry(context, packageFilter) {
1420
+ const meta = {};
1421
+ const surface = {};
1422
+ const entries = {};
1423
+ for (const [binding, id] of Object.entries(context.surface)) {
1424
+ const entry = context.plugins[id];
1425
+ if (!entry || entry.pluginType === "aggregate") continue;
1426
+ surface[binding] = entry.value;
1427
+ entries[binding] = entry;
1428
+ const m = pluginEntryMeta(entry);
1429
+ if (m) meta[binding] = m;
1430
+ }
1431
+ const formatters = {};
1432
+ const boundResolvers = {};
1433
+ const positional = {};
1434
+ for (const [binding, entry] of Object.entries(entries)) {
1435
+ const f = normalizeFormatter(entry, surface);
1436
+ if (f) formatters[binding] = f;
1437
+ const r = normalizeBoundResolvers(entry);
1438
+ if (r) boundResolvers[binding] = r;
1439
+ const p = methodPositional(entry);
1440
+ if (p) positional[binding] = p;
1441
+ }
1442
+ return buildRegistry({
1443
+ sdk: surface,
1444
+ meta,
1445
+ formatters,
1446
+ boundResolvers,
1447
+ positional,
1448
+ packageFilter
1449
+ });
1450
+ }
1451
+
1452
+ // src/model/builtins.ts
1453
+ var dangerousContextPlugin = {
1454
+ pluginType: "property",
1455
+ name: "context",
1456
+ namespace: "kitcore",
1457
+ id: "kitcore/context",
1458
+ imports: [],
1459
+ importBindings: [],
1460
+ privileged: true
1461
+ };
1462
+ var getRegistryPlugin = defineMethod({
1463
+ name: "getRegistry",
1464
+ namespace: "kitcore",
1465
+ imports: [dangerousContextPlugin],
1466
+ inputSchema: z2.object({ package: z2.string().optional() }).optional(),
1467
+ run: ({ imports, input }) => buildSurfaceRegistry(imports.context, input?.package)
1468
+ });
1469
+
1470
+ // src/model/materialize.ts
1471
+ function normalizeOutput(output) {
1472
+ if (output === void 0) return { type: "raw" };
1473
+ if (typeof output === "string") return { type: output };
1474
+ return output;
1475
+ }
1476
+ var CONTEXT = Symbol("kitcore.context");
1477
+ function getContext(sdk) {
1478
+ return sdk[CONTEXT];
1479
+ }
1480
+ function isResolverRef(value) {
1481
+ return "ref" in value;
1482
+ }
1483
+ function nestedResolvers(resolver) {
1484
+ const out = [];
1485
+ if (resolver.type === "object") {
1486
+ for (const field of Object.values(resolver.properties ?? {})) {
1487
+ if (!isResolverRef(field.resolver)) out.push(field.resolver);
1488
+ }
1489
+ out.push(...Object.values(resolver.definitions ?? {}));
1490
+ } else if (resolver.type === "array") {
1491
+ if (!isResolverRef(resolver.items)) out.push(resolver.items);
1492
+ out.push(...Object.values(resolver.definitions ?? {}));
1493
+ }
1494
+ return out;
1495
+ }
1496
+ function resolverImportEdges(resolver) {
1497
+ const out = [...resolver.imports];
1498
+ for (const child of nestedResolvers(resolver)) {
1499
+ out.push(...resolverImportEdges(child));
1500
+ }
1501
+ return out;
1502
+ }
1503
+ function methodAttachmentEdges(plugin) {
1504
+ const out = [];
1505
+ if (plugin.resolvers) {
1506
+ for (const resolver of Object.values(plugin.resolvers)) {
1507
+ out.push(...resolverImportEdges(resolver));
1508
+ }
1509
+ }
1510
+ if (plugin.formatter) out.push(...plugin.formatter.imports);
1511
+ return out;
1512
+ }
1513
+ function edgesOf(plugin) {
1514
+ if (plugin.pluginType === "aggregate") {
1515
+ return [...Object.values(plugin.exports), ...plugin.imports];
1516
+ }
1517
+ if (plugin.pluginType === "method") {
1518
+ return [...plugin.imports, ...methodAttachmentEdges(plugin)];
1519
+ }
1520
+ return plugin.imports;
1521
+ }
1522
+ function isStandIn(plugin) {
1523
+ return (plugin.pluginType === "method" || plugin.pluginType === "property" || plugin.pluginType === "aggregate") && plugin.standIn === true;
1524
+ }
1525
+ function topoOrder(descriptors) {
1526
+ const order = [];
1527
+ const visited = /* @__PURE__ */ new Set();
1528
+ const visit = (id) => {
1529
+ if (visited.has(id)) return;
1530
+ visited.add(id);
1531
+ const descriptor = descriptors.get(id);
1532
+ if (descriptor) for (const edge of edgesOf(descriptor)) visit(edge.id);
1533
+ order.push(id);
1534
+ };
1535
+ for (const id of descriptors.keys()) visit(id);
1536
+ return order;
1537
+ }
1538
+ function collectPlugins(root, materialized = /* @__PURE__ */ new Set()) {
1539
+ const byId = /* @__PURE__ */ new Map();
1540
+ const visit = (plugin) => {
1541
+ if (materialized.has(plugin.id)) return;
1542
+ const existing = byId.get(plugin.id);
1543
+ if (existing === plugin) return;
1544
+ if (existing) {
1545
+ const bothReal = !isStandIn(existing) && !isStandIn(plugin);
1546
+ if (bothReal) {
1547
+ throw new Error(
1548
+ `createSdk: duplicate plugin id "${plugin.id}". Two different plugins registered under the same id.`
1549
+ );
1550
+ }
1551
+ if (isStandIn(existing) && !isStandIn(plugin)) {
1552
+ byId.set(plugin.id, plugin);
1553
+ for (const edge of edgesOf(plugin)) visit(edge);
1554
+ }
1555
+ return;
1556
+ }
1557
+ byId.set(plugin.id, plugin);
1558
+ for (const edge of edgesOf(plugin)) visit(edge);
1559
+ };
1560
+ visit(root);
1561
+ for (const [id, plugin] of byId) {
1562
+ if (isStandIn(plugin)) {
1563
+ throw new Error(
1564
+ `createSdk: missing dependency "${id}". A plugin depends on it (via a stand-in) but no implementation was registered.`
1565
+ );
1566
+ }
1567
+ }
1568
+ return byId;
1569
+ }
1570
+ function bindValue(target, key2, entry) {
1571
+ if (entry.pluginType === "property" && entry.getValue) {
1572
+ Object.defineProperty(target, key2, {
1573
+ get: entry.getValue,
1574
+ enumerable: true,
1575
+ configurable: true
1576
+ });
1577
+ } else {
1578
+ Object.defineProperty(target, key2, {
1579
+ value: entry.value,
1580
+ writable: true,
1581
+ enumerable: true,
1582
+ configurable: true
1583
+ });
1584
+ }
1585
+ }
1586
+ function buildSurface(context, ...maps) {
1587
+ const sdk = {};
1588
+ for (const map of maps) {
1589
+ Object.defineProperties(sdk, Object.getOwnPropertyDescriptors(map));
1590
+ }
1591
+ sdk.context = context;
1592
+ sdk[CONTEXT] = context;
1593
+ return sdk;
1594
+ }
1595
+ function buildImports(plugins, importBindings) {
1596
+ const imports = {};
1597
+ for (const { binding, id } of importBindings) {
1598
+ bindValue(imports, binding, plugins[id]);
1599
+ }
1600
+ return imports;
1601
+ }
1602
+ function mirrorLegacyRootKeys(context, rootKeys, meta) {
1603
+ const exports = {};
1604
+ for (const [name, value] of Object.entries(rootKeys)) {
1605
+ context.plugins[name] = legacyGraphEntry(name, value, meta[name]);
1606
+ exports[name] = value;
1607
+ }
1608
+ return exports;
1609
+ }
1610
+ function recordExportSurface(context, exports) {
1611
+ for (const [binding, child] of Object.entries(exports)) {
1612
+ context.surface[binding] = child.id;
1613
+ }
1614
+ }
1615
+ function materialize(descriptors, context) {
1616
+ const states = /* @__PURE__ */ new Map();
1617
+ runLegacyPass(descriptors, context);
1618
+ buildMethodEntries(descriptors, context, states);
1619
+ buildEagerArtifacts(descriptors, context, states);
1620
+ bindAttachments(descriptors, context);
1621
+ resolveAggregates(descriptors, context);
1622
+ assembleMiddleware(descriptors, context);
1623
+ return context.plugins;
1624
+ }
1625
+ function bindResolver(resolver, plugins) {
1626
+ switch (resolver.type) {
1627
+ case "static":
1628
+ return {
1629
+ type: "static",
1630
+ requireParameters: resolver.requireParameters,
1631
+ inputType: resolver.inputType,
1632
+ placeholder: resolver.placeholder
1633
+ };
1634
+ case "constant":
1635
+ return {
1636
+ type: "constant",
1637
+ value: resolver.value,
1638
+ requireParameters: resolver.requireParameters
1639
+ };
1640
+ case "info":
1641
+ return { type: "info", text: resolver.text };
1642
+ case "object": {
1643
+ const imports = buildImports(plugins, resolver.importBindings);
1644
+ const bound = {
1645
+ type: "object",
1646
+ requireParameters: resolver.requireParameters
1647
+ };
1648
+ if (resolver.properties)
1649
+ bound.properties = bindFields(resolver.properties, plugins);
1650
+ if (resolver.definitions)
1651
+ bound.definitions = bindDefinitions(resolver.definitions, plugins);
1652
+ const { getProperties } = resolver;
1653
+ if (getProperties)
1654
+ bound.getProperties = ({ input }) => getProperties({ imports, input });
1655
+ return bound;
1656
+ }
1657
+ case "array": {
1658
+ const bound = {
1659
+ type: "array",
1660
+ requireParameters: resolver.requireParameters,
1661
+ minItems: resolver.minItems,
1662
+ maxItems: resolver.maxItems,
1663
+ itemValueType: resolver.itemValueType,
1664
+ items: isResolverRef(resolver.items) ? resolver.items : bindResolver(resolver.items, plugins)
1665
+ };
1666
+ if (resolver.definitions)
1667
+ bound.definitions = bindDefinitions(resolver.definitions, plugins);
1668
+ return bound;
1669
+ }
1670
+ default: {
1671
+ const imports = buildImports(plugins, resolver.importBindings);
1672
+ const bound = {
1673
+ type: "dynamic",
1674
+ requireParameters: resolver.requireParameters,
1675
+ inputType: resolver.inputType,
1676
+ placeholder: resolver.placeholder,
1677
+ prompt: resolver.prompt
1678
+ };
1679
+ const {
1680
+ getContext: getContext2,
1681
+ listItems,
1682
+ tryResolveWithoutPrompt,
1683
+ tryResolveFromSearch
1684
+ } = resolver;
1685
+ if (getContext2)
1686
+ bound.getContext = ({ input }) => getContext2({ imports, input });
1687
+ if (listItems)
1688
+ bound.listItems = ({ input, context, search, cursor }) => listItems({ imports, input, context, search, cursor });
1689
+ if (tryResolveWithoutPrompt) {
1690
+ bound.tryResolveWithoutPrompt = ({ input }) => tryResolveWithoutPrompt({ imports, input });
1691
+ }
1692
+ if (tryResolveFromSearch) {
1693
+ bound.tryResolveFromSearch = ({ input, search }) => tryResolveFromSearch({ imports, input, search });
1694
+ }
1695
+ return bound;
1696
+ }
1697
+ }
1698
+ }
1699
+ function bindFields(fields, plugins) {
1700
+ const out = {};
1701
+ for (const [key2, field] of Object.entries(fields)) {
1702
+ out[key2] = {
1703
+ ...field,
1704
+ resolver: isResolverRef(field.resolver) ? field.resolver : bindResolver(field.resolver, plugins)
1705
+ };
1706
+ }
1707
+ return out;
1708
+ }
1709
+ function bindDefinitions(definitions, plugins) {
1710
+ const out = {};
1711
+ for (const [key2, def] of Object.entries(definitions)) {
1712
+ out[key2] = bindResolver(def, plugins);
1713
+ }
1714
+ return out;
1715
+ }
1716
+ function bindFormatter(formatter, plugins) {
1717
+ const imports = buildImports(plugins, formatter.importBindings);
1718
+ const bound = { format: formatter.format };
1719
+ const { getContext: getContext2 } = formatter;
1720
+ if (getContext2)
1721
+ bound.getContext = ({ items, input, context }) => getContext2({ imports, items, input, context });
1722
+ return bound;
1723
+ }
1724
+ function bindAttachments(descriptors, context) {
1725
+ const plugins = context.plugins;
1726
+ for (const [id, descriptor] of descriptors) {
1727
+ if (descriptor.pluginType !== "method") continue;
1728
+ const entry = plugins[id];
1729
+ if (!entry || entry.pluginType !== "method") continue;
1730
+ if (descriptor.resolvers) {
1731
+ const bound = {};
1732
+ for (const [param, resolver] of Object.entries(descriptor.resolvers)) {
1733
+ bound[param] = bindResolver(resolver, plugins);
1734
+ }
1735
+ entry.resolvers = bound;
1736
+ }
1737
+ if (descriptor.formatter) {
1738
+ entry.formatter = bindFormatter(descriptor.formatter, plugins);
1739
+ }
1740
+ }
1741
+ }
1742
+ function runLegacyPass(descriptors, context) {
1743
+ const plugins = context.plugins;
1744
+ const compatView = new Proxy(
1745
+ {},
1746
+ {
1747
+ get: (_target, prop) => {
1748
+ if (prop === "context") return context;
1749
+ const entry = plugins[prop];
1750
+ return entry?.value;
1751
+ }
1752
+ }
1753
+ );
1754
+ for (const id of topoOrder(descriptors)) {
1755
+ const descriptor = descriptors.get(id);
1756
+ if (!descriptor || descriptor.pluginType !== "legacy") continue;
1757
+ const { rootKeys, meta, hooks, contextRest } = splitPluginContribution(
1758
+ descriptor.run(compatView)
1759
+ );
1760
+ Object.assign(context.meta, meta);
1761
+ Object.assign(context, contextRest);
1762
+ context.hooks = buildHooks(context.hooks, hooks);
1763
+ const exports = mirrorLegacyRootKeys(context, rootKeys, meta);
1764
+ if (!("getRegistry" in exports)) {
1765
+ let getRegistry2 = function(options) {
1766
+ const sdk = this ?? exports;
1767
+ const meta2 = {};
1768
+ const formatters = {};
1769
+ const boundResolvers = {};
1770
+ for (const [binding, id2] of Object.entries(context.surface)) {
1771
+ const entry = context.plugins[id2];
1772
+ if (!entry || entry.pluginType === "aggregate") continue;
1773
+ const m = pluginEntryMeta(entry);
1774
+ if (m) meta2[binding] = m;
1775
+ const f = normalizeFormatter(entry, sdk);
1776
+ if (f) formatters[binding] = f;
1777
+ const r = normalizeBoundResolvers(entry);
1778
+ if (r) boundResolvers[binding] = r;
1779
+ }
1780
+ Object.assign(meta2, context.meta);
1781
+ return buildRegistry({
1782
+ sdk,
1783
+ meta: meta2,
1784
+ formatters,
1785
+ boundResolvers,
1786
+ packageFilter: options?.package
1787
+ });
1788
+ };
1789
+ var getRegistry = getRegistry2;
1790
+ exports.getRegistry = getRegistry2;
1791
+ plugins.getRegistry = {
1792
+ pluginType: "method",
1793
+ name: "getRegistry",
1794
+ value: getRegistry2,
1795
+ chain: []
1796
+ };
1797
+ }
1798
+ plugins[id] = { pluginType: "aggregate", name: descriptor.name, exports };
1799
+ }
1800
+ }
1801
+ function buildMethodEntries(descriptors, context, states) {
1802
+ const plugins = context.plugins;
1803
+ for (const [id, descriptor] of descriptors) {
1804
+ if (descriptor.pluginType !== "method") continue;
1805
+ const out = normalizeOutput(descriptor.output);
1806
+ const entry = {
1807
+ pluginType: "method",
1808
+ name: descriptor.name,
1809
+ chain: [],
1810
+ inputSchema: descriptor.inputSchema,
1811
+ // Derive the presentation type from the output mode when the author did
1812
+ // not set one; an explicit meta.type (e.g. "create") still wins.
1813
+ meta: out.type === "raw" || descriptor.meta?.type ? descriptor.meta : { ...descriptor.meta, type: out.type },
1814
+ output: out,
1815
+ // Replaced below; never called.
1816
+ value: () => void 0
1817
+ };
1818
+ const callRun = (input) => descriptor.run({
1819
+ imports: buildImports(plugins, descriptor.importBindings),
1820
+ state: states.get(id),
1821
+ input
1822
+ });
1823
+ const fold = (coreFn) => (input) => {
1824
+ let next = coreFn;
1825
+ for (const wrap of entry.chain) {
1826
+ const inner = next;
1827
+ next = (i) => wrap.run({
1828
+ imports: buildImports(plugins, wrap.owner.importBindings),
1829
+ next: inner,
1830
+ input: i
1831
+ });
1832
+ }
1833
+ return next(input);
1834
+ };
1835
+ const sdk = { context };
1836
+ if (out.type === "list") {
1837
+ entry.value = createPaginatedFunction(
1838
+ fold(callRun),
1839
+ {
1840
+ sdk,
1841
+ schema: descriptor.inputSchema,
1842
+ name: descriptor.name,
1843
+ defaultPageSize: out.defaultPageSize,
1844
+ adaptPage: out.adaptPage
1845
+ }
1846
+ );
1847
+ } else if (out.type === "item") {
1848
+ const itemCore = async (input) => ({
1849
+ data: await callRun(input)
1850
+ });
1851
+ entry.value = createFunction(
1852
+ fold(itemCore),
1853
+ { sdk, schema: descriptor.inputSchema, name: descriptor.name }
1854
+ );
1855
+ } else {
1856
+ entry.value = (rawInput) => {
1857
+ const input = descriptor.inputSchema ? descriptor.inputSchema.parse(rawInput) : rawInput;
1858
+ return fold(callRun)(input);
1859
+ };
1860
+ }
1861
+ if (descriptor.positional) {
1862
+ const names = descriptor.positional;
1863
+ const canonicalValue = entry.value;
1864
+ entry.value = (...args) => {
1865
+ const packed = {};
1866
+ names.forEach((name, i) => {
1867
+ if (i < args.length) packed[name] = args[i];
1868
+ });
1869
+ return canonicalValue(packed);
1870
+ };
1871
+ entry.positional = names;
1872
+ }
1873
+ plugins[id] = entry;
1874
+ }
1875
+ }
1876
+ function buildEagerArtifacts(descriptors, context, states) {
1877
+ const plugins = context.plugins;
1878
+ const built = /* @__PURE__ */ new Set();
1879
+ const building = /* @__PURE__ */ new Set();
1880
+ const ensureBuilt = (id) => {
1881
+ if (built.has(id)) return;
1882
+ const descriptor = descriptors.get(id);
1883
+ if (!descriptor || descriptor.pluginType === "aggregate" || descriptor.pluginType === "legacy") {
1884
+ built.add(id);
1885
+ return;
1886
+ }
1887
+ if (building.has(id)) {
1888
+ throw new Error(`createSdk: dependency cycle at "${id}".`);
1889
+ }
1890
+ building.add(id);
1891
+ for (const { id: depId } of descriptor.importBindings) ensureBuilt(depId);
1892
+ if (descriptor.pluginType === "method") {
1893
+ states.set(
1894
+ id,
1895
+ descriptor.setup ? descriptor.setup({
1896
+ imports: buildImports(plugins, descriptor.importBindings)
1897
+ }) : void 0
1898
+ );
1899
+ } else {
1900
+ states.set(
1901
+ id,
1902
+ descriptor.setup ? descriptor.setup({
1903
+ imports: buildImports(plugins, descriptor.importBindings)
1904
+ }) : void 0
1905
+ );
1906
+ if (descriptor.privileged) {
1907
+ plugins[id] = {
1908
+ pluginType: "property",
1909
+ name: descriptor.name,
1910
+ value: context,
1911
+ meta: descriptor.meta
1912
+ };
1913
+ } else if (descriptor.get) {
1914
+ const get = descriptor.get;
1915
+ const importBindings = descriptor.importBindings;
1916
+ plugins[id] = {
1917
+ pluginType: "property",
1918
+ name: descriptor.name,
1919
+ getValue: () => get({
1920
+ imports: buildImports(plugins, importBindings),
1921
+ state: states.get(id)
1922
+ }),
1923
+ meta: descriptor.meta
1924
+ };
1925
+ } else {
1926
+ plugins[id] = {
1927
+ pluginType: "property",
1928
+ name: descriptor.name,
1929
+ value: descriptor.value,
1930
+ meta: descriptor.meta
1931
+ };
1932
+ }
1933
+ }
1934
+ building.delete(id);
1935
+ built.add(id);
1936
+ };
1937
+ for (const id of descriptors.keys()) ensureBuilt(id);
1938
+ }
1939
+ function resolveAggregates(descriptors, context) {
1940
+ const plugins = context.plugins;
1941
+ for (const [id, descriptor] of descriptors) {
1942
+ if (descriptor.pluginType !== "aggregate") continue;
1943
+ const exports = {};
1944
+ for (const [binding, child] of Object.entries(descriptor.exports)) {
1945
+ bindValue(exports, binding, plugins[child.id]);
1946
+ }
1947
+ plugins[id] = { pluginType: "aggregate", name: descriptor.name, exports };
1948
+ }
1949
+ }
1950
+ function assembleMiddleware(descriptors, context) {
1951
+ const plugins = context.plugins;
1952
+ for (const id of topoOrder(descriptors)) {
1953
+ const descriptor = descriptors.get(id);
1954
+ if (!descriptor || descriptor.pluginType !== "aggregate" || !descriptor.middleware) {
1955
+ continue;
1956
+ }
1957
+ for (const [targetBinding, fn] of Object.entries(descriptor.middleware)) {
1958
+ const edge = descriptor.importBindings.find(
1959
+ (b) => b.binding === targetBinding
1960
+ );
1961
+ if (!edge) {
1962
+ throw new Error(
1963
+ `createSdk: middleware target "${targetBinding}" in plugin "${id}" is not a direct dependency. A middleware target must be a declared dependency of the wrapping plugin.`
1964
+ );
1965
+ }
1966
+ const target = plugins[edge.id];
1967
+ if (!target || target.pluginType !== "method") {
1968
+ throw new Error(
1969
+ `createSdk: middleware target "${targetBinding}" in plugin "${id}" does not resolve to a method.`
1970
+ );
1971
+ }
1972
+ if (target.output?.type === "list") {
1973
+ throw new Error(
1974
+ `createSdk: middleware target "${targetBinding}" in plugin "${id}" resolves to a list-output method, which does not support middleware yet.`
1975
+ );
1976
+ }
1977
+ target.chain.push({ run: fn, owner: descriptor });
1978
+ }
1979
+ }
1980
+ }
1981
+ function createSdk(root) {
1982
+ const context = { plugins: {}, meta: {}, hooks: {}, surface: {} };
1983
+ if (root.pluginType === "legacy-merge") {
1984
+ const { legacy, plugin } = root;
1985
+ const collectRoot = {
1986
+ pluginType: "aggregate",
1987
+ name: root.name,
1988
+ id: `${root.id}:merge`,
1989
+ imports: [legacy, plugin],
1990
+ importBindings: [],
1991
+ exports: {}
1992
+ };
1993
+ const plugins2 = materialize(collectPlugins(collectRoot), context);
1994
+ const legacyExports = plugins2[legacy.id].exports;
1995
+ let pluginSurface;
1996
+ if (plugin.pluginType === "aggregate") {
1997
+ pluginSurface = plugins2[plugin.id].exports;
1998
+ } else {
1999
+ pluginSurface = {};
2000
+ bindValue(pluginSurface, plugin.name, plugins2[plugin.id]);
2001
+ }
2002
+ for (const key2 of Object.keys(legacyExports)) context.surface[key2] = key2;
2003
+ if (plugin.pluginType === "aggregate") {
2004
+ recordExportSurface(context, plugin.exports);
2005
+ } else {
2006
+ context.surface[plugin.name] = plugin.id;
2007
+ }
2008
+ return buildSurface(context, legacyExports, pluginSurface);
2009
+ }
2010
+ const plugins = materialize(collectPlugins(root), context);
2011
+ if (root.pluginType === "method" || root.pluginType === "property") {
2012
+ context.surface[root.name] = root.id;
2013
+ const sdk = buildSurface(context);
2014
+ bindValue(sdk, root.name, plugins[root.id]);
2015
+ return sdk;
2016
+ }
2017
+ if (root.pluginType === "aggregate")
2018
+ recordExportSurface(context, root.exports);
2019
+ return buildSurface(context, plugins[root.id].exports);
2020
+ }
2021
+ function addModelPlugin(sdk, plugin, options = {}) {
2022
+ const override = options.override === true;
2023
+ const context = getContext(sdk);
2024
+ const surfaceKeys = plugin.pluginType === "aggregate" ? Object.keys(plugin.exports) : [plugin.name];
2025
+ checkRootKeyCollisions(sdk, surfaceKeys, override, "addPlugin");
2026
+ const materialized = new Set(Object.keys(context.plugins));
2027
+ if (override && materialized.has(plugin.id)) {
2028
+ throw new Error(
2029
+ `addPlugin: cannot override already-materialized plugin "${plugin.id}" on the incremental path. Rebuild the SDK with the replacement via createSdk.`
2030
+ );
2031
+ }
2032
+ materialize(collectPlugins(plugin, materialized), context);
2033
+ const entry = context.plugins[plugin.id];
2034
+ if (entry.pluginType === "aggregate") {
2035
+ Object.defineProperties(
2036
+ sdk,
2037
+ Object.getOwnPropertyDescriptors(entry.exports)
2038
+ );
2039
+ for (const [binding, child] of Object.entries(
2040
+ plugin.exports
2041
+ )) {
2042
+ context.surface[binding] = child.id;
2043
+ }
2044
+ } else {
2045
+ bindValue(sdk, plugin.name, entry);
2046
+ context.surface[plugin.name] = plugin.id;
2047
+ }
2048
+ }
2049
+ function addPlugin(sdk, plugin, options) {
2050
+ if (typeof plugin === "function") {
2051
+ const record = sdk;
2052
+ const contribution = applyPluginToSdk(
2053
+ record,
2054
+ plugin,
2055
+ options ?? {}
2056
+ );
2057
+ const context = record[CONTEXT];
2058
+ if (context) {
2059
+ mirrorLegacyRootKeys(context, contribution.rootKeys, contribution.meta);
2060
+ for (const name of Object.keys(contribution.rootKeys)) {
2061
+ context.surface[name] = name;
2062
+ }
2063
+ }
2064
+ return;
2065
+ }
2066
+ addModelPlugin(
2067
+ sdk,
2068
+ plugin,
2069
+ options ?? {}
2070
+ );
2071
+ }
2072
+
2073
+ // src/model/resolution/controller.ts
2074
+ import { z as z4 } from "zod";
2075
+
2076
+ // src/types/signals.ts
2077
+ var CORE_SIGNAL_SYMBOL = Symbol.for("kitcore.signal");
2078
+ var CoreSignal = class extends Error {
2079
+ constructor(message) {
2080
+ super(message);
2081
+ Object.setPrototypeOf(this, new.target.prototype);
2082
+ Object.defineProperty(this, CORE_SIGNAL_SYMBOL, {
2083
+ value: true,
2084
+ enumerable: false,
2085
+ configurable: true,
2086
+ writable: false
2087
+ });
2088
+ }
2089
+ };
2090
+ function isCoreSignal(value) {
2091
+ return Boolean(
2092
+ value && typeof value === "object" && value[CORE_SIGNAL_SYMBOL] === true
2093
+ );
2094
+ }
2095
+ var CoreCancelledSignal = class extends CoreSignal {
2096
+ constructor(message = "resolution cancelled") {
2097
+ super(message);
2098
+ this.name = "CoreCancelledSignal";
2099
+ this.code = "CANCELLED";
2100
+ }
2101
+ };
2102
+
2103
+ // src/model/resolution/plan.ts
2104
+ import { z as z3 } from "zod";
2105
+ function unwrap(schema) {
2106
+ let inner = schema;
2107
+ let required = true;
2108
+ for (; ; ) {
2109
+ if (inner instanceof z3.ZodOptional) {
2110
+ required = false;
2111
+ inner = inner._zod.def.innerType;
2112
+ } else if (inner instanceof z3.ZodDefault) {
2113
+ required = false;
2114
+ inner = inner._zod.def.innerType;
2115
+ } else if (inner instanceof z3.ZodNullable) {
2116
+ inner = inner._zod.def.innerType;
2117
+ } else {
2118
+ break;
2119
+ }
2120
+ }
2121
+ return { inner, required };
2122
+ }
2123
+ function valueTypeOf(inner) {
2124
+ if (inner instanceof z3.ZodString) return "string";
2125
+ if (inner instanceof z3.ZodNumber) return "number";
2126
+ if (inner instanceof z3.ZodBoolean) return "boolean";
2127
+ if (inner instanceof z3.ZodEnum) return "string";
2128
+ if (inner instanceof z3.ZodArray) return "array";
2129
+ if (inner instanceof z3.ZodObject) return "object";
2130
+ return void 0;
2131
+ }
2132
+ function staticChoicesOf(inner) {
2133
+ if (inner instanceof z3.ZodEnum) {
2134
+ const values = inner.options;
2135
+ return values.map((value) => ({ label: value, value }));
2136
+ }
2137
+ return void 0;
2138
+ }
2139
+ function objectShape(schema) {
2140
+ const { inner } = schema ? unwrap(schema) : { inner: void 0 };
2141
+ if (inner instanceof z3.ZodObject) {
2142
+ return inner.shape;
2143
+ }
2144
+ return void 0;
2145
+ }
2146
+ function topoOrder2(specs) {
2147
+ const byName = new Map(specs.map((s) => [s.name, s]));
2148
+ const ordered = [];
2149
+ const placed = /* @__PURE__ */ new Set();
2150
+ let progressed = true;
2151
+ while (ordered.length < specs.length && progressed) {
2152
+ progressed = false;
2153
+ for (const spec of specs) {
2154
+ if (placed.has(spec.name)) continue;
2155
+ const ready = spec.requires.every((r) => !byName.has(r) || placed.has(r));
2156
+ if (ready) {
2157
+ ordered.push(spec);
2158
+ placed.add(spec.name);
2159
+ progressed = true;
2160
+ }
2161
+ }
2162
+ }
2163
+ for (const spec of specs) if (!placed.has(spec.name)) ordered.push(spec);
2164
+ return ordered;
2165
+ }
2166
+ function planParameters(entry) {
2167
+ const shape = objectShape(entry.inputSchema);
2168
+ const resolvers = entry.boundResolvers ?? {};
2169
+ const names = shape ? Object.keys(shape) : Object.keys(resolvers);
2170
+ const specs = names.map((name) => {
2171
+ const field = shape?.[name];
2172
+ const { inner, required } = field ? unwrap(field) : { inner: void 0, required: false };
2173
+ const resolver = resolvers[name];
2174
+ return {
2175
+ name,
2176
+ required,
2177
+ valueType: inner ? valueTypeOf(inner) : void 0,
2178
+ staticChoices: inner ? staticChoicesOf(inner) : void 0,
2179
+ resolver,
2180
+ requires: resolver?.requireParameters ?? []
2181
+ };
2182
+ });
2183
+ return { parameters: topoOrder2(specs) };
2184
+ }
2185
+
2186
+ // src/model/resolution/engine.ts
2187
+ function getAtPath(root, path) {
2188
+ let node = root;
2189
+ for (const seg of path) {
2190
+ if (node == null || typeof node !== "object") return void 0;
2191
+ node = node[seg];
2192
+ }
2193
+ return node;
2194
+ }
2195
+ function setAtPath(root, path, value) {
2196
+ let node = root;
2197
+ for (let i = 0; i < path.length - 1; i++) {
2198
+ const seg = path[i];
2199
+ if (node[seg] == null || typeof node[seg] !== "object") node[seg] = {};
2200
+ node = node[seg];
2201
+ }
2202
+ node[path[path.length - 1]] = value;
2203
+ }
2204
+ var key = (path) => path.join(".");
2205
+ function isSettled(state, path) {
2206
+ return state.settled.includes(key(path));
2207
+ }
2208
+ function settle(state, path) {
2209
+ const k = key(path);
2210
+ if (!state.settled.includes(k)) state.settled.push(k);
2211
+ }
2212
+ function clone(state) {
2213
+ return JSON.parse(JSON.stringify(state));
2214
+ }
2215
+ function coerce(leaf, raw) {
2216
+ if (typeof raw !== "string") return raw;
2217
+ if (leaf.valueType === "number") {
2218
+ const n = Number(raw);
2219
+ return raw.trim() !== "" && !Number.isNaN(n) ? n : raw;
2220
+ }
2221
+ if (leaf.valueType === "boolean") {
2222
+ if (raw === "true") return true;
2223
+ if (raw === "false") return false;
2224
+ }
2225
+ return raw;
2226
+ }
2227
+ async function validationError(leaf, value, state) {
2228
+ const context = await resolveContext(leaf, state.resolved);
2229
+ const config = leaf.resolver?.prompt?.({
2230
+ items: state.listing?.items ?? [],
2231
+ input: mergeInput(state.resolved, leaf.extraInput),
2232
+ context
2233
+ });
2234
+ if (!config?.validate) return null;
2235
+ const verdict = config.validate(value);
2236
+ if (verdict === true) return null;
2237
+ return typeof verdict === "string" ? verdict : `${leaf.name}: invalid value`;
2238
+ }
2239
+ function toChoice(c) {
2240
+ const label = "label" in c ? c.label : c.name;
2241
+ const hint = Array.isArray(c.hint) ? c.hint.join(", ") : c.hint;
2242
+ return { label, value: String(c.value), hint };
2243
+ }
2244
+ function isRef(r) {
2245
+ return typeof r === "object" && r !== null && "ref" in r;
2246
+ }
2247
+ function toLeaf(name, field, definitions) {
2248
+ let resolver;
2249
+ let extraInput;
2250
+ if (isRef(field.resolver)) {
2251
+ resolver = definitions?.[field.resolver.ref];
2252
+ extraInput = field.resolver.input;
2253
+ } else {
2254
+ resolver = field.resolver;
2255
+ }
2256
+ return {
2257
+ name,
2258
+ required: field.required ?? false,
2259
+ resolver,
2260
+ extraInput,
2261
+ // Carry the field's value type so nested answers coerce (number/boolean)
2262
+ // the same way top-level params do. Without this a nested `z.number()`
2263
+ // field's typed answer stays a string and fails final validation.
2264
+ valueType: field.valueType,
2265
+ requires: resolver?.requireParameters ?? []
2266
+ };
2267
+ }
2268
+ async function objectChildren(resolver, input) {
2269
+ if (resolver.properties) {
2270
+ return Object.entries(resolver.properties).map(
2271
+ ([name, field]) => toLeaf(name, field, resolver.definitions)
2272
+ );
2273
+ }
2274
+ if (!resolver.getProperties) return [];
2275
+ const fields = await resolver.getProperties({ input });
2276
+ return Object.entries(fields).map(([name, field]) => {
2277
+ if (!isRef(field.resolver) && (field.resolver.imports?.length ?? 0) > 0) {
2278
+ throw new Error(
2279
+ `dynamic object field "${name}" inlines an import-bearing resolver; use { ref } into the object's definitions so its imports bind`
2280
+ );
2281
+ }
2282
+ return toLeaf(name, field, resolver.definitions);
2283
+ });
2284
+ }
2285
+ function arrayItem(resolver) {
2286
+ const items = resolver.items;
2287
+ const valueType = resolver.itemValueType;
2288
+ if (isRef(items)) {
2289
+ return {
2290
+ name: "",
2291
+ required: true,
2292
+ resolver: resolver.definitions?.[items.ref],
2293
+ extraInput: items.input,
2294
+ valueType,
2295
+ requires: []
2296
+ };
2297
+ }
2298
+ return {
2299
+ name: "",
2300
+ required: true,
2301
+ resolver: items,
2302
+ valueType,
2303
+ requires: []
2304
+ };
2305
+ }
2306
+ function mergeInput(input, extra) {
2307
+ return extra ? { ...input, ...extra } : input;
2308
+ }
2309
+ async function childrenAt(ctx, path, resolved) {
2310
+ if (path.length === 0) return ctx.parameters;
2311
+ const leaf = await leafAt(ctx, path, resolved);
2312
+ if (!leaf?.resolver || leaf.resolver.type !== "object") return [];
2313
+ return objectChildren(leaf.resolver, mergeInput(resolved, leaf.extraInput));
2314
+ }
2315
+ async function leafAt(ctx, path, resolved) {
2316
+ let children = ctx.parameters;
2317
+ let leaf;
2318
+ for (let i = 0; i < path.length; i++) {
2319
+ const seg = path[i];
2320
+ if (typeof seg === "number") {
2321
+ if (leaf?.resolver?.type !== "array") return void 0;
2322
+ leaf = arrayItem(leaf.resolver);
2323
+ } else {
2324
+ leaf = children.find((c) => c.name === seg);
2325
+ if (!leaf) return void 0;
2326
+ }
2327
+ if (i < path.length - 1 && typeof path[i + 1] === "string") {
2328
+ if (leaf?.resolver?.type !== "object") return void 0;
2329
+ children = await objectChildren(
2330
+ leaf.resolver,
2331
+ mergeInput(resolved, leaf.extraInput)
2332
+ );
2333
+ }
2334
+ }
2335
+ return leaf;
2336
+ }
2337
+ async function arrayInfoAt(ctx, path, resolved) {
2338
+ const leaf = await leafAt(ctx, path, resolved);
2339
+ const resolver = leaf?.resolver;
2340
+ if (resolver?.type !== "array") {
2341
+ throw new Error(`expected an array resolver at "${key(path)}"`);
2342
+ }
2343
+ return {
2344
+ min: resolver.minItems ?? 0,
2345
+ max: resolver.maxItems ?? Infinity,
2346
+ item: { ...arrayItem(resolver), name: String(path[path.length - 1]) }
2347
+ };
2348
+ }
2349
+ var AFFORDANCE = {
2350
+ choose: { action: "choose", description: "Pick one of the listed options" },
2351
+ custom: {
2352
+ action: "custom",
2353
+ description: "Provide a value directly",
2354
+ supply: "value"
2355
+ },
2356
+ search: {
2357
+ action: "search",
2358
+ description: "Filter the options by a search term",
2359
+ supply: "term"
2360
+ },
2361
+ more: { action: "more", description: "Load more options" },
2362
+ skip: { action: "skip", description: "Omit this optional parameter" },
2363
+ add: { action: "add", description: "Add another item" },
2364
+ done: { action: "done", description: "Finish the list" },
2365
+ retry: { action: "retry", description: "Retry loading the options" },
2366
+ cancel: { action: "cancel", description: "Cancel resolution" }
2367
+ };
2368
+ async function firstPage(result) {
2369
+ const page = await result;
2370
+ return {
2371
+ data: Array.isArray(page?.data) ? page.data : [],
2372
+ nextCursor: page?.nextCursor
2373
+ };
2374
+ }
2375
+ async function resolveContext(leaf, input) {
2376
+ return leaf.resolver?.getContext?.({
2377
+ input: mergeInput(input, leaf.extraInput)
2378
+ });
2379
+ }
2380
+ async function fetchListing(leaf, input, opts = {}) {
2381
+ const page = await firstPage(
2382
+ leaf.resolver?.listItems?.({
2383
+ input: mergeInput(input, leaf.extraInput),
2384
+ context: opts.context,
2385
+ search: opts.search,
2386
+ cursor: opts.cursor
2387
+ })
2388
+ );
2389
+ return {
2390
+ items: [...opts.priorItems ?? [], ...page.data],
2391
+ cursor: page.nextCursor,
2392
+ search: opts.search,
2393
+ exhausted: page.nextCursor == null
2394
+ };
2395
+ }
2396
+ function selectActions(leaf, listing, multiple) {
2397
+ const actions = multiple ? [AFFORDANCE.choose] : [AFFORDANCE.choose, AFFORDANCE.custom];
2398
+ if (leaf.resolver?.inputType === "search") actions.push(AFFORDANCE.search);
2399
+ if (listing.cursor) actions.push(AFFORDANCE.more);
2400
+ if (!leaf.required) actions.push(AFFORDANCE.skip);
2401
+ return actions;
2402
+ }
2403
+ function selectQuestion(leaf, input, listing, context) {
2404
+ const config = leaf.resolver?.prompt?.({
2405
+ items: listing.items,
2406
+ input: mergeInput(input, leaf.extraInput),
2407
+ context
2408
+ });
2409
+ const multiple = config?.type === "checkbox";
2410
+ return {
2411
+ type: "select",
2412
+ message: config?.message ?? `Select ${leaf.name}:`,
2413
+ choices: (config?.choices ?? []).map(toChoice),
2414
+ ...multiple ? { multiple: true } : {},
2415
+ ...config?.notes?.length ? { notes: config.notes } : {},
2416
+ actions: selectActions(leaf, listing, multiple)
2417
+ };
2418
+ }
2419
+ function toControllerError(error) {
2420
+ if (error instanceof Error) {
2421
+ const code = error.code;
2422
+ return {
2423
+ name: error.name,
2424
+ message: error.message,
2425
+ ...typeof code === "string" ? { code } : {}
2426
+ };
2427
+ }
2428
+ return { name: "Error", message: String(error) };
2429
+ }
2430
+ function failedResult(state, name, error) {
2431
+ return {
2432
+ state,
2433
+ result: {
2434
+ status: "failed",
2435
+ error: toControllerError(error),
2436
+ question: {
2437
+ type: "select",
2438
+ message: `Could not load options for ${name}.`,
2439
+ choices: [],
2440
+ actions: [AFFORDANCE.retry, AFFORDANCE.cancel]
2441
+ }
2442
+ }
2443
+ };
2444
+ }
2445
+ async function buildQuestion(leaf, input) {
2446
+ const optional = !leaf.required;
2447
+ const resolver = leaf.resolver;
2448
+ if (resolver?.listItems) {
2449
+ const context = await resolveContext(leaf, input);
2450
+ const listing = await fetchListing(leaf, input, { context });
2451
+ return {
2452
+ question: selectQuestion(leaf, input, listing, context),
2453
+ listing
2454
+ };
2455
+ }
2456
+ if (leaf.staticChoices) {
2457
+ const actions2 = [AFFORDANCE.choose];
2458
+ if (optional) actions2.push(AFFORDANCE.skip);
2459
+ return {
2460
+ question: {
2461
+ type: "select",
2462
+ message: `Select ${leaf.name}:`,
2463
+ choices: leaf.staticChoices,
2464
+ actions: actions2
2465
+ }
2466
+ };
2467
+ }
2468
+ const inputType = resolver?.inputType && resolver.inputType !== "search" ? resolver.inputType : "text";
2469
+ const actions = [AFFORDANCE.custom];
2470
+ if (optional) actions.push(AFFORDANCE.skip);
2471
+ return {
2472
+ question: {
2473
+ type: "input",
2474
+ message: `Enter ${leaf.name}:`,
2475
+ inputType,
2476
+ placeholder: resolver?.placeholder,
2477
+ actions
2478
+ }
2479
+ };
2480
+ }
2481
+ function finalize(ctx, resolved) {
2482
+ if (!ctx.schema) return { status: "done", value: resolved };
2483
+ const parsed = ctx.schema.safeParse(resolved);
2484
+ if (parsed.success) {
2485
+ return { status: "done", value: parsed.data };
2486
+ }
2487
+ const issues = parsed.error.issues.map((i) => ({
2488
+ parameter: i.path.map(String).join(".") || void 0,
2489
+ message: i.message
2490
+ }));
2491
+ return { status: "invalid", issues };
2492
+ }
2493
+ function collectionQuestion(t) {
2494
+ const actions = [AFFORDANCE.add];
2495
+ if (t.count >= t.min) actions.push(AFFORDANCE.done);
2496
+ return {
2497
+ type: "collection",
2498
+ message: `Add another ${t.path[t.path.length - 1]}? (${t.count} so far)`,
2499
+ count: t.count,
2500
+ min: t.min,
2501
+ // An unbounded array's max is Infinity, which JSON.stringify turns to null;
2502
+ // omit it so the question round-trips across the wall as plain data.
2503
+ ...Number.isFinite(t.max) ? { max: t.max } : {},
2504
+ actions
2505
+ };
2506
+ }
2507
+ async function findInArray(ctx, state, path) {
2508
+ if (isSettled(state, path)) return null;
2509
+ if (getAtPath(state.resolved, path) == null)
2510
+ setAtPath(state.resolved, path, []);
2511
+ if (!state.interactive) {
2512
+ settle(state, path);
2513
+ return null;
2514
+ }
2515
+ const { min, max, item } = await arrayInfoAt(ctx, path, state.resolved);
2516
+ const items = getAtPath(state.resolved, path);
2517
+ const len = items.length;
2518
+ const itemType = item.resolver?.type;
2519
+ if (len > 0 && (itemType === "object" || itemType === "array")) {
2520
+ const inner = await findNext(ctx, state, [...path, len - 1]);
2521
+ if (inner) return inner;
2522
+ }
2523
+ if (len < min) return descendItem(ctx, state, path, len, item);
2524
+ if (len < max) return { kind: "array", path, count: len, min, max };
2525
+ settle(state, path);
2526
+ return null;
2527
+ }
2528
+ function seedItemSlot(state, itemPath, item) {
2529
+ const type = item.resolver?.type;
2530
+ if (type === "object") {
2531
+ setAtPath(state.resolved, itemPath, {});
2532
+ return "object";
2533
+ }
2534
+ if (type === "array") {
2535
+ setAtPath(state.resolved, itemPath, []);
2536
+ return "array";
2537
+ }
2538
+ return "leaf";
2539
+ }
2540
+ async function descendItem(ctx, state, arrayPath, index, item) {
2541
+ const itemPath = [...arrayPath, index];
2542
+ const kind = seedItemSlot(state, itemPath, item);
2543
+ if (kind === "object") return findNext(ctx, state, itemPath);
2544
+ if (kind === "array") return findInArray(ctx, state, itemPath);
2545
+ return { kind: "leaf", path: itemPath, leaf: item };
2546
+ }
2547
+ async function findNext(ctx, state, path = []) {
2548
+ const container = getAtPath(state.resolved, path) ?? {};
2549
+ for (const leaf of await childrenAt(ctx, path, state.resolved)) {
2550
+ const childPath = [...path, leaf.name];
2551
+ if (!leaf.requires.every((r) => container[r] !== void 0)) continue;
2552
+ if (leaf.resolver?.type === "object") {
2553
+ if (getAtPath(state.resolved, childPath) == null)
2554
+ setAtPath(state.resolved, childPath, {});
2555
+ const inner = await findNext(ctx, state, childPath);
2556
+ if (inner) return inner;
2557
+ continue;
2558
+ }
2559
+ if (leaf.resolver?.type === "array") {
2560
+ const inner = await findInArray(ctx, state, childPath);
2561
+ if (inner) return inner;
2562
+ continue;
2563
+ }
2564
+ if (container[leaf.name] !== void 0 || isSettled(state, childPath))
2565
+ continue;
2566
+ return { kind: "leaf", path: childPath, leaf };
2567
+ }
2568
+ return null;
2569
+ }
2570
+ async function askLeaf(state, path, leaf, opts = {}) {
2571
+ state.current = path;
2572
+ try {
2573
+ const { question, listing } = await buildQuestion(leaf, state.resolved);
2574
+ state.listing = listing;
2575
+ return {
2576
+ state,
2577
+ result: {
2578
+ status: "ask",
2579
+ question,
2580
+ ...opts.error ? { error: opts.error } : {}
2581
+ }
2582
+ };
2583
+ } catch (error) {
2584
+ state.listing = { items: [], exhausted: false };
2585
+ return failedResult(state, leaf.name, error);
2586
+ }
2587
+ }
2588
+ async function advance(ctx, state) {
2589
+ for (; ; ) {
2590
+ const target = await findNext(ctx, state);
2591
+ if (!target) {
2592
+ delete state.current;
2593
+ delete state.listing;
2594
+ return { state, result: finalize(ctx, state.resolved) };
2595
+ }
2596
+ if (target.kind === "array") {
2597
+ state.current = target.path;
2598
+ delete state.listing;
2599
+ return {
2600
+ state,
2601
+ result: { status: "ask", question: collectionQuestion(target) }
2602
+ };
2603
+ }
2604
+ const { path, leaf } = target;
2605
+ const auto = await leaf.resolver?.tryResolveWithoutPrompt?.({
2606
+ input: mergeInput(state.resolved, leaf.extraInput)
2607
+ });
2608
+ if (auto) {
2609
+ if (auto.resolvedValue !== void 0)
2610
+ setAtPath(state.resolved, path, auto.resolvedValue);
2611
+ settle(state, path);
2612
+ continue;
2613
+ }
2614
+ if (!state.interactive) {
2615
+ if (!leaf.required) {
2616
+ settle(state, path);
2617
+ continue;
2618
+ }
2619
+ } else if (!leaf.required && !leaf.resolver) {
2620
+ settle(state, path);
2621
+ continue;
2622
+ }
2623
+ return askLeaf(state, path, leaf);
2624
+ }
2625
+ }
2626
+ async function start(ctx, input = {}, interactive = true) {
2627
+ const resolved = {};
2628
+ for (const spec of ctx.parameters) {
2629
+ if (spec.resolver?.type === "constant")
2630
+ resolved[spec.name] = spec.resolver.value;
2631
+ }
2632
+ Object.assign(resolved, input);
2633
+ return advance(ctx, {
2634
+ method: ctx.method,
2635
+ resolved,
2636
+ settled: [],
2637
+ interactive
2638
+ });
2639
+ }
2640
+ async function step(ctx, prior, action) {
2641
+ const state = clone(prior);
2642
+ if (action.type === "cancel") {
2643
+ delete state.current;
2644
+ delete state.listing;
2645
+ return { state, result: { status: "cancelled" } };
2646
+ }
2647
+ const path = state.current;
2648
+ if (!path) throw new Error("step called with no outstanding question");
2649
+ const leaf = await leafAt(ctx, path, state.resolved);
2650
+ if (leaf && (action.type === "search" || action.type === "more" || action.type === "retry")) {
2651
+ return refine(ctx, state, leaf, path, action);
2652
+ }
2653
+ if (action.type === "add" || action.type === "done") {
2654
+ delete state.current;
2655
+ delete state.listing;
2656
+ if (action.type === "done") {
2657
+ settle(state, path);
2658
+ return advance(ctx, state);
2659
+ }
2660
+ const items = getAtPath(state.resolved, path) ?? [];
2661
+ const { item } = await arrayInfoAt(ctx, path, state.resolved);
2662
+ const itemPath = [...path, items.length];
2663
+ if (seedItemSlot(state, itemPath, item) === "leaf")
2664
+ return askLeaf(state, itemPath, item);
2665
+ return advance(ctx, state);
2666
+ }
2667
+ switch (action.type) {
2668
+ case "choose":
2669
+ case "custom": {
2670
+ if (leaf) {
2671
+ const error = await validationError(leaf, action.value, state);
2672
+ if (error) return askLeaf(state, path, leaf, { error });
2673
+ }
2674
+ setAtPath(
2675
+ state.resolved,
2676
+ path,
2677
+ leaf ? coerce(leaf, action.value) : action.value
2678
+ );
2679
+ break;
2680
+ }
2681
+ case "skip":
2682
+ settle(state, path);
2683
+ break;
2684
+ default:
2685
+ throw new Error(`action "${action.type}" is not supported here`);
2686
+ }
2687
+ delete state.current;
2688
+ delete state.listing;
2689
+ return advance(ctx, state);
2690
+ }
2691
+ async function refine(ctx, state, leaf, path, action) {
2692
+ const attempt = action.type === "search" ? { search: action.term, cursor: void 0, priorItems: [] } : {
2693
+ search: state.listing?.search,
2694
+ cursor: state.listing?.cursor,
2695
+ priorItems: state.listing?.items ?? []
2696
+ };
2697
+ try {
2698
+ if (action.type === "search") {
2699
+ const exact = await leaf.resolver?.tryResolveFromSearch?.({
2700
+ input: mergeInput(state.resolved, leaf.extraInput),
2701
+ search: action.term
2702
+ });
2703
+ if (exact) {
2704
+ setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
2705
+ delete state.current;
2706
+ delete state.listing;
2707
+ return advance(ctx, state);
2708
+ }
2709
+ }
2710
+ const context = await resolveContext(leaf, state.resolved);
2711
+ state.listing = await fetchListing(leaf, state.resolved, {
2712
+ ...attempt,
2713
+ context
2714
+ });
2715
+ return {
2716
+ state,
2717
+ result: {
2718
+ status: "ask",
2719
+ question: selectQuestion(leaf, state.resolved, state.listing, context)
2720
+ }
2721
+ };
2722
+ } catch (error) {
2723
+ state.listing = {
2724
+ items: attempt.priorItems,
2725
+ search: attempt.search,
2726
+ cursor: attempt.cursor,
2727
+ exhausted: false
2728
+ };
2729
+ return failedResult(state, leaf.name, error);
2730
+ }
2731
+ }
2732
+
2733
+ // src/model/resolution/controller.ts
2734
+ function toJsonSchema(schema) {
2735
+ if (!schema) return void 0;
2736
+ try {
2737
+ return z4.toJSONSchema(schema);
2738
+ } catch {
2739
+ return void 0;
2740
+ }
2741
+ }
2742
+ function projectSummary(entry) {
2743
+ return {
2744
+ name: entry.name,
2745
+ ...entry.description ? { description: entry.description } : {},
2746
+ ...entry.categories?.length ? { categories: entry.categories } : {}
2747
+ };
2748
+ }
2749
+ function projectMethod(entry) {
2750
+ const inputProperties = toJsonSchema(entry.inputSchema)?.properties;
2751
+ const parameters = {};
2752
+ for (const spec of planParameters(entry).parameters) {
2753
+ parameters[spec.name] = {
2754
+ required: spec.required,
2755
+ dynamic: Boolean(spec.resolver?.listItems),
2756
+ ...spec.resolver?.inputType === "search" ? { searchable: true } : {},
2757
+ ...inputProperties?.[spec.name] ? { schema: inputProperties[spec.name] } : {},
2758
+ ...spec.staticChoices ? { choices: spec.staticChoices } : {},
2759
+ ...spec.requires.length ? { requireParameters: spec.requires } : {}
2760
+ };
2761
+ }
2762
+ const output = toJsonSchema(entry.outputSchema);
2763
+ return {
2764
+ name: entry.name,
2765
+ ...entry.description ? { description: entry.description } : {},
2766
+ ...entry.categories?.length ? { categories: entry.categories } : {},
2767
+ parameters,
2768
+ ...entry.positional?.length ? { positional: entry.positional } : {},
2769
+ ...output ? { output } : {}
2770
+ };
2771
+ }
2772
+ function createController(sdk) {
2773
+ function entryFor(method) {
2774
+ const entry = sdk.getRegistry().functions.find((f) => f.name === method);
2775
+ if (!entry) throw new Error(`unknown method "${method}"`);
2776
+ return entry;
2777
+ }
2778
+ function contextFor(method) {
2779
+ const entry = entryFor(method);
2780
+ return {
2781
+ method,
2782
+ schema: entry.inputSchema,
2783
+ parameters: planParameters(entry).parameters
2784
+ };
2785
+ }
2786
+ const start2 = ({ method, input, interactive }) => start(contextFor(method), input, interactive);
2787
+ const step2 = ({ state, action }) => step(contextFor(state.method), state, action);
2788
+ const resolve = async ({
2789
+ method,
2790
+ input,
2791
+ answer,
2792
+ interactive
2793
+ }) => {
2794
+ const ctx = contextFor(method);
2795
+ let { state, result } = await start(ctx, input, interactive);
2796
+ while (result.status === "ask" || result.status === "failed") {
2797
+ const action = await answer({ state, result });
2798
+ ({ state, result } = await step(ctx, state, action));
2799
+ }
2800
+ if (result.status === "done") return result.value;
2801
+ if (result.status === "cancelled") {
2802
+ throw new CoreCancelledSignal(`resolution cancelled for "${method}"`);
2803
+ }
2804
+ const detail = result.issues.map((i) => i.parameter ? `${i.parameter}: ${i.message}` : i.message).join("; ");
2805
+ throw new Error(`invalid input for "${method}": ${detail}`);
2806
+ };
2807
+ const listMethods = () => ({
2808
+ data: sdk.getRegistry().functions.map(projectSummary)
2809
+ });
2810
+ const getMethod = ({ method }) => ({
2811
+ data: projectMethod(entryFor(method))
2812
+ });
2813
+ const listChoices = async ({
2814
+ method,
2815
+ parameter,
2816
+ input = {},
2817
+ search,
2818
+ cursor
2819
+ }) => {
2820
+ const spec = contextFor(method).parameters.find(
2821
+ (p) => p.name === parameter
2822
+ );
2823
+ if (!spec?.resolver?.listItems) return { data: [] };
2824
+ const context = await spec.resolver.getContext?.({ input });
2825
+ const page = await firstPage(
2826
+ spec.resolver.listItems({ input, context, search, cursor })
2827
+ );
2828
+ const config = spec.resolver.prompt?.({ items: page.data, input, context });
2829
+ const data = (config?.choices ?? []).map(toChoice);
2830
+ return { data, nextCursor: page.nextCursor };
2831
+ };
2832
+ return { resolve, start: start2, step: step2, listMethods, getMethod, listChoices };
2833
+ }
2834
+
2835
+ // src/utils/core-plugin.ts
2836
+ function createCorePlugin(options) {
2837
+ return () => ({
2838
+ context: {
2839
+ core: options
2840
+ }
2841
+ });
2842
+ }
2843
+
2844
+ // src/utils/schema-utils.ts
2845
+ import { z as z5 } from "zod";
2846
+ function getOutputSchema(inputSchema) {
2847
+ return inputSchema._zod.def.outputSchema;
2848
+ }
2849
+ function withOutputSchema(inputSchema, outputSchema) {
2850
+ Object.assign(inputSchema._zod.def, {
2851
+ outputSchema
2852
+ });
2853
+ return inputSchema;
2854
+ }
2855
+ function withResolver(schema, config) {
2856
+ schema._zod.def.resolverMeta = config;
2857
+ return schema;
2858
+ }
2859
+ function getSchemaDescription(schema) {
2860
+ return schema.description;
2861
+ }
2862
+ function getFieldDescriptions(schema) {
2863
+ const descriptions = {};
2864
+ const shape = schema.shape;
2865
+ for (const [key2, fieldSchema] of Object.entries(shape)) {
2866
+ if (fieldSchema instanceof z5.ZodType && fieldSchema.description) {
2867
+ descriptions[key2] = fieldSchema.description;
2868
+ }
2869
+ }
2870
+ return descriptions;
2871
+ }
2872
+ function withPositional(schema) {
2873
+ Object.assign(schema._zod.def, {
2874
+ positionalMeta: { positional: true }
2875
+ });
2876
+ return schema;
2877
+ }
2878
+ function schemaHasPositionalMeta(schema) {
2879
+ return "positionalMeta" in schema._zod.def;
2880
+ }
2881
+ function isPositional(schema) {
2882
+ if (schemaHasPositionalMeta(schema) && schema._zod.def.positionalMeta?.positional) {
2883
+ return true;
2884
+ }
2885
+ if (schema instanceof z5.ZodOptional) {
2886
+ return isPositional(schema._zod.def.innerType);
2887
+ }
2888
+ if (schema instanceof z5.ZodDefault) {
2889
+ return isPositional(schema._zod.def.innerType);
2890
+ }
2891
+ return false;
2892
+ }
2893
+ function openEnum(values, description) {
2894
+ return z5.union([z5.enum(values), z5.string()]).describe(description);
2895
+ }
2896
+ export {
2897
+ CONTEXT,
2898
+ CORE_ERROR_SYMBOL,
2899
+ CORE_SIGNAL_SYMBOL,
2900
+ CoreCancelledSignal,
2901
+ CoreError,
2902
+ CoreErrorCode,
2903
+ CoreSignal,
2904
+ addPlugin,
2905
+ composePlugins,
2906
+ concatPaginated,
2907
+ createAsyncContext,
2908
+ createController,
2909
+ createCoreError,
2910
+ createCorePlugin,
2911
+ createDeprecationLogger,
2912
+ createFunction,
2913
+ createPaginatedFunction,
2914
+ createPaginatedPluginMethod,
2915
+ createPluginMethod,
2916
+ createPluginStack,
2917
+ createPrefixedCursor,
2918
+ createSdk,
2919
+ createValidator,
2920
+ dangerousContextPlugin,
2921
+ declareMethod,
2922
+ declarePlugin,
2923
+ declareProperty,
2924
+ decodeIncomingCursor,
2925
+ defineFormatter,
2926
+ defineLegacyMerge,
2927
+ defineMethod,
2928
+ definePlugin,
2929
+ defineProperty,
2930
+ defineResolver,
2931
+ fromFunctionPlugin,
2932
+ getContext,
2933
+ getCoreErrorCause,
2934
+ getCoreErrorCode,
2935
+ getCurrentDepth,
2936
+ getCurrentScope,
2937
+ getFieldDescriptions,
2938
+ getOutputSchema,
2939
+ getRegistryPlugin,
2940
+ getSchemaDescription,
2941
+ isCoreError,
2942
+ isCoreSignal,
2943
+ isNestedMethodCall,
2944
+ isPositional,
2945
+ isTelemetryNested,
2946
+ openEnum,
2947
+ paginate,
2948
+ paginateBuffered,
2949
+ paginateMaxItems,
2950
+ runInMethodScope,
2951
+ runWithTelemetryContext,
2952
+ selectExports,
2953
+ splitPrefixedCursor,
2954
+ toIterable,
2955
+ toSnakeCase,
2956
+ toTitleCase,
2957
+ validateOptions,
2958
+ withOutputSchema,
2959
+ withPositional,
2960
+ withResolver
2961
+ };
2962
+ //# sourceMappingURL=index.mjs.map