@kb-labs/shared-command-kit 1.0.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.js ADDED
@@ -0,0 +1,1543 @@
1
+ import { platform } from '@kb-labs/core-runtime';
2
+ import { z } from 'zod';
3
+ import * as fs from 'fs/promises';
4
+ import * as path from 'path';
5
+ import { existsSync } from 'fs';
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+
17
+ // src/helpers/use-platform.ts
18
+ var use_platform_exports = {};
19
+ __export(use_platform_exports, {
20
+ isPlatformConfigured: () => isPlatformConfigured,
21
+ usePlatform: () => usePlatform
22
+ });
23
+ function usePlatform() {
24
+ return platform;
25
+ }
26
+ function isPlatformConfigured(adapterName) {
27
+ const platform = usePlatform();
28
+ const adapter = platform[adapterName];
29
+ if (!adapter) {
30
+ return false;
31
+ }
32
+ if ("hasAdapter" in platform && typeof platform.hasAdapter === "function") {
33
+ return platform.hasAdapter(adapterName);
34
+ }
35
+ if (typeof adapter === "object" && adapter.constructor) {
36
+ const constructorName = adapter.constructor.name;
37
+ return !constructorName.toLowerCase().includes("noop") && !constructorName.toLowerCase().includes("fallback");
38
+ }
39
+ return true;
40
+ }
41
+ var init_use_platform = __esm({
42
+ "src/helpers/use-platform.ts"() {
43
+ }
44
+ });
45
+
46
+ // src/flags/types.ts
47
+ var FlagValidationError = class extends Error {
48
+ constructor(flag, message, value, schema2, commandName) {
49
+ super(message);
50
+ this.flag = flag;
51
+ this.value = value;
52
+ this.schema = schema2;
53
+ this.commandName = commandName;
54
+ this.name = "FlagValidationError";
55
+ }
56
+ };
57
+
58
+ // src/flags/define.ts
59
+ function defineFlags(definition) {
60
+ return {
61
+ schema: definition,
62
+ infer: {}
63
+ };
64
+ }
65
+
66
+ // src/flags/validate.ts
67
+ function coerceValue(value, type) {
68
+ if (value === void 0 || value === null) {
69
+ return value;
70
+ }
71
+ switch (type) {
72
+ case "boolean":
73
+ if (typeof value === "boolean") {
74
+ return value;
75
+ }
76
+ if (typeof value === "string") {
77
+ const lower = value.toLowerCase().trim();
78
+ if (lower === "true" || lower === "1" || lower === "yes") {
79
+ return true;
80
+ }
81
+ if (lower === "false" || lower === "0" || lower === "no" || lower === "") {
82
+ return false;
83
+ }
84
+ }
85
+ return Boolean(value);
86
+ case "number":
87
+ if (typeof value === "number") {
88
+ return value;
89
+ }
90
+ if (typeof value === "string") {
91
+ const parsed = Number(value);
92
+ if (!Number.isNaN(parsed) && Number.isFinite(parsed)) {
93
+ return parsed;
94
+ }
95
+ }
96
+ return Number(value);
97
+ case "array":
98
+ if (Array.isArray(value)) {
99
+ return value;
100
+ }
101
+ if (typeof value === "string") {
102
+ return value.split(",").map((item) => item.trim());
103
+ }
104
+ return [value];
105
+ case "string":
106
+ return String(value);
107
+ default:
108
+ return value;
109
+ }
110
+ }
111
+ async function validateFlag(flagName, value, schema2) {
112
+ const { type, required } = schema2;
113
+ const choices = "choices" in schema2 ? schema2.choices : void 0;
114
+ const pattern = "pattern" in schema2 ? schema2.pattern : void 0;
115
+ const min = "min" in schema2 ? schema2.min : void 0;
116
+ const max = "max" in schema2 ? schema2.max : void 0;
117
+ const validate = "validate" in schema2 ? schema2.validate : void 0;
118
+ const minLength = "minLength" in schema2 ? schema2.minLength : void 0;
119
+ const maxLength = "maxLength" in schema2 ? schema2.maxLength : void 0;
120
+ const items = "items" in schema2 ? schema2.items : void 0;
121
+ if (required && (value === void 0 || value === null || value === "")) {
122
+ return `Flag --${flagName} is required`;
123
+ }
124
+ if (value === void 0 || value === null) {
125
+ return true;
126
+ }
127
+ const coerced = coerceValue(value, type);
128
+ switch (type) {
129
+ case "boolean":
130
+ if (typeof coerced !== "boolean") {
131
+ return `Flag --${flagName} must be a boolean`;
132
+ }
133
+ break;
134
+ case "string":
135
+ if (typeof coerced !== "string") {
136
+ return `Flag --${flagName} must be a string`;
137
+ }
138
+ if (minLength !== void 0 && coerced.length < minLength) {
139
+ return `Flag --${flagName} must be at least ${minLength} characters long`;
140
+ }
141
+ if (maxLength !== void 0 && coerced.length > maxLength) {
142
+ return `Flag --${flagName} must be at most ${maxLength} characters long`;
143
+ }
144
+ if (choices && !choices.includes(coerced)) {
145
+ return `Flag --${flagName} must be one of: ${choices.join(", ")} (got: ${coerced})`;
146
+ }
147
+ if (pattern && !pattern.test(coerced)) {
148
+ return `Flag --${flagName} must match pattern ${pattern.toString()}`;
149
+ }
150
+ if (validate) {
151
+ const stringValidate = validate;
152
+ const result = await stringValidate(coerced);
153
+ if (result !== true) {
154
+ return result;
155
+ }
156
+ }
157
+ break;
158
+ case "number":
159
+ if (typeof coerced !== "number" || !Number.isFinite(coerced)) {
160
+ return `Flag --${flagName} must be a number`;
161
+ }
162
+ if (min !== void 0 && coerced < min) {
163
+ return `Flag --${flagName} must be >= ${min} (got: ${coerced})`;
164
+ }
165
+ if (max !== void 0 && coerced > max) {
166
+ return `Flag --${flagName} must be <= ${max} (got: ${coerced})`;
167
+ }
168
+ if (validate) {
169
+ const numberValidate = validate;
170
+ const result = await numberValidate(coerced);
171
+ if (result !== true) {
172
+ return result;
173
+ }
174
+ }
175
+ break;
176
+ case "array":
177
+ if (!Array.isArray(coerced)) {
178
+ return `Flag --${flagName} must be an array`;
179
+ }
180
+ if (minLength !== void 0 && coerced.length < minLength) {
181
+ return `Flag --${flagName} must have at least ${minLength} items`;
182
+ }
183
+ if (maxLength !== void 0 && coerced.length > maxLength) {
184
+ return `Flag --${flagName} must have at most ${maxLength} items`;
185
+ }
186
+ if (items) {
187
+ for (let i = 0; i < coerced.length; i++) {
188
+ const item = coerced[i];
189
+ if (items === "string" && typeof item !== "string") {
190
+ return `Flag --${flagName}[${i}] must be a string`;
191
+ }
192
+ if (items === "number" && typeof item !== "number") {
193
+ return `Flag --${flagName}[${i}] must be a number`;
194
+ }
195
+ if (items === "boolean" && typeof item !== "boolean") {
196
+ return `Flag --${flagName}[${i}] must be a boolean`;
197
+ }
198
+ }
199
+ }
200
+ break;
201
+ }
202
+ return true;
203
+ }
204
+ async function validateFlags(rawFlags, schemaDefinition) {
205
+ const schema2 = "schema" in schemaDefinition ? schemaDefinition.schema : schemaDefinition;
206
+ const errors = [];
207
+ const result = {};
208
+ const flagValues = { ...rawFlags };
209
+ for (const [flagName, flagSchema] of Object.entries(schema2)) {
210
+ const value = flagValues[flagName];
211
+ if (value !== void 0 && value !== null && value !== false && value !== "") {
212
+ const implies = flagSchema.implies;
213
+ if (implies) {
214
+ for (const implied of implies) {
215
+ if (Array.isArray(implied) && implied.length === 2) {
216
+ const [impliedFlag, impliedValue] = implied;
217
+ if (flagValues[impliedFlag] === void 0) {
218
+ flagValues[impliedFlag] = impliedValue;
219
+ }
220
+ } else if (typeof implied === "string") {
221
+ if (flagValues[implied] === void 0) {
222
+ flagValues[implied] = true;
223
+ }
224
+ }
225
+ }
226
+ }
227
+ }
228
+ }
229
+ for (const [flagName, flagSchema] of Object.entries(schema2)) {
230
+ const value = flagValues[flagName];
231
+ const schemaWithName = { ...flagSchema, name: flagName };
232
+ const conflicts = flagSchema.conflicts;
233
+ if (conflicts && value !== void 0 && value !== null && value !== false && value !== "") {
234
+ for (const conflictingFlag of conflicts) {
235
+ const conflictingValue = flagValues[conflictingFlag];
236
+ if (conflictingValue !== void 0 && conflictingValue !== null && conflictingValue !== false && conflictingValue !== "") {
237
+ errors.push({
238
+ flag: flagName,
239
+ message: `Flag --${flagName} conflicts with --${conflictingFlag}`,
240
+ value
241
+ });
242
+ break;
243
+ }
244
+ }
245
+ if (errors.some((e) => e.flag === flagName)) {
246
+ continue;
247
+ }
248
+ }
249
+ const dependsOn = flagSchema.dependsOn;
250
+ if (dependsOn && value !== void 0 && value !== null && value !== "") {
251
+ for (const dependency of dependsOn) {
252
+ const dependencyValue = flagValues[dependency];
253
+ if (dependencyValue === void 0 || dependencyValue === null || dependencyValue === "") {
254
+ errors.push({
255
+ flag: flagName,
256
+ message: `Flag --${flagName} depends on --${dependency}`,
257
+ value
258
+ });
259
+ break;
260
+ }
261
+ }
262
+ if (errors.some((e) => e.flag === flagName)) {
263
+ continue;
264
+ }
265
+ }
266
+ if (flagSchema.required && (value === void 0 || value === null || value === "")) {
267
+ errors.push({
268
+ flag: flagName,
269
+ message: `Flag --${flagName} is required`,
270
+ value
271
+ });
272
+ continue;
273
+ }
274
+ const finalValue = value !== void 0 ? value : flagSchema.default;
275
+ if (finalValue === void 0 && !flagSchema.required) {
276
+ continue;
277
+ }
278
+ const validationResult = await validateFlag(flagName, finalValue, schemaWithName);
279
+ if (validationResult !== true) {
280
+ errors.push({
281
+ flag: flagName,
282
+ message: validationResult,
283
+ value: finalValue
284
+ });
285
+ continue;
286
+ }
287
+ let transformedValue = coerceValue(finalValue, flagSchema.type);
288
+ const transform = flagSchema.transform;
289
+ if (transform) {
290
+ transformedValue = await transform(transformedValue);
291
+ }
292
+ result[flagName] = transformedValue;
293
+ }
294
+ if (errors.length > 0) {
295
+ const firstError = errors[0];
296
+ throw new FlagValidationError(
297
+ firstError.flag,
298
+ firstError.message,
299
+ firstError.value,
300
+ schema2
301
+ // Pass schema for usage generation
302
+ );
303
+ }
304
+ return result;
305
+ }
306
+ async function validateFlagsSafe(rawFlags, schemaDefinition) {
307
+ try {
308
+ const data = await validateFlags(rawFlags, schemaDefinition);
309
+ return {
310
+ success: true,
311
+ data,
312
+ errors: []
313
+ };
314
+ } catch (error) {
315
+ if (error instanceof FlagValidationError) {
316
+ return {
317
+ success: false,
318
+ errors: [
319
+ {
320
+ flag: error.flag,
321
+ message: error.message,
322
+ value: error.value
323
+ }
324
+ ]
325
+ };
326
+ }
327
+ throw error;
328
+ }
329
+ }
330
+
331
+ // src/analytics/with-analytics.ts
332
+ async function withAnalytics(ctx, eventName, events, operation) {
333
+ const analytics = ctx.platform?.analytics;
334
+ const startTime = Date.now();
335
+ if (analytics && events.started) {
336
+ await analytics.track(`${eventName}.started`, {
337
+ ...events.started,
338
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
339
+ });
340
+ }
341
+ try {
342
+ const result = await operation();
343
+ if (analytics && events.completed) {
344
+ const completedProps = typeof events.completed === "function" ? events.completed(result) : events.completed;
345
+ await analytics.track(`${eventName}.completed`, {
346
+ ...completedProps,
347
+ durationMs: Date.now() - startTime,
348
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
349
+ });
350
+ }
351
+ return result;
352
+ } catch (error) {
353
+ if (analytics && events.failed) {
354
+ const failedProps = typeof events.failed === "function" ? events.failed(error) : events.failed;
355
+ await analytics.track(`${eventName}.failed`, {
356
+ ...failedProps,
357
+ durationMs: Date.now() - startTime,
358
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
359
+ });
360
+ }
361
+ throw error;
362
+ }
363
+ }
364
+ function createAnalyticsWrapper(eventName, defaultEvents) {
365
+ return async (ctx, additionalEvents, operation) => {
366
+ const mergedEvents = {
367
+ started: { ...defaultEvents.started, ...additionalEvents.started },
368
+ completed: additionalEvents.completed || defaultEvents.completed,
369
+ failed: additionalEvents.failed || defaultEvents.failed
370
+ };
371
+ return withAnalytics(ctx, eventName, mergedEvents, operation);
372
+ };
373
+ }
374
+ async function trackEvent(ctx, eventName, properties) {
375
+ const analytics = ctx.platform?.analytics;
376
+ if (analytics) {
377
+ await analytics.track(eventName, {
378
+ ...properties,
379
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
380
+ });
381
+ }
382
+ }
383
+
384
+ // src/errors/format-validation.ts
385
+ function formatValidationError(error, options = {}) {
386
+ const { commandName, schema: schema2 } = options;
387
+ const lines = [];
388
+ const errorMsg = error.message;
389
+ if (errorMsg.includes("is required")) {
390
+ lines.push(`\u274C Missing required flag: --${error.flag}`);
391
+ } else if (errorMsg.includes("must be one of")) {
392
+ const valueStr = error.value !== void 0 ? ` ${error.value}` : "";
393
+ lines.push(`\u274C Invalid value for --${error.flag}:${valueStr}`);
394
+ } else if (errorMsg.includes("must be a")) {
395
+ lines.push(`\u274C Invalid type for --${error.flag}`);
396
+ } else if (errorMsg.includes("conflicts with")) {
397
+ lines.push(`\u274C Flag conflict: --${error.flag}`);
398
+ } else if (errorMsg.includes("depends on")) {
399
+ lines.push(`\u274C Missing dependency for --${error.flag}`);
400
+ } else {
401
+ lines.push(`\u274C ${errorMsg}`);
402
+ }
403
+ lines.push("");
404
+ if (commandName && schema2) {
405
+ const usageLine = generateUsageLine(commandName, schema2, error.flag);
406
+ if (usageLine) {
407
+ lines.push(`Usage: ${usageLine}`);
408
+ }
409
+ }
410
+ if (commandName) {
411
+ lines.push(`Hint: Try ${commandName} --help`);
412
+ } else {
413
+ lines.push("Hint: Try --help for more information");
414
+ }
415
+ return lines.join("\n");
416
+ }
417
+ function generateUsageLine(commandName, schema2, errorFlag) {
418
+ const parts = [commandName];
419
+ const errorFlagSchema = schema2[errorFlag];
420
+ if (errorFlagSchema) {
421
+ const flagStr = formatFlagForUsage(errorFlag, errorFlagSchema);
422
+ parts.push(flagStr);
423
+ }
424
+ const otherRequiredFlags = Object.entries(schema2).filter(
425
+ ([name, flagSchema]) => name !== errorFlag && flagSchema.required
426
+ );
427
+ if (otherRequiredFlags.length > 0) {
428
+ for (const [name, flagSchema] of otherRequiredFlags) {
429
+ parts.push(formatFlagForUsage(name, flagSchema));
430
+ }
431
+ }
432
+ const hasOptionalFlags = Object.values(schema2).some((s) => !s.required);
433
+ if (hasOptionalFlags) {
434
+ parts.push("[options]");
435
+ }
436
+ return parts.join(" ");
437
+ }
438
+ function formatFlagForUsage(name, schema2) {
439
+ let valueHint;
440
+ if ("choices" in schema2 && schema2.choices && schema2.choices.length > 0) {
441
+ valueHint = `<${schema2.choices.join("|")}>`;
442
+ } else if (schema2.type === "boolean") {
443
+ return schema2.required ? `--${name}` : `[--${name}]`;
444
+ } else {
445
+ valueHint = `<${name}>`;
446
+ }
447
+ const flagPart = `--${name} ${valueHint}`;
448
+ return schema2.required ? flagPart : `[${flagPart}]`;
449
+ }
450
+
451
+ // src/errors/format.ts
452
+ function formatError(error, options = {}) {
453
+ const { showStack = false, timingMs } = options;
454
+ if (error instanceof FlagValidationError) {
455
+ const friendlyMessage = formatValidationError(error, {
456
+ commandName: error.commandName,
457
+ schema: error.schema
458
+ });
459
+ const json3 = {
460
+ ok: false,
461
+ error: error.message
462
+ };
463
+ if (timingMs !== void 0) {
464
+ json3.timingMs = timingMs;
465
+ }
466
+ if (showStack && error.stack) {
467
+ json3.stack = error.stack;
468
+ }
469
+ let message2 = friendlyMessage;
470
+ if (showStack && error.stack) {
471
+ message2 = `${friendlyMessage}
472
+
473
+ Stack trace:
474
+ ${error.stack}`;
475
+ }
476
+ return {
477
+ message: message2,
478
+ json: json3
479
+ };
480
+ }
481
+ const errorMessage = error instanceof Error ? error.message : String(error);
482
+ const errorStack = error instanceof Error ? error.stack : void 0;
483
+ const json2 = {
484
+ ok: false,
485
+ error: errorMessage
486
+ };
487
+ if (timingMs !== void 0) {
488
+ json2.timingMs = timingMs;
489
+ }
490
+ if (showStack && errorStack) {
491
+ json2.stack = errorStack;
492
+ }
493
+ let message = errorMessage;
494
+ if (showStack && errorStack) {
495
+ message = `${errorMessage}
496
+
497
+ ${errorStack}`;
498
+ }
499
+ return {
500
+ message,
501
+ json: json2
502
+ };
503
+ }
504
+
505
+ // src/errors/factory.ts
506
+ var PluginError = class _PluginError extends Error {
507
+ statusCode;
508
+ errorCode;
509
+ details;
510
+ constructor(errorCode, message, statusCode, details) {
511
+ super(message);
512
+ this.name = "PluginError";
513
+ this.errorCode = errorCode;
514
+ this.statusCode = statusCode;
515
+ this.details = details;
516
+ if (Error.captureStackTrace) {
517
+ Error.captureStackTrace(this, _PluginError);
518
+ }
519
+ }
520
+ /**
521
+ * Convert error to JSON for logging/serialization
522
+ */
523
+ toJSON() {
524
+ return {
525
+ name: this.name,
526
+ errorCode: this.errorCode,
527
+ message: this.message,
528
+ statusCode: this.statusCode,
529
+ details: this.details,
530
+ stack: this.stack
531
+ };
532
+ }
533
+ /**
534
+ * Check if error is a PluginError
535
+ */
536
+ static isPluginError(error) {
537
+ return error instanceof _PluginError;
538
+ }
539
+ };
540
+ function defineError(prefix, definitions) {
541
+ const errorNamespace = {};
542
+ for (const [key, def] of Object.entries(definitions)) {
543
+ const errorCode = `${prefix}_${key.toUpperCase()}`;
544
+ class DefinedError extends PluginError {
545
+ constructor(...args) {
546
+ const { message, details } = buildMessageAndDetails(def, args);
547
+ super(errorCode, message, def.code, details);
548
+ this.name = `${prefix}Error`;
549
+ }
550
+ }
551
+ errorNamespace[key] = DefinedError;
552
+ }
553
+ errorNamespace.is = (error) => {
554
+ return PluginError.isPluginError(error) && error.errorCode.startsWith(prefix + "_");
555
+ };
556
+ errorNamespace.hasCode = (error, code) => {
557
+ const errorCode = `${prefix}_${String(code).toUpperCase()}`;
558
+ return PluginError.isPluginError(error) && error.errorCode === errorCode;
559
+ };
560
+ return errorNamespace;
561
+ }
562
+ function buildMessageAndDetails(def, args) {
563
+ let message;
564
+ let details;
565
+ if (typeof def.message === "function") {
566
+ const lastArg = args[args.length - 1];
567
+ const hasDetails = lastArg && typeof lastArg === "object" && "details" in lastArg;
568
+ if (hasDetails) {
569
+ const templateArgs = args.slice(0, -1);
570
+ message = def.message(...templateArgs);
571
+ details = { ...def.details, ...lastArg.details };
572
+ } else {
573
+ message = def.message(...args);
574
+ details = def.details;
575
+ }
576
+ } else {
577
+ message = def.message;
578
+ if (args.length > 0 && typeof args[0] === "object" && args[0] !== null) {
579
+ details = { ...def.details, ...args[0].details };
580
+ } else {
581
+ details = def.details;
582
+ }
583
+ }
584
+ return { message, details };
585
+ }
586
+ var commonErrors = {
587
+ /**
588
+ * Validation error (400)
589
+ */
590
+ ValidationFailed: {
591
+ code: 400,
592
+ message: "Validation failed"
593
+ },
594
+ /**
595
+ * Resource not found (404)
596
+ */
597
+ NotFound: {
598
+ code: 404,
599
+ message: (resource) => `${resource} not found`
600
+ },
601
+ /**
602
+ * Unauthorized access (401)
603
+ */
604
+ Unauthorized: {
605
+ code: 401,
606
+ message: "Unauthorized"
607
+ },
608
+ /**
609
+ * Forbidden access (403)
610
+ */
611
+ Forbidden: {
612
+ code: 403,
613
+ message: "Forbidden"
614
+ },
615
+ /**
616
+ * Internal server error (500)
617
+ */
618
+ InternalError: {
619
+ code: 500,
620
+ message: "Internal server error"
621
+ },
622
+ /**
623
+ * Service unavailable (503)
624
+ */
625
+ ServiceUnavailable: {
626
+ code: 503,
627
+ message: (service) => `Service '${service}' is unavailable`
628
+ },
629
+ /**
630
+ * Timeout error (504)
631
+ */
632
+ Timeout: {
633
+ code: 504,
634
+ message: (operation) => `Operation '${operation}' timed out`
635
+ },
636
+ /**
637
+ * Conflict error (409)
638
+ */
639
+ Conflict: {
640
+ code: 409,
641
+ message: (resource) => `${resource} already exists`
642
+ }
643
+ };
644
+
645
+ // src/helpers/index.ts
646
+ init_use_platform();
647
+
648
+ // src/helpers/use-config.ts
649
+ async function useConfig(productId, profileId) {
650
+ let effectiveProductId = productId;
651
+ if (!effectiveProductId) {
652
+ effectiveProductId = globalThis.__KB_CONFIG_SECTION__;
653
+ }
654
+ if (!effectiveProductId) {
655
+ return void 0;
656
+ }
657
+ const { usePlatform: usePlatform2 } = await Promise.resolve().then(() => (init_use_platform(), use_platform_exports));
658
+ const platform = usePlatform2();
659
+ if (!platform) {
660
+ return void 0;
661
+ }
662
+ return await platform.config.getConfig(effectiveProductId, profileId);
663
+ }
664
+
665
+ // src/helpers/use-logger.ts
666
+ init_use_platform();
667
+ function useLogger() {
668
+ const platform = usePlatform();
669
+ return platform.logger;
670
+ }
671
+ function useLoggerWithContext(context) {
672
+ const logger = useLogger();
673
+ return logger.child(context);
674
+ }
675
+
676
+ // src/helpers/use-llm.ts
677
+ init_use_platform();
678
+ function useLLM(options) {
679
+ const platform = usePlatform();
680
+ const llm = platform.llm;
681
+ if (!llm) {
682
+ return void 0;
683
+ }
684
+ if (options && isLLMRouter(llm)) {
685
+ return new LazyBoundLLM(llm, options);
686
+ }
687
+ return llm;
688
+ }
689
+ var LazyBoundLLM = class {
690
+ constructor(router, options) {
691
+ this.router = router;
692
+ this.options = options;
693
+ }
694
+ _resolved = null;
695
+ resolve() {
696
+ if (!this._resolved) {
697
+ this._resolved = this.router.resolveAdapter(this.options);
698
+ }
699
+ return this._resolved;
700
+ }
701
+ mergeExecutionPolicy(callOptions) {
702
+ const globalPolicy = this.options.execution;
703
+ const localPolicy = callOptions?.execution;
704
+ if (!globalPolicy && !localPolicy) {
705
+ return void 0;
706
+ }
707
+ return {
708
+ ...globalPolicy,
709
+ ...localPolicy,
710
+ cache: { ...globalPolicy?.cache, ...localPolicy?.cache },
711
+ stream: { ...globalPolicy?.stream, ...localPolicy?.stream }
712
+ };
713
+ }
714
+ async resolveProtocolCapabilities(adapter) {
715
+ if (!adapter.getProtocolCapabilities) {
716
+ return {
717
+ cache: { supported: false },
718
+ stream: { supported: true }
719
+ };
720
+ }
721
+ return adapter.getProtocolCapabilities();
722
+ }
723
+ enforceCachePolicy(caps, execution) {
724
+ if (execution?.cache?.mode === "require" && !caps.cache.supported) {
725
+ throw new Error("CACHE_NOT_SUPPORTED: adapter does not support required cache policy");
726
+ }
727
+ }
728
+ buildDecisionTrace(caps, execution, streamAppliedMode, streamFallback, reason) {
729
+ const requestedCacheMode = execution?.cache?.mode ?? "prefer";
730
+ const requestedStreamMode = execution?.stream?.mode ?? "prefer";
731
+ return {
732
+ cacheRequestedMode: requestedCacheMode,
733
+ cacheSupported: caps.cache.supported,
734
+ cacheAppliedMode: requestedCacheMode === "require" || requestedCacheMode === "bypass" ? requestedCacheMode : caps.cache.supported ? "prefer" : "bypass",
735
+ streamRequestedMode: requestedStreamMode,
736
+ streamSupported: caps.stream.supported,
737
+ streamAppliedMode,
738
+ streamFallback,
739
+ reason
740
+ };
741
+ }
742
+ withDecisionMetadata(options, trace) {
743
+ if (!options) {
744
+ return { metadata: { cacheDecisionTrace: trace } };
745
+ }
746
+ return {
747
+ ...options,
748
+ metadata: {
749
+ ...options.metadata,
750
+ cacheDecisionTrace: trace
751
+ }
752
+ };
753
+ }
754
+ async complete(prompt, options) {
755
+ const { adapter, model } = await this.resolve();
756
+ const execution = this.mergeExecutionPolicy(options);
757
+ const caps = await this.resolveProtocolCapabilities(adapter);
758
+ this.enforceCachePolicy(caps, execution);
759
+ const trace = this.buildDecisionTrace(caps, execution, "off");
760
+ const optionsWithTrace = this.withDecisionMetadata(options, trace);
761
+ return adapter.complete(prompt, { ...optionsWithTrace, model, execution });
762
+ }
763
+ async *stream(prompt, options) {
764
+ const { adapter, model } = await this.resolve();
765
+ const execution = this.mergeExecutionPolicy(options);
766
+ const caps = await this.resolveProtocolCapabilities(adapter);
767
+ this.enforceCachePolicy(caps, execution);
768
+ const streamMode = execution?.stream?.mode ?? "prefer";
769
+ const canStream = caps.stream.supported;
770
+ const allowFallback = execution?.stream?.fallbackToComplete ?? true;
771
+ if (streamMode === "off" || !canStream && streamMode === "prefer" && allowFallback) {
772
+ const fallbackReason = streamMode === "off" ? "STREAM_OFF" : "STREAM_UNSUPPORTED_FALLBACK_TO_COMPLETE";
773
+ const trace2 = this.buildDecisionTrace(caps, execution, "off", "complete", fallbackReason);
774
+ const optionsWithTrace2 = this.withDecisionMetadata(options, trace2);
775
+ const response = await adapter.complete(prompt, { ...optionsWithTrace2, model, execution });
776
+ if (response.content) {
777
+ yield response.content;
778
+ }
779
+ return;
780
+ }
781
+ if (!canStream && streamMode === "require") {
782
+ throw new Error("STREAM_NOT_SUPPORTED: adapter does not support required streaming");
783
+ }
784
+ const trace = this.buildDecisionTrace(caps, execution, streamMode);
785
+ const optionsWithTrace = this.withDecisionMetadata(options, trace);
786
+ yield* adapter.stream(prompt, { ...optionsWithTrace, model, execution });
787
+ }
788
+ async chatWithTools(messages, options) {
789
+ const { adapter, model, tier } = await this.resolve();
790
+ const execution = this.mergeExecutionPolicy(options);
791
+ const caps = await this.resolveProtocolCapabilities(adapter);
792
+ this.enforceCachePolicy(caps, execution);
793
+ if (!adapter.chatWithTools) {
794
+ throw new Error("Current adapter does not support chatWithTools");
795
+ }
796
+ const trace = this.buildDecisionTrace(caps, execution, "off");
797
+ const optionsWithTrace = this.withDecisionMetadata(options, trace);
798
+ return adapter.chatWithTools(messages, {
799
+ ...optionsWithTrace,
800
+ model,
801
+ execution,
802
+ metadata: { ...optionsWithTrace.metadata, tier }
803
+ });
804
+ }
805
+ };
806
+ function isLLMAvailable() {
807
+ const llm = useLLM();
808
+ return !!llm;
809
+ }
810
+ function getLLMTier() {
811
+ const platform = usePlatform();
812
+ const llm = platform.llm;
813
+ if (llm && isLLMRouter(llm)) {
814
+ return llm.getConfiguredTier();
815
+ }
816
+ return void 0;
817
+ }
818
+ function isLLMRouter(llm) {
819
+ return typeof llm.getConfiguredTier === "function" && typeof llm.resolve === "function";
820
+ }
821
+
822
+ // src/helpers/use-embeddings.ts
823
+ init_use_platform();
824
+ function useEmbeddings() {
825
+ const platform = usePlatform();
826
+ return platform.embeddings;
827
+ }
828
+ function isEmbeddingsAvailable() {
829
+ const embeddings = useEmbeddings();
830
+ return !!embeddings;
831
+ }
832
+
833
+ // src/helpers/use-vector-store.ts
834
+ init_use_platform();
835
+ function useVectorStore() {
836
+ const platform = usePlatform();
837
+ return platform.vectorStore;
838
+ }
839
+ function isVectorStoreAvailable() {
840
+ const vectorStore = useVectorStore();
841
+ return !!vectorStore;
842
+ }
843
+
844
+ // src/helpers/use-analytics.ts
845
+ init_use_platform();
846
+ function useAnalytics() {
847
+ const platform = usePlatform();
848
+ return platform.analytics;
849
+ }
850
+ async function trackAnalyticsEvent(event, properties) {
851
+ const analytics = useAnalytics();
852
+ if (analytics) {
853
+ await analytics.track(event, properties);
854
+ }
855
+ }
856
+
857
+ // src/helpers/use-storage.ts
858
+ init_use_platform();
859
+ function useStorage() {
860
+ const platform = usePlatform();
861
+ return platform.storage;
862
+ }
863
+
864
+ // src/helpers/use-cache.ts
865
+ init_use_platform();
866
+ function useCache() {
867
+ const platform = usePlatform();
868
+ return platform.cache;
869
+ }
870
+ function isCacheAvailable() {
871
+ const cache = useCache();
872
+ return !!cache;
873
+ }
874
+
875
+ // src/define-system-command.ts
876
+ function convertFlagSchema(schema2) {
877
+ return Object.entries(schema2).map(([name, def]) => {
878
+ const result = {
879
+ name,
880
+ type: def.type,
881
+ alias: def.alias,
882
+ description: def.description,
883
+ default: def.default,
884
+ required: def.required
885
+ };
886
+ if (def.type === "string" && "choices" in def && Array.isArray(def.choices)) {
887
+ result.choices = [...def.choices];
888
+ }
889
+ return result;
890
+ });
891
+ }
892
+ function defineSystemCommand(config) {
893
+ const { name, description, longDescription, category, aliases, examples, flags, handler, formatter } = config;
894
+ return {
895
+ name,
896
+ describe: description,
897
+ longDescription,
898
+ category: category || "system",
899
+ aliases: aliases || [],
900
+ flags: flags ? convertFlagSchema(flags) : [],
901
+ examples: examples || [],
902
+ run: async (ctx, argv, rawFlags) => {
903
+ const jsonMode = Boolean(rawFlags.json);
904
+ ctx.platform?.logger?.info?.(`Command ${name} started`);
905
+ let validatedFlags;
906
+ if (flags) {
907
+ const flagSchema = defineFlags(flags);
908
+ try {
909
+ validatedFlags = await validateFlags(rawFlags, flagSchema);
910
+ } catch (error) {
911
+ if (error instanceof FlagValidationError && name && !error.commandName) {
912
+ error.commandName = name;
913
+ }
914
+ const showStack = Boolean(rawFlags.debug);
915
+ const formatted = formatError(error, { showStack});
916
+ if (jsonMode) {
917
+ ctx.ui?.json(formatted.json);
918
+ } else {
919
+ ctx.ui?.error(formatted.message);
920
+ }
921
+ return 3;
922
+ }
923
+ } else {
924
+ validatedFlags = rawFlags;
925
+ }
926
+ let result;
927
+ try {
928
+ result = await handler(ctx, argv, validatedFlags);
929
+ } catch (error) {
930
+ const errorMessage = error instanceof Error ? error.message : String(error);
931
+ ctx.platform?.logger?.error?.(`Command ${name} failed: ${errorMessage}`);
932
+ if (jsonMode) {
933
+ ctx.ui?.json({ ok: false, error: errorMessage });
934
+ } else {
935
+ ctx.ui?.error(errorMessage);
936
+ }
937
+ return 1;
938
+ }
939
+ if (formatter && typeof result !== "number") {
940
+ formatter(result, ctx, validatedFlags, argv);
941
+ }
942
+ ctx.platform?.logger?.info?.(`Command ${name} completed`);
943
+ if (typeof result === "number") {
944
+ return result;
945
+ }
946
+ return result.ok ? 0 : 1;
947
+ }
948
+ };
949
+ }
950
+ function defineSystemCommandGroup(name, describe, commands) {
951
+ return {
952
+ name,
953
+ describe,
954
+ commands
955
+ };
956
+ }
957
+
958
+ // src/manifest.ts
959
+ function defineManifest(manifest) {
960
+ return manifest;
961
+ }
962
+ function defineCommandFlags(flags) {
963
+ return Object.entries(flags).map(([name, flag]) => ({
964
+ name,
965
+ type: flag.type,
966
+ ...flag.alias !== void 0 && { alias: flag.alias },
967
+ ...flag.default !== void 0 && { default: flag.default },
968
+ ...flag.description !== void 0 && { description: flag.description },
969
+ ...flag.choices !== void 0 && { choices: flag.choices },
970
+ ...flag.required !== void 0 && { required: flag.required }
971
+ }));
972
+ }
973
+ function cwd() {
974
+ return z.string().optional().describe("Current working directory path");
975
+ }
976
+ function scopeId() {
977
+ return z.string().min(1).describe("Scope identifier");
978
+ }
979
+ function text(options) {
980
+ let schema2 = z.string();
981
+ if (options?.min !== void 0) {
982
+ schema2 = schema2.min(options.min);
983
+ }
984
+ if (options?.max !== void 0) {
985
+ schema2 = schema2.max(options.max);
986
+ }
987
+ if (options?.default !== void 0) {
988
+ return schema2.default(options.default).describe("Text string");
989
+ }
990
+ return schema2.describe("Text string");
991
+ }
992
+ function positiveInt(options) {
993
+ let schema2 = z.number().int().positive();
994
+ if (options?.min !== void 0) {
995
+ schema2 = schema2.min(options.min);
996
+ }
997
+ if (options?.max !== void 0) {
998
+ schema2 = schema2.max(options.max);
999
+ }
1000
+ if (options?.default !== void 0) {
1001
+ return schema2.default(options.default).describe("Positive integer");
1002
+ }
1003
+ return schema2.describe("Positive integer");
1004
+ }
1005
+ function nonNegativeInt(options) {
1006
+ let schema2 = z.number().int().min(0);
1007
+ if (options?.max !== void 0) {
1008
+ schema2 = schema2.max(options.max);
1009
+ }
1010
+ if (options?.default !== void 0) {
1011
+ return schema2.default(options.default).describe("Non-negative integer");
1012
+ }
1013
+ return schema2.describe("Non-negative integer");
1014
+ }
1015
+ function enumSchema(values, options) {
1016
+ const schema2 = z.enum(values);
1017
+ if (options?.default !== void 0) {
1018
+ return schema2.default(options.default);
1019
+ }
1020
+ return schema2;
1021
+ }
1022
+ function pluginId() {
1023
+ return z.string().regex(/^@kb-labs\/[a-z][a-z0-9-]*$/, "Must be in format @kb-labs/package-name").describe("Plugin ID");
1024
+ }
1025
+ function commandId() {
1026
+ return z.string().regex(/^[a-z][a-z0-9-]*:[a-z][a-z0-9-]*$/, "Must be in format plugin:command").describe("Command ID");
1027
+ }
1028
+ function artifactId() {
1029
+ return z.string().regex(/^[a-z][a-z0-9-]*\.[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)*$/, "Must be in format plugin.artifact.id").describe("Artifact ID");
1030
+ }
1031
+ function filePath(options) {
1032
+ const schema2 = z.string().describe("File path");
1033
+ if (options?.optional) {
1034
+ return schema2.optional();
1035
+ }
1036
+ return schema2;
1037
+ }
1038
+ function url(options) {
1039
+ const schema2 = z.string().url().describe("URL");
1040
+ if (options?.optional) {
1041
+ return schema2.optional();
1042
+ }
1043
+ return schema2;
1044
+ }
1045
+ function email(options) {
1046
+ const schema2 = z.string().email().describe("Email address");
1047
+ if (options?.optional) {
1048
+ return schema2.optional();
1049
+ }
1050
+ return schema2;
1051
+ }
1052
+ function uuid(options) {
1053
+ const schema2 = z.string().uuid().describe("UUID");
1054
+ if (options?.optional) {
1055
+ return schema2.optional();
1056
+ }
1057
+ return schema2;
1058
+ }
1059
+ function datetime(options) {
1060
+ const schema2 = z.string().datetime().describe("ISO datetime");
1061
+ if (options?.optional) {
1062
+ return schema2.optional();
1063
+ }
1064
+ return schema2;
1065
+ }
1066
+ function json() {
1067
+ return z.record(z.unknown()).describe("JSON object");
1068
+ }
1069
+ function boolean(options) {
1070
+ const schema2 = z.boolean();
1071
+ if (options?.default !== void 0) {
1072
+ return schema2.default(options.default);
1073
+ }
1074
+ return schema2;
1075
+ }
1076
+ function array(itemSchema, options) {
1077
+ let schema2 = z.array(itemSchema);
1078
+ if (options?.min !== void 0) {
1079
+ schema2 = schema2.min(options.min);
1080
+ }
1081
+ if (options?.max !== void 0) {
1082
+ schema2 = schema2.max(options.max);
1083
+ }
1084
+ return schema2;
1085
+ }
1086
+ function object(shape) {
1087
+ return z.object(shape);
1088
+ }
1089
+ var schema = {
1090
+ // Path and ID builders
1091
+ cwd,
1092
+ scopeId,
1093
+ pluginId,
1094
+ commandId,
1095
+ artifactId,
1096
+ filePath,
1097
+ // String builders
1098
+ text,
1099
+ url,
1100
+ email,
1101
+ uuid,
1102
+ datetime,
1103
+ // Number builders
1104
+ positiveInt,
1105
+ nonNegativeInt,
1106
+ // Other builders
1107
+ enum: enumSchema,
1108
+ boolean,
1109
+ json,
1110
+ array,
1111
+ object
1112
+ };
1113
+
1114
+ // src/rest/define-handler.ts
1115
+ function defineHandler(definition) {
1116
+ return {
1117
+ execute: async (ctx, input) => {
1118
+ return await definition.execute(ctx, input);
1119
+ }
1120
+ };
1121
+ }
1122
+ function defineSetupHandler(definition) {
1123
+ return async (ctx) => {
1124
+ const log = ctx.log || ((level, msg, meta) => {
1125
+ console.log(`[${level}] ${msg}`, meta || "");
1126
+ });
1127
+ try {
1128
+ log("info", "Setup started", { handler: definition.name, outdir: ctx.outdir });
1129
+ if (definition.workspace) {
1130
+ await setupWorkspace(ctx.outdir, definition.workspace, log);
1131
+ }
1132
+ if (definition.config) {
1133
+ await updateConfigFiles(ctx.outdir, definition.config, log);
1134
+ }
1135
+ if (definition.handler) {
1136
+ const result = await definition.handler(ctx);
1137
+ if (!result.ok) {
1138
+ return result;
1139
+ }
1140
+ }
1141
+ log("info", "Setup completed", { handler: definition.name });
1142
+ return { ok: true, message: `${definition.name} setup completed` };
1143
+ } catch (error) {
1144
+ log("error", "Setup failed", {
1145
+ handler: definition.name,
1146
+ error: error.message,
1147
+ stack: error.stack
1148
+ });
1149
+ return { ok: false, message: `Setup failed: ${error.message}` };
1150
+ }
1151
+ };
1152
+ }
1153
+ function defineDestroyHandler(definition) {
1154
+ return async (ctx) => {
1155
+ const log = ctx.log || ((level, msg, meta) => {
1156
+ console.log(`[${level}] ${msg}`, meta || "");
1157
+ });
1158
+ try {
1159
+ log("info", "Destroy started", { handler: definition.name, outdir: ctx.outdir });
1160
+ if (definition.config) {
1161
+ await cleanupConfigFiles(ctx.outdir, definition.config, log);
1162
+ }
1163
+ if (definition.workspace) {
1164
+ await cleanupWorkspace(ctx.outdir, definition.workspace, log);
1165
+ }
1166
+ if (definition.handler) {
1167
+ const result = await definition.handler(ctx);
1168
+ if (!result.ok) {
1169
+ return result;
1170
+ }
1171
+ }
1172
+ log("info", "Destroy completed", { handler: definition.name });
1173
+ return { ok: true, message: `${definition.name} destroy completed` };
1174
+ } catch (error) {
1175
+ log("error", "Destroy failed", {
1176
+ handler: definition.name,
1177
+ error: error.message,
1178
+ stack: error.stack
1179
+ });
1180
+ return { ok: false, message: `Destroy failed: ${error.message}` };
1181
+ }
1182
+ };
1183
+ }
1184
+ async function setupWorkspace(outdir, config, log) {
1185
+ if (config.directories) {
1186
+ for (const dir of config.directories) {
1187
+ const dirPath = path.resolve(outdir, dir);
1188
+ await fs.mkdir(dirPath, { recursive: true });
1189
+ log("debug", "Created directory", { path: dirPath });
1190
+ }
1191
+ }
1192
+ if (config.files) {
1193
+ for (const [filePath2, content] of Object.entries(config.files)) {
1194
+ const fullPath = path.resolve(outdir, filePath2);
1195
+ const dirPath = path.dirname(fullPath);
1196
+ await fs.mkdir(dirPath, { recursive: true });
1197
+ await fs.writeFile(fullPath, content, "utf-8");
1198
+ log("debug", "Created file", { path: fullPath });
1199
+ }
1200
+ }
1201
+ }
1202
+ async function updateConfigFiles(outdir, updates, log) {
1203
+ for (const [configFile, configUpdates] of Object.entries(updates)) {
1204
+ const configPath = path.resolve(outdir, configFile);
1205
+ let config = {};
1206
+ if (existsSync(configPath)) {
1207
+ const content = await fs.readFile(configPath, "utf-8");
1208
+ try {
1209
+ config = JSON.parse(content);
1210
+ } catch (error) {
1211
+ log("warn", "Failed to parse existing config, starting fresh", { path: configPath });
1212
+ }
1213
+ }
1214
+ config = { ...config, ...configUpdates };
1215
+ const dirPath = path.dirname(configPath);
1216
+ await fs.mkdir(dirPath, { recursive: true });
1217
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
1218
+ log("debug", "Updated config file", { path: configPath });
1219
+ }
1220
+ }
1221
+ async function cleanupWorkspace(outdir, config, log) {
1222
+ if (!config) {
1223
+ return;
1224
+ }
1225
+ if (config.files) {
1226
+ for (const file of config.files) {
1227
+ const filePath2 = path.resolve(outdir, file);
1228
+ if (existsSync(filePath2)) {
1229
+ await fs.unlink(filePath2);
1230
+ log("debug", "Removed file", { path: filePath2 });
1231
+ }
1232
+ }
1233
+ }
1234
+ if (config.directories) {
1235
+ for (const dir of config.directories) {
1236
+ const dirPath = path.resolve(outdir, dir);
1237
+ if (existsSync(dirPath)) {
1238
+ await fs.rm(dirPath, { recursive: true, force: true });
1239
+ log("debug", "Removed directory", { path: dirPath });
1240
+ }
1241
+ }
1242
+ }
1243
+ }
1244
+ async function cleanupConfigFiles(outdir, cleanups, log) {
1245
+ for (const [configFile, keysToRemove] of Object.entries(cleanups)) {
1246
+ const configPath = path.resolve(outdir, configFile);
1247
+ if (!existsSync(configPath)) {
1248
+ continue;
1249
+ }
1250
+ const content = await fs.readFile(configPath, "utf-8");
1251
+ let config;
1252
+ try {
1253
+ config = JSON.parse(content);
1254
+ } catch (error) {
1255
+ log("warn", "Failed to parse config for cleanup", { path: configPath });
1256
+ continue;
1257
+ }
1258
+ for (const key of keysToRemove) {
1259
+ delete config[key];
1260
+ }
1261
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
1262
+ log("debug", "Cleaned up config file", { path: configPath, removed: keysToRemove });
1263
+ }
1264
+ }
1265
+
1266
+ // src/jobs.ts
1267
+ function defineJob(definition) {
1268
+ const { handler, ...config } = definition;
1269
+ return {
1270
+ config: { ...config, handler: "" },
1271
+ // handler path will be set in toManifest()
1272
+ handler,
1273
+ toManifest(handlerPath) {
1274
+ return {
1275
+ id: config.id,
1276
+ schedule: config.schedule,
1277
+ job: {
1278
+ type: config.id,
1279
+ // Use job id as type
1280
+ payload: {}
1281
+ // Empty payload by default
1282
+ },
1283
+ describe: config.describe,
1284
+ enabled: config.enabled,
1285
+ permissions: definition.permissions
1286
+ };
1287
+ }
1288
+ };
1289
+ }
1290
+
1291
+ // src/define-command.ts
1292
+ function defineCommand(definition) {
1293
+ return {
1294
+ execute: (context, input) => {
1295
+ if (context.host !== "cli" && context.host !== "workflow") {
1296
+ throw new Error(
1297
+ `Command ${definition.id} can only run in CLI or workflow host (current: ${context.host})`
1298
+ );
1299
+ }
1300
+ return definition.handler.execute(context, input);
1301
+ },
1302
+ cleanup: definition.handler.cleanup
1303
+ };
1304
+ }
1305
+ function isCLIHost(hostContext) {
1306
+ return hostContext.host === "cli";
1307
+ }
1308
+
1309
+ // src/define-route.ts
1310
+ function defineRoute(definition) {
1311
+ const wrappedHandler = {
1312
+ execute: async (context, input) => {
1313
+ if (context.host !== "rest") {
1314
+ throw new Error(
1315
+ `Route ${definition.path} can only run in REST host (current: ${context.host})`
1316
+ );
1317
+ }
1318
+ if (isRESTHost(context.hostContext)) {
1319
+ const expectedMethod = definition.method.toUpperCase();
1320
+ const actualMethod = context.hostContext.method.toUpperCase();
1321
+ if (actualMethod !== expectedMethod) {
1322
+ throw new Error(
1323
+ `Route ${definition.path} expects ${expectedMethod} but got ${actualMethod}`
1324
+ );
1325
+ }
1326
+ }
1327
+ try {
1328
+ return await definition.handler.execute(context, input);
1329
+ } finally {
1330
+ await definition.handler.cleanup?.();
1331
+ }
1332
+ },
1333
+ cleanup: definition.handler.cleanup
1334
+ };
1335
+ return wrappedHandler;
1336
+ }
1337
+ function isRESTHost(hostContext) {
1338
+ return hostContext.host === "rest";
1339
+ }
1340
+
1341
+ // src/define-webhook.ts
1342
+ function defineWebhook(definition) {
1343
+ const wrappedHandler = {
1344
+ execute: async (context, input) => {
1345
+ if (context.host !== "webhook") {
1346
+ throw new Error(
1347
+ `Webhook ${definition.event} can only run in webhook host (current: ${context.host})`
1348
+ );
1349
+ }
1350
+ if (isWebhookHost(context.hostContext)) {
1351
+ const expectedEvent = definition.event;
1352
+ const actualEvent = context.hostContext.event;
1353
+ if (actualEvent !== expectedEvent) {
1354
+ throw new Error(
1355
+ `Webhook expects event ${expectedEvent} but got ${actualEvent}`
1356
+ );
1357
+ }
1358
+ }
1359
+ try {
1360
+ return await definition.handler.execute(context, input);
1361
+ } finally {
1362
+ await definition.handler.cleanup?.();
1363
+ }
1364
+ },
1365
+ cleanup: definition.handler.cleanup
1366
+ };
1367
+ return wrappedHandler;
1368
+ }
1369
+ function isWebhookHost(hostContext) {
1370
+ return hostContext.host === "webhook";
1371
+ }
1372
+
1373
+ // src/define-websocket.ts
1374
+ function validateWSMessage(message) {
1375
+ if (!message || typeof message !== "object") {
1376
+ throw new Error("Invalid WebSocket message: must be an object");
1377
+ }
1378
+ const msg = message;
1379
+ if (typeof msg.type !== "string" || msg.type.length === 0) {
1380
+ throw new Error("Invalid WebSocket message: type must be a non-empty string");
1381
+ }
1382
+ if (msg.timestamp !== void 0 && typeof msg.timestamp !== "number") {
1383
+ throw new Error("Invalid WebSocket message: timestamp must be a number");
1384
+ }
1385
+ if (msg.messageId !== void 0 && typeof msg.messageId !== "string") {
1386
+ throw new Error("Invalid WebSocket message: messageId must be a string");
1387
+ }
1388
+ }
1389
+ function createTypedSender(raw) {
1390
+ return {
1391
+ send: (msg) => raw.send(msg),
1392
+ broadcast: (msg, exclude) => raw.broadcast(msg, exclude),
1393
+ sendTo: (ids, msg) => raw.sendTo(ids, msg),
1394
+ close: raw.close.bind(raw),
1395
+ getConnectionId: raw.getConnectionId.bind(raw),
1396
+ raw
1397
+ };
1398
+ }
1399
+ function defineWebSocket(definition) {
1400
+ return {
1401
+ async execute(context, input) {
1402
+ if (context.host !== "ws") {
1403
+ throw new Error(
1404
+ `WebSocket channel ${definition.path} can only run in ws host (current: ${context.host})`
1405
+ );
1406
+ }
1407
+ if (isWSHost(context.hostContext)) {
1408
+ const expectedPath = definition.path;
1409
+ const actualPath = context.hostContext.channelPath;
1410
+ if (actualPath !== expectedPath) {
1411
+ throw new Error(
1412
+ `WebSocket expects channel ${expectedPath} but got ${actualPath}`
1413
+ );
1414
+ }
1415
+ }
1416
+ const sender = input.sender;
1417
+ if (!sender && input.event !== "disconnect") {
1418
+ throw new Error("WebSocket sender not provided in input");
1419
+ }
1420
+ const typedSender = sender ? createTypedSender(sender) : void 0;
1421
+ try {
1422
+ switch (input.event) {
1423
+ case "connect":
1424
+ if (typedSender) {
1425
+ await definition.handler.onConnect?.(context, typedSender);
1426
+ }
1427
+ break;
1428
+ case "message":
1429
+ if (input.message && typedSender && sender) {
1430
+ try {
1431
+ validateWSMessage(input.message);
1432
+ } catch (error) {
1433
+ context.platform.logger.error("Invalid WebSocket message received", error, {
1434
+ connectionId: sender.getConnectionId(),
1435
+ message: input.message
1436
+ });
1437
+ await sender.send({
1438
+ type: "error",
1439
+ payload: { error: "Invalid message format" },
1440
+ timestamp: Date.now()
1441
+ });
1442
+ break;
1443
+ }
1444
+ const incomingMessage = input.message;
1445
+ await definition.handler.onMessage?.(context, incomingMessage, typedSender);
1446
+ }
1447
+ break;
1448
+ case "disconnect":
1449
+ await definition.handler.onDisconnect?.(
1450
+ context,
1451
+ input.disconnectCode ?? 1e3,
1452
+ input.disconnectReason ?? ""
1453
+ );
1454
+ break;
1455
+ case "error":
1456
+ if (input.error && typedSender) {
1457
+ await definition.handler.onError?.(context, input.error, typedSender);
1458
+ }
1459
+ break;
1460
+ }
1461
+ } finally {
1462
+ await definition.handler.cleanup?.();
1463
+ }
1464
+ return { exitCode: 0 };
1465
+ }
1466
+ };
1467
+ }
1468
+ function isWSHost(hostContext) {
1469
+ return hostContext.host === "ws";
1470
+ }
1471
+
1472
+ // src/define-action.ts
1473
+ function defineAction(definition) {
1474
+ const wrappedHandler = {
1475
+ execute: (context, input) => {
1476
+ if (context.host !== "workflow") {
1477
+ throw new Error(
1478
+ `Action ${definition.id} can only run in workflow host (current: ${context.host})`
1479
+ );
1480
+ }
1481
+ return definition.handler.execute(context, input);
1482
+ },
1483
+ cleanup: definition.handler.cleanup
1484
+ };
1485
+ return wrappedHandler;
1486
+ }
1487
+ function isWorkflowHost(hostContext) {
1488
+ return hostContext.host === "workflow";
1489
+ }
1490
+
1491
+ // src/ws-types.ts
1492
+ var MessageBuilder = class {
1493
+ constructor(type) {
1494
+ this.type = type;
1495
+ }
1496
+ /**
1497
+ * Create message with payload
1498
+ */
1499
+ create(payload, messageId) {
1500
+ return {
1501
+ type: this.type,
1502
+ payload,
1503
+ messageId,
1504
+ timestamp: Date.now()
1505
+ };
1506
+ }
1507
+ /**
1508
+ * Match against incoming message type (type guard)
1509
+ */
1510
+ is(message) {
1511
+ return message.type === this.type;
1512
+ }
1513
+ };
1514
+ function defineMessage(type) {
1515
+ return new MessageBuilder(type);
1516
+ }
1517
+ var MessageRouter = class {
1518
+ handlers = /* @__PURE__ */ new Map();
1519
+ /**
1520
+ * Register message handler
1521
+ */
1522
+ on(message, handler) {
1523
+ this.handlers.set(message["type"], handler);
1524
+ return this;
1525
+ }
1526
+ /**
1527
+ * Handle incoming message
1528
+ *
1529
+ * @returns true if message was handled, false otherwise
1530
+ */
1531
+ async handle(ctx, message, sender) {
1532
+ const handler = this.handlers.get(message.type);
1533
+ if (handler) {
1534
+ await handler(ctx, message.payload, sender);
1535
+ return true;
1536
+ }
1537
+ return false;
1538
+ }
1539
+ };
1540
+
1541
+ export { FlagValidationError, MessageBuilder, MessageRouter, PluginError, array, artifactId, boolean, commandId, commonErrors, createAnalyticsWrapper, cwd, datetime, defineAction, defineCommand, defineCommandFlags, defineDestroyHandler, defineError, defineFlags, defineHandler, defineJob, defineManifest, defineMessage, defineRoute, defineSetupHandler, defineSystemCommand, defineSystemCommandGroup, defineWebSocket, defineWebhook, email, enumSchema, filePath, formatError, getLLMTier, isCLIHost, isCacheAvailable, isEmbeddingsAvailable, isLLMAvailable, isPlatformConfigured, isRESTHost, isVectorStoreAvailable, isWSHost, isWebhookHost, isWorkflowHost, json, nonNegativeInt, object, pluginId, positiveInt, schema, scopeId, text, trackAnalyticsEvent, trackEvent, url, useAnalytics, useCache, useConfig, useEmbeddings, useLLM, useLogger, useLoggerWithContext, usePlatform, useStorage, useVectorStore, uuid, validateFlags, validateFlagsSafe, withAnalytics };
1542
+ //# sourceMappingURL=index.js.map
1543
+ //# sourceMappingURL=index.js.map