@kb-labs/shared-command-kit 2.94.0 → 2.98.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.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { PluginContextV3, ManifestV3, PermissionSpec, JobDecl, CommandResult as CommandResult$1, HostContext, WSMessage, WSSender, WSInput } from '@kb-labs/plugin-contracts';
1
+ import { PluginContextV3, ManifestV3, CliGroupMeta, CliCommandDecl, PermissionSpec, RestRouteDecl, WebhookHandlerDecl, WebhookAuthConfig, JobDecl, CommandResult as CommandResult$1, MutateIntent, ExecuteIntent, HostContext, WSMessage, WSSender, WSInput } from '@kb-labs/plugin-contracts';
2
2
  export { PluginContextV3 } from '@kb-labs/plugin-contracts';
3
3
  import { FlagSchemaDefinition as FlagSchemaDefinition$1, InferFlags } from './flags/index.js';
4
4
  export { ArrayFlagSchema, BaseFlagSchema, BooleanFlagSchema, FlagSchema, FlagSchemaWithInfer, FlagType, FlagValidationError, NumberFlagSchema, SafeValidationResult, StringFlagSchema, ValidationResult, defineFlags, validateFlags, validateFlagsSafe } from './flags/index.js';
5
5
  export { AnalyticsContext, AnalyticsEvents, createAnalyticsWrapper, trackEvent, withAnalytics } from './analytics/index.js';
6
6
  export { ErrorDefinition, ErrorDefinitions, FormatErrorOptions, FormattedError, PluginError, commonErrors, defineError, formatError } from './errors/index.js';
7
- export { getLLMTier, isCacheAvailable, isEmbeddingsAvailable, isLLMAvailable, isPlatformConfigured, isVectorStoreAvailable, trackAnalyticsEvent, useAnalytics, useCache, useConfig, useEmbeddings, useEnv, useLLM, useLogger, useLoggerWithContext, usePlatform, useStorage, useVectorStore } from './helpers/index.js';
7
+ export { getLLMTier, isCacheAvailable, isDocumentDatabaseAvailable, isEmbeddingsAvailable, isKVStoreAvailable, isLLMAvailable, isPlatformConfigured, isVectorStoreAvailable, trackAnalyticsEvent, useAnalytics, useCache, useConfig, useDocumentDatabase, useEmbeddings, useEnv, useKVStore, useLLM, useLogger, useLoggerWithContext, useNotifications, usePlatform, useStorage, useVectorStore } from './helpers/index.js';
8
8
  import { z } from 'zod';
9
9
  export { CommandOutput } from '@kb-labs/shared-cli-ui';
10
10
  export { LLMTier, UseLLMOptions } from '@kb-labs/core-platform';
@@ -317,6 +317,213 @@ declare function defineCommandFlags<TFlags extends FlagSchemaDefinition>(flags:
317
317
  required?: boolean;
318
318
  }>;
319
319
 
320
+ /**
321
+ * Manifest helpers — optional, additive utilities for reducing boilerplate.
322
+ *
323
+ * Manifests can always be written as plain TypeScript literal objects.
324
+ * These helpers exist purely to cut repetition in the CLI commands and REST
325
+ * routes sections, which are the two highest-density areas.
326
+ *
327
+ * Inspired by:
328
+ * - Commander.js → cmd() fluent builder for CLI commands
329
+ * - Hono → GET/POST/... standalone functions for HTTP routes
330
+ * - Vite → createManifest() thin wrapper for type safety
331
+ */
332
+
333
+ /** Plugin identifier: must follow `@scope/name` format */
334
+ type PluginId = `@${string}/${string}`;
335
+ /** Semver string: `major.minor.patch[suffix]` */
336
+ type SemVer = `${number}.${number}.${number}${string}`;
337
+ /**
338
+ * Handler file reference.
339
+ * Must start with `./` and end with `.js` (optionally with `#exportName`).
340
+ * @example './commands/health.js'
341
+ * @example './commands/health.js#default'
342
+ */
343
+ type HandlerRef = `./${string}.js` | `./${string}.js#${string}`;
344
+ /** Base path for REST routes under the gateway. */
345
+ type RestBase = `/v1/plugins/${string}`;
346
+ /** Base path for WebSocket channels. */
347
+ type WsBase = `/v1/ws/plugins/${string}`;
348
+ type ManifestFlagDef = Record<string, {
349
+ type: 'string' | 'boolean' | 'number' | 'array';
350
+ alias?: string;
351
+ default?: unknown;
352
+ description?: string;
353
+ choices?: string[];
354
+ required?: boolean;
355
+ }>;
356
+ /**
357
+ * Fluent builder for a single CLI command declaration.
358
+ *
359
+ * Constructed via `cmd()` — not instantiated directly.
360
+ *
361
+ * @example
362
+ * ```ts
363
+ * cmd('workflow health', './commands/health.js#default', 'Check daemon health.')
364
+ * .read()
365
+ * .flags(healthFlags)
366
+ * .examples(['kb workflow health', 'kb workflow health --json'])
367
+ * ```
368
+ */
369
+ declare class CmdBuilder {
370
+ private readonly _state;
371
+ constructor(path: string, handler: string, describe: string);
372
+ /** operationType: 'read' — auto-injects --output, --limit, --offset */
373
+ read(): this;
374
+ /** operationType: 'mutate' — auto-injects --output, --dry-run, --yes */
375
+ mutate(): this;
376
+ /** operationType: 'execute' — auto-injects --output, --wait, --watch, --timeout, --yes */
377
+ execute(): this;
378
+ /** operationType: 'analyze' — auto-injects --output, --format, --stream */
379
+ analyze(): this;
380
+ /**
381
+ * Define command flags.
382
+ * Calls `defineCommandFlags()` internally — no need to wrap manually.
383
+ */
384
+ flags(def: ManifestFlagDef): this;
385
+ /** Long description shown in `--help` output. */
386
+ long(text: string): this;
387
+ /** Usage examples shown in `--help` output. */
388
+ examples(list: string[]): this;
389
+ /**
390
+ * Display category label.
391
+ * When using `group()`, the group's `category` is applied to commands
392
+ * that don't have their own category set.
393
+ */
394
+ category(cat: string): this;
395
+ /** Alternative full paths for this command. */
396
+ aliases(list: string[]): this;
397
+ /** Command-specific permissions (override plugin defaults). */
398
+ perms(spec: PermissionSpec): this;
399
+ /** Build the final `CliCommandDecl`. */
400
+ build(): CliCommandDecl;
401
+ }
402
+ /**
403
+ * Create a CLI command builder.
404
+ *
405
+ * Three required positional args cover the most repetitive fields.
406
+ * Everything else is chained: `.read()`, `.flags(def)`, `.examples([...])`.
407
+ *
408
+ * Eliminates:
409
+ * - `operationType: 'read' as const` → `.read()`
410
+ * - `flags: defineCommandFlags(def)` → `.flags(def)`
411
+ * - repeated `category: 'X'` → set once in `group()`
412
+ *
413
+ * @example
414
+ * ```ts
415
+ * cmd('workflow health', './commands/health.js#default', 'Check daemon health.')
416
+ * .read()
417
+ * .flags(healthFlags)
418
+ * .examples(['kb workflow health'])
419
+ * ```
420
+ */
421
+ declare function cmd(path: string, handler: HandlerRef, describe: string): CmdBuilder;
422
+ /** Result of `group()` — passed to `mergeCliGroups()` or spread manually. */
423
+ interface CliGroup {
424
+ meta: CliGroupMeta;
425
+ commands: CliCommandDecl[];
426
+ }
427
+ /**
428
+ * Group a set of commands under a shared `groupMeta` entry.
429
+ *
430
+ * If `meta.category` is provided, it is applied to every command inside
431
+ * that does not already have its own category set.
432
+ *
433
+ * @example
434
+ * ```ts
435
+ * const runsGroup = group(
436
+ * { path: 'workflow runs', describe: 'Run management', category: 'Runs' },
437
+ * [
438
+ * cmd('workflow runs list', './commands/runs-list.js#default', 'List runs.').read().flags(runsListFlags),
439
+ * cmd('workflow runs view', './commands/runs-view.js#default', 'View run details.').read().flags(runsViewFlags),
440
+ * ]
441
+ * );
442
+ * ```
443
+ */
444
+ declare function group(meta: {
445
+ path: string;
446
+ describe: string;
447
+ category?: string;
448
+ }, cmds: Array<CmdBuilder | CliCommandDecl>): CliGroup;
449
+ /**
450
+ * Merge multiple `CliGroup` results into a single `cli` section object.
451
+ *
452
+ * @example
453
+ * ```ts
454
+ * cli: mergeCliGroups(daemonGroup, jobsGroup, runsGroup),
455
+ * // → { commands: [...all commands], groupMeta: [...all group metas] }
456
+ * ```
457
+ */
458
+ declare function mergeCliGroups(...groups: CliGroup[]): Required<ManifestV3>['cli'];
459
+ type RouteOpts = Omit<RestRouteDecl, 'method' | 'path' | 'handler'>;
460
+ /**
461
+ * Declare a GET route.
462
+ * @example GET(ROUTES.STATS, './rest/stats.js#default', { describe: 'Get stats' })
463
+ */
464
+ declare const GET: (path: string, handler: HandlerRef, opts?: RouteOpts) => RestRouteDecl;
465
+ /**
466
+ * Declare a POST route.
467
+ * @example POST(ROUTES.RUN, './rest/run.js#default', { describe: 'Run workflow' })
468
+ */
469
+ declare const POST: (path: string, handler: HandlerRef, opts?: RouteOpts) => RestRouteDecl;
470
+ /**
471
+ * Declare a PUT route.
472
+ */
473
+ declare const PUT: (path: string, handler: HandlerRef, opts?: RouteOpts) => RestRouteDecl;
474
+ /**
475
+ * Declare a PATCH route.
476
+ */
477
+ declare const PATCH: (path: string, handler: HandlerRef, opts?: RouteOpts) => RestRouteDecl;
478
+ /**
479
+ * Declare a DELETE route.
480
+ */
481
+ declare const DELETE: (path: string, handler: HandlerRef, opts?: RouteOpts) => RestRouteDecl;
482
+ type WebhookOpts = Omit<WebhookHandlerDecl, 'event' | 'handler'>;
483
+ /**
484
+ * Declare a webhook handler in the plugin manifest.
485
+ *
486
+ * `auth` is required at the call site — the gateway will refuse to start if
487
+ * any webhook handler has no auth config.
488
+ *
489
+ * @example
490
+ * ```ts
491
+ * webhook('alert', './webhooks/alert.js#default', {
492
+ * auth: { type: 'secret', header: 'X-Webhook-Secret' },
493
+ * async: true,
494
+ * })
495
+ * ```
496
+ */
497
+ declare function webhook(event: string, handler: HandlerRef, opts: WebhookOpts & {
498
+ auth: WebhookAuthConfig;
499
+ }): WebhookHandlerDecl;
500
+ /**
501
+ * Create a type-safe `ManifestV3`.
502
+ *
503
+ * Provides branded-type validation for `id` and `version`, and
504
+ * automatically injects `schema: 'kb.plugin/3'`.
505
+ * Everything else is a plain literal object — no fluent chain.
506
+ *
507
+ * Writing manifests as plain object literals without this wrapper
508
+ * is always valid.
509
+ *
510
+ * @example
511
+ * ```ts
512
+ * export const manifest = createManifest('@kb-labs/workflow', '1.0.0', {
513
+ * display: { name: 'Workflow CLI' },
514
+ * cli: mergeCliGroups(daemonGroup, runsGroup),
515
+ * rest: {
516
+ * basePath: WORKFLOW_BASE_PATH,
517
+ * routes: [
518
+ * GET(ROUTES.STATS, './rest/stats.js#default', { describe: 'Dashboard stats' }),
519
+ * ],
520
+ * },
521
+ * permissions: pluginPermissions,
522
+ * });
523
+ * ```
524
+ */
525
+ declare function createManifest(id: PluginId, version: SemVer, body: Omit<ManifestV3, 'id' | 'version' | 'schema'>): ManifestV3;
526
+
320
527
  /**
321
528
  * Schema Builders for KB Labs Plugins
322
529
  *
@@ -984,6 +1191,13 @@ interface CommandHandlerV3<TConfig = unknown, TInput = unknown, TResult = unknow
984
1191
  * Execute the command
985
1192
  */
986
1193
  execute(context: PluginContextV3<TConfig>, input: TInput): Promise<CommandResult$1<TResult>> | CommandResult$1<TResult>;
1194
+ /**
1195
+ * Describe what the command *would* do without executing.
1196
+ * Implement this to support `--dry-run` for mutate/execute commands.
1197
+ * When present and `input.flags['dry-run']` is true, `defineCommand` calls
1198
+ * this instead of `execute` and renders the intent output automatically.
1199
+ */
1200
+ intent?(context: PluginContextV3<TConfig>, input: TInput): Promise<MutateIntent | ExecuteIntent>;
987
1201
  /**
988
1202
  * Optional cleanup - called after execute completes
989
1203
  */
@@ -1694,4 +1908,4 @@ interface CommandConfig<TFlags extends FlagSchemaDefinition$1 = FlagSchemaDefini
1694
1908
  formatter?: CommandFormatter<TConfig, InferFlags<TFlags>, TResult, TArgv, TEnv>;
1695
1909
  }
1696
1910
 
1697
- export { type ActionDefinition, type ActionHandler, type CLIInput, type Command, type CommandConfig, type CommandDefinition, type CommandFormatter, type CommandGroup, type CommandHandler, type CommandHandlerV3, type CommandResult, type CommandStatus, type ConfigUpdates, type DefinedJob, type DestroyHandlerDefinition, type ErrorResult, FlagSchemaDefinition$1 as FlagSchemaDefinition, type Handler, type HandlerDefinition, InferFlags, type JobDefinition, type JobHandler, type JobInput, type LifecycleContext, MessageBuilder, MessageRouter, type RestInput, type ResultWith, type RouteDefinition, type RouteHandler, type SetupHandlerDefinition, type SetupResult, type SuccessResult, type SystemCommandConfig, type TypedSender, type WebSocketDefinition, type WebSocketHandler, type WebhookDefinition, type WebhookHandler, type WorkspaceConfig, array, artifactId, boolean, commandId, cwd, datetime, defineAction, defineCommand, defineCommandFlags, defineDestroyHandler, defineHandler, defineJob, defineManifest, defineMessage, defineRoute, defineSetupHandler, defineSystemCommand, defineSystemCommandGroup, defineWebSocket, defineWebhook, email, enumSchema, filePath, isCLIHost, isRESTHost, isWSHost, isWebhookHost, isWorkflowHost, json, nonNegativeInt, object, pluginId, positiveInt, schema, scopeId, text, url, uuid };
1911
+ export { type ActionDefinition, type ActionHandler, type CLIInput, type CliGroup, CmdBuilder, type Command, type CommandConfig, type CommandDefinition, type CommandFormatter, type CommandGroup, type CommandHandler, type CommandHandlerV3, type CommandResult, type CommandStatus, type ConfigUpdates, DELETE, type DefinedJob, type DestroyHandlerDefinition, type ErrorResult, FlagSchemaDefinition$1 as FlagSchemaDefinition, GET, type Handler, type HandlerDefinition, type HandlerRef, InferFlags, type JobDefinition, type JobHandler, type JobInput, type LifecycleContext, MessageBuilder, MessageRouter, PATCH, POST, PUT, type PluginId, type RestBase, type RestInput, type ResultWith, type RouteDefinition, type RouteHandler, type SemVer, type SetupHandlerDefinition, type SetupResult, type SuccessResult, type SystemCommandConfig, type TypedSender, type WebSocketDefinition, type WebSocketHandler, type WebhookDefinition, type WebhookHandler, type WorkspaceConfig, type WsBase, array, artifactId, boolean, cmd, commandId, createManifest, cwd, datetime, defineAction, defineCommand, defineCommandFlags, defineDestroyHandler, defineHandler, defineJob, defineManifest, defineMessage, defineRoute, defineSetupHandler, defineSystemCommand, defineSystemCommandGroup, defineWebSocket, defineWebhook, email, enumSchema, filePath, group, isCLIHost, isRESTHost, isWSHost, isWebhookHost, isWorkflowHost, json, mergeCliGroups, nonNegativeInt, object, pluginId, positiveInt, schema, scopeId, text, url, uuid, webhook };
package/dist/index.js CHANGED
@@ -659,12 +659,34 @@ async function useConfig(productId, profileId) {
659
659
  if (!effectiveProductId) {
660
660
  return void 0;
661
661
  }
662
+ const g = globalThis;
663
+ const rawConfig = g.__KB_EFFECTIVE_CONFIG__ ?? g.__KB_RAW_CONFIG__;
664
+ if (rawConfig) {
665
+ return selectProductSection(rawConfig, effectiveProductId, profileId);
666
+ }
662
667
  const { usePlatform: usePlatform2 } = await Promise.resolve().then(() => (init_use_platform(), use_platform_exports));
663
668
  const platform = usePlatform2();
664
- if (!platform) {
665
- return void 0;
669
+ if (platform?.config) {
670
+ return await platform.config.getConfig(effectiveProductId, profileId);
671
+ }
672
+ return void 0;
673
+ }
674
+ function selectProductSection(rawConfig, productId, profileId) {
675
+ const effectiveProfileId = profileId ?? process.env.KB_PROFILE ?? "default";
676
+ const profilesField = rawConfig.profiles;
677
+ if (Array.isArray(profilesField)) {
678
+ const profiles = profilesField;
679
+ const profile = profiles.find((p) => p.id === effectiveProfileId) ?? profiles[0];
680
+ if (profile?.products?.[productId] !== void 0) {
681
+ return profile.products[productId];
682
+ }
683
+ }
684
+ const legacyKeyMap = { mind: "knowledge" };
685
+ const legacyKey = legacyKeyMap[productId] ?? productId;
686
+ if (rawConfig[legacyKey] !== void 0) {
687
+ return rawConfig[legacyKey];
666
688
  }
667
- return await platform.config.getConfig(effectiveProductId, profileId);
689
+ return void 0;
668
690
  }
669
691
 
670
692
  // src/helpers/use-logger.ts
@@ -878,6 +900,33 @@ function isCacheAvailable() {
878
900
  const cache = useCache();
879
901
  return !!cache;
880
902
  }
903
+
904
+ // src/helpers/use-document-database.ts
905
+ init_use_platform();
906
+ function useDocumentDatabase() {
907
+ const platform = usePlatform();
908
+ return platform.documentDatabase;
909
+ }
910
+ function isDocumentDatabaseAvailable() {
911
+ return useDocumentDatabase() !== void 0;
912
+ }
913
+
914
+ // src/helpers/use-kv-store.ts
915
+ init_use_platform();
916
+ function useKVStore() {
917
+ const platform = usePlatform();
918
+ return platform.kvStore;
919
+ }
920
+ function isKVStoreAvailable() {
921
+ return useKVStore() !== void 0;
922
+ }
923
+
924
+ // src/helpers/use-notifications.ts
925
+ init_use_platform();
926
+ function useNotifications() {
927
+ const platform = usePlatform();
928
+ return platform.notifier;
929
+ }
881
930
  function useEnv(key) {
882
931
  const runtime = runtimeContext.getStore();
883
932
  if (runtime?.env) {
@@ -984,6 +1033,142 @@ function defineCommandFlags(flags) {
984
1033
  ...flag.required !== void 0 && { required: flag.required }
985
1034
  }));
986
1035
  }
1036
+
1037
+ // src/manifest-builder.ts
1038
+ var CmdBuilder = class {
1039
+ _state;
1040
+ constructor(path2, handler, describe) {
1041
+ this._state = { path: path2, handler, describe };
1042
+ }
1043
+ /** operationType: 'read' — auto-injects --output, --limit, --offset */
1044
+ read() {
1045
+ this._state.operationType = "read";
1046
+ return this;
1047
+ }
1048
+ /** operationType: 'mutate' — auto-injects --output, --dry-run, --yes */
1049
+ mutate() {
1050
+ this._state.operationType = "mutate";
1051
+ return this;
1052
+ }
1053
+ /** operationType: 'execute' — auto-injects --output, --wait, --watch, --timeout, --yes */
1054
+ execute() {
1055
+ this._state.operationType = "execute";
1056
+ return this;
1057
+ }
1058
+ /** operationType: 'analyze' — auto-injects --output, --format, --stream */
1059
+ analyze() {
1060
+ this._state.operationType = "analyze";
1061
+ return this;
1062
+ }
1063
+ /**
1064
+ * Define command flags.
1065
+ * Calls `defineCommandFlags()` internally — no need to wrap manually.
1066
+ */
1067
+ flags(def) {
1068
+ this._state.flags = defineCommandFlags(def);
1069
+ return this;
1070
+ }
1071
+ /** Long description shown in `--help` output. */
1072
+ long(text2) {
1073
+ this._state.longDescription = text2;
1074
+ return this;
1075
+ }
1076
+ /** Usage examples shown in `--help` output. */
1077
+ examples(list) {
1078
+ this._state.examples = list;
1079
+ return this;
1080
+ }
1081
+ /**
1082
+ * Display category label.
1083
+ * When using `group()`, the group's `category` is applied to commands
1084
+ * that don't have their own category set.
1085
+ */
1086
+ category(cat) {
1087
+ this._state.category = cat;
1088
+ return this;
1089
+ }
1090
+ /** Alternative full paths for this command. */
1091
+ aliases(list) {
1092
+ this._state.aliases = list;
1093
+ return this;
1094
+ }
1095
+ /** Command-specific permissions (override plugin defaults). */
1096
+ perms(spec) {
1097
+ this._state.permissions = spec;
1098
+ return this;
1099
+ }
1100
+ /** Build the final `CliCommandDecl`. */
1101
+ build() {
1102
+ const decl = {
1103
+ path: this._state.path,
1104
+ handler: this._state.handler,
1105
+ describe: this._state.describe
1106
+ };
1107
+ if (this._state.operationType !== void 0) {
1108
+ decl.operationType = this._state.operationType;
1109
+ }
1110
+ if (this._state.longDescription !== void 0) {
1111
+ decl.longDescription = this._state.longDescription;
1112
+ }
1113
+ if (this._state.flags !== void 0) {
1114
+ decl.flags = this._state.flags;
1115
+ }
1116
+ if (this._state.examples !== void 0) {
1117
+ decl.examples = this._state.examples;
1118
+ }
1119
+ if (this._state.category !== void 0) {
1120
+ decl.category = this._state.category;
1121
+ }
1122
+ if (this._state.aliases !== void 0) {
1123
+ decl.aliases = this._state.aliases;
1124
+ }
1125
+ if (this._state.permissions !== void 0) {
1126
+ decl.permissions = this._state.permissions;
1127
+ }
1128
+ return decl;
1129
+ }
1130
+ };
1131
+ function cmd(path2, handler, describe) {
1132
+ return new CmdBuilder(path2, handler, describe);
1133
+ }
1134
+ function group(meta, cmds) {
1135
+ const commands = cmds.map((c) => {
1136
+ const decl = c instanceof CmdBuilder ? c.build() : c;
1137
+ if (meta.category !== void 0 && decl.category === void 0) {
1138
+ return { ...decl, category: meta.category };
1139
+ }
1140
+ return decl;
1141
+ });
1142
+ return {
1143
+ meta: { path: meta.path, describe: meta.describe },
1144
+ commands
1145
+ };
1146
+ }
1147
+ function mergeCliGroups(...groups) {
1148
+ return {
1149
+ commands: groups.flatMap((g) => g.commands),
1150
+ groupMeta: groups.map((g) => g.meta)
1151
+ };
1152
+ }
1153
+ function routeHelper(method, path2, handler, opts) {
1154
+ return { method, path: path2, handler, ...opts };
1155
+ }
1156
+ var GET = (path2, handler, opts) => routeHelper("GET", path2, handler, opts);
1157
+ var POST = (path2, handler, opts) => routeHelper("POST", path2, handler, opts);
1158
+ var PUT = (path2, handler, opts) => routeHelper("PUT", path2, handler, opts);
1159
+ var PATCH = (path2, handler, opts) => routeHelper("PATCH", path2, handler, opts);
1160
+ var DELETE = (path2, handler, opts) => routeHelper("DELETE", path2, handler, opts);
1161
+ function webhook(event, handler, opts) {
1162
+ return { event, handler, ...opts };
1163
+ }
1164
+ function createManifest(id, version, body) {
1165
+ return {
1166
+ schema: "kb.plugin/3",
1167
+ id,
1168
+ version,
1169
+ ...body
1170
+ };
1171
+ }
987
1172
  function cwd() {
988
1173
  return z.string().optional().describe("Current working directory path");
989
1174
  }
@@ -1313,11 +1498,35 @@ function defineCommand(definition) {
1313
1498
  `Command ${definition.id} can only run in CLI or workflow host (current: ${context.host})`
1314
1499
  );
1315
1500
  }
1501
+ const flags = input?.flags;
1502
+ if (flags?.["dry-run"] && typeof definition.handler.intent === "function") {
1503
+ return (async () => {
1504
+ const intent = await definition.handler.intent(context, input);
1505
+ renderDryRunIntent(context.ui, intent);
1506
+ return { exitCode: 0, result: intent };
1507
+ })();
1508
+ }
1316
1509
  return definition.handler.execute(context, input);
1317
1510
  },
1318
1511
  cleanup: definition.handler.cleanup
1319
1512
  };
1320
1513
  }
1514
+ function renderDryRunIntent(ui, intent) {
1515
+ if ("operations" in intent) {
1516
+ ui.info(`Dry-run: ${intent.summary}`, {
1517
+ sections: [{
1518
+ header: "Operations",
1519
+ items: intent.operations.map((op) => {
1520
+ const detail = op.details ? ` \u2014 ${JSON.stringify(op.details)}` : "";
1521
+ return `${op.type.toUpperCase()} ${op.resource}${detail}`;
1522
+ })
1523
+ }]
1524
+ });
1525
+ } else {
1526
+ const hint = intent.estimatedDurationMs ? ` (~${Math.round(intent.estimatedDurationMs / 1e3)}s)` : "";
1527
+ ui.info(`Dry-run: ${intent.summary}${hint}`);
1528
+ }
1529
+ }
1321
1530
  function isCLIHost(hostContext) {
1322
1531
  return hostContext.host === "cli";
1323
1532
  }
@@ -1556,6 +1765,6 @@ var MessageRouter = class {
1556
1765
  }
1557
1766
  };
1558
1767
 
1559
- 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, useEnv, useLLM, useLogger, useLoggerWithContext, usePlatform, useStorage, useVectorStore, uuid, validateFlags, validateFlagsSafe, withAnalytics };
1768
+ export { CmdBuilder, DELETE, FlagValidationError, GET, MessageBuilder, MessageRouter, PATCH, POST, PUT, PluginError, array, artifactId, boolean, cmd, commandId, commonErrors, createAnalyticsWrapper, createManifest, cwd, datetime, defineAction, defineCommand, defineCommandFlags, defineDestroyHandler, defineError, defineFlags, defineHandler, defineJob, defineManifest, defineMessage, defineRoute, defineSetupHandler, defineSystemCommand, defineSystemCommandGroup, defineWebSocket, defineWebhook, email, enumSchema, filePath, formatError, getLLMTier, group, isCLIHost, isCacheAvailable, isDocumentDatabaseAvailable, isEmbeddingsAvailable, isKVStoreAvailable, isLLMAvailable, isPlatformConfigured, isRESTHost, isVectorStoreAvailable, isWSHost, isWebhookHost, isWorkflowHost, json, mergeCliGroups, nonNegativeInt, object, pluginId, positiveInt, schema, scopeId, text, trackAnalyticsEvent, trackEvent, url, useAnalytics, useCache, useConfig, useDocumentDatabase, useEmbeddings, useEnv, useKVStore, useLLM, useLogger, useLoggerWithContext, useNotifications, usePlatform, useStorage, useVectorStore, uuid, validateFlags, validateFlagsSafe, webhook, withAnalytics };
1560
1769
  //# sourceMappingURL=index.js.map
1561
1770
  //# sourceMappingURL=index.js.map